diff --git a/.asf.yaml b/.asf.yaml new file mode 100644 index 0000000000..c43fe91b7f --- /dev/null +++ b/.asf.yaml @@ -0,0 +1,23 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +notifications: + commits: commits@mynewt.apache.org + issues: notifications@mynewt.apache.org + pullrequests: notifications@mynewt.apache.org diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000000..193a5f6b51 --- /dev/null +++ b/.clang-format @@ -0,0 +1,88 @@ +# Use LLVM style as a base +BasedOnStyle: LLVM + +# Indentation settings +IndentWidth: 4 +UseTab: Never +TabWidth: 10 + +# Line length +ColumnLimit: 79 +PenaltyExcessCharacter: 2 + +# Braces placement +BreakBeforeBraces: Custom +BraceWrapping: + AfterClass: true + AfterControlStatement: false + AfterEnum: false + AfterFunction: true + AfterNamespace: true + AfterStruct: false + AfterUnion: false + BeforeCatch: false + BeforeElse: false + IndentBraces: false + SplitEmptyFunction: false + SplitEmptyRecord: false + SplitEmptyNamespace: false + +MacroBlockBegin: '(STATS_NAME_START|STATS_SECT_START)' +MacroBlockEnd: '(STATS_NAME_END|STATS_SECT_END)' +StatementMacros: ['SLIST_HEAD'] + +ForEachMacros: + - 'LINK_TABLE_FOREACH' + - 'SLIST_FOREACH' + - 'SLIST_FOREACH_FROM' + - 'SLIST_FOREACH_SAFE' + - 'SLIST_FOREACH_FROM_SAFE' + - 'SLIST_FOREACH_PREVPTR' + - 'STAILQ_FOREACH' + - 'STAILQ_FOREACH_FROM' + - 'STAILQ_FOREACH_SAFE' + - 'STAILQ_FOREACH_FROM_SAFE' + - 'LIST_FOREACH' + - 'LIST_FOREACH_FROM' + - 'LIST_FOREACH_SAFE' + - 'LIST_FOREACH_FROM_SAFE' + - 'TAILQ_FOREACH' + - 'TAILQ_FOREACH_FROM' + - 'TAILQ_FOREACH_SAFE' + - 'TAILQ_FOREACH_FROM_SAFE' + - 'TAILQ_FOREACH_REVERSE' + - 'TAILQ_FOREACH_REVERSE_FROM' + - 'TAILQ_FOREACH_REVERSE_SAFE' + - 'TAILQ_FOREACH_REVERSE_FROM_SAFE' + +# Pointer and reference alignment +PointerAlignment: Right + +# Function declaration formatting +AllowAllParametersOfDeclarationOnNextLine: false +BinPackParameters: true +BinPackArguments: true +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignConsecutiveMacros: true + +# Control statements +AlwaysBreakAfterReturnType: TopLevelDefinitions +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AllowShortFunctionsOnASingleLine: InlineOnly +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false + +Cpp11BracedListStyle: false +SpacesInParentheses: false +SpaceAfterCStyleCast: false +SpaceBeforeParens: ControlStatementsExceptControlMacros +SpaceInEmptyParentheses: false +BreakStringLiterals: false + +AlignArrayOfStructures: Left +SortIncludes: false +DisableFormat: false +InsertNewlineAtEOF: true diff --git a/.github/LICENSE_TEMPLATE b/.github/LICENSE_TEMPLATE new file mode 100644 index 0000000000..80b586513c --- /dev/null +++ b/.github/LICENSE_TEMPLATE @@ -0,0 +1,18 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ diff --git a/.github/check_doxygen.py b/.github/check_doxygen.py new file mode 100755 index 0000000000..0f47a10bc0 --- /dev/null +++ b/.github/check_doxygen.py @@ -0,0 +1,115 @@ +#!/usr/bin/env python3 + +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +import os +import re +import subprocess +import sys +from pathlib import Path + +TMP_FOLDER = "/tmp/doxygen_check" +WARN_FILE_NAME = "warnings.log" +allowed_files = [ + "nimble/include/nimble/ble.h", +] + + +def run_cmd(cmd: str) -> list[str]: + out = subprocess.check_output(cmd, text=True, shell=True) + return out.splitlines() + + +def run_cmd_no_check(cmd: str) -> list[str]: + out = subprocess.run(cmd, text=True, shell=True, stdout=subprocess.PIPE, + stderr=subprocess.DEVNULL).stdout + return out.splitlines() + + +def is_ignored(filename: str, allowed: list[str]) -> bool: + if Path(filename).suffix != ".h" or "priv" in filename: + return True + if filename in allowed: + return False + if re.search(r"nimble/host.*include.*", filename): + return False + + return True + + +def main() -> bool: + if len(sys.argv) > 1: + commit = sys.argv[1] + else: + commit = "HEAD" + if len(sys.argv) > 2: + upstream = sys.argv[2] + else: + upstream = "origin/master" + + mb = run_cmd(f"git merge-base {upstream} {commit}") + upstream = mb[0] + + results_ok = [] + results_fail = [] + results_ign = [] + + os.makedirs(Path(TMP_FOLDER, WARN_FILE_NAME).parent, mode=0o755, + exist_ok=True) + + files = run_cmd(f"git diff --diff-filter=AM --name-only {upstream} {commit}") + for fname in files: + if is_ignored(fname, allowed_files): + results_ign.append(fname) + continue + + os.environ['DOXYGEN_INPUT'] = fname + try: + run_cmd_no_check("doxygen") + + except subprocess.CalledProcessError as e: + print(f"\033[31m[FAIL] {e.returncode}\033[0m") + return False + + with open(os.path.join(TMP_FOLDER, WARN_FILE_NAME)) as warn_log: + warnings = warn_log.read() + if len(warnings) == 0: + results_ok.append(fname) + else: + results_fail.append((fname, warnings)) + + for fname in results_ign: + print(f"\033[90m[ NA ] {fname}\033[0m") + for fname in results_ok: + print(f"\033[32m[ OK ] {fname}\033[0m") + for fname, warnings in results_fail: + print(f"\033[31m[FAIL] {fname}\033[0m") + print(warnings) + + if len(results_fail) > 0: + print(f"\033[31mYour code has documentation style problems, see the logs " + f"for details.\033[0m") + + return len(results_fail) == 0 + + +if __name__ == "__main__": + if not main(): + sys.exit(1) diff --git a/.github/labeler_cfg.yml b/.github/labeler_cfg.yml new file mode 100644 index 0000000000..45e245cf58 --- /dev/null +++ b/.github/labeler_cfg.yml @@ -0,0 +1,30 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +host: + - changed-files: + - any-glob-to-any-file: nimble/host/** + +controller: + - changed-files: + - any-glob-to-any-file: nimble/controller/** + +CI: + - changed-files: + - any-glob-to-any-file: .github/workflows/** diff --git a/.github/project.yml b/.github/project.yml new file mode 100644 index 0000000000..c030061996 --- /dev/null +++ b/.github/project.yml @@ -0,0 +1,36 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +project.name: "my_project" + +project.repositories: + - apache-mynewt-core + +# Use github's distribution mechanism for core ASF libraries. +# This provides mirroring automatically for us. +# +repository.apache-mynewt-core: + type: github + vers: 0.0.0 + user: apache + repo: mynewt-core + +project.repositories.ignored: + - stm-* + - atmel-samd21xx diff --git a/.github/project_newt_test_all.yml b/.github/project_newt_test_all.yml new file mode 100644 index 0000000000..960c844bad --- /dev/null +++ b/.github/project_newt_test_all.yml @@ -0,0 +1,39 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +project.name: "my_project" + +project.repositories: + - apache-mynewt-core + +# Use github's distribution mechanism for core ASF libraries. +# This provides mirroring automatically for us. +# +repository.apache-mynewt-core: + type: github + vers: 0.0.0 + user: apache + repo: mynewt-core + +project.repositories.allowed: + - apache-mynewt-core + - apache-mynewt-nimble + - apache-mynewt-mcumgr + - mcuboot + - mbedtls diff --git a/.github/targets/nordic_pca10028_blehci/pkg.yml b/.github/targets/nordic_pca10028_blehci/pkg.yml new file mode 100644 index 0000000000..1cf0a3629c --- /dev/null +++ b/.github/targets/nordic_pca10028_blehci/pkg.yml @@ -0,0 +1,26 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +### Package: "targets/blehci-nordic_pca10028 +pkg.name: "targets/nordic_pca10028_blehci" +pkg.type: "target" +pkg.description: +pkg.author: +pkg.homepage: + diff --git a/nimble/transport/da1469x/cmac_driver/syscfg.yml b/.github/targets/nordic_pca10028_blehci/syscfg.yml similarity index 81% rename from nimble/transport/da1469x/cmac_driver/syscfg.yml rename to .github/targets/nordic_pca10028_blehci/syscfg.yml index be2e62d900..90a965d2af 100644 --- a/nimble/transport/da1469x/cmac_driver/syscfg.yml +++ b/.github/targets/nordic_pca10028_blehci/syscfg.yml @@ -1,3 +1,4 @@ +# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information @@ -16,8 +17,9 @@ # under the License. # -syscfg.defs: - CMAC_IMAGE_FILE_NAME: - description: > - Path to library with CMAC firmware. See README for details. - value: "libble_stack_da1469x.a" +syscfg.vals: + BLE_MAX_CONNECTIONS: 4 + + BLE_TRANSPORT_UART_BAUDRATE: 115200 + BLE_TRANSPORT_UART_FLOW_CONTROL: off + BLE_TRANSPORT_ACL_SIZE: 128 diff --git a/.github/targets/nordic_pca10028_blehci/target.yml b/.github/targets/nordic_pca10028_blehci/target.yml new file mode 100644 index 0000000000..fe0f6a6db5 --- /dev/null +++ b/.github/targets/nordic_pca10028_blehci/target.yml @@ -0,0 +1,23 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +### Target: targets/blehci-nordic_pca10028 +target.app: "@apache-mynewt-nimble/apps/blehci" +target.bsp: "@apache-mynewt-core/hw/bsp/nordic_pca10028" +target.build_profile: "optimized" diff --git a/.github/targets/nordic_pca10056-blehci-usb/pkg.yml b/.github/targets/nordic_pca10056-blehci-usb/pkg.yml new file mode 100644 index 0000000000..2c8307d3df --- /dev/null +++ b/.github/targets/nordic_pca10056-blehci-usb/pkg.yml @@ -0,0 +1,27 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +pkg.name: "targets/nordic_pca10056-blehci-usb" +pkg.type: target +pkg.description: +pkg.author: +pkg.homepage: + +pkg.deps: + - "@apache-mynewt-core/hw/usb/tinyusb" + - "@apache-mynewt-core/hw/usb/tinyusb/std_descriptors" diff --git a/nimble/drivers/nrf5340/syscfg.yml b/.github/targets/nordic_pca10056-blehci-usb/syscfg.yml similarity index 85% rename from nimble/drivers/nrf5340/syscfg.yml rename to .github/targets/nordic_pca10056-blehci-usb/syscfg.yml index dd8b93047c..0c5701a98b 100644 --- a/nimble/drivers/nrf5340/syscfg.yml +++ b/.github/targets/nordic_pca10056-blehci-usb/syscfg.yml @@ -16,8 +16,9 @@ # under the License. # -syscfg.defs: - BLE_PHY_SYSVIEW: - description: > - Enable SystemView tracing module for radio driver. - value: 0 +syscfg.vals: + BLE_TRANSPORT_HS: usb + USBD_BTH: 1 + + USBD_PID: 0xC01A + USBD_VID: 0xC0CA diff --git a/.github/targets/nordic_pca10056-blehci-usb/target.yml b/.github/targets/nordic_pca10056-blehci-usb/target.yml new file mode 100644 index 0000000000..ce455d45c9 --- /dev/null +++ b/.github/targets/nordic_pca10056-blehci-usb/target.yml @@ -0,0 +1,21 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +target.app: "@apache-mynewt-nimble/apps/blehci" +target.bsp: "@apache-mynewt-core/hw/bsp/nordic_pca10056" +target.build_profile: debug diff --git a/.github/targets/nordic_pca10056_blehci/pkg.yml b/.github/targets/nordic_pca10056_blehci/pkg.yml new file mode 100644 index 0000000000..b66dab9879 --- /dev/null +++ b/.github/targets/nordic_pca10056_blehci/pkg.yml @@ -0,0 +1,25 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +pkg.name: "targets/nordic_pca10056_blehci" +pkg.type: "target" +pkg.description: +pkg.author: +pkg.homepage: + diff --git a/.github/targets/nordic_pca10056_blehci/target.yml b/.github/targets/nordic_pca10056_blehci/target.yml new file mode 100644 index 0000000000..103dd2996c --- /dev/null +++ b/.github/targets/nordic_pca10056_blehci/target.yml @@ -0,0 +1,21 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +target.app: "@apache-mynewt-nimble/apps/blehci" +target.bsp: "@apache-mynewt-core/hw/bsp/nordic_pca10056" diff --git a/.github/targets/nordic_pca10056_btshell/pkg.yml b/.github/targets/nordic_pca10056_btshell/pkg.yml new file mode 100644 index 0000000000..adcbd6990a --- /dev/null +++ b/.github/targets/nordic_pca10056_btshell/pkg.yml @@ -0,0 +1,25 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +### Package: "targets/nordic_pca10056_btshell +pkg.name: "targets/nordic_pca10056_btshell" +pkg.type: "target" +pkg.description: +pkg.author: +pkg.homepage: diff --git a/.github/targets/nordic_pca10056_btshell/target.yml b/.github/targets/nordic_pca10056_btshell/target.yml new file mode 100644 index 0000000000..be48db4ac3 --- /dev/null +++ b/.github/targets/nordic_pca10056_btshell/target.yml @@ -0,0 +1,23 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +### Target: targets/nordic_pca10056_btshell +target.app: "@apache-mynewt-nimble/apps/btshell" +target.bsp: "@apache-mynewt-core/hw/bsp/nordic_pca10056" +target.build_profile: "debug" diff --git a/.github/targets/nordic_pca10095_blehci/pkg.yml b/.github/targets/nordic_pca10095_blehci/pkg.yml new file mode 100644 index 0000000000..21fa5f2cd7 --- /dev/null +++ b/.github/targets/nordic_pca10095_blehci/pkg.yml @@ -0,0 +1,26 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +### Package: "targets/blehci-nordic_pca10095 +pkg.name: "targets/nordic_pca10095_blehci" +pkg.type: "target" +pkg.description: +pkg.author: +pkg.homepage: + diff --git a/.github/targets/nordic_pca10095_blehci/syscfg.yml b/.github/targets/nordic_pca10095_blehci/syscfg.yml new file mode 100644 index 0000000000..4c16ba61c6 --- /dev/null +++ b/.github/targets/nordic_pca10095_blehci/syscfg.yml @@ -0,0 +1,39 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +syscfg.vals: + BLE_MAX_CONNECTIONS: 4 + BLE_PHY_2M: 1 + BLE_PHY_CODED: 1 + + + BLE_LL_CFG_FEAT_DATA_LEN_EXT: 1 + BLE_LL_CFG_FEAT_LL_PRIVACY: 1 + BLE_LL_CONN_INIT_MAX_TX_BYTES: 251 + BLE_LL_CONN_INIT_SLOTS: 4 + BLE_LL_DTM: 1 + BLE_LL_DTM_EXTENSIONS: 1 + BLE_LL_HCI_VS_EVENT_ON_ASSERT: 1 + BLE_MAX_CONNECTIONS: 5 + BLE_MAX_PERIODIC_SYNCS: 5 + BLE_MULTI_ADV_INSTANCES: 5 + BLE_EXT_ADV: 1 + BLE_PERIODIC_ADV: 1 + BLE_PERIODIC_ADV_SYNC_TRANSFER: 1 + BLE_VERSION: 51 diff --git a/.github/targets/nordic_pca10095_blehci/target.yml b/.github/targets/nordic_pca10095_blehci/target.yml new file mode 100644 index 0000000000..854cd3dab6 --- /dev/null +++ b/.github/targets/nordic_pca10095_blehci/target.yml @@ -0,0 +1,23 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +### Target: targets/blehci-nordic_pca10095 +target.app: "@apache-mynewt-nimble/apps/blehci" +target.bsp: "@apache-mynewt-core/hw/bsp/nordic_pca10095_net" +target.build_profile: "debug" diff --git a/.github/targets/nordic_pca10095_btshell/pkg.yml b/.github/targets/nordic_pca10095_btshell/pkg.yml new file mode 100644 index 0000000000..c669e30ea3 --- /dev/null +++ b/.github/targets/nordic_pca10095_btshell/pkg.yml @@ -0,0 +1,25 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +### Package: "targets/nordic_pca10056_btshell +pkg.name: "targets/nordic_pca10095_btshell" +pkg.type: "target" +pkg.description: +pkg.author: +pkg.homepage: diff --git a/.github/targets/nordic_pca10095_btshell/syscfg.yml b/.github/targets/nordic_pca10095_btshell/syscfg.yml new file mode 100644 index 0000000000..c37554dcd4 --- /dev/null +++ b/.github/targets/nordic_pca10095_btshell/syscfg.yml @@ -0,0 +1,21 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +syscfg.vals: + BSP_NRF5340_NET_ENABLE: 1 diff --git a/.github/targets/nordic_pca10095_btshell/target.yml b/.github/targets/nordic_pca10095_btshell/target.yml new file mode 100644 index 0000000000..ffbee16b4b --- /dev/null +++ b/.github/targets/nordic_pca10095_btshell/target.yml @@ -0,0 +1,23 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +### Target: targets/nordic_pca10095_btshell +target.app: "@apache-mynewt-nimble/apps/btshell" +target.bsp: "@apache-mynewt-core/hw/bsp/nordic_pca10095" +target.build_profile: "debug" diff --git a/.github/targets_linux/native_btshell/pkg.yml b/.github/targets_linux/native_btshell/pkg.yml new file mode 100644 index 0000000000..a252525536 --- /dev/null +++ b/.github/targets_linux/native_btshell/pkg.yml @@ -0,0 +1,24 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +pkg.name: targets/native_btshell +pkg.type: target +pkg.description: +pkg.author: +pkg.homepage: diff --git a/.github/targets_linux/native_btshell/syscfg.yml b/.github/targets_linux/native_btshell/syscfg.yml new file mode 100644 index 0000000000..e3d568e15c --- /dev/null +++ b/.github/targets_linux/native_btshell/syscfg.yml @@ -0,0 +1,25 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +syscfg.vals: + BLE_TRANSPORT_LL: socket + BLE_SOCK_USE_LINUX_BLUE: 1 + BLE_SOCK_LINUX_DEV: 0 + BLE_SOCK_USE_TCP: 0 + diff --git a/.github/targets_linux/native_btshell/target.yml b/.github/targets_linux/native_btshell/target.yml new file mode 100644 index 0000000000..a95cc6072f --- /dev/null +++ b/.github/targets_linux/native_btshell/target.yml @@ -0,0 +1,23 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +target.app: "@apache-mynewt-nimble/apps/btshell" +target.bsp: "@apache-mynewt-core/hw/bsp/native" +target.build_profile: debug + diff --git a/.github/test_build_apps.sh b/.github/test_build_apps.sh new file mode 100644 index 0000000000..cbf25cfffa --- /dev/null +++ b/.github/test_build_apps.sh @@ -0,0 +1,60 @@ +#!/bin/bash -x + +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +EXIT_CODE=0 + +APPS=$(basename -a `ls -d repos/apache-mynewt-nimble/apps/*/`) + +IGNORED_APPS="mesh_badge" + +for app in ${APPS}; do + # NOTE: do not remove the spaces around IGNORED_APPS; it's required to + # match against the first and last entries + if [[ " ${IGNORED_APPS} " =~ [[:blank:]]${app}[[:blank:]] ]]; then + echo "Skipping $app" + continue + fi + + echo "Testing $app" + + target="test-$app" + newt target delete -s -f $target &> /dev/null + newt target create -s $target + newt target set -s $target bsp="@apache-mynewt-core/hw/bsp/nordic_pca10056" + newt target set -s $target app="@apache-mynewt-nimble/apps/$app" + + echo "Building with app default config" + newt build -q $target + + rc=$? + [[ $rc -ne 0 ]] && EXIT_CODE=$rc + + echo "Building with all-enabled config" + newt clean $target + cp -f ../.github/test_build_apps_syscfg.yml targets/$target/syscfg.yml + newt build -q $target + + rc=$? + [[ $rc -ne 0 ]] && EXIT_CODE=$rc + + newt clean $target + newt target delete -s -f $target +done + +exit $EXIT_CODE diff --git a/.github/test_build_apps_syscfg.yml b/.github/test_build_apps_syscfg.yml new file mode 100644 index 0000000000..a83a5c3d87 --- /dev/null +++ b/.github/test_build_apps_syscfg.yml @@ -0,0 +1,66 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +syscfg.vals: + # common + BLE_ROLE_CENTRAL: 1 + BLE_ROLE_PERIPHERAL: 1 + BLE_ROLE_BROADCASTER: 1 + BLE_ROLE_OBSERVER: 1 + BLE_WHITELIST: 1 + BLE_PERIODIC_ADV_SYNC_BIGINFO_REPORTS: 1 + BLE_ISO: 1 + BLE_ISO_TEST: 1 + BLE_AUDIO: 1 + BLE_AUDIO_BROADCAST_SINK: 1 + BLE_AUDIO_SCAN_DELEGATOR: 1 + BLE_ISO_BROADCAST_SINK: 1 + BLE_ISO_BROADCAST_SOURCE: 1 + BLE_HCI_VS: 1 + BLE_POWER_CONTROL: 1 + BLE_CONN_SUBRATING: 1 + BLE_EXT_ADV: 1 + BLE_EXT_ADV_MAX_SIZE: 1650 + BLE_VERSION: 54 + BLE_MULTI_ADV_INSTANCES: 5 + BLE_PERIODIC_ADV: 1 + BLE_MAX_PERIODIC_SYNCS: 5 + + # host + BLE_EDDYSTONE: 1 + BLE_HS_DEBUG: 1 + BLE_L2CAP_COC_MAX_NUM: 5 + BLE_L2CAP_ENHANCED_COC: 1 + BLE_MAX_CONNECTIONS: 5 + BLE_MONITOR_RTT: 1 + BLE_PERIODIC_ADV_SYNC_TRANSFER: 1 + BLE_SM_BONDING: 1 + BLE_SM_LEGACY: 1 + BLE_SM_SC: 1 + BLE_STORE_MAX_BONDS: 5 + BLE_EATT_CHAN_NUM: 2 + BLE_PHY_2M: 1 + BLE_PHY_CODED: 1 + BLE_AUDIO_MAX_CODEC_RECORDS: 2 + + # controller + BLE_LL_CFG_FEAT_LL_PRIVACY: 1 + BLE_LL_CONN_INIT_MAX_TX_BYTES: 251 + BLE_LL_DTM: 1 + BLE_LL_DTM_EXTENSIONS: 1 diff --git a/.github/workflows/build_all_apps.yml b/.github/workflows/build_all_apps.yml new file mode 100644 index 0000000000..7881d96c62 --- /dev/null +++ b/.github/workflows/build_all_apps.yml @@ -0,0 +1,68 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +name: Build check + +on: [push, pull_request] + +jobs: + targets: + name: Build all apps + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-go@v3 + with: + go-version: 'stable' + - uses: carlosperate/arm-none-eabi-gcc-action@48db4484a55750df7a0ccca63347fcdea6534d78 + with: + release: '12.2.Rel1' + - name: Install Dependencies + shell: bash + if: matrix.os == 'ubuntu-latest' + run: | + sudo apt-get update + sudo apt-get install -y gcc-multilib + - name: Install newt + shell: bash + run: | + go version + go install mynewt.apache.org/newt/newt@latest + - name: Setup project + shell: bash + run: | + newt new build + cp -f .github/project.yml build/project.yml + cd build + newt upgrade --shallow=1 + rm -rf targets + rm -rf repos/apache-mynewt-nimble + git clone .. repos/apache-mynewt-nimble + cd .. + - name: Build applications + shell: bash + if: matrix.os == 'ubuntu-latest' + run: | + cd build + bash ../.github/test_build_apps.sh + cd .. diff --git a/.github/workflows/build_cc_target.yml b/.github/workflows/build_cc_target.yml new file mode 100644 index 0000000000..4b78c6536f --- /dev/null +++ b/.github/workflows/build_cc_target.yml @@ -0,0 +1,64 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +name: Build check + +on: [push, pull_request] + +jobs: + targets: + name: Build GCC test target + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest] + gcc: ['14.2.Rel1', '13.2.Rel1', '12.2.Rel1', '11.3.Rel1', '10.3-2021.10', '9-2020-q2', '8-2019-q3'] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-go@v3 + with: + go-version: 'stable' + - uses: carlosperate/arm-none-eabi-gcc-action@v1.10.1 + with: + release: ${{ matrix.gcc }} + - name: Install newt + shell: bash + run: | + go version + go install mynewt.apache.org/newt/newt@latest + - name: Setup project + shell: bash + run: | + newt new build + cp -f .github/project.yml build/project.yml + cd build + newt upgrade --shallow=1 + rm -rf repos/apache-mynewt-nimble + git clone .. repos/apache-mynewt-nimble + cd .. + - name: Build test target + shell: bash + run: | + cd build + newt target create cc_test + newt target set cc_test bsp="@apache-mynewt-core/hw/bsp/nordic_pca10056" + newt target set cc_test app="@apache-mynewt-nimble/apps/btshell" + cp -f ../.github/test_build_apps_syscfg.yml targets/cc_test/syscfg.yml + newt build -j 1 cc_test diff --git a/.github/workflows/build_ports.yml b/.github/workflows/build_ports.yml new file mode 100644 index 0000000000..83efa8047e --- /dev/null +++ b/.github/workflows/build_ports.yml @@ -0,0 +1,65 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +name: Build check + +on: [push, pull_request] + +jobs: + ports: + name: Build ports + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: carlosperate/arm-none-eabi-gcc-action@48db4484a55750df7a0ccca63347fcdea6534d78 + with: + release: '12.2.Rel1' + - name: Install Dependencies + shell: bash + run: | + sudo apt-get update + sudo apt-get install -y make ccache gcc-multilib g++-multilib kconfig-frontends + - name: Build example ports + shell: bash + run: | + make -C porting/examples/dummy/ clean all + make -C porting/examples/linux/ clean all + make -C porting/examples/linux_blemesh/ clean all + make -C porting/npl/linux/test/ clean all test + - name: Build RIOT port + shell: bash + if: success() || failure() + continue-on-error: true + run: | + git clone --depth=1 https://github.com/RIOT-OS/RIOT + rm RIOT/pkg/nimble/patches/ -rf + sed -i 's|PKG_URL.*|PKG_URL = '$(pwd)'|' RIOT/pkg/nimble/Makefile + sed -i 's|PKG_VERSION.*|PKG_VERSION = '${{ github.sha }}'|' RIOT/pkg/nimble/Makefile + make -C RIOT/examples/networking/ble/nimble/nimble_gatt + - name: Build Nuttx port + shell: bash + if: success() || failure() + continue-on-error: true + run: | + mkdir nuttx-build + git clone --depth=1 https://github.com/apache/nuttx.git nuttx-build/nuttx + git clone --depth=1 https://github.com/apache/nuttx-apps nuttx-build/apps + ./nuttx-build/nuttx/tools/configure.sh -l nrf52840-dk:sdc_nimble + sed -i 's|CONFIG_NIMBLE_REF :=.*|CONFIG_NIMBLE_REF := ${{ github.sha }}|' nuttx-build/apps/wireless/bluetooth/nimble/Makefile + make -C nuttx-build/nuttx diff --git a/.github/workflows/build_targets.yml b/.github/workflows/build_targets.yml new file mode 100644 index 0000000000..b666a0cb22 --- /dev/null +++ b/.github/workflows/build_targets.yml @@ -0,0 +1,78 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +name: Build check + +on: [push, pull_request] + +jobs: + targets: + name: Build all test targets + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-go@v3 + with: + go-version: 'stable' + - uses: carlosperate/arm-none-eabi-gcc-action@48db4484a55750df7a0ccca63347fcdea6534d78 + with: + release: '12.2.Rel1' + - name: Install Dependencies + shell: bash + if: matrix.os == 'ubuntu-latest' + run: | + sudo apt-get update + sudo apt-get install -y gcc-multilib + - name: Install newt + shell: bash + run: | + go version + go install mynewt.apache.org/newt/newt@latest + - name: Setup project + shell: bash + run: | + newt new build + cp -f .github/project.yml build/project.yml + cd build + newt upgrade --shallow=1 + rm -rf targets + rm -rf repos/apache-mynewt-nimble + git clone .. repos/apache-mynewt-nimble + cd .. + - name: Build targets + shell: bash + run: | + cp -r .github/targets build/targets + cd build + ls targets | xargs -n1 sh -c 'echo "Testing $0"; newt build -q $0' + rm -rf targets + cd .. + - name: Build Linux-only targets + shell: bash + if: matrix.os == 'ubuntu-latest' + run: | + cp -r .github/targets_linux build/targets + cd build + ls targets | xargs -n1 sh -c 'echo "Testing $0"; newt build -q $0' + rm -rf targets + cd .. diff --git a/.github/workflows/check_workflows.yml b/.github/workflows/check_workflows.yml new file mode 100644 index 0000000000..1d9f6e90be --- /dev/null +++ b/.github/workflows/check_workflows.yml @@ -0,0 +1,71 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +name: Check workflows status + +on: + pull_request_target: + types: [opened, synchronize, reopened, labeled, unlabeled] + +permissions: + pull-requests: read + contents: read + +jobs: + check-workflows: + runs-on: ubuntu-latest + steps: + - name: Check out master branch (base) + uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.base.ref }} + path: master_branch + + - name: Check out PR branch (head) + uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha }} + path: pr_branch + + - name: Check for label override + id: label_check + uses: actions/github-script@v7 + with: + script: | + const labelName = 'workflows-update'; + const labels = await github.rest.issues.listLabelsOnIssue({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.payload.pull_request.number, + }); + const hasLabel = labels.data.some(label => label.name === labelName); + core.setOutput('skip', hasLabel); + + - name: Compare workflows between master and PR + if: steps.label_check.outputs.skip != 'true' + run: | + echo "Checking if .github/workflows/ differs from master..." + diff -r master_branch/.github/workflows pr_branch/.github/workflows || { + echo "::error::Workflows differ from master. Please rebase or apply 'workflows-update' label to bypass."; + exit 1; + } + + - name: Skip message if label present + if: steps.label_check.outputs.skip == 'true' + run: echo "Skipping workflows check because 'workflows-update' label is present." diff --git a/.github/workflows/codeql-buildscript.sh b/.github/workflows/codeql-buildscript.sh new file mode 100644 index 0000000000..46f73397f6 --- /dev/null +++ b/.github/workflows/codeql-buildscript.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +sudo apt-get update +sudo apt-get install -y make ccache gcc-multilib g++-multilib + +make -C porting/examples/dummy/ clean all +make -C porting/examples/linux/ clean all +make -C porting/examples/linux_blemesh/ clean all diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000000..9c5c927091 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,126 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: "CodeQL" + +on: + # push: + # branches: [ "main", "master" ] + schedule: + - cron: '0 0 * * *' + pull_request: + branches: '*' + +jobs: + analyze: + name: Analyze + # Runner size impacts CodeQL analysis time. To learn more, please see: + # - https://gh.io/recommended-hardware-resources-for-running-codeql + # - https://gh.io/supported-runners-and-hardware-resources + # - https://gh.io/using-larger-runners + # Consider using larger runners for possible analysis time improvements. + runs-on: ubuntu-latest + timeout-minutes: ${{ (matrix.language == 'swift' && 120) || 360 }} + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: [ 'cpp' ] + # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby', 'swift' ] + # Use only 'java' to analyze code written in Java, Kotlin or both + # Use only 'javascript' to analyze code written in JavaScript, TypeScript or both + # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + with: + submodules: recursive + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + + # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs + # queries: security-extended,security-and-quality + queries: security-and-quality + + + # Autobuild attempts to build any compiled languages (C/C++, C#, Go, Java, or Swift). + # If this step fails, then you should remove it and run the build manually (see below) + #- name: Autobuild + # uses: github/codeql-action/autobuild@v3 + + # â„šī¸ Command-line programs to run using the OS shell. + # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun + + # If the Autobuild fails above, remove it and uncomment the following three lines. + # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. + + - run: | + ./.github/workflows/codeql-buildscript.sh + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v3 + with: + category: "/language:${{matrix.language}}" + upload: false + id: step1 + + # Filter out rules with low severity or high false positve rate + # Also filter out warnings in third-party code + - name: Filter out unwanted errors and warnings + uses: advanced-security/filter-sarif@v1 + with: + patterns: | + -**:cpp/path-injection + -**:cpp/world-writable-file-creation + -**:cpp/poorly-documented-function + -**:cpp/potentially-dangerous-function + -**:cpp/use-of-goto + -**:cpp/integer-multiplication-cast-to-long + -**:cpp/comparison-with-wider-type + -**:cpp/leap-year/* + -**:cpp/ambiguously-signed-bit-field + -**:cpp/suspicious-pointer-scaling + -**:cpp/suspicious-pointer-scaling-void + -**:cpp/unsigned-comparison-zero + -**/cmake*/Modules/** + input: ${{ steps.step1.outputs.sarif-output }}/cpp.sarif + output: ${{ steps.step1.outputs.sarif-output }}/cpp.sarif + + - name: Upload CodeQL results to code scanning + uses: github/codeql-action/upload-sarif@v3 + with: + sarif_file: ${{ steps.step1.outputs.sarif-output }} + category: "/language:${{matrix.language}}" + + - name: Upload CodeQL results as an artifact + if: success() || failure() + uses: actions/upload-artifact@v4 + with: + name: codeql-results + path: ${{ steps.step1.outputs.sarif-output }} + retention-days: 5 + + - name: Fail if an error is found + run: | + ./.github/workflows/fail_on_error.py \ + ${{ steps.step1.outputs.sarif-output }}/cpp.sarif diff --git a/.github/workflows/compliance_check.yml b/.github/workflows/compliance_check.yml new file mode 100644 index 0000000000..23fdfdfbcd --- /dev/null +++ b/.github/workflows/compliance_check.yml @@ -0,0 +1,182 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +name: Compliance check + +on: + pull_request: + types: [opened, synchronize, reopened, labeled, unlabeled] + +jobs: + style_check: + name: Coding style + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Install Dependencies + shell: bash + run: | + python -m pip install clang-format + + - name: Check label + id: label_check + uses: actions/github-script@v7 + with: + script: | + const labelName = 'skip-style-check'; + const labels = await github.rest.issues.listLabelsOnIssue({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.payload.pull_request.number, + }); + const hasLabel = labels.data.some(label => label.name === labelName); + core.setOutput('skip', hasLabel); + + - name: check style + if: steps.label_check.outputs.skip != 'true' + shell: bash + run: | + set +e + INFO_URL="https://github.com/apache/mynewt-core/blob/master/CODING_STANDARDS.md" + GIT_BASE=$(git merge-base origin/master HEAD) + git diff -U0 "$GIT_BASE"...HEAD > diff.patch + clang-format-diff.py -p1 -style=file < diff.patch > clang-fmt.patch + if [ -s clang-fmt.patch ]; then + echo "Code formatting issues found:" + cat clang-fmt.patch + echo "" + echo "For formatting guidelines, see:" + echo " $INFO_URL" + exit 1 + else + echo "All good, no formatting issues." + fi + + - name: Skip style-check if label present + if: steps.label_check.outputs.skip == 'true' + run: echo "Skipping style check because 'skip-style-check' label is present." + + style_license: + name: Licensing + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Install Dependencies + shell: bash + run: | + mkdir repos + git clone --depth=1 https://github.com/apache/mynewt-core repos/apache-mynewt-core + wget https://archive.apache.org/dist/creadur/apache-rat-0.17/apache-rat-0.17-bin.tar.gz + tar zxf apache-rat-0.17-bin.tar.gz apache-rat-0.17/apache-rat-0.17.jar + mv apache-rat-0.17/apache-rat-0.17.jar apache-rat.jar + - name: Check licensing + shell: bash + run: | + ./repos/apache-mynewt-core/.github/check_license.py + + style_doxygen: + name: Doxygen Style + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Install Dependencies + shell: bash + run: | + sudo apt-get update + sudo apt-get install -y doxygen graphviz + - name: Check Doxygen + shell: bash + run: | + .github/check_doxygen.py + + commits-check: + name: Check commit messages + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Validate commit message style + shell: bash + run: | + set -e + has_errors=0 + COMMIT_URL="https://cwiki.apache.org/confluence/display/MYNEWT/Contributing+to+Apache+Mynewt" + + # Determine commit range for PR or fallback to origin/master + if [ -n "${GITHUB_BASE_REF}" ]; then + base_ref="origin/${GITHUB_BASE_REF}" + else + base_ref="origin/master" + fi + + base_commit=$(git merge-base HEAD ${base_ref}) + + echo "Checking commits from ${base_commit} to HEAD" + + for commit in $(git rev-list --no-merges ${base_commit}..HEAD); do + short_sha=$(git rev-parse --short=7 $commit) + subject=$(git log -1 --pretty=format:%s $commit) + body=$(git log -1 --pretty=format:%b $commit) + + if [ ${#subject} -gt 72 ]; then + echo "Commit $short_sha subject too long (${#subject} > 72):" + echo "$subject" + has_errors=1 + fi + + if [[ "$subject" != *:* ]]; then + echo "Commit $short_sha subject missing colon (e.g. 'subsystem: msg')" + echo "$subject" + has_errors=1 + fi + + if [ -z "$body" ]; then + echo "Commit $short_sha body is missing" + has_errors=1 + else + line_num=0 + while IFS= read -r line; do + line_num=$((line_num + 1)) + if [ ${#line} -gt 72 ]; then + echo "Commit $short_sha body line $line_num too long (${#line} > 72):" + echo "$line" + has_errors=1 + fi + done <<< "$body" + fi + + echo "" + done + + if [ "$has_errors" -eq 1 ]; then + echo "::error::Commit message check failed." + echo "For contributing guidelines, see:" + echo " $COMMIT_URL" + exit 1 + else + echo "All commit messages pass style rules." + fi diff --git a/.github/workflows/fail_on_error.py b/.github/workflows/fail_on_error.py new file mode 100755 index 0000000000..e500e24df1 --- /dev/null +++ b/.github/workflows/fail_on_error.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python3 + +import json +import sys + +# Return whether SARIF file contains error-level results +def codeql_sarif_contain_error(filename): + with open(filename, 'r') as f: + s = json.load(f) + + for run in s.get('runs', []): + rules_metadata = run['tool']['driver']['rules'] + if not rules_metadata: + for extension in run['tool']['extensions']: + if 'rules' in extension: + rules_metadata = extension['rules'] + break + + for res in run.get('results', []): + if 'ruleIndex' in res: + rule_index = res['ruleIndex'] + elif 'rule' in res and 'index' in res['rule']: + rule_index = res['rule']['index'] + else: + continue + try: + rule_level = rules_metadata[rule_index]['defaultConfiguration']['level'] + except IndexError as e: + print(e, rule_index, len(rules_metadata)) + else: + if rule_level == 'error': + return True + return False + +if __name__ == "__main__": + if codeql_sarif_contain_error(sys.argv[1]): + sys.exit(1) diff --git a/.github/workflows/format_file_check.yml b/.github/workflows/format_file_check.yml new file mode 100644 index 0000000000..f67a053117 --- /dev/null +++ b/.github/workflows/format_file_check.yml @@ -0,0 +1,69 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +name: Sync clang-format + +on: + schedule: + - cron: '0 6 * * *' + +jobs: + sync: + runs-on: ubuntu-24.04 + permissions: + contents: write + pull-requests: write + + if: github.event.repository.fork == false + steps: + - name: Checkout current repo + uses: actions/checkout@v4 + + - name: Download .clang-format from source + run: | + wget -O .clang-format-core https://raw.githubusercontent.com/apache/mynewt-core/refs/heads/master/.clang-format + + - name: Check for changes & replace + id: changed + run: | + set +e + if ! cmp -s ".clang-format-core" ".clang-format"; then + echo "🔄 .clang-format has changed, updating..." + diff -u .clang-format .clang-format-core + mv .clang-format-core .clang-format + echo "changed=true" >> $GITHUB_OUTPUT + else + echo "✅ No changes detected." + echo "changed=false" >> $GITHUB_OUTPUT + fi + + - name: Create Pull Request + if: steps.changed.outputs.changed == 'true' + uses: peter-evans/create-pull-request@v7 + with: + author: Mynewt Bot + token: ${{ secrets.GITHUB_TOKEN }} + commit-message: | + ci: Update .clang-format from apache-mynewt-core + branch: update-clang-format + title: "Update clang format" + body: | + Syncing the latest .clang-format file from apache-mynewt-core + + [1]: https://github.com/peter-evans/create-pull-request diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml new file mode 100644 index 0000000000..c084f29d81 --- /dev/null +++ b/.github/workflows/labeler.yml @@ -0,0 +1,45 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +name: "Pull Request Labeler" +on: + - pull_request_target + +jobs: + labeler: + permissions: + contents: read + pull-requests: write + issues: write + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Assign labels based on paths + uses: actions/labeler@v5 + with: + sync-labels: true + configuration-path: .github/labeler_cfg.yml + + - name: Assign labels based on the PR's size + uses: codelytv/pr-size-labeler@v1.10.0 + with: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + ignore_file_deletions: true diff --git a/.github/workflows/newt_test_all.yml b/.github/workflows/newt_test_all.yml new file mode 100644 index 0000000000..04299bdbec --- /dev/null +++ b/.github/workflows/newt_test_all.yml @@ -0,0 +1,62 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +name: Unit tests + +on: [push, pull_request] + +jobs: + newt_test: + name: Run newt test all + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, macos-13] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-go@v3 + with: + go-version: 'stable' + - name: Install Dependencies + if: matrix.os == 'ubuntu-latest' + shell: bash + run: | + sudo apt-get update + sudo apt-get install -y gcc-multilib + - name: Install newt + shell: bash + run: | + go version + go install mynewt.apache.org/newt/newt@latest + - name: Setup project + shell: bash + run: | + newt new build + cp -f .github/project_newt_test_all.yml build/project.yml + cd build + newt upgrade --shallow=1 + rm -rf repos/apache-mynewt-nimble + git clone .. repos/apache-mynewt-nimble + cd .. + - name: newt test all + shell: bash + run: | + cd build + newt test all diff --git a/.github/workflows/ports_syscfg_check.yml b/.github/workflows/ports_syscfg_check.yml new file mode 100644 index 0000000000..5755a490e9 --- /dev/null +++ b/.github/workflows/ports_syscfg_check.yml @@ -0,0 +1,107 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +name: Check ports syscfg update + +on: + push: + branches: + - 'master' + schedule: + - cron: '37 21 * * *' + +jobs: + targets: + name: Check ports syscfg update + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + if: github.event.repository.fork == false + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-go@v3 + with: + go-version: 'stable' + - uses: carlosperate/arm-none-eabi-gcc-action@48db4484a55750df7a0ccca63347fcdea6534d78 + with: + release: '12.2.Rel1' + - name: Install Dependencies + shell: bash + run: | + sudo apt-get update + sudo apt-get install -y gcc-multilib + - name: Install newt + shell: bash + run: | + go version + go install mynewt.apache.org/newt/newt@latest + - name: Setup project + shell: bash + run: | + newt new build + cp -f .github/project.yml build/project.yml + cd build + newt upgrade --shallow=1 + rm -rf repos/apache-mynewt-nimble + git clone .. repos/apache-mynewt-nimble + - name: Build ports tests targets + shell: bash + run: | + cd build + ./repos/apache-mynewt-nimble/porting/update_generated_files.sh + - name: Check ports syscfg (debug) + shell: bash + if: runner.debug == '1' + run: | + cd build/repos/apache-mynewt-nimble + git diff + - name: Check ports syscfg + shell: bash + run: | + cd build/repos/apache-mynewt-nimble + if ! git diff --quiet; then + echo -e "\033[0;31mChanges in system configuration files detected:" + git diff --name-only + cp porting/examples/linux/include/syscfg/syscfg.h ../../../porting/examples/linux/include/syscfg/syscfg.h + cp porting/examples/linux_blemesh/include/syscfg/syscfg.h ../../../porting/examples/linux_blemesh/include/syscfg/syscfg.h + cp porting/examples/nuttx/include/syscfg/syscfg.h ../../../porting/examples/nuttx/include/syscfg/syscfg.h + cp porting/nimble/include/syscfg/syscfg.h ../../../porting/nimble/include/syscfg/syscfg.h + cp porting/npl/riot/include/syscfg/syscfg.h ../../../porting/npl/riot/include/syscfg/syscfg.h + else + echo "No changes detected in system configuration files." + fi + cd ../../.. + rm -rf build + - name: Create Pull Request + uses: peter-evans/create-pull-request@v6 + with: + author: Mynewt Bot + token: ${{ secrets.GITHUB_TOKEN }} + commit-message: | + porting: Update ports syscfg + branch: update-ports-syscfg + title: "Update ports syscfg" + body: | + Update NimBLE ports configurations: + - Removes all /* */ comments from `syscfg.h` files. + - Adds the license header to each `syscfg.h` file. + - Auto-generated by [create-pull-request][1] + + [1]: https://github.com/peter-evans/create-pull-request diff --git a/.gitignore b/.gitignore index bcc3a72bd1..66b3d75410 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,7 @@ # Dummy NPL build *.o -/porting/examples/dummy/dummy -/porting/examples/linux/nimble-linux -/porting/examples/linux_blemesh/nimble-linux-blemesh +porting/examples/dummy/dummy +porting/examples/linux/nimble-linux +porting/examples/linux_blemesh/nimble-linux-blemesh +porting/npl/linux/test/.depend +porting/npl/linux/test/*.exe diff --git a/.mailmap b/.mailmap new file mode 100644 index 0000000000..61be657c2a --- /dev/null +++ b/.mailmap @@ -0,0 +1,20 @@ +Brian Giori +Christopher Collins +Christopher Collins +Jakub Rotkiewicz +Jakub Rotkiewicz +Magdalena Kasenberg +Magdalena Kasenberg <–magdalena.kasenberg@codecoup.pl> +Marko Kiiskila +Michał Narajowski +Sterling Hughes +Sterling Hughes +Szymon Czapracki +Szymon Janc +Vipul Rahane +Vipul Rahane +Vipul Rahane +Will San Filippo +Will San Filippo +Will San Filippo + diff --git a/.rat-excludes b/.rat-excludes index bed75ef701..85397a1dc4 100644 --- a/.rat-excludes +++ b/.rat-excludes @@ -1,33 +1,30 @@ # Can't easily add license to rat-excludes file. .rat-excludes - -# Ignore documentation folder -docs +repos # Non-source files RELEASE_NOTES.md -.gitignore -README.md -pts-gap.txt -pts-gatt.txt -pts-l2cap.txt -pts-sm.txt -94654-20170317-085122560.tpg -94654-20170317-085441153.pts -uncrustify.cfg +**/README.md +Doxyfile +.clang-format +.mailmap .style_ignored_dirs +**/requirements.txt + +# Ignore documentation folder +docs # tinycrypt - BSD License. -tinycrypt +ext/tinycrypt -# Bluetooth Mesh - Apache 2.0 License -mesh +# mbuf implementation - BSD License +porting/nimble/src/os_mbuf.c -# Queue implementation - BSD License -queue.h +# Nordic nRF5 SDK - BSD License +babblesim/hw/mcu/nordic/nrf52_bsim/src/system_nrf52.c -# mbuf implementation - BSD License -os_mbuf.c +# CMSIS-CORE - BSD License. +babblesim/hw/mcu/nordic/nrf52_bsim/include/mcu/cmsis_nvic.h -# Bluetooth Mesh badge sample - Apache 2.0 License -mesh_badge +# Linker scripts for Nordics nRF5X - TCL license +targets/auracast_usb/nrf5340-mcu.ld diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 285b81e5d0..0000000000 --- a/.travis.yml +++ /dev/null @@ -1,169 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - -language: go - -dist: bionic - -_addons: &addon_conf - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - gcc-multilib - - gcc-7-multilib - -go: - - "1.12" - -git: - depth: false - -matrix: - include: - # Style checking - - os: linux - language: python - python: - - "3.5" - addons: - apt: - packages: - - "python3-pip" - env: - - TEST=STYLE - - DEBUG=1 - - # newt build - - os: linux - addons: *addon_conf - env: - - TEST=BUILD_TARGETS - - VM_AMOUNT=4 - - TARGET_SET=1 - - os: linux - addons: *addon_conf - env: - - TEST=BUILD_TARGETS - - VM_AMOUNT=4 - - TARGET_SET=2 - - os: linux - addons: *addon_conf - env: - - TEST=BUILD_TARGETS - - VM_AMOUNT=4 - - TARGET_SET=3 - - os: linux - addons: *addon_conf - env: - - TEST=BUILD_TARGETS - - VM_AMOUNT=4 - - TARGET_SET=4 - - # newt test all (Linux) - - os: linux - addons: *addon_conf - env: - - TEST=TEST_ALL - - VM_AMOUNT=2 - - TARGET_SET=1 - - os: linux - addons: *addon_conf - env: - - TEST=TEST_ALL - - VM_AMOUNT=2 - - TARGET_SET=2 - - # ports - - os: linux - addons: *addon_conf - env: - - TEST=BUILD_PORTS - - VM_AMOUNT=1 - - TARGET_SET=1 - - # newt test all - - os: osx - osx_image: xcode9.2 - env: - - TEST=TEST_ALL - - VM_AMOUNT=3 - - TARGET_SET=1 - - os: osx - osx_image: xcode9.2 - env: - - TEST=TEST_ALL - - VM_AMOUNT=3 - - TARGET_SET=2 - - os: osx - osx_image: xcode9.2 - env: - - TEST=TEST_ALL - - VM_AMOUNT=3 - - TARGET_SET=3 - - os: windows - env: - - TEST=BUILD_TARGETS_WINDOWS - - VM_AMOUNT=1 - - TARGET_SET=1 - -before_install: - - printenv - - export GOPATH=$HOME/gopath - - go version - -install: - - git clone https://github.com/JuulLabs-OSS/mynewt-travis-ci $HOME/ci - - chmod +x $HOME/ci/*.sh - - | - if [ "${TEST}" == "STYLE" ]; then - pip3 install requests - else - $HOME/ci/${TRAVIS_OS_NAME}_travis_install.sh - fi - -before_script: - - | - if [ "${TEST}" == "STYLE" ]; then - $HOME/ci/install_uncrustify.sh - else - newt version - gcc --version - if [ "${TEST}" != "TEST_ALL" ]; then arm-none-eabi-gcc --version; fi - cp -R $HOME/ci/mynewt-nimble-project.yml project.yml - mkdir -p targets - cp -R $HOME/ci/mynewt-nimble-targets targets - $HOME/ci/prepare_test.sh $VM_AMOUNT - mkdir -p repos && pushd repos/ - git clone --depth=1 https://github.com/apache/mynewt-core apache-mynewt-core - git clone --depth=1 https://github.com/JuulLabs-OSS/mcuboot mcuboot - git clone --depth=1 https://github.com/apache/mynewt-mcumgr apache-mynewt-mcumgr - popd - fi - -script: - - | - if [ "${TEST}" == "STYLE" ]; then - python3 $HOME/ci/check_style.py - else - $HOME/ci/run_test.sh - fi - -cache: - directories: - - $HOME/TOOLCHAIN - - $HOME/Library/Caches/Homebrew diff --git a/Doxyfile b/Doxyfile new file mode 100644 index 0000000000..91870efd74 --- /dev/null +++ b/Doxyfile @@ -0,0 +1,8 @@ +WARN_NO_PARAMDOC = YES +WARN_LOGFILE = /tmp/doxygen_check/warnings.log +INPUT = $(DOXYGEN_INPUT) +GENERATE_HTML = YES +HTML_OUTPUT = /tmp/doxygen_check/html +GENERATE_LATEX = NO +MACRO_EXPANSION = YES +WARN_FORMAT = $line: $text diff --git a/LICENSE b/LICENSE index 08b9b218a2..ca697aee3f 100644 --- a/LICENSE +++ b/LICENSE @@ -215,3 +215,16 @@ under the following license: This product bundles tinycrypt, which is available under the "3-clause BSD" license. For details, and bundled files see: * ext/tinycrypt/LICENSE + +This product bundles and partly derives from parts of the Nordic nRF52 SDK, +which are available under a BSD style license. Relevant files are: + * babblesim/hw/mcu/nordic/nrf52_bsim/src/system_nrf52.c + +This product bundles additional files from CMSIS-CORE, but these files are +missing licensing information. The BSD license was subsequently added to +these files in later releases. These files are: + * babblesim/hw/mcu/nordic/nrf52_bsim/include/mcu/cmsis_nvic.h + +This product bundles part of linker scripts from Nordic Semiconductor, +which is available under the "modified Tcl/Tk" license. Bundled files are: + * targets/auracast_usb/nrf5340-mcu.ld diff --git a/NOTICE b/NOTICE index 90952ecc53..740162388b 100644 --- a/NOTICE +++ b/NOTICE @@ -1,5 +1,5 @@ Apache Mynewt NimBLE -Copyright 2015-2021 The Apache Software Foundation +Copyright 2015-2024 The Apache Software Foundation This product includes software developed at The Apache Software Foundation (http://www.apache.org/). diff --git a/README.md b/README.md index 96c636634c..00cb27c636 100644 --- a/README.md +++ b/README.md @@ -19,29 +19,45 @@ # --> + Apache Mynewt + ## Overview -Apache NimBLE is an open-source Bluetooth 5.1 stack (both Host & Controller) + + + + + + + + + + + + +

+ +Apache NimBLE is an open-source Bluetooth 5.4 stack (both Host & Controller) that completely replaces the proprietary SoftDevice on Nordic chipsets. It is part of [Apache Mynewt project](https://github.com/apache/mynewt-core). -Features highlight: - - Support for 251 byte packet size +Feature highlight: + - Support for 251 byte packet size. - Support for all 4 roles concurrently - Broadcaster, Observer, Peripheral and Central - Support for up to 32 simultaneous connections. - Legacy and SC (secure connections) SMP support (pairing and bonding). - Advertising Extensions. - Periodic Advertising. - - Coded (aka Long Range) and 2M PHYs. + - Coded (a.k.a. Long Range) and 2M PHYs. - Bluetooth Mesh. ## Supported hardware -Controller supports Nordic nRF51 and nRF52 chipsets. Host runs on any board -and architecture [supported](https://github.com/apache/mynewt-core#overview) -by Apache Mynewt OS. +Controller supports Nordic nRF51, nRF52 and nRF5340 chipsets as well as DA1469x (cmac) +from Renesas. Host runs on any board and architecture +[supported](https://github.com/apache/mynewt-core#overview) by Apache Mynewt OS. ## Browsing @@ -103,6 +119,16 @@ Implements a simple BLE peripheral that supports the Nordic UART / Serial Port Emulation service (https://developer.nordicsemi.com/nRF5_SDK/nRF51_SDK_v8.x.x/doc/8.0.0/s110/html/a00072.html). +## External projects using NimBLE + +Several other projects provide support for using NimBLE either by [NPL port](https://github.com/apache/mynewt-nimble/tree/master/porting) or forking: + + * [The Espressif ESP-IDF](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/bluetooth/nimble/index.html) contains a NimBLE port for ESP-32 devices. + * [The RIOT](https://doc.riot-os.org/group__pkg__nimble.html) operating system contains a package for using NimBLE. + * [The Open IOT SDK](https://gitlab.arm.com/iot/open-iot-sdk/sdk) contains a NimBLE [port](https://gitlab.arm.com/iot/open-iot-sdk/sdk/-/tree/main/components/bluetooth) based on [CMSIS RTOSv2](https://www.keil.com/pack/doc/CMSIS/RTOS2/html/index.html), which is an RTOS interface implemented by either Amazon Freertos, CMSIS RTX or Azure ThreadX. + + If you publish a NimBLE port, please let us know to include it here! + # Getting Help If you are having trouble using or contributing to Apache Mynewt NimBLE, or just @@ -112,7 +138,7 @@ want to talk to a human about what you're working on, you can contact us via the Although not a formal channel, you can also find a number of core developers on the #mynewt channel on Freenode IRC or #general channel on [Mynewt Slack](https://mynewt.slack.com/join/shared_invite/enQtNjA1MTg0NzgyNzg3LTcyMmZiOGQzOGMxM2U4ODFmMTIwNjNmYTE5Y2UwYjQwZWIxNTE0MTUzY2JmMTEzOWFjYWZkNGM0YmM4MzAxNWQ) -Also, be sure to checkout the [Frequently Asked Questions](https://mynewt.apache.org/faq/answers) +Also, be sure to checkout the [Frequently Asked Questions](https://mynewt.apache.org/latest/mynewt_faq) for some help troubleshooting first. # Contributing diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 99810a718d..3a83f16832 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,21 +1,17 @@ # RELEASE NOTES -24 March 2021 - Apache NimBLE v1.4.0 +13 November 2024 - Apache NimBLE v1.8.0 For full release notes, please visit the [Apache Mynewt Wiki](https://cwiki.apache.org/confluence/display/MYNEWT/Release+Notes). -Apache NimBLE is an open-source Bluetooth 5.1 stack (both Host & Controller) that completely +Apache NimBLE is an open-source Bluetooth 5.4 stack (both Host & Controller) that completely replaces the proprietary SoftDevice on Nordic chipsets. New features in this version of NimBLE include: -* Support for PHY on Dialog Configurable MAC (CMAC) -* Support for PHY on Nordic nRF5340 -* Support for Apache NuttX port of NimBLE -* Controller-to-host flow control support -* Support for USB transport -* Various bugfixes +* Initial support for Channel Sounding (host) +* Support for SKY66405 FEM If working on next-generation RTOS and Bluetooth protocol stack sounds exciting to you, get in touch, by sending a mail to the Apache Mynewt diff --git a/apps/advertiser/pkg.yml b/apps/advertiser/pkg.yml index 662e282e8b..2693cdad34 100644 --- a/apps/advertiser/pkg.yml +++ b/apps/advertiser/pkg.yml @@ -24,10 +24,10 @@ pkg.author: "Krzysztof Kopyściński " pkg.deps: - "@apache-mynewt-core/kernel/os" - - "@apache-mynewt-core/sys/console/full" - - "@apache-mynewt-core/sys/log/full" - - "@apache-mynewt-core/sys/stats/full" + - "@apache-mynewt-core/sys/console" + - "@apache-mynewt-core/sys/log" + - "@apache-mynewt-core/sys/stats" - "@apache-mynewt-core/sys/log/modlog" + - "@apache-mynewt-nimble/nimble/host" - "@apache-mynewt-nimble/nimble/host/util" - "@apache-mynewt-nimble/nimble/host/services/gap" - - "@apache-mynewt-nimble/nimble/transport" diff --git a/apps/advertiser/src/main.c b/apps/advertiser/src/main.c index 486d5c59a0..245d7410b2 100644 --- a/apps/advertiser/src/main.c +++ b/apps/advertiser/src/main.c @@ -114,7 +114,7 @@ on_reset(int reason) } int -main(int argc, char **argv) +mynewt_main(int argc, char **argv) { int rc; diff --git a/apps/advertiser/syscfg.yml b/apps/advertiser/syscfg.yml index 963839fc35..63b136bebe 100644 --- a/apps/advertiser/syscfg.yml +++ b/apps/advertiser/syscfg.yml @@ -17,6 +17,10 @@ syscfg.vals: + CONSOLE_IMPLEMENTATION: full + LOG_IMPLEMENTATION: full + STATS_IMPLEMENTATION: full + BLE_ROLE_BROADCASTER: 1 BLE_ROLE_CENTRAL: 0 BLE_ROLE_OBSERVER: 0 diff --git a/apps/auracast/include/tusb_config.h b/apps/auracast/include/tusb_config.h new file mode 100644 index 0000000000..053ed762c8 --- /dev/null +++ b/apps/auracast/include/tusb_config.h @@ -0,0 +1,445 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +#ifndef _TUSB_CONFIG_H_ +#define _TUSB_CONFIG_H_ + +#include "syscfg/syscfg.h" + +#ifdef __cplusplus +extern "C" { +#endif +/** + * COMMON CONFIGURATION + */ + +#include + +/* defined by compiler flags for flexibility */ +#ifndef CFG_TUSB_MCU +#error CFG_TUSB_MCU must be defined +#endif + +#define CFG_TUSB_RHPORT0_MODE OPT_MODE_DEVICE + +#define CFG_TUSB_OS OPT_OS_MYNEWT +#define CFG_TUSB_DEBUG 1 + +#define CFG_TUD_EP_MAX 9 + +#ifndef CFG_TUSB_MEM_SECTION +#define CFG_TUSB_MEM_SECTION +#endif + +#ifndef CFG_TUSB_MEM_ALIGN +#define CFG_TUSB_MEM_ALIGN __attribute__ ((aligned(4))) +#endif + +/** + * DEVICE CONFIGURATION + */ +#define CFG_TUD_ENDPOINT0_SIZE MYNEWT_VAL(USBD_EP0_SIZE) + +/* ------------- CLASS ------------- */ +#define CFG_TUD_CDC MYNEWT_VAL(USBD_CDC) +#define CFG_TUD_HID MYNEWT_VAL(USBD_HID) +#define CFG_TUD_MSC 0 +#define CFG_TUD_MIDI 0 +#define CFG_TUD_VENDOR 0 +#define CFG_TUD_USBTMC 0 +#define CFG_TUD_DFU_RT 0 +#define CFG_TUD_ECM_RNDIS 0 +#define CFG_TUD_BTH MYNEWT_VAL(USBD_BTH) +#define CFG_TUD_AUDIO_IN MYNEWT_VAL(USBD_AUDIO_IN) +#define CFG_TUD_AUDIO_OUT MYNEWT_VAL(USBD_AUDIO_OUT) +#define CFG_TUD_AUDIO_IN_OUT MYNEWT_VAL(USBD_AUDIO_IN_OUT) +#define CFG_TUD_AUDIO (MYNEWT_VAL(USBD_AUDIO_IN) || MYNEWT_VAL(USBD_AUDIO_OUT) || \ + MYNEWT_VAL(USBD_AUDIO_IN_OUT)) + +/* Audio format type */ +#define CFG_TUD_AUDIO_FORMAT_TYPE_TX AUDIO_FORMAT_TYPE_I +#define CFG_TUD_AUDIO_FORMAT_TYPE_RX AUDIO_FORMAT_TYPE_I + +/* Audio format type I specifications */ +#define CFG_TUD_AUDIO_FORMAT_TYPE_I_TX AUDIO_DATA_FORMAT_TYPE_I_PCM +#define CFG_TUD_AUDIO_FORMAT_TYPE_I_RX AUDIO_DATA_FORMAT_TYPE_I_PCM +#define CFG_TUD_AUDIO_N_CHANNELS_TX 2 +#define CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX 2 +#define CFG_TUD_AUDIO_N_CHANNELS_RX MYNEWT_VAL(USB_AUDIO_OUT_CHANNELS) +#define CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX 2 +#define CFG_TUD_AUDIO_RX_ITEMSIZE 2 +#define CFG_TUD_AUDIO_SAMPLE_RATE MYNEWT_VAL(USB_AUDIO_OUT_SAMPLE_RATE) +#define SAMPLES_PER_PACKET ((((CFG_TUD_AUDIO_SAMPLE_RATE) -1) / 1000) + 1) + +/* EP and buffer size - for isochronous EP´s, the buffer and EP size are equal (different sizes would not make sense) */ +#define CFG_TUD_AUDIO_EPSIZE_IN (CFG_TUD_AUDIO_IN * SAMPLES_PER_PACKET * \ + (CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_TX) *(CFG_TUD_AUDIO_N_CHANNELS_TX)) /* 48 Samples (48 kHz) x 2 Bytes/Sample x n Channels */ +#define CFG_TUD_AUDIO_TX_FIFO_COUNT (CFG_TUD_AUDIO_IN * 1) +#define CFG_TUD_AUDIO_TX_FIFO_SIZE (CFG_TUD_AUDIO_IN ? ((CFG_TUD_AUDIO_EPSIZE_IN)) : 0) + +/* EP and buffer size - for isochronous EP´s, the buffer and EP size are equal (different sizes would not make sense) */ +#define CFG_TUD_AUDIO_ENABLE_EP_OUT 1 +#define CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP 0 +#define CFG_TUD_AUDIO_EPSIZE_OUT (CFG_TUD_AUDIO_OUT * \ + ((SAMPLES_PER_PACKET + 1) * \ + (CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX) *(CFG_TUD_AUDIO_N_CHANNELS_RX))) /* N Samples (N kHz) x 2 Bytes/Sample x n Channels */ +#define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX CFG_TUD_AUDIO_EPSIZE_OUT +#define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ (CFG_TUD_AUDIO_EPSIZE_OUT * 40) +#define CFG_TUD_AUDIO_RX_FIFO_COUNT (CFG_TUD_AUDIO_OUT * 1) +#define CFG_TUD_AUDIO_RX_FIFO_SIZE (CFG_TUD_AUDIO_OUT ? (3 * \ + (CFG_TUD_AUDIO_EPSIZE_OUT / \ + CFG_TUD_AUDIO_RX_FIFO_COUNT)) : 0) + +/* Number of Standard AS Interface Descriptors (4.9.1) defined per audio function - this is required to be able to remember the current alternate settings of these interfaces - We restrict us here to have a constant number for all audio functions (which means this has to be the maximum number of AS interfaces an audio function has and a second audio function with less AS interfaces just wastes a few bytes) */ +#define CFG_TUD_AUDIO_N_AS_INT 1 + +/* Size of control request buffer */ +#define CFG_TUD_AUDIO_CTRL_BUF_SIZE 64 + +/* Minimal number for alternative interfaces that is recognized by Windows as Bluetooth radio controller */ +#define CFG_TUD_BTH_ISO_ALT_COUNT 2 + +/* CDC FIFO size of TX and RX */ +#define CFG_TUD_CDC_RX_BUFSIZE 64 +#define CFG_TUD_CDC_TX_BUFSIZE 64 + +/* HID buffer size Should be sufficient to hold ID (if any) + Data */ +#define CFG_TUD_HID_BUFSIZE 16 + +#define TUD_AUDIO_SPEAKER_MONO_DESC_LEN (TUD_AUDIO_DESC_IAD_LEN \ + + TUD_AUDIO_DESC_STD_AC_LEN \ + + TUD_AUDIO_DESC_CS_AC_LEN \ + + TUD_AUDIO_DESC_CLK_SRC_LEN \ + + TUD_AUDIO_DESC_INPUT_TERM_LEN \ + + TUD_AUDIO_DESC_OUTPUT_TERM_LEN \ + + TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL_LEN \ + + TUD_AUDIO_DESC_STD_AS_INT_LEN \ + + TUD_AUDIO_DESC_STD_AS_INT_LEN \ + + TUD_AUDIO_DESC_CS_AS_INT_LEN \ + + TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN \ + + TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN \ + + TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN) + +#define TUD_AUDIO_SPEAKER_MONO_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epout, _epsize) \ + /* Standard Interface Association Descriptor (IAD) */ \ + TUD_AUDIO_DESC_IAD(/*_firstitfs*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00), \ + /* Standard AC Interface Descriptor(4.7.1) */ \ + TUD_AUDIO_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx), \ + /* Class-Specific AC Interface Header Descriptor(4.7.2) */ \ + TUD_AUDIO_DESC_CS_AC(/*_bcdADC*/ 0x0200, /*_category*/ AUDIO_FUNC_DESKTOP_SPEAKER, \ + /*_totallen*/ TUD_AUDIO_DESC_CLK_SRC_LEN+TUD_AUDIO_DESC_INPUT_TERM_LEN+ \ + TUD_AUDIO_DESC_OUTPUT_TERM_LEN+TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL_LEN, \ + /*_ctrl*/ AUDIO_CS_AS_INTERFACE_CTRL_LATENCY_POS), \ + /* Clock Source Descriptor(4.7.2.1) */ \ + TUD_AUDIO_DESC_CLK_SRC(/*_clkid*/ 0x04, /*_attr*/ AUDIO_CLOCK_SOURCE_ATT_INT_FIX_CLK, \ + /*_ctrl*/ (AUDIO_CTRL_R << AUDIO_CLOCK_SOURCE_CTRL_CLK_FRQ_POS), /*_assocTerm*/ 0x00, \ + /*_stridx*/ 0x00), \ + /* Input Terminal Descriptor(4.7.2.4) */ \ + TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ 0x01, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x00, \ + /*_clkid*/ 0x04, /*_nchannelslogical*/ 0x01, \ + /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, \ + /*_ctrl*/ 0 * (AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS), /*_stridx*/ 0x00), \ + /* Output Terminal Descriptor(4.7.2.5) */ \ + TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ 0x03, /*_termtype*/ AUDIO_TERM_TYPE_OUT_DESKTOP_SPEAKER, \ + /*_assocTerm*/ 0x00, /*_srcid*/ 0x02, /*_clkid*/ 0x04, /*_ctrl*/ 0x0000, \ + /*_stridx*/ 0x00), \ + /* Feature Unit Descriptor(4.7.2.8) */ \ + TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL(/*_unitid*/ 0x02, /*_srcid*/ 0x01, \ + /*_ctrlch0master*/ 0 * (AUDIO_CTRL_RW << \ + AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | \ + AUDIO_CTRL_RW << \ + AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS), \ + /*_ctrlch1*/ 0 * (AUDIO_CTRL_RW << \ + AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << \ + AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS), \ + /*_stridx*/ 0x00), \ + /* Standard AS Interface Descriptor(4.9.1) */ \ + /* Interface 1, Alternate 0 - default alternate setting with 0 bandwidth */ \ + TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x00, /*_nEPs*/ 0x00, \ + /*_stridx*/ 0x00), \ + /* Standard AS Interface Descriptor(4.9.1) */ \ + /* Interface 1, Alternate 1 - alternate interface for data streaming */ \ + TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x01, /*_nEPs*/ 0x01, \ + /*_stridx*/ 0x00), \ + /* Class-Specific AS Interface Descriptor(4.9.2) */ \ + TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ 0x01, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, \ + /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ 0x01, \ + /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00), \ + /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */ \ + TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample), \ + /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */ \ + TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, \ + /*_attr*/ (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_SYNCHRONOUS | \ + TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, \ + /*_interval*/ (CFG_TUSB_RHPORT0_MODE & OPT_MODE_HIGH_SPEED) ? 0x04 : 0x01), \ + /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */ \ + TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, \ + /*_ctrl*/ AUDIO_CTRL_NONE, \ + /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, \ + /*_lockdelay*/ 0x0000) \ + +/* XXXXX + * 3 iso endpoint alternative for 16,32,48 kHz does not work on windows, works on Linux, on MAC reported freq is 48kHz and mac sends data for 16kHz + * MAC does not change clock selection like Linux does + */ + +#define TUD_AUDIO_SPEAKER3_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epout, _epsize1, \ + _epsize2, _epsize3) \ + /* Standard Interface Association Descriptor (IAD) */ \ + TUD_AUDIO_DESC_IAD(/*_firstitfs*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00), \ + /* Standard AC Interface Descriptor(4.7.1) */ \ + TUD_AUDIO_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx), \ + /* Class-Specific AC Interface Header Descriptor(4.7.2) */ \ + TUD_AUDIO_DESC_CS_AC(/*_bcdADC*/ 0x0200, /*_category*/ AUDIO_FUNC_DESKTOP_SPEAKER, \ + /*_totallen*/ TUD_AUDIO_DESC_CLK_SRC_LEN+TUD_AUDIO_DESC_INPUT_TERM_LEN+ \ + TUD_AUDIO_DESC_OUTPUT_TERM_LEN+0*TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL_LEN, \ + /*_ctrl*/ AUDIO_CS_AS_INTERFACE_CTRL_LATENCY_POS), \ + /* Clock Source Descriptor(4.7.2.1) */ \ + TUD_AUDIO_DESC_CLK_SRC(/*_clkid*/ 0x04, /*_attr*/ AUDIO_CLOCK_SOURCE_ATT_INT_FIX_CLK, \ + /*_ctrl*/ (AUDIO_CTRL_RW << AUDIO_CLOCK_SOURCE_CTRL_CLK_FRQ_POS), /*_assocTerm*/ 0x00, \ + /*_stridx*/ 0x00), \ + /* Input Terminal Descriptor(4.7.2.4) */ \ + TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ 0x01, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x00, \ + /*_clkid*/ 0x04, /*_nchannelslogical*/ 0x02, \ + /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_FRONT_LEFT | AUDIO_CHANNEL_CONFIG_FRONT_RIGHT, \ + /*_idxchannelnames*/ 0x00, \ + /*_ctrl*/ 0 * (AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS), /*_stridx*/ 0x00), \ + /* Output Terminal Descriptor(4.7.2.5) */ \ + TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ 0x03, /*_termtype*/ AUDIO_TERM_TYPE_OUT_DESKTOP_SPEAKER, \ + /*_assocTerm*/ 0x00, /*_srcid*/ 0x01, /*_clkid*/ 0x04, /*_ctrl*/ 0x0000, \ + /*_stridx*/ 0x00), \ + /* Standard AS Interface Descriptor(4.9.1) */ \ + /* Interface 1, Alternate 0 - default alternate setting with 0 bandwidth */ \ + TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x00, /*_nEPs*/ 0x00, \ + /*_stridx*/ 0x00), \ + /* Standard AS Interface Descriptor(4.9.1) */ \ + \ + /* Interface 1, Alternate 1 - alternate interface for data streaming */ \ + TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x01, /*_nEPs*/ 0x01, \ + /*_stridx*/ 0x00), \ + /* Class-Specific AS Interface Descriptor(4.9.2) */ \ + TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ 0x01, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, \ + /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ 0x02, \ + /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_FRONT_LEFT | AUDIO_CHANNEL_CONFIG_FRONT_RIGHT, \ + /*_stridx*/ 0x00), \ + /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */ \ + TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample), \ + /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */ \ + TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, \ + /*_attr*/ (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_SYNCHRONOUS | \ + TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize1, \ + /*_interval*/ (CFG_TUSB_RHPORT0_MODE & OPT_MODE_HIGH_SPEED) ? 0x04 : 0x01), \ + /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */ \ + TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, \ + /*_ctrl*/ AUDIO_CTRL_NONE, \ + /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, \ + /*_lockdelay*/ 0x0000), \ + \ + /* Interface 1, Alternate 2 - alternate interface for data streaming */ \ + TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x02, /*_nEPs*/ 0x01, \ + /*_stridx*/ 0x00), \ + /* Class-Specific AS Interface Descriptor(4.9.2) */ \ + TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ 0x01, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, \ + /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ 0x02, \ + /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_FRONT_LEFT | AUDIO_CHANNEL_CONFIG_FRONT_RIGHT, \ + /*_stridx*/ 0x00), \ + /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */ \ + TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample), \ + /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */ \ + TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, \ + /*_attr*/ (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_SYNCHRONOUS | \ + TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize2, \ + /*_interval*/ (CFG_TUSB_RHPORT0_MODE & OPT_MODE_HIGH_SPEED) ? 0x04 : 0x01), \ + /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */ \ + TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, \ + /*_ctrl*/ AUDIO_CTRL_NONE, \ + /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, \ + /*_lockdelay*/ 0x0000), \ + \ + /* Interface 1, Alternate 1 - alternate interface for data streaming */ \ + TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x03, /*_nEPs*/ 0x01, \ + /*_stridx*/ 0x00), \ + /* Class-Specific AS Interface Descriptor(4.9.2) */ \ + TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ 0x01, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, \ + /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ 0x02, \ + /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_FRONT_LEFT | AUDIO_CHANNEL_CONFIG_FRONT_RIGHT, \ + /*_stridx*/ 0x00), \ + /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */ \ + TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample), \ + /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */ \ + TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, \ + /*_attr*/ (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_SYNCHRONOUS | \ + TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize3, \ + /*_interval*/ (CFG_TUSB_RHPORT0_MODE & OPT_MODE_HIGH_SPEED) ? 0x04 : 0x01), \ + /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */ \ + TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, \ + /*_ctrl*/ AUDIO_CTRL_NONE, \ + /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, \ + /*_lockdelay*/ 0x0000) \ + +#define TUD_AUDIO_SPK3_DESC_LEN (TUD_AUDIO_DESC_IAD_LEN \ + + TUD_AUDIO_DESC_STD_AC_LEN \ + + TUD_AUDIO_DESC_CS_AC_LEN \ + + TUD_AUDIO_DESC_CLK_SRC_LEN \ + + TUD_AUDIO_DESC_INPUT_TERM_LEN \ + + TUD_AUDIO_DESC_OUTPUT_TERM_LEN \ + + 0 * TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL_LEN \ + + TUD_AUDIO_DESC_STD_AS_INT_LEN \ + + (TUD_AUDIO_DESC_STD_AS_INT_LEN \ + + TUD_AUDIO_DESC_CS_AS_INT_LEN \ + + TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN \ + + TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN \ + + TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN) * 3) + + +#define TUD_AUDIO_SPEAKER_DESCRIPTOR_FLOAT(_itfnum, _stridx, _epout, _epsize) \ + /* Standard Interface Association Descriptor (IAD) */ \ + TUD_AUDIO_DESC_IAD(/*_firstitfs*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00), \ + /* Standard AC Interface Descriptor(4.7.1) */ \ + TUD_AUDIO_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx), \ + /* Class-Specific AC Interface Header Descriptor(4.7.2) */ \ + TUD_AUDIO_DESC_CS_AC(/*_bcdADC*/ 0x0200, /*_category*/ AUDIO_FUNC_DESKTOP_SPEAKER, \ + /*_totallen*/ TUD_AUDIO_DESC_CLK_SRC_LEN+TUD_AUDIO_DESC_INPUT_TERM_LEN+ \ + TUD_AUDIO_DESC_OUTPUT_TERM_LEN+0*TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL_LEN, \ + /*_ctrl*/ AUDIO_CS_AS_INTERFACE_CTRL_LATENCY_POS), \ + /* Clock Source Descriptor(4.7.2.1) */ \ + TUD_AUDIO_DESC_CLK_SRC(/*_clkid*/ 0x04, /*_attr*/ AUDIO_CLOCK_SOURCE_ATT_INT_FIX_CLK, \ + /*_ctrl*/ (AUDIO_CTRL_RW << AUDIO_CLOCK_SOURCE_CTRL_CLK_FRQ_POS), /*_assocTerm*/ 0x00, \ + /*_stridx*/ 0x00), \ + /* Input Terminal Descriptor(4.7.2.4) */ \ + TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ 0x01, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x00, \ + /*_clkid*/ 0x04, /*_nchannelslogical*/ 0x02, \ + /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_FRONT_LEFT | AUDIO_CHANNEL_CONFIG_FRONT_RIGHT, \ + /*_idxchannelnames*/ 0x00, \ + /*_ctrl*/ 0 * (AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS), /*_stridx*/ 0x00), \ + /* Output Terminal Descriptor(4.7.2.5) */ \ + TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ 0x03, /*_termtype*/ AUDIO_TERM_TYPE_OUT_DESKTOP_SPEAKER, \ + /*_assocTerm*/ 0x00, /*_srcid*/ 0x01, /*_clkid*/ 0x04, /*_ctrl*/ 0x0000, \ + /*_stridx*/ 0x00), \ + /* Standard AS Interface Descriptor(4.9.1) */ \ + /* Interface 1, Alternate 0 - default alternate setting with 0 bandwidth */ \ + TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x00, /*_nEPs*/ 0x00, \ + /*_stridx*/ 0x00), \ + /* Standard AS Interface Descriptor(4.9.1) */ \ + /* Interface 1, Alternate 1 - alternate interface for data streaming */ \ + TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x01, /*_nEPs*/ 0x01, \ + /*_stridx*/ 0x00), \ + /* Class-Specific AS Interface Descriptor(4.9.2) */ \ + TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ 0x01, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, \ + /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_IEEE_FLOAT, /*_nchannelsphysical*/ 0x02, \ + /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_FRONT_LEFT | AUDIO_CHANNEL_CONFIG_FRONT_RIGHT, \ + /*_stridx*/ 0x00), \ + /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */ \ + TUD_AUDIO_DESC_TYPE_I_FORMAT(4, 32), \ + /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */ \ + TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, \ + /*_attr*/ (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_SYNCHRONOUS | \ + TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, \ + /*_interval*/ (CFG_TUSB_RHPORT0_MODE & OPT_MODE_HIGH_SPEED) ? 0x04 : 0x01), \ + /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */ \ + TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, \ + /*_ctrl*/ AUDIO_CTRL_NONE, \ + /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, \ + /*_lockdelay*/ 0x0000) \ + +#define TUD_AUDIO_SPEAKER_STEREO_DESC_LEN (TUD_AUDIO_DESC_IAD_LEN \ + + TUD_AUDIO_DESC_STD_AC_LEN \ + + TUD_AUDIO_DESC_CS_AC_LEN \ + + TUD_AUDIO_DESC_CLK_SRC_LEN \ + + TUD_AUDIO_DESC_INPUT_TERM_LEN \ + + TUD_AUDIO_DESC_OUTPUT_TERM_LEN \ + + 0 * TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL_LEN \ + + TUD_AUDIO_DESC_STD_AS_INT_LEN \ + + (TUD_AUDIO_DESC_STD_AS_INT_LEN \ + + TUD_AUDIO_DESC_CS_AS_INT_LEN \ + + TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN \ + + TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN \ + + TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN) * 1) + +#define TUD_AUDIO_SPEAKER_STEREO_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epout, _epsize) \ + /* Standard Interface Association Descriptor (IAD) */ \ + TUD_AUDIO_DESC_IAD(/*_firstitfs*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00), \ + /* Standard AC Interface Descriptor(4.7.1) */ \ + TUD_AUDIO_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx), \ + /* Class-Specific AC Interface Header Descriptor(4.7.2) */ \ + TUD_AUDIO_DESC_CS_AC(/*_bcdADC*/ 0x0200, /*_category*/ AUDIO_FUNC_DESKTOP_SPEAKER, \ + /*_totallen*/ TUD_AUDIO_DESC_CLK_SRC_LEN+TUD_AUDIO_DESC_INPUT_TERM_LEN+ \ + TUD_AUDIO_DESC_OUTPUT_TERM_LEN+0*TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL_LEN, \ + /*_ctrl*/ AUDIO_CS_AS_INTERFACE_CTRL_LATENCY_POS), \ + /* Clock Source Descriptor(4.7.2.1) */ \ + TUD_AUDIO_DESC_CLK_SRC(/*_clkid*/ 0x04, /*_attr*/ AUDIO_CLOCK_SOURCE_ATT_INT_FIX_CLK, \ + /*_ctrl*/ (AUDIO_CTRL_RW << AUDIO_CLOCK_SOURCE_CTRL_CLK_FRQ_POS), /*_assocTerm*/ 0x00, \ + /*_stridx*/ 0x00), \ + /* Input Terminal Descriptor(4.7.2.4) */ \ + TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ 0x01, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x00, \ + /*_clkid*/ 0x04, /*_nchannelslogical*/ 0x02, \ + /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_FRONT_LEFT | AUDIO_CHANNEL_CONFIG_FRONT_RIGHT, \ + /*_idxchannelnames*/ 0x00, \ + /*_ctrl*/ 0 * (AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS), /*_stridx*/ 0x00), \ + /* Output Terminal Descriptor(4.7.2.5) */ \ + TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ 0x03, /*_termtype*/ AUDIO_TERM_TYPE_OUT_DESKTOP_SPEAKER, \ + /*_assocTerm*/ 0x00, /*_srcid*/ 0x01, /*_clkid*/ 0x04, /*_ctrl*/ 0x0000, \ + /*_stridx*/ 0x00), \ + /* Standard AS Interface Descriptor(4.9.1) */ \ + /* Interface 1, Alternate 0 - default alternate setting with 0 bandwidth */ \ + TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x00, /*_nEPs*/ 0x00, \ + /*_stridx*/ 0x00), \ + /* Standard AS Interface Descriptor(4.9.1) */ \ + /* Interface 1, Alternate 1 - alternate interface for data streaming */ \ + TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x01, /*_nEPs*/ 0x01, \ + /*_stridx*/ 0x00), \ + /* Class-Specific AS Interface Descriptor(4.9.2) */ \ + TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ 0x01, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, \ + /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ 0x02, \ + /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_FRONT_LEFT | AUDIO_CHANNEL_CONFIG_FRONT_RIGHT, \ + /*_stridx*/ 0x00), \ + /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */ \ + TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample), \ + /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */ \ + TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, \ + /*_attr*/ (TUSB_XFER_ISOCHRONOUS | TUSB_ISO_EP_ATT_SYNCHRONOUS | \ + TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, \ + /*_interval*/ (CFG_TUSB_RHPORT0_MODE & OPT_MODE_HIGH_SPEED) ? 0x04 : 0x01), \ + /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */ \ + TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, \ + /*_ctrl*/ AUDIO_CTRL_NONE, \ + /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, \ + /*_lockdelay*/ 0x0000) \ + +#define CFG_TUD_AUDIO_FUNC_1_DESC_LEN ( \ + (1 - CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP) * CFG_TUD_AUDIO_OUT * \ + (TUD_AUDIO_SPEAKER_MONO_DESC_LEN * (CFG_TUD_AUDIO_N_CHANNELS_RX == 1 ? 1 : 0)) + \ + (0 + CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP) * CFG_TUD_AUDIO_OUT * \ + (TUD_AUDIO_SPEAKER_MONO_FB_DESC_LEN * (CFG_TUD_AUDIO_N_CHANNELS_RX == 1 ? 1 : 0)) + \ + (1 - CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP) * CFG_TUD_AUDIO_OUT * \ + (TUD_AUDIO_SPEAKER_STEREO_DESC_LEN * (CFG_TUD_AUDIO_N_CHANNELS_RX == 2 ? 1 : 0))) +#define CFG_TUD_AUDIO_FUNC_1_N_AS_INT 1 +#define CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ 64 + +#ifdef __cplusplus +} +#endif + +#endif /* _TUSB_CONFIG_H_ */ diff --git a/apps/auracast/include/usb_audio.h b/apps/auracast/include/usb_audio.h new file mode 100644 index 0000000000..ea93b9fc5b --- /dev/null +++ b/apps/auracast/include/usb_audio.h @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_USB_AUDIO_ +#define H_USB_AUDIO_ + +#include + +typedef void (* usb_audio_sample_rate_cb_t)(uint32_t); + +/* Set default sample rate, should only be used before USB is initialized */ +void usb_desc_sample_rate_set(uint32_t sample_rate); + +#endif /* H_USB_AUDIO_ */ diff --git a/apps/auracast/pkg.yml b/apps/auracast/pkg.yml new file mode 100644 index 0000000000..902c38028e --- /dev/null +++ b/apps/auracast/pkg.yml @@ -0,0 +1,48 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +pkg.name: apps/auracast +pkg.type: app +pkg.description: Auracast sample application. + +pkg.author: "Krzysztof Kopyściński" +pkg.email: "krzysztof.kopyscinski@codecoup.pl" +pkg.homepage: "http://mynewt.apache.org/" +pkg.keywords: + +pkg.deps: + - nimble/host + - nimble/host/util + - nimble/host/services/gap + - nimble/host/store/config + - nimble/host/audio/services/auracast + - "@apache-mynewt-core/kernel/os" + - "@apache-mynewt-core/sys/config" + - "@apache-mynewt-core/sys/console" + - "@apache-mynewt-core/sys/log" + - "@apache-mynewt-core/sys/stats" + - "@apache-mynewt-core/sys/sysinit" + - "@apache-mynewt-core/sys/id" + +pkg.deps.AUDIO_USB: + - ext/liblc3 + - ext/libsamplerate + - "@apache-mynewt-core/hw/usb/tinyusb" + +pkg.init: + audio_init: 402 diff --git a/apps/auracast/src/app_priv.h b/apps/auracast/src/app_priv.h new file mode 100644 index 0000000000..87b0f97685 --- /dev/null +++ b/apps/auracast/src/app_priv.h @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_APP_PRIV_ +#define H_APP_PRIV_ + +#include +#include + +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +#define AUDIO_CHANNELS MYNEWT_VAL(AURACAST_CHAN_NUM) +#define AUDIO_SAMPLE_SIZE sizeof(int16_t) +#if MYNEWT_VAL(ISO_HCI_FEEDBACK) +#define AUDIO_PCM_SAMPLE_RATE LC3_SAMPLING_FREQ +#else +#define AUDIO_PCM_SAMPLE_RATE MYNEWT_VAL(USB_AUDIO_OUT_SAMPLE_RATE) +#endif + +#define LC3_FRAME_DURATION (MYNEWT_VAL(LC3_FRAME_DURATION)) +#define LC3_SAMPLING_FREQ (MYNEWT_VAL(LC3_SAMPLING_FREQ)) +#define LC3_BITRATE (MYNEWT_VAL(LC3_BITRATE)) +#define LC3_FPDT (AUDIO_PCM_SAMPLE_RATE * LC3_FRAME_DURATION / 1000000) +#define BIG_NUM_BIS (MIN(AUDIO_CHANNELS, MYNEWT_VAL(BIG_NUM_BIS))) + +void audio_chan_set_conn_handle(uint8_t chan_idx, uint16_t conn_handle); +#endif /* H_APP_PRIV_ */ diff --git a/apps/auracast/src/audio.c b/apps/auracast/src/audio.c new file mode 100644 index 0000000000..15c64511a9 --- /dev/null +++ b/apps/auracast/src/audio.c @@ -0,0 +1,378 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#include +#include + +#include "console/console.h" +#include "host/ble_hs.h" +#include "host/ble_iso.h" + +#include "app_priv.h" + +struct chan { + void *encoder; + uint16_t handle; +} chans[AUDIO_CHANNELS]; + +#if MYNEWT_VAL(AUDIO_USB) +#include +#include +#include + +#include +#include +#include + +#include "host/ble_gap.h" +#include "os/os_cputime.h" + +#define AUDIO_BUF_SIZE 1024 + +static uint8_t g_usb_enabled; + +static void usb_data_func(struct os_event *ev); + +static struct os_event usb_data_ev = { + .ev_cb = usb_data_func, +}; + +static uint32_t frame_bytes_lc3; +static uint16_t big_sdu; + +static int16_t out_buf[AUDIO_BUF_SIZE]; +/* Reserve twice the size of input, so we'll always have space for resampler output */ +static uint8_t encoded_frame[155]; +static int out_idx = 0; +#if MYNEWT_VAL(ISO_HCI_FEEDBACK) +static int samples_idx = 0; +static int16_t samples_read[AUDIO_BUF_SIZE]; +/* 155 is maximum value Octets Per Codec Frame described in Table 3.5 of BAP specification */ +static float samples_read_float[AUDIO_BUF_SIZE]; +static float resampled_float[AUDIO_BUF_SIZE]; +float resampler_in_rate = MYNEWT_VAL(USB_AUDIO_OUT_SAMPLE_RATE); +float resampler_out_rate = LC3_SAMPLING_FREQ; +float resampler_ratio; +SRC_STATE *resampler_state; +static struct ble_gap_event_listener feedback_listener; +#endif +static uint32_t pkt_counter = 0; + + +#if MYNEWT_VAL(ISO_HCI_FEEDBACK) +static int +ble_hs_gap_event_handler(struct ble_gap_event *event, void *arg) +{ + struct ble_hci_vs_subev_iso_hci_feedback *feedback_pkt; + float adjust = 0; + + if (event->type == BLE_GAP_EVENT_UNHANDLED_HCI_EVENT && + event->unhandled_hci.is_le_meta == false && + event->unhandled_hci.is_vs == true) { + const struct ble_hci_ev_vs *ev = event->unhandled_hci.ev; + + if (ev->id == BLE_HCI_VS_SUBEV_ISO_HCI_FEEDBACK) { + feedback_pkt = (struct ble_hci_vs_subev_iso_hci_feedback *) ev->data; + assert(feedback_pkt->count == MYNEWT_VAL(BLE_ISO_MAX_BIGS)); + /* There is only one BIG in this sample */ + if (feedback_pkt->feedback[0].diff > 0) { + adjust += 10; + } else if (feedback_pkt->feedback[0].diff < 0) { + adjust -= 10; + } + resampler_ratio = (resampler_out_rate + adjust) / resampler_in_rate; + } + } + + return 0; +} + +static void +resample(void) +{ + static int resampled_len; + int samples_consumed; + int samples_left; + SRC_DATA sd; + int resample_avail = ARRAY_SIZE(out_buf) - out_idx; + int rc; + + src_short_to_float_array(samples_read, samples_read_float, samples_idx); + + sd.data_in = samples_read_float; + sd.data_out = resampled_float; + sd.input_frames = samples_idx / AUDIO_CHANNELS; + sd.output_frames = resample_avail / AUDIO_CHANNELS; + sd.end_of_input = 0; + sd.input_frames_used = 0; + sd.output_frames_gen = 0; + sd.src_ratio = resampler_ratio; + + rc = src_process(resampler_state, &sd); + assert(rc == 0); + + resampled_len = sd.output_frames_gen * AUDIO_CHANNELS; + + assert(resampled_len <= resample_avail); + + src_float_to_short_array(resampled_float, + &out_buf[out_idx], + resampled_len); + + out_idx += resampled_len; + + samples_consumed = sd.input_frames_used * AUDIO_CHANNELS; + samples_left = samples_idx - samples_consumed; + memmove(samples_read, &samples_read[samples_consumed], samples_left); + samples_idx -= samples_consumed; +} +#endif + +static void +usb_data_func(struct os_event *ev) +{ + int ch_idx; + unsigned int num_bytes; + unsigned int num_samples; + unsigned int num_frames; + int read; + int skip; + + if (!g_usb_enabled) { + tud_audio_clear_ep_out_ff(); + return; + } + + while ((num_bytes = tud_audio_available()) > 0) { + num_frames = num_bytes / (AUDIO_CHANNELS * AUDIO_SAMPLE_SIZE); + num_samples = num_frames * AUDIO_CHANNELS; + if (out_idx + num_samples >= ARRAY_SIZE(out_buf)) { + num_samples = ARRAY_SIZE(out_buf) - out_idx - 1; + } + num_frames = num_samples / AUDIO_CHANNELS; + num_bytes = num_frames * AUDIO_SAMPLE_SIZE * AUDIO_CHANNELS; + +#if MYNEWT_VAL(ISO_HCI_FEEDBACK) + assert(samples_idx + num_samples < ARRAY_SIZE(samples_read)); + read = tud_audio_read(&samples_read[samples_idx], num_bytes); + samples_idx += num_samples; + resample(); +#else + assert(out_idx + num_samples < ARRAY_SIZE(out_buf)); + read = tud_audio_read(&out_buf[out_idx], num_bytes); + out_idx += num_samples; +#endif + assert(read == num_bytes); + + assert((out_idx & 0x80000000) == 0); + if (out_idx / AUDIO_CHANNELS >= LC3_FPDT) { + pkt_counter++; + skip = 0; + + for (ch_idx = 0; ch_idx < AUDIO_CHANNELS; ch_idx++) { + if (chans[ch_idx].handle == 0) { + skip = 1; + continue; + } + } + + if (!skip) { + memset(encoded_frame, 0, sizeof(encoded_frame)); + lc3_encode(chans[0].encoder, LC3_PCM_FORMAT_S16, out_buf + 0, + AUDIO_CHANNELS, (int) frame_bytes_lc3, + encoded_frame); + if (AUDIO_CHANNELS == 2) { + if (MYNEWT_VAL(BIG_NUM_BIS) == 1) { + lc3_encode(chans[0].encoder, LC3_PCM_FORMAT_S16, + out_buf + 1, AUDIO_CHANNELS, + (int) frame_bytes_lc3, encoded_frame + big_sdu / 2); + ble_iso_tx(chans[0].handle, encoded_frame, big_sdu); + } else { + ble_iso_tx(chans[0].handle, encoded_frame, big_sdu); + memset(encoded_frame, 0, sizeof(encoded_frame)); + lc3_encode(chans[1].encoder, LC3_PCM_FORMAT_S16, out_buf + 1, + AUDIO_CHANNELS, (int) frame_bytes_lc3, + encoded_frame); + ble_iso_tx(chans[1].handle, encoded_frame, big_sdu); + } + } else { + ble_iso_tx(chans[0].handle, encoded_frame, big_sdu); + } + + if (out_idx / AUDIO_CHANNELS >= LC3_FPDT) { + out_idx -= LC3_FPDT * AUDIO_CHANNELS; + memmove(out_buf, &out_buf[LC3_FPDT * AUDIO_CHANNELS], + out_idx * AUDIO_SAMPLE_SIZE); + } else { + out_idx = 0; + } + } + } + } +} + +bool +tud_audio_rx_done_post_read_cb(uint8_t rhport, uint16_t n_bytes_received, + uint8_t func_id, uint8_t ep_out, + uint8_t cur_alt_setting) +{ + (void)rhport; + (void)n_bytes_received; + (void)func_id; + (void)ep_out; + (void)cur_alt_setting; + + if (!usb_data_ev.ev_queued) { + os_eventq_put(os_eventq_dflt_get(), &usb_data_ev); + } + + return true; +} + +static void +audio_usb_init(void) +{ + /* Need to reference those explicitly, so they are always pulled by linker + * instead of weak symbols in tinyusb. + */ + (void)tud_audio_rx_done_post_read_cb; + + usb_desc_sample_rate_set(AUDIO_PCM_SAMPLE_RATE); + + assert(LC3_FPDT == lc3_frame_samples(LC3_FRAME_DURATION, + AUDIO_PCM_SAMPLE_RATE)); + + unsigned esize = lc3_encoder_size(LC3_FRAME_DURATION, + AUDIO_PCM_SAMPLE_RATE); + for (int i = 0; i < AUDIO_CHANNELS; i++) { + chans[i].encoder = calloc(1, esize); + lc3_setup_encoder(LC3_FRAME_DURATION, LC3_SAMPLING_FREQ, + AUDIO_PCM_SAMPLE_RATE, chans[i].encoder); + } + + g_usb_enabled = 1; + + frame_bytes_lc3 = lc3_frame_bytes(LC3_FRAME_DURATION, LC3_BITRATE); + big_sdu = frame_bytes_lc3 * + (1 + ((AUDIO_CHANNELS == 2) && (BIG_NUM_BIS == 1))); + +#if MYNEWT_VAL(ISO_HCI_FEEDBACK) + int rc; + + assert(resampler_state == NULL); + resampler_state = src_new(SRC_SINC_FASTEST, AUDIO_CHANNELS, NULL); + assert(resampler_state != NULL); + + rc = ble_gap_event_listener_register(&feedback_listener, + ble_hs_gap_event_handler, NULL); + assert(rc == 0); + + resampler_ratio = resampler_out_rate / resampler_in_rate; +#endif +} +#else +#include "audio_data.h" + +#define BROADCAST_MAX_SDU 120 + +static int audio_data_offset; +static struct os_callout audio_broadcast_callout; + +static void +audio_broadcast_event_cb(struct os_event *ev) +{ + assert(ev != NULL); + uint32_t ev_start_time = os_cputime_ticks_to_usecs(os_cputime_get32()); + +#if MYNEWT_VAL(AURACAST_CHAN_NUM) > 1 + if (audio_data_offset + BROADCAST_MAX_SDU >= sizeof(audio_data)) { + audio_data_offset = 0; + } + + if (chans[0].handle != BLE_HS_CONN_HANDLE_NONE) { + ble_iso_tx(chans[0].handle, (void *) (audio_data + audio_data_offset), + BROADCAST_MAX_SDU); + } + if (chans[1].handle != BLE_HS_CONN_HANDLE_NONE) { + ble_iso_tx(chans[1].handle, (void *) (audio_data + audio_data_offset), + BROADCAST_MAX_SDU); + } +#else + if (audio_data_offset + 2 * BROADCAST_MAX_SDU >= sizeof(audio_data)) { + audio_data_offset = 0; + } + + uint8_t lr_payload[BROADCAST_MAX_SDU * 2]; + memcpy(lr_payload, audio_data + audio_data_offset, BROADCAST_MAX_SDU); + memcpy(lr_payload + BROADCAST_MAX_SDU, audio_data + audio_data_offset, + BROADCAST_MAX_SDU); + + if (chans[0].handle != BLE_HS_CONN_HANDLE_NONE) { + ble_iso_tx(chans[0].handle, (void *) (lr_payload), + BROADCAST_MAX_SDU * 2); + } +#endif + audio_data_offset += BROADCAST_MAX_SDU; + + /** Use cputime to time LC3_FRAME_DURATION, as these ticks are more + * accurate than os_time ones. This assures that we do not push + * LC3 data to ISO before interval, which could lead to + * controller running out of buffers. This is only needed because + * we already have coded data in an array - in real world application + * we usually wait for new audio to arrive, and lose time to code it too. + */ + while (os_cputime_ticks_to_usecs(os_cputime_get32()) - ev_start_time < + (MYNEWT_VAL(LC3_FRAME_DURATION))); + + os_callout_reset(&audio_broadcast_callout, 0); +} + +static void +audio_dummy_init(void) +{ + os_callout_init(&audio_broadcast_callout, os_eventq_dflt_get(), + audio_broadcast_event_cb, NULL); + + os_callout_reset(&audio_broadcast_callout, 0); +} +#endif /* AUDIO_USB */ + +void +audio_init(void) +{ + for (size_t i = 0; i < ARRAY_SIZE(chans); i++) { + chans[i].handle = BLE_HS_CONN_HANDLE_NONE; + } + +#if MYNEWT_VAL(AUDIO_USB) + audio_usb_init(); +#else + audio_dummy_init(); +#endif /* AUDIO_USB */ +} + +void +audio_chan_set_conn_handle(uint8_t chan_idx, uint16_t conn_handle) +{ + assert(chan_idx < ARRAY_SIZE(chans)); + chans[chan_idx].handle = conn_handle; +} diff --git a/apps/auracast/src/audio_data.h b/apps/auracast/src/audio_data.h new file mode 100644 index 0000000000..0bb90a4a1f --- /dev/null +++ b/apps/auracast/src/audio_data.h @@ -0,0 +1,4412 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/** LC3 coded audio data, with 48kHz sample rate. + * Audio signal coded here is 100Hz-20kHz sweep signal, in sinus form + */ +const uint8_t audio_data[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x33, 0x99, 0xb9, 0x51, 0x64, 0x62, 0x1d, 0x6c, 0x3c, 0xf8, 0xae, 0xb5, 0xbd, 0x64, 0xba, 0x9e, + 0xe2, 0x0c, 0x72, 0x7a, 0x4c, 0xdc, 0xed, 0x84, 0x9d, 0x8a, 0x75, 0x28, 0x61, 0x88, 0xcc, 0x11, + 0xef, 0x66, 0x35, 0x9e, 0xbf, 0x34, 0xdd, 0x56, 0xcb, 0x39, 0x9a, 0xed, 0x53, 0xe7, 0xc6, 0x6e, + 0x73, 0x53, 0x29, 0x4e, 0x02, 0x2f, 0xb2, 0x65, 0x81, 0xe9, 0xb6, 0xee, 0xf5, 0x35, 0x20, 0xfc, + 0xc1, 0x31, 0x7e, 0x63, 0x28, 0x9f, 0x03, 0xe0, 0x7e, 0x07, 0xe0, 0x7e, 0x07, 0xe0, 0x3d, 0xe0, + 0xf9, 0x11, 0xcf, 0x5d, 0xab, 0x9c, 0xc4, 0x78, 0xed, 0x64, 0xbd, 0x3e, 0x4c, 0x6b, 0x06, 0x27, + 0x1a, 0x80, 0xf1, 0xb0, 0xec, 0x96, 0x4a, 0x21, 0x07, 0xb2, 0x13, 0xf0, 0x3f, 0x03, 0xf3, 0x02, + 0x38, 0x26, 0x1e, 0x8b, 0x82, 0x6a, 0x63, 0x34, 0x33, 0x9e, 0x72, 0xd8, 0xa9, 0x96, 0xbe, 0x10, + 0x87, 0xca, 0x68, 0x69, 0x81, 0xa0, 0x5e, 0x6d, 0xeb, 0xbb, 0x09, 0x50, 0x8c, 0x3c, 0xda, 0xbd, + 0x5b, 0x20, 0x77, 0xae, 0xa8, 0x4f, 0x74, 0xde, 0x0a, 0xa7, 0xe4, 0x2f, 0x0a, 0x8c, 0x91, 0x84, + 0xb5, 0x97, 0x9e, 0xdf, 0x04, 0x86, 0xce, 0x02, 0xdc, 0xa2, 0xf2, 0x33, 0x0c, 0xe5, 0x0d, 0x2a, + 0x36, 0x59, 0xd7, 0x03, 0x0c, 0xb7, 0xb3, 0xa1, 0xe3, 0x7f, 0x21, 0x58, 0xd1, 0x5d, 0xb8, 0x3f, + 0x03, 0xf0, 0x3f, 0x01, 0xfc, 0x07, 0xf0, 0x0f, 0xe0, 0x5f, 0x83, 0xb8, 0x07, 0x8b, 0x04, 0xe4, + 0x32, 0x08, 0x21, 0x4a, 0x97, 0x4a, 0x76, 0x4a, 0x06, 0x71, 0xba, 0x1b, 0xb9, 0x6f, 0x05, 0xb4, + 0x67, 0xf1, 0x0b, 0xee, 0x03, 0xf0, 0x1f, 0x18, 0x38, 0x26, 0x1e, 0x8f, 0x82, 0x6a, 0x63, 0x34, + 0x33, 0x99, 0xb9, 0x7c, 0x0f, 0xda, 0x8d, 0xcf, 0x8f, 0x01, 0xff, 0x62, 0x63, 0xf0, 0x32, 0x2f, + 0xd1, 0x7f, 0xc9, 0x4a, 0xe1, 0x4f, 0x8c, 0x0f, 0xf3, 0x9b, 0x09, 0xb7, 0xad, 0xdd, 0xe8, 0xba, + 0xd5, 0x9c, 0xf1, 0x88, 0x8d, 0x7f, 0x56, 0x46, 0x8b, 0x8d, 0x5a, 0x1e, 0xd1, 0xe7, 0xdf, 0x70, + 0xf5, 0x06, 0x80, 0x58, 0xb7, 0xe1, 0x9d, 0x60, 0x1e, 0xcf, 0x07, 0x7c, 0xfb, 0xdf, 0x3a, 0x26, + 0x27, 0x53, 0x54, 0xe3, 0x33, 0x8f, 0x42, 0x0f, 0x0f, 0x87, 0x81, 0xf8, 0x0f, 0xc0, 0xfe, 0x07, + 0xe0, 0x7b, 0xad, 0x59, 0x8a, 0xea, 0x1f, 0xaa, 0x87, 0x79, 0x6b, 0x6e, 0x60, 0x0c, 0x81, 0xf0, + 0x60, 0x2d, 0x62, 0x78, 0xc8, 0x1d, 0x27, 0x28, 0x0f, 0xc0, 0x3d, 0x98, 0x07, 0xe0, 0x1f, 0x10, + 0x38, 0xed, 0x92, 0x2b, 0x82, 0x6a, 0x73, 0x2c, 0xaf, 0xdd, 0x4d, 0x39, 0x00, 0xfc, 0x8e, 0x80, + 0x31, 0x4b, 0xdc, 0x52, 0x82, 0x9c, 0x16, 0x03, 0x87, 0xd5, 0xca, 0x62, 0xe5, 0xd4, 0xb3, 0x0b, + 0xe2, 0xae, 0x6c, 0x4f, 0xfe, 0x46, 0xf7, 0x90, 0xdd, 0x29, 0xf5, 0xb6, 0x42, 0x3f, 0xd1, 0x5a, + 0xa1, 0xdf, 0x46, 0x4c, 0x20, 0x4a, 0x86, 0x72, 0x5f, 0x5b, 0xc6, 0xff, 0x0d, 0x44, 0x35, 0x91, + 0xf7, 0x3d, 0xbe, 0x78, 0x7c, 0xb7, 0x03, 0x0e, 0x7d, 0x91, 0x24, 0xf2, 0xe8, 0x78, 0x1f, 0x03, + 0xf8, 0x0f, 0xe0, 0x7f, 0x03, 0xf0, 0x3e, 0x1f, 0x64, 0x1b, 0x84, 0x67, 0x94, 0x12, 0x20, 0x78, + 0xf3, 0x20, 0x26, 0x56, 0x7f, 0xd7, 0x1c, 0xf3, 0xfd, 0xf0, 0xe8, 0x29, 0xf0, 0x7c, 0xf2, 0x82, + 0x6f, 0x81, 0x07, 0x90, 0x3f, 0x03, 0xe2, 0x88, 0x31, 0x2b, 0xc8, 0x3d, 0xd2, 0x6a, 0x03, 0xcc, + 0x63, 0xc0, 0x39, 0xbf, 0x1b, 0x8d, 0x08, 0xa5, 0xfd, 0xdd, 0x32, 0x8e, 0x3c, 0x8e, 0x4c, 0x58, + 0xd8, 0x33, 0x7f, 0xa7, 0xb8, 0xbf, 0x8a, 0xbb, 0xe2, 0xd8, 0x12, 0xc5, 0x52, 0x1a, 0xe1, 0xb1, + 0x42, 0x07, 0xcc, 0x22, 0x76, 0x3e, 0x90, 0xb3, 0x00, 0xa6, 0x41, 0xb2, 0xa1, 0xd6, 0xfb, 0x57, + 0x00, 0x5b, 0xd3, 0x1e, 0x83, 0x1c, 0xab, 0x1d, 0x13, 0x25, 0x0b, 0xac, 0xff, 0x98, 0xd4, 0x57, + 0x9b, 0x0c, 0xb8, 0x0f, 0x0f, 0x87, 0xe0, 0x7e, 0x07, 0xf0, 0x1f, 0xc0, 0xf8, 0x05, 0xff, 0x9e, + 0x3b, 0x45, 0xc0, 0xfc, 0x69, 0xfc, 0x75, 0x6b, 0x4b, 0x2c, 0xc7, 0xf6, 0xbf, 0x22, 0x2c, 0xea, + 0x17, 0x89, 0xc3, 0x7f, 0x08, 0xee, 0x38, 0x22, 0x67, 0x74, 0x65, 0x0f, 0x7f, 0x00, 0xf7, 0x04, + 0x27, 0x38, 0xa9, 0xbf, 0xd2, 0x6a, 0x23, 0x1c, 0x63, 0xc6, 0xc2, 0x42, 0xcd, 0x56, 0x9d, 0x10, + 0x13, 0xbe, 0xdb, 0x5f, 0x7c, 0x58, 0x95, 0x42, 0xb0, 0xf7, 0x0c, 0xe7, 0xa2, 0x41, 0x72, 0x06, + 0xd0, 0xa2, 0x50, 0xd7, 0x6e, 0x9b, 0xd3, 0x91, 0xf9, 0x36, 0xea, 0x12, 0x6b, 0x10, 0xdc, 0x17, + 0xd5, 0x1d, 0xab, 0x1a, 0xea, 0x55, 0xe8, 0xba, 0xf4, 0x3d, 0x68, 0x0a, 0x46, 0x18, 0xc7, 0xef, + 0xfe, 0x94, 0x1f, 0x80, 0x52, 0x23, 0x36, 0x0e, 0x7a, 0xf4, 0xb7, 0x03, 0xf0, 0x7e, 0x07, 0xe0, + 0x7e, 0x07, 0xe0, 0x3f, 0x03, 0xe0, 0xeb, 0xed, 0xd1, 0x6a, 0xb9, 0xd0, 0xaa, 0x93, 0x61, 0xe7, + 0x00, 0xea, 0x7a, 0x34, 0x0e, 0x80, 0x04, 0x20, 0x86, 0x8f, 0xd7, 0x96, 0x22, 0xff, 0x64, 0x45, + 0xed, 0xc0, 0x44, 0xf7, 0x30, 0x44, 0xf2, 0x92, 0x27, 0x50, 0x01, 0x3f, 0xd2, 0x6a, 0x23, 0x5c, + 0xa7, 0x93, 0x9c, 0x4e, 0x56, 0x0f, 0xc9, 0x0e, 0x09, 0x8f, 0x16, 0x16, 0x67, 0x00, 0xc3, 0x9c, + 0x78, 0x02, 0xca, 0xb1, 0x24, 0x26, 0x40, 0x37, 0xce, 0xd5, 0x00, 0xee, 0x86, 0x26, 0x76, 0x6b, + 0xb0, 0xb3, 0x97, 0x5f, 0x92, 0x10, 0x13, 0x95, 0xcf, 0xf6, 0x49, 0x33, 0x7b, 0x85, 0xf6, 0x01, + 0x26, 0x4e, 0x12, 0xe2, 0xc6, 0xa5, 0x19, 0x1d, 0x63, 0x97, 0xd1, 0x60, 0xfa, 0x44, 0xf8, 0x75, + 0x8f, 0x50, 0xb2, 0x2a, 0x9f, 0x07, 0xe0, 0xfc, 0x0f, 0x80, 0xfe, 0x07, 0xf0, 0x3e, 0x0f, 0xb1, + 0x05, 0x05, 0x19, 0x2c, 0x20, 0x39, 0xaf, 0x8a, 0x48, 0xe9, 0xfb, 0x4e, 0xed, 0xc7, 0xbe, 0x6f, + 0x5b, 0xac, 0x58, 0x02, 0x3c, 0x84, 0xc6, 0xf6, 0xc0, 0x40, 0xf7, 0x78, 0x4d, 0xdd, 0x8b, 0x0d, + 0xe7, 0x50, 0x01, 0x3f, 0xd2, 0x6a, 0x43, 0x2c, 0xaf, 0xdd, 0xed, 0xea, 0x51, 0x7d, 0x91, 0x2c, + 0x07, 0x57, 0x30, 0x76, 0x1d, 0xd0, 0xe8, 0x5e, 0xf5, 0x2e, 0x02, 0xa0, 0xf5, 0x04, 0x52, 0x9d, + 0x22, 0xbf, 0xda, 0x21, 0x3b, 0x04, 0x96, 0x7e, 0x4f, 0xea, 0x2d, 0x0f, 0x69, 0xf0, 0xc3, 0xc2, + 0xea, 0x8e, 0x0f, 0xd9, 0xed, 0x9f, 0x91, 0x6a, 0x71, 0x7a, 0x1b, 0x5d, 0x3f, 0xc4, 0x5b, 0x93, + 0x64, 0xfb, 0x08, 0x49, 0x96, 0xd1, 0xd5, 0xf3, 0x2e, 0x38, 0x9f, 0x96, 0xd7, 0x43, 0xc3, 0xe0, + 0xf0, 0x7c, 0x1f, 0x81, 0xf8, 0x1f, 0x83, 0xd6, 0xb7, 0x69, 0x60, 0x02, 0xec, 0x37, 0xb8, 0x28, + 0x6f, 0x34, 0x37, 0xf5, 0x1d, 0x4b, 0x4b, 0x9f, 0x97, 0xb5, 0xfa, 0x5a, 0x50, 0xa6, 0xec, 0x01, + 0x3f, 0xb0, 0x07, 0x9a, 0x42, 0x7f, 0xc3, 0x09, 0xe7, 0x50, 0x01, 0x3f, 0xd2, 0x6a, 0x14, 0x34, + 0x33, 0xd3, 0xb2, 0xb7, 0x84, 0x00, 0x6e, 0x91, 0xe1, 0x20, 0x56, 0xef, 0x8b, 0x8e, 0x44, 0x6e, + 0xe5, 0xa7, 0x44, 0x89, 0x53, 0x82, 0xb6, 0xb2, 0xa1, 0xef, 0xa8, 0x9d, 0x42, 0x98, 0xa5, 0xde, + 0x26, 0xe5, 0xf2, 0xe6, 0x33, 0x76, 0x66, 0x58, 0x45, 0xeb, 0x40, 0x57, 0xc6, 0x91, 0x06, 0x8b, + 0x1c, 0xcf, 0x58, 0x89, 0xd9, 0x41, 0x93, 0x51, 0x18, 0xfe, 0x08, 0x86, 0x4f, 0x68, 0xbf, 0x21, + 0x65, 0x19, 0x76, 0xa6, 0x87, 0xe0, 0x7e, 0x0f, 0xc0, 0xfc, 0x0f, 0xe0, 0x3f, 0x81, 0xf8, 0x73, + 0x82, 0xc4, 0x87, 0x41, 0xe7, 0x37, 0x70, 0xf0, 0x0a, 0x9e, 0xeb, 0xa3, 0x02, 0x7c, 0x17, 0x81, + 0x2c, 0x26, 0xab, 0xa3, 0xa4, 0x84, 0xe0, 0x07, 0xf3, 0x00, 0x1f, 0x6e, 0x10, 0xf3, 0xc3, 0x06, + 0x27, 0x50, 0x01, 0x3f, 0xd2, 0x6a, 0x43, 0x34, 0xaf, 0xdd, 0x47, 0x5c, 0xd0, 0x54, 0x05, 0x05, + 0xec, 0x4a, 0x53, 0xf8, 0x78, 0x29, 0xbc, 0x82, 0x18, 0x56, 0x38, 0xd4, 0xcd, 0x63, 0xde, 0x94, + 0x75, 0xba, 0xcc, 0xd3, 0xaa, 0xcb, 0xce, 0x4e, 0x27, 0x05, 0x71, 0x74, 0xa6, 0xba, 0xa7, 0xae, + 0xe2, 0x30, 0x16, 0x21, 0x1f, 0x59, 0x51, 0x74, 0xac, 0x13, 0x24, 0xd8, 0x89, 0x5b, 0x7a, 0x61, + 0xa4, 0x49, 0x3e, 0xac, 0x0e, 0xe1, 0xa1, 0xf0, 0x10, 0x78, 0x17, 0xcd, 0x04, 0xf9, 0xb7, 0xac, + 0x9f, 0x0f, 0x83, 0xe0, 0xf8, 0x1f, 0x81, 0xf8, 0x1f, 0x83, 0xc0, 0x0e, 0x9f, 0x5b, 0xda, 0x2f, + 0xdc, 0x72, 0x49, 0x73, 0x02, 0xcf, 0x94, 0x18, 0xa7, 0x16, 0x1b, 0x52, 0x14, 0x1f, 0x1b, 0x7a, + 0xfd, 0x04, 0xcf, 0xc0, 0xfc, 0x07, 0xc6, 0x82, 0x67, 0x52, 0xfc, 0x3f, 0xd2, 0x6a, 0x23, 0x44, + 0x69, 0xd4, 0x3e, 0xe9, 0x79, 0x25, 0x1d, 0x3f, 0xe3, 0x88, 0x05, 0x0b, 0x8c, 0x76, 0x29, 0x7e, + 0xe7, 0xd5, 0x8a, 0xb6, 0x5f, 0x02, 0x85, 0x0e, 0x92, 0x70, 0xb8, 0x44, 0xff, 0x73, 0x7e, 0x47, + 0xe4, 0x30, 0xa4, 0x7f, 0x8a, 0x52, 0x2d, 0x18, 0xa6, 0x28, 0xa1, 0x43, 0x41, 0x2f, 0xaa, 0x69, + 0xba, 0xdb, 0x82, 0xd2, 0xc7, 0x8b, 0xa4, 0x31, 0x85, 0x9b, 0x87, 0x00, 0x00, 0x00, 0x00, 0x06, + 0x73, 0xec, 0x31, 0x42, 0xd2, 0xa7, 0xf9, 0x71, 0x47, 0xc3, 0xe1, 0xf8, 0x1f, 0x81, 0xf8, 0x3e, + 0x0f, 0x11, 0xe9, 0xd3, 0x35, 0xef, 0x37, 0xd6, 0xe4, 0x1a, 0xed, 0x15, 0x73, 0xa7, 0xf3, 0x93, + 0x76, 0xb1, 0x56, 0x5f, 0x78, 0xdc, 0x92, 0x39, 0xbb, 0x90, 0x03, 0xf8, 0x1f, 0x83, 0xf3, 0x05, + 0x67, 0xe7, 0xfa, 0x3f, 0xd2, 0x6a, 0x26, 0x34, 0x35, 0x15, 0x69, 0xd5, 0x3a, 0xa2, 0xc3, 0x59, + 0x46, 0x4c, 0x85, 0x96, 0xaa, 0xc2, 0x9f, 0x34, 0x4c, 0x72, 0x21, 0x98, 0xa7, 0xea, 0xfb, 0xce, + 0xf8, 0xec, 0xce, 0x01, 0x02, 0xa1, 0x70, 0x16, 0x25, 0x1b, 0x7c, 0xb2, 0x38, 0x91, 0x9c, 0xbf, + 0xb8, 0x0a, 0xd4, 0x06, 0xf7, 0x30, 0xcb, 0x51, 0xbf, 0x76, 0x56, 0x2e, 0x9a, 0xeb, 0xb5, 0x8f, + 0x2d, 0x97, 0x6c, 0xc2, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x76, 0x62, 0xab, 0xeb, 0x7d, + 0x4f, 0x07, 0xc1, 0xf0, 0x7e, 0x07, 0xe0, 0x7e, 0x0f, 0x83, 0x9c, 0x10, 0x6d, 0x2a, 0x41, 0x2c, + 0x62, 0x51, 0xc2, 0x35, 0x2d, 0xb3, 0x88, 0x9e, 0x77, 0xc1, 0xe7, 0xad, 0x83, 0xe6, 0x48, 0x80, + 0xde, 0x80, 0x0f, 0xb2, 0x03, 0xf0, 0x3e, 0x88, 0x27, 0xe7, 0xfa, 0x3f, 0xd2, 0x6a, 0x36, 0x3c, + 0xa7, 0x91, 0xec, 0x56, 0xe1, 0x98, 0x95, 0xe9, 0x1d, 0xbc, 0xc2, 0x4a, 0x52, 0x0b, 0x1c, 0x89, + 0x27, 0x28, 0x9b, 0x34, 0x2c, 0x75, 0xb2, 0x56, 0x2f, 0x2c, 0x3f, 0x02, 0x00, 0xc6, 0x99, 0xff, + 0x88, 0x4e, 0x09, 0xde, 0xde, 0x4f, 0xec, 0xe1, 0xdf, 0x4d, 0x20, 0x62, 0x10, 0x56, 0x83, 0x17, + 0x96, 0x25, 0x37, 0x43, 0xc4, 0x8b, 0x9b, 0xaf, 0xd1, 0x13, 0x84, 0x3c, 0x08, 0x4a, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x76, 0x0f, 0xdb, 0xda, 0x39, 0xd6, 0xf0, 0x7c, 0x1e, 0x07, 0xc1, 0xf8, + 0x1f, 0x83, 0xc3, 0xdc, 0x81, 0x20, 0x60, 0x23, 0x26, 0x5c, 0x10, 0x75, 0xc4, 0x4b, 0x4e, 0xa8, + 0x84, 0x8c, 0x3b, 0x5c, 0xc4, 0xdc, 0x28, 0x39, 0x91, 0x01, 0xe7, 0x03, 0xf8, 0x0f, 0xc3, 0x0b, + 0x27, 0xe7, 0xfa, 0x3f, 0xd2, 0x6a, 0x66, 0x1c, 0xaf, 0xdd, 0xe6, 0x14, 0x51, 0x1d, 0x3e, 0x4d, + 0xf9, 0x6e, 0xb8, 0x18, 0x1f, 0x89, 0x35, 0xa4, 0xc6, 0x79, 0x15, 0x60, 0xeb, 0x82, 0xb7, 0xae, + 0x98, 0x7c, 0x70, 0x5c, 0x5d, 0xab, 0x99, 0x44, 0xd0, 0x4d, 0x7d, 0xb2, 0xb2, 0x18, 0x15, 0x99, + 0x4b, 0x1d, 0x06, 0xad, 0x85, 0x51, 0xd7, 0x4f, 0xe8, 0x3b, 0xbf, 0x3b, 0x20, 0x5d, 0xb5, 0x9e, + 0xec, 0x2b, 0x9d, 0xa1, 0xd8, 0x8b, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xb5, 0x43, 0xbf, + 0xbc, 0x78, 0x3e, 0x0f, 0x83, 0xf0, 0x1f, 0x83, 0xc3, 0x9a, 0x3c, 0xc6, 0x22, 0x02, 0x31, 0x0d, + 0x74, 0xd6, 0x10, 0xb1, 0x8a, 0x37, 0xab, 0x8d, 0xdb, 0xa0, 0xc8, 0x26, 0x8d, 0x8e, 0x44, 0x5f, + 0x60, 0xbc, 0xe0, 0x3f, 0x01, 0xf8, 0x1f, 0x04, 0x27, 0xe7, 0xfa, 0x3f, 0xd2, 0x6a, 0x45, 0xa4, + 0x3f, 0xa9, 0x40, 0x35, 0xdd, 0x67, 0x11, 0x0b, 0xa4, 0x4d, 0x3c, 0xc4, 0xc1, 0x33, 0x8d, 0xe7, + 0xcc, 0x54, 0xe6, 0xf9, 0x68, 0x49, 0xa7, 0x13, 0x19, 0x19, 0xe1, 0x34, 0x9e, 0xc9, 0xcc, 0x42, + 0x08, 0x36, 0xb6, 0x53, 0x01, 0xc2, 0x13, 0x36, 0x48, 0xe5, 0x05, 0x1c, 0xa1, 0x51, 0xa7, 0x17, + 0x43, 0x1e, 0x4e, 0xe4, 0x2c, 0x56, 0xbe, 0x00, 0x00, 0x00, 0x0a, 0x96, 0x82, 0xdd, 0x7b, 0xa1, + 0xdc, 0x9b, 0xc7, 0xae, 0xce, 0xd3, 0x6a, 0x04, 0x8a, 0x5c, 0x0c, 0xf8, 0x70, 0x0f, 0xbf, 0x57, + 0x5a, 0xdc, 0x3a, 0x27, 0xd0, 0x9f, 0x66, 0xda, 0x2c, 0xbd, 0x47, 0x2f, 0xbe, 0x1a, 0x91, 0x47, + 0xe8, 0x8e, 0x27, 0x8b, 0x9a, 0xcb, 0xf2, 0x48, 0x7e, 0x07, 0xc1, 0xf8, 0x1e, 0xf6, 0x0a, 0x87, + 0x27, 0xe7, 0xfa, 0x3f, 0xd2, 0x79, 0xf6, 0x3c, 0x33, 0x99, 0xb9, 0xa2, 0xb8, 0x20, 0xa8, 0xd0, + 0x14, 0xc3, 0xc7, 0xbd, 0x56, 0x64, 0x68, 0x11, 0x39, 0x6c, 0xd6, 0x71, 0x8f, 0xca, 0x73, 0x0f, + 0x39, 0xce, 0xf3, 0x2d, 0xd2, 0xb6, 0xc2, 0x0d, 0x00, 0x0d, 0xd7, 0xda, 0xb7, 0xa8, 0xa7, 0x2f, + 0x64, 0xdd, 0x61, 0x33, 0x6a, 0xe5, 0x01, 0x56, 0xdb, 0x57, 0xc8, 0xd0, 0x99, 0x25, 0xa3, 0xbf, + 0xe8, 0x99, 0xad, 0x1b, 0x14, 0xe5, 0x19, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0xf1, + 0xff, 0xe3, 0xc0, 0xfc, 0x0f, 0xc0, 0xfc, 0x07, 0xe0, 0x78, 0x0f, 0x66, 0x77, 0xb9, 0xf7, 0xfc, + 0x8e, 0xa8, 0x45, 0xe2, 0xed, 0xcc, 0xa3, 0xbc, 0x63, 0x25, 0xe0, 0x8c, 0xdb, 0xf1, 0x03, 0x99, + 0x03, 0xf6, 0x00, 0x9f, 0xe0, 0x1f, 0xc3, 0x0d, 0x27, 0xe7, 0x96, 0x3f, 0xd2, 0x6a, 0x55, 0xbc, + 0x69, 0xac, 0x33, 0x2a, 0x32, 0xd6, 0x00, 0xf5, 0x23, 0x68, 0xb5, 0x0a, 0x0d, 0x7a, 0xcf, 0x1f, + 0xf7, 0xa3, 0x8e, 0xf6, 0x01, 0x61, 0x3c, 0x7d, 0x41, 0x95, 0x21, 0xce, 0x2f, 0xe9, 0x70, 0xb3, + 0xc3, 0x30, 0x21, 0xc6, 0xe5, 0x8a, 0x27, 0x72, 0x7f, 0x0f, 0xcc, 0x0a, 0x90, 0x9f, 0xbd, 0xcd, + 0x5a, 0x8c, 0xf5, 0x59, 0xcb, 0x29, 0xff, 0xc5, 0x58, 0x00, 0x79, 0x88, 0xdc, 0xf3, 0x8a, 0x19, + 0x7f, 0x5f, 0x1d, 0x73, 0x4b, 0x32, 0xa4, 0xdb, 0x74, 0xe1, 0xac, 0x3e, 0x0f, 0xc0, 0x00, 0xd0, + 0xe2, 0x5e, 0xa2, 0x12, 0x93, 0x5b, 0x2f, 0x83, 0x88, 0x00, 0x52, 0xdd, 0x2a, 0xd0, 0x12, 0x31, + 0x85, 0x4f, 0x62, 0x18, 0x7f, 0xae, 0x3e, 0x90, 0x3c, 0x3e, 0x0f, 0xc1, 0xf1, 0x91, 0x3a, 0x16, + 0x27, 0xe7, 0x96, 0x3b, 0xd2, 0x7a, 0x06, 0x3c, 0xaf, 0xdc, 0xb8, 0x33, 0x53, 0x0e, 0x82, 0xd0, + 0x2d, 0x35, 0x02, 0x56, 0x8b, 0xa3, 0x75, 0x19, 0xce, 0x1d, 0xd0, 0x3f, 0x25, 0x19, 0x13, 0xc6, + 0x96, 0xc5, 0x1d, 0x4a, 0x0f, 0x06, 0xae, 0x07, 0x3e, 0xf1, 0x0d, 0x05, 0x99, 0x16, 0xce, 0x7d, + 0x6e, 0x50, 0xed, 0xdb, 0x6e, 0x7e, 0x7d, 0x90, 0xb4, 0xd0, 0x78, 0x5a, 0x98, 0x33, 0xa1, 0x7f, + 0xfc, 0x43, 0x27, 0x4b, 0x2a, 0xe3, 0x8c, 0xd0, 0x90, 0x1f, 0xae, 0x5f, 0x26, 0x1e, 0x1e, 0x0f, + 0xc0, 0xfc, 0x0f, 0xc1, 0xf0, 0x3f, 0x8e, 0x2a, 0x7b, 0xdc, 0x96, 0x1f, 0x9b, 0x7c, 0x27, 0x8f, + 0x6e, 0x0d, 0x0c, 0xd8, 0xa4, 0xf8, 0xd6, 0x9e, 0x3b, 0xf1, 0x4f, 0x01, 0xc0, 0x86, 0x63, 0xb6, + 0x01, 0xf8, 0x23, 0xee, 0x07, 0xe0, 0x3e, 0x9f, 0x26, 0x4c, 0x20, 0xfb, 0xd2, 0x6a, 0x03, 0xec, + 0x17, 0x53, 0xd0, 0x86, 0xa5, 0xe8, 0x6d, 0x4d, 0xbe, 0x39, 0xb9, 0xa5, 0x84, 0xc6, 0x65, 0x73, + 0x7c, 0x85, 0x03, 0x8b, 0xa7, 0xda, 0x83, 0x20, 0x7d, 0x0b, 0x4d, 0xcf, 0x76, 0xcb, 0x5c, 0x2e, + 0x2c, 0x4a, 0x51, 0xfc, 0xed, 0xf5, 0xb2, 0x0b, 0x0f, 0x0f, 0xe5, 0xe1, 0x2d, 0x10, 0x1a, 0xa3, + 0xcb, 0x72, 0x90, 0xab, 0xda, 0x00, 0xda, 0xcf, 0x45, 0xcc, 0x92, 0xb1, 0x56, 0x88, 0xae, 0x86, + 0x27, 0x58, 0x70, 0x80, 0x20, 0x0f, 0xe0, 0x3e, 0x07, 0xf0, 0x1f, 0x80, 0xfe, 0x07, 0x8f, 0xb0, + 0x83, 0xb1, 0xc0, 0x27, 0x20, 0x70, 0xa1, 0xc8, 0x62, 0x2a, 0xdc, 0xae, 0x70, 0xe8, 0xd5, 0xec, + 0x9e, 0xfb, 0xfe, 0xcd, 0x42, 0x2f, 0x80, 0x0f, 0xb8, 0x0f, 0xf0, 0x0f, 0xb7, 0x00, 0xfa, 0x95, + 0x27, 0xce, 0x0d, 0xbb, 0xd2, 0x6a, 0x43, 0xdc, 0x35, 0x7f, 0x0d, 0x4c, 0x15, 0xef, 0xff, 0x79, + 0x66, 0x85, 0x1c, 0x28, 0xef, 0x72, 0x31, 0xf1, 0x4a, 0x76, 0x45, 0x5a, 0xd5, 0xf2, 0xed, 0xb9, + 0x36, 0xad, 0x63, 0x9c, 0x43, 0x33, 0xc0, 0xf2, 0x26, 0xad, 0x99, 0x18, 0xb7, 0xdf, 0x09, 0x9e, + 0xd2, 0xc1, 0x55, 0x5b, 0x95, 0xa5, 0xba, 0x98, 0xec, 0x96, 0x3b, 0x93, 0x0d, 0x94, 0x6d, 0xc9, + 0x0e, 0xae, 0x65, 0xcc, 0x9b, 0x1a, 0xd8, 0x54, 0x18, 0xe1, 0x80, 0x0a, 0xe0, 0x1c, 0xe4, 0xf3, + 0xe0, 0x7c, 0x1f, 0x83, 0xf0, 0x1f, 0xc0, 0xf8, 0x3c, 0x1f, 0xab, 0xa9, 0xe8, 0xee, 0x30, 0x5d, + 0x8f, 0x19, 0x57, 0xf5, 0xaa, 0x78, 0xe5, 0x69, 0xf4, 0x11, 0x13, 0x73, 0x17, 0x47, 0xfd, 0xc0, + 0x3d, 0xc8, 0x1f, 0xc0, 0xfc, 0x07, 0xe2, 0xa0, 0xc6, 0x3d, 0xab, 0x3b, 0xd2, 0x6a, 0x24, 0x5c, + 0xb7, 0xcc, 0x62, 0xe4, 0x68, 0xfe, 0x89, 0x40, 0x8a, 0x0a, 0xc0, 0x0e, 0xf8, 0x35, 0x2d, 0xc7, + 0x90, 0xc0, 0x07, 0xbf, 0x4e, 0x32, 0xd5, 0x0a, 0xb2, 0x89, 0xe3, 0xa5, 0x6c, 0x0f, 0xe7, 0x49, + 0x27, 0xe3, 0xa8, 0xf5, 0xb5, 0x51, 0x96, 0x00, 0x4b, 0x3a, 0x4a, 0xbd, 0x2f, 0xd8, 0x45, 0x20, + 0x14, 0x82, 0xd8, 0xaf, 0xd5, 0x17, 0x3d, 0xf5, 0x1b, 0xd9, 0x37, 0x8a, 0x56, 0xf6, 0x19, 0x16, + 0xd3, 0x02, 0x37, 0xb5, 0xc0, 0xf1, 0x7e, 0xf3, 0x87, 0xc3, 0xf0, 0xfc, 0x3e, 0x1f, 0x03, 0xa6, + 0xa6, 0xbd, 0x86, 0x87, 0x7f, 0xee, 0xef, 0x69, 0x80, 0x7c, 0xee, 0x8b, 0x3f, 0xf2, 0x04, 0x82, + 0xc1, 0xad, 0xe9, 0x10, 0x56, 0x98, 0xa9, 0x4c, 0xb2, 0xa3, 0x9d, 0xf0, 0x3c, 0xf8, 0x7a, 0x17, + 0x07, 0xcb, 0x15, 0xbb, 0xd2, 0x79, 0xf5, 0x7c, 0xaf, 0xdd, 0x5d, 0x70, 0x6c, 0xfd, 0x44, 0x6a, + 0x11, 0x28, 0x28, 0x00, 0x01, 0x20, 0x77, 0x41, 0xb0, 0x01, 0xde, 0x49, 0x2e, 0x48, 0x76, 0xa1, + 0x4b, 0x17, 0xe0, 0x0e, 0x04, 0x23, 0xca, 0x32, 0x74, 0x27, 0x50, 0x02, 0xcc, 0x4d, 0xc6, 0x49, + 0x5b, 0xbb, 0x7e, 0xa4, 0xbf, 0xa0, 0x6c, 0x12, 0x85, 0xa8, 0x0f, 0x26, 0xfe, 0x97, 0x52, 0x68, + 0xc7, 0xfc, 0x0f, 0x5d, 0x9c, 0xbb, 0x6c, 0x13, 0xf9, 0xd1, 0x86, 0x83, 0x58, 0x79, 0xef, 0x61, + 0x87, 0x8d, 0x06, 0x30, 0xe3, 0xf8, 0x49, 0x11, 0x76, 0x45, 0x21, 0x2a, 0x4f, 0x46, 0x57, 0xf6, + 0x38, 0xce, 0xb4, 0x2b, 0x2f, 0xe7, 0x74, 0x68, 0x49, 0x5e, 0x64, 0x62, 0x5f, 0x1d, 0xe6, 0x3e, + 0x50, 0x78, 0x7c, 0x18, 0x0f, 0xe0, 0x3e, 0x35, 0x07, 0xcb, 0x15, 0xbb, 0xd2, 0x79, 0xe4, 0xf4, + 0x69, 0xd4, 0x53, 0xa1, 0xf3, 0x0e, 0xec, 0xe2, 0xa2, 0x7e, 0xde, 0xe0, 0x5d, 0x49, 0x92, 0x4e, + 0xd9, 0xca, 0x6c, 0x1f, 0x60, 0x07, 0x32, 0x68, 0xab, 0x6d, 0xb7, 0x0d, 0x45, 0xa5, 0x93, 0x71, + 0xd3, 0x2c, 0x11, 0x24, 0xfc, 0xbb, 0x5e, 0x0f, 0xea, 0xdd, 0x33, 0x13, 0xcd, 0x83, 0x46, 0x14, + 0x3d, 0x11, 0xcc, 0x97, 0x03, 0x18, 0x90, 0x2e, 0x52, 0x83, 0xae, 0xff, 0xa8, 0x79, 0x15, 0x2a, + 0x2f, 0xac, 0x3b, 0x0b, 0x4c, 0xea, 0xa0, 0x63, 0x38, 0xf0, 0x7f, 0xfd, 0xa7, 0xfb, 0xa3, 0xca, + 0x5f, 0x79, 0xeb, 0x67, 0x49, 0x51, 0x09, 0x44, 0x02, 0x41, 0x2d, 0xa0, 0xc2, 0x1c, 0x9f, 0x99, + 0x3b, 0xab, 0xdb, 0x09, 0x59, 0xca, 0xb4, 0xd0, 0xc7, 0xc0, 0xfc, 0x1f, 0xb0, 0x88, 0xfe, 0xab, + 0x06, 0x3d, 0xab, 0x3b, 0xd2, 0x79, 0xc4, 0x34, 0xb0, 0xdc, 0x62, 0xbe, 0x61, 0x09, 0x75, 0x38, + 0x4f, 0x05, 0x02, 0xd7, 0xea, 0xbb, 0x0b, 0x1e, 0xb9, 0x2f, 0x21, 0x73, 0x59, 0x34, 0x24, 0x53, + 0x10, 0x1f, 0xa4, 0x1c, 0xc2, 0xf3, 0x7c, 0x46, 0x5a, 0x20, 0x6b, 0x6f, 0x0a, 0x76, 0xc7, 0x10, + 0xeb, 0x21, 0x8c, 0x46, 0x57, 0xf9, 0x2d, 0xd9, 0x54, 0x4c, 0x51, 0x7a, 0xf0, 0xdd, 0x77, 0xae, + 0x94, 0xe3, 0x9e, 0xaa, 0xb4, 0x01, 0xc6, 0x7a, 0x00, 0x00, 0x00, 0x02, 0x37, 0xed, 0x8b, 0x51, + 0x48, 0xc7, 0x0f, 0x0e, 0x0f, 0x07, 0xf9, 0x1a, 0x0a, 0x06, 0xa0, 0x83, 0x00, 0x52, 0x9e, 0xf9, + 0xee, 0xbe, 0xc2, 0x1d, 0xab, 0x26, 0xa6, 0x5c, 0x95, 0x51, 0x0b, 0x55, 0xee, 0x4f, 0x8b, 0x19, + 0x8f, 0x33, 0x01, 0x07, 0xe1, 0x83, 0xc6, 0x39, 0x47, 0xcb, 0x15, 0xbf, 0xd2, 0x79, 0xf5, 0x84, + 0x69, 0xd5, 0x7f, 0x4f, 0xd0, 0xba, 0xd5, 0xf0, 0xca, 0xf9, 0x55, 0x53, 0x2d, 0x5d, 0xdd, 0x68, + 0x17, 0x3c, 0xa0, 0x7f, 0x91, 0xde, 0xfe, 0x79, 0x26, 0x2c, 0x56, 0x0d, 0x6d, 0xbc, 0x41, 0x2c, + 0xb6, 0x6e, 0xdf, 0x46, 0x8f, 0x3a, 0xbd, 0x82, 0x4b, 0xd1, 0x64, 0xb2, 0x65, 0xb6, 0x5c, 0x11, + 0x7a, 0xb1, 0xfc, 0x37, 0xda, 0x1d, 0x15, 0x9c, 0x73, 0x2f, 0x39, 0x0e, 0xc8, 0xf9, 0x00, 0x00, + 0x00, 0x00, 0x32, 0x44, 0x6c, 0x0c, 0xb5, 0x36, 0x6e, 0xe1, 0xf0, 0x1e, 0x9f, 0x1d, 0x73, 0xab, + 0x16, 0x46, 0x7e, 0xfb, 0x8e, 0x41, 0xd1, 0xb6, 0x4e, 0xa6, 0x92, 0xe3, 0x5b, 0x6b, 0xd7, 0x28, + 0xfc, 0x56, 0x60, 0x6d, 0x8b, 0x11, 0x2f, 0x38, 0x37, 0xe7, 0x1f, 0x1e, 0x1f, 0x80, 0xf2, 0x95, + 0x06, 0x3d, 0x3d, 0x3f, 0xd2, 0x79, 0xe5, 0x64, 0x69, 0x36, 0x3a, 0x20, 0x8b, 0xb3, 0x05, 0xc1, + 0x8d, 0xe6, 0x37, 0xe2, 0xef, 0xf6, 0xf5, 0xee, 0x37, 0x32, 0xb7, 0x81, 0xc1, 0x18, 0xe6, 0x32, + 0xf3, 0x50, 0x34, 0x2a, 0x5c, 0xba, 0x54, 0xab, 0x34, 0x15, 0x96, 0xb0, 0x9e, 0xb2, 0x8e, 0xe8, + 0x28, 0xac, 0x26, 0xd9, 0xf5, 0x46, 0xbd, 0x94, 0x28, 0x3f, 0x7a, 0x32, 0x28, 0xe7, 0x60, 0x20, + 0x9c, 0xe7, 0x1b, 0x88, 0xfa, 0x7b, 0x18, 0x45, 0xfc, 0xdd, 0x20, 0xd0, 0xe3, 0x4e, 0xe6, 0x62, + 0xc3, 0x87, 0x07, 0xc1, 0xfb, 0x2e, 0xec, 0xbe, 0xe6, 0xb2, 0x98, 0xa8, 0x8d, 0x00, 0x8e, 0x64, + 0xa3, 0xb4, 0x36, 0xc0, 0x9c, 0x87, 0x14, 0xc4, 0x14, 0x72, 0xd8, 0xa3, 0x34, 0x13, 0x0b, 0x41, + 0x7e, 0x71, 0x81, 0xe1, 0xf8, 0x80, 0xf6, 0x88, 0xe7, 0xcc, 0x07, 0xbf, 0xd2, 0x79, 0xe6, 0x2c, + 0x69, 0xf1, 0xf5, 0x5a, 0x22, 0xc4, 0xa2, 0x02, 0x0f, 0x0f, 0xb1, 0xc4, 0x35, 0xad, 0x7d, 0x21, + 0x7b, 0x26, 0xb6, 0x63, 0xe4, 0xa4, 0xe7, 0xc7, 0x26, 0xcc, 0xf7, 0x6d, 0x7e, 0x33, 0x1a, 0xd2, + 0x9d, 0xd7, 0xb4, 0xca, 0x97, 0x5b, 0x15, 0xc0, 0x99, 0xb4, 0xe8, 0x3e, 0xad, 0xcb, 0x14, 0x87, + 0xc4, 0x96, 0x1e, 0x78, 0xad, 0x9d, 0x40, 0x31, 0x51, 0x02, 0xdb, 0x18, 0x33, 0x50, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x81, 0x64, 0xdb, 0xf1, 0xe1, 0xf0, 0x7c, 0x1f, 0x03, 0xfb, 0x93, 0x0c, + 0x33, 0x50, 0x84, 0x93, 0xc8, 0x54, 0xed, 0x60, 0xe6, 0x1a, 0x78, 0xc4, 0x78, 0x91, 0x96, 0xaa, + 0x6c, 0x7d, 0x77, 0xd8, 0x3e, 0x1d, 0x19, 0x3b, 0xf3, 0x01, 0xc1, 0xf8, 0x7e, 0x07, 0xe2, 0x97, + 0x26, 0x3d, 0x3d, 0x3f, 0xd2, 0x79, 0xd6, 0x14, 0x69, 0xd4, 0x53, 0xa3, 0xe8, 0x70, 0x4a, 0x81, + 0xf6, 0xd3, 0x9c, 0x63, 0xec, 0x68, 0x9c, 0x8e, 0x6f, 0x1f, 0xde, 0xce, 0x4c, 0xcf, 0xa4, 0x67, + 0x8a, 0x6b, 0x6e, 0x1e, 0x80, 0x26, 0x85, 0x95, 0xe8, 0x72, 0x78, 0x6f, 0xca, 0xb7, 0x41, 0xe1, + 0x34, 0x8f, 0xdb, 0x72, 0x39, 0xd0, 0xc8, 0x29, 0xf9, 0x57, 0xd3, 0x74, 0x8c, 0x2d, 0xcb, 0xf0, + 0x33, 0x50, 0x09, 0x12, 0x31, 0xea, 0x1f, 0xc0, 0xe4, 0x6d, 0x7f, 0x00, 0x00, 0x0e, 0x50, 0xd9, + 0x0a, 0x23, 0xe1, 0xc0, 0xf8, 0x3e, 0x07, 0x96, 0x4e, 0x4f, 0x83, 0x5c, 0xef, 0xea, 0xf2, 0xd9, + 0x5c, 0xf9, 0x62, 0x0b, 0x5b, 0xf5, 0xb0, 0xaa, 0xd0, 0x38, 0x17, 0x16, 0x93, 0x6f, 0x0f, 0xc0, + 0xce, 0x72, 0x30, 0xf8, 0xfc, 0x20, 0xfa, 0x8b, 0x27, 0xcc, 0x07, 0xbf, 0xd2, 0x79, 0xf6, 0x14, + 0x69, 0xd4, 0x8e, 0x07, 0x5e, 0x1e, 0xb3, 0x98, 0x6c, 0x51, 0x60, 0xba, 0xd9, 0x89, 0xde, 0xb9, + 0x2a, 0x19, 0xcf, 0x18, 0xd0, 0x53, 0x46, 0x8a, 0x36, 0xe6, 0xf6, 0x48, 0x89, 0xb4, 0x96, 0x8b, + 0x86, 0xe9, 0xb4, 0x36, 0xec, 0x19, 0x7e, 0x88, 0x8f, 0x0d, 0xd3, 0xd6, 0x6a, 0xd0, 0xc8, 0x3e, + 0xf7, 0xe7, 0x03, 0xac, 0xb8, 0xaa, 0x0f, 0xd1, 0x66, 0x30, 0x13, 0x44, 0x12, 0x98, 0xc3, 0x64, + 0x5b, 0x90, 0x08, 0x4d, 0xb5, 0x4d, 0xde, 0x6f, 0x20, 0x2d, 0xf8, 0x7d, 0xb9, 0x57, 0x8f, 0x0f, + 0x83, 0xfc, 0xd4, 0x10, 0xcd, 0xe5, 0x65, 0xd7, 0xb8, 0x54, 0x7c, 0x78, 0xe6, 0xb4, 0xe0, 0xc3, + 0x74, 0x04, 0xf9, 0x0e, 0xdd, 0xf2, 0x69, 0xc1, 0x69, 0xcc, 0x82, 0x67, 0x8c, 0x0f, 0xe2, 0x96, + 0x27, 0xcc, 0x07, 0xbf, 0xd2, 0x79, 0xc6, 0x3c, 0xaa, 0xf5, 0xee, 0xed, 0x94, 0x04, 0x6b, 0x57, + 0x87, 0xef, 0xe1, 0xd8, 0x8b, 0x2f, 0x73, 0x7e, 0xbf, 0xbe, 0x65, 0x4a, 0x47, 0xe4, 0xea, 0x59, + 0x02, 0xde, 0xdd, 0x6e, 0xd0, 0xf6, 0x07, 0x3f, 0x8d, 0x19, 0x4b, 0x8e, 0xa0, 0x35, 0xb7, 0x93, + 0xe2, 0x6a, 0xd8, 0x58, 0xbb, 0x32, 0xa9, 0xcc, 0xe4, 0xa4, 0xbf, 0x73, 0xfe, 0xfd, 0xf8, 0x34, + 0x45, 0x00, 0x00, 0xdd, 0xf7, 0x80, 0x28, 0x98, 0x95, 0x80, 0x28, 0xd1, 0x78, 0x30, 0x55, 0x82, + 0x70, 0xe1, 0xe0, 0x7e, 0x03, 0x1d, 0xfe, 0xd3, 0xf1, 0xe0, 0x7c, 0x17, 0x3f, 0x46, 0x0b, 0x04, + 0xbb, 0xc4, 0x24, 0x0c, 0x0b, 0xa2, 0xb3, 0x08, 0xa4, 0x97, 0xa2, 0x2b, 0x8d, 0xe9, 0xd1, 0xaf, + 0xf8, 0x61, 0xc1, 0xe7, 0xf0, 0x08, 0xfa, 0x9e, 0x27, 0xcc, 0x07, 0xbf, 0xd2, 0x79, 0xd5, 0x44, + 0x69, 0xd4, 0x54, 0x54, 0x30, 0x36, 0x69, 0x18, 0x07, 0xe4, 0xba, 0x8e, 0xd5, 0x08, 0xe6, 0x1b, + 0xf4, 0x6f, 0x93, 0xe0, 0xb0, 0xf5, 0xa7, 0x30, 0x34, 0x47, 0x53, 0x4f, 0xde, 0xbb, 0x83, 0xd9, + 0x24, 0x1e, 0xa3, 0xd5, 0x8a, 0x63, 0xda, 0x21, 0xf5, 0xfe, 0xe2, 0x61, 0x05, 0x10, 0xc2, 0x95, + 0xe7, 0xc4, 0x35, 0xcb, 0xa9, 0xe5, 0xe4, 0xe8, 0xde, 0x10, 0xc7, 0xcd, 0x16, 0x15, 0x03, 0xa3, + 0xa7, 0x00, 0x00, 0x42, 0xcc, 0x9c, 0x39, 0x31, 0xcc, 0x66, 0x8f, 0x0f, 0x0f, 0x83, 0xf0, 0x42, + 0xff, 0xee, 0xd0, 0x26, 0x62, 0x0b, 0x80, 0xd0, 0x86, 0xee, 0x19, 0x19, 0x41, 0xcf, 0x8d, 0xfa, + 0x7e, 0x51, 0xd4, 0x46, 0x81, 0x84, 0x45, 0x84, 0x7b, 0x87, 0x87, 0xc7, 0xf0, 0x00, 0xf2, 0x95, + 0x27, 0xcc, 0x07, 0xbf, 0xd2, 0x79, 0xe6, 0x2c, 0xaf, 0xdd, 0x74, 0x2e, 0x0e, 0x76, 0xa9, 0x35, + 0xf5, 0xa3, 0x37, 0xa7, 0x42, 0xd0, 0x54, 0x22, 0x66, 0xf7, 0xb4, 0x42, 0x4f, 0x70, 0x9f, 0x2c, + 0x9b, 0xf8, 0x69, 0x44, 0x94, 0xae, 0xf8, 0x40, 0xd0, 0x67, 0x52, 0x53, 0xdd, 0x46, 0xf5, 0xc8, + 0xa4, 0x08, 0xfc, 0x4f, 0xcb, 0xc5, 0x31, 0x69, 0xc2, 0x4b, 0x60, 0x1d, 0x6a, 0x4a, 0xba, 0x46, + 0x7b, 0xc8, 0xad, 0x97, 0x83, 0x3b, 0x38, 0x02, 0xdd, 0xf9, 0x49, 0x76, 0xfa, 0xbf, 0xc2, 0xf6, + 0xcf, 0x98, 0xfe, 0x02, 0xcf, 0xc7, 0x43, 0xaa, 0xc8, 0x0f, 0xe3, 0xcc, 0x2d, 0x32, 0x58, 0x75, + 0x93, 0x36, 0x08, 0x3f, 0x70, 0x55, 0xda, 0x2f, 0x68, 0x67, 0x6b, 0x97, 0x3b, 0x69, 0xd4, 0xf1, + 0x3d, 0x2c, 0x03, 0x97, 0xc0, 0x77, 0xe2, 0x0f, 0x27, 0xd4, 0x8f, 0x3f, 0xd2, 0x79, 0xc5, 0x8c, + 0xaf, 0xae, 0x9d, 0x0f, 0x5d, 0x27, 0xcd, 0xc5, 0x34, 0x0d, 0xe2, 0x2b, 0x3e, 0xcf, 0x3b, 0x14, + 0xa2, 0xc5, 0x5f, 0x8b, 0x51, 0x2f, 0x5e, 0x93, 0x79, 0x92, 0xbc, 0x5f, 0x61, 0xb2, 0xfe, 0xa1, + 0x69, 0xc9, 0x22, 0x6c, 0xb3, 0xfc, 0xd2, 0x19, 0xbe, 0x36, 0x6e, 0x50, 0x24, 0xbe, 0xc8, 0x78, + 0xc6, 0xfc, 0x9a, 0xe2, 0xa0, 0x78, 0x53, 0x05, 0xef, 0x1d, 0xe9, 0x97, 0x11, 0x45, 0xa6, 0x3a, + 0xf5, 0x5e, 0x00, 0x02, 0x5a, 0x27, 0x4e, 0x69, 0x44, 0x36, 0x47, 0x0f, 0xc0, 0x7c, 0xb8, 0xad, + 0x43, 0xea, 0xe3, 0x81, 0x07, 0x0a, 0xd3, 0x5b, 0x09, 0x4f, 0x08, 0x3d, 0x95, 0xca, 0x49, 0xed, + 0x56, 0x4e, 0xe9, 0x1a, 0xec, 0xc1, 0x61, 0x1f, 0x08, 0x84, 0xef, 0x8c, 0x71, 0xf0, 0x3e, 0x0c, + 0x27, 0xd4, 0x8f, 0x3f, 0xd2, 0x79, 0xd5, 0x5c, 0xaf, 0x08, 0x0c, 0xb0, 0xd5, 0x02, 0xc9, 0xe1, + 0xde, 0x81, 0xec, 0xbf, 0x8e, 0x50, 0x01, 0x65, 0x64, 0x09, 0xc1, 0xd9, 0x1e, 0x6f, 0x1c, 0x05, + 0x0f, 0xde, 0x11, 0xa3, 0x05, 0xc8, 0xc8, 0xda, 0x48, 0xae, 0x1d, 0x18, 0xfb, 0xd6, 0x3b, 0xe7, + 0x8a, 0x3c, 0xb9, 0xe8, 0x5a, 0x45, 0xa1, 0x58, 0xd0, 0xfe, 0xf7, 0xde, 0x8e, 0x43, 0x1c, 0xd2, + 0xbc, 0x63, 0x48, 0xde, 0xce, 0x7a, 0x52, 0xa2, 0x83, 0x2a, 0x7f, 0x10, 0x52, 0x1c, 0x1f, 0x95, + 0x11, 0x5c, 0x7e, 0x01, 0xfb, 0x0c, 0x2b, 0x1c, 0xc0, 0x77, 0xaf, 0x0f, 0xf5, 0xff, 0x1f, 0xa8, + 0x56, 0x40, 0xcb, 0x7a, 0xfc, 0xa9, 0x5d, 0x05, 0x1c, 0x96, 0x95, 0x49, 0x6b, 0x85, 0xc5, 0x5c, + 0x59, 0x95, 0xfe, 0x18, 0xe0, 0x7b, 0x22, 0x06, 0x27, 0xd4, 0x8f, 0x3f, 0xd2, 0x79, 0xd4, 0x7c, + 0x69, 0xd5, 0x83, 0x56, 0xab, 0xe8, 0xbe, 0xf6, 0x6b, 0x41, 0x7a, 0x2c, 0xf4, 0x58, 0x26, 0xfc, + 0x33, 0x23, 0xd2, 0x32, 0x34, 0x7a, 0x01, 0xaa, 0x66, 0xe1, 0x6c, 0x54, 0x0a, 0xe0, 0xae, 0x92, + 0x63, 0xea, 0x1b, 0x40, 0x05, 0xd6, 0x19, 0xfe, 0xe8, 0x56, 0x4a, 0xd7, 0x4c, 0xee, 0xd4, 0x3f, + 0x99, 0xd5, 0x56, 0x57, 0x34, 0xb1, 0x9b, 0x5a, 0x00, 0x00, 0x00, 0x06, 0x1f, 0x5f, 0x00, 0x10, + 0xc4, 0x91, 0x33, 0xea, 0xbb, 0x2f, 0x2a, 0xee, 0x87, 0xa0, 0x00, 0x06, 0xe1, 0xd8, 0xb4, 0x92, + 0xfd, 0xc1, 0xab, 0x6a, 0x1b, 0x2a, 0x32, 0x9c, 0x9f, 0xf6, 0xf5, 0xb7, 0x4c, 0x73, 0x16, 0xca, + 0x42, 0xc7, 0xd0, 0x0d, 0x7e, 0x5d, 0x41, 0x4a, 0x0f, 0x33, 0xe1, 0xe3, 0xf1, 0x19, 0x36, 0x0e, + 0x3b, 0xc6, 0x06, 0x9e, 0xe2, 0x79, 0xd6, 0x3c, 0x69, 0xd4, 0x53, 0xa1, 0xf3, 0x6d, 0xc1, 0x0c, + 0x7b, 0xab, 0xe2, 0xf3, 0xe0, 0xb6, 0x7c, 0x32, 0xe5, 0xe4, 0x15, 0x1f, 0x09, 0x5d, 0xf6, 0x30, + 0x93, 0x8e, 0xb2, 0x70, 0x09, 0x55, 0x78, 0xb4, 0x7c, 0x12, 0xe8, 0x38, 0x3b, 0x9d, 0x4a, 0x4e, + 0x4c, 0xa1, 0xc7, 0x46, 0xad, 0x6f, 0xb0, 0xbf, 0x9f, 0x98, 0x64, 0xb6, 0x4b, 0x25, 0x6d, 0xd1, + 0xf4, 0xbd, 0xc8, 0x9f, 0xfe, 0x15, 0x1b, 0xe0, 0xe2, 0xb3, 0x57, 0xc2, 0x94, 0xb9, 0x81, 0xfc, + 0x28, 0xd4, 0x74, 0x28, 0x22, 0x92, 0x0b, 0xd8, 0x40, 0x9c, 0x66, 0x95, 0x4c, 0xa1, 0x0b, 0x5f, + 0x0f, 0xfc, 0xf7, 0x83, 0x4a, 0x3b, 0x87, 0x8c, 0xe7, 0xd6, 0x19, 0xe8, 0x57, 0x03, 0x8f, 0x1e, + 0x0f, 0xc1, 0xf0, 0x7f, 0x00, 0x4c, 0xee, 0x88, 0x3b, 0xc6, 0x06, 0x9e, 0xe2, 0x79, 0xc5, 0x44, + 0xaf, 0xdd, 0x90, 0x4e, 0xf2, 0x1c, 0xb4, 0x53, 0xed, 0x62, 0x62, 0x07, 0xe8, 0xff, 0x8b, 0x75, + 0x9a, 0xae, 0xca, 0x1b, 0x89, 0xd0, 0x3c, 0x5f, 0x68, 0x9e, 0xe5, 0x46, 0xdd, 0x74, 0x5a, 0x7d, + 0x73, 0xbc, 0xe4, 0x94, 0xa5, 0x14, 0xd6, 0x53, 0x83, 0x2c, 0x3d, 0x6f, 0x3c, 0xa1, 0x3d, 0x39, + 0x79, 0xe6, 0xa7, 0xb3, 0x24, 0x00, 0x1d, 0x36, 0x16, 0x00, 0x02, 0x64, 0xed, 0x01, 0x6d, 0x15, + 0x57, 0x89, 0xa3, 0x29, 0x10, 0x6d, 0xbe, 0x03, 0x79, 0xdb, 0xcf, 0xad, 0xa1, 0x86, 0x77, 0x75, + 0x19, 0x3c, 0x19, 0x58, 0x6a, 0xf2, 0x3a, 0xd9, 0x3e, 0xbb, 0x24, 0x75, 0xd5, 0x42, 0xf0, 0x54, + 0x26, 0xe6, 0x98, 0x19, 0x1d, 0x36, 0xaf, 0x70, 0xc3, 0x83, 0xc7, 0x80, 0xf6, 0x42, 0x22, 0x05, + 0x7b, 0xc6, 0x06, 0x9e, 0xe2, 0x79, 0xc5, 0xd4, 0x69, 0xd5, 0x83, 0x27, 0xa4, 0x2f, 0xb1, 0xee, + 0xfe, 0xfb, 0x55, 0x90, 0x7c, 0xf9, 0xa6, 0x08, 0x7d, 0x96, 0x78, 0x1f, 0x8d, 0x21, 0xb7, 0xb5, + 0x9b, 0x23, 0x0a, 0x25, 0x6d, 0x7d, 0xc1, 0x06, 0x3d, 0xb8, 0x45, 0x5b, 0x4e, 0x03, 0x91, 0x2d, + 0xef, 0x07, 0x89, 0xd7, 0xb2, 0xe3, 0xd8, 0xe1, 0xf2, 0x31, 0xe7, 0xd8, 0xf1, 0x94, 0x9a, 0x4d, + 0xe5, 0xb4, 0x00, 0x00, 0x00, 0xe5, 0x49, 0xfe, 0x76, 0x9f, 0x61, 0x2e, 0x22, 0xf2, 0x08, 0xd6, + 0xc7, 0xe0, 0x02, 0x62, 0xf1, 0x1c, 0xa0, 0x8b, 0x85, 0x28, 0x14, 0x91, 0xf2, 0x0a, 0xc8, 0xeb, + 0x51, 0x64, 0xc0, 0x1d, 0xaa, 0x64, 0x4d, 0xdd, 0x6d, 0x71, 0xd5, 0x49, 0x87, 0x76, 0x05, 0xcc, + 0x64, 0x96, 0xf0, 0xe1, 0xc7, 0x38, 0x1e, 0x0a, 0x3b, 0xc6, 0x06, 0x9e, 0xe2, 0x79, 0xc6, 0x3c, + 0x37, 0xca, 0x9f, 0xb8, 0x92, 0xad, 0xf0, 0xa9, 0xc0, 0x45, 0x97, 0x26, 0x99, 0xa0, 0x58, 0xa5, + 0xfb, 0x57, 0x8f, 0x72, 0x42, 0x94, 0xed, 0xc2, 0x7b, 0xa6, 0x49, 0xb0, 0x16, 0x71, 0x54, 0xb1, + 0x8c, 0xa8, 0x65, 0xc6, 0x68, 0xbc, 0xcd, 0xc5, 0xf5, 0x0d, 0xe2, 0x12, 0x21, 0xf5, 0xfd, 0xd1, + 0x6b, 0xe9, 0xe2, 0x1f, 0x68, 0x9c, 0xb8, 0xe6, 0x5c, 0x41, 0xd7, 0xb2, 0x4d, 0xba, 0xaf, 0xf4, + 0x61, 0x7e, 0x02, 0xcd, 0x05, 0x32, 0xa0, 0xc3, 0x1f, 0x18, 0x70, 0xe0, 0xf9, 0x1e, 0x09, 0xc1, + 0x9d, 0x3e, 0x4d, 0x35, 0x21, 0x84, 0x3d, 0x75, 0xe1, 0xac, 0x52, 0x20, 0xaa, 0xa9, 0x85, 0xe8, + 0x93, 0x8a, 0x0d, 0xe1, 0x6a, 0x63, 0x9c, 0xa1, 0x5b, 0xa1, 0xc7, 0x07, 0x38, 0x3f, 0x83, 0x01, + 0x1d, 0xe3, 0x03, 0x4f, 0x71, 0x3a, 0x05, 0xe9, 0x69, 0xd4, 0x53, 0x77, 0xbb, 0xff, 0x67, 0x70, + 0x39, 0x68, 0x91, 0x89, 0x3c, 0xd1, 0x1f, 0x23, 0x75, 0x50, 0xae, 0x4b, 0x77, 0xa2, 0xe3, 0x76, + 0x5c, 0xf4, 0x72, 0x1d, 0xa8, 0x0f, 0x55, 0x7a, 0x73, 0x45, 0xbe, 0xd4, 0xe0, 0xe8, 0x99, 0x95, + 0x9a, 0xc9, 0x98, 0xb8, 0x34, 0x03, 0xd1, 0xee, 0x2a, 0x96, 0xde, 0x05, 0xd5, 0xe3, 0x3a, 0x64, + 0xa7, 0x23, 0xdd, 0xe4, 0x00, 0x00, 0x00, 0x0b, 0xd8, 0x35, 0xfd, 0x8c, 0x47, 0x0d, 0xe9, 0xba, + 0xd0, 0xfd, 0xf0, 0x38, 0xf3, 0xe0, 0xf8, 0x33, 0xfa, 0x08, 0x77, 0x0a, 0xc3, 0xca, 0x7b, 0x9f, + 0x25, 0xa7, 0x0c, 0x84, 0xbd, 0x28, 0xa1, 0x72, 0x6c, 0x95, 0x59, 0xb7, 0x35, 0x31, 0xda, 0x8b, + 0xe3, 0xe2, 0x80, 0xdb, 0x8d, 0xf0, 0x3b, 0x06, 0x1d, 0xe3, 0x03, 0x4f, 0x71, 0x3a, 0x35, 0xf1, + 0x69, 0xd4, 0x53, 0x7a, 0xa6, 0x57, 0xdf, 0xe0, 0xec, 0xd6, 0x52, 0x4c, 0x37, 0x16, 0xbc, 0x17, + 0xd6, 0x92, 0x5e, 0xf8, 0x71, 0xa2, 0xb3, 0x49, 0xf2, 0x3b, 0x94, 0xb1, 0x4d, 0xe9, 0x39, 0x1e, + 0xb7, 0x3c, 0x2d, 0xdd, 0x5f, 0xfe, 0x9c, 0x89, 0x26, 0x7b, 0xfd, 0x7c, 0x1f, 0xcc, 0xbd, 0x6f, + 0x35, 0x7f, 0x6f, 0x2d, 0x5b, 0xe3, 0x53, 0x1c, 0x7c, 0x04, 0x77, 0x08, 0x30, 0xc1, 0xa1, 0xa2, + 0xed, 0x99, 0x8a, 0x91, 0x26, 0x61, 0xb2, 0x72, 0x99, 0x92, 0xce, 0x1e, 0x0e, 0x1e, 0x0c, 0x3f, + 0xea, 0x80, 0xde, 0x29, 0xef, 0x60, 0xd3, 0xf3, 0xac, 0xa5, 0x09, 0x18, 0x42, 0x0b, 0x6e, 0x63, + 0xe1, 0x31, 0xdb, 0x8d, 0x6b, 0xe7, 0x84, 0xac, 0xc7, 0x18, 0x19, 0x98, 0x6f, 0x80, 0x78, 0xc2, + 0x1d, 0xe3, 0x03, 0x4f, 0x71, 0x3a, 0x26, 0x39, 0x05, 0xc2, 0xd1, 0x02, 0xeb, 0x04, 0x30, 0x1f, + 0xcf, 0x8f, 0x99, 0x5a, 0x19, 0xa7, 0x82, 0xcb, 0x70, 0xf0, 0xf2, 0xa9, 0xc3, 0xfe, 0x36, 0x90, + 0xd7, 0x19, 0xda, 0xce, 0x16, 0xf6, 0xcc, 0x85, 0xe9, 0x73, 0x15, 0x2a, 0xeb, 0x53, 0xdf, 0x4b, + 0xec, 0x7f, 0x01, 0x5b, 0x50, 0x75, 0xcc, 0x9d, 0x62, 0xfd, 0x8b, 0x11, 0x7e, 0x07, 0xfb, 0x79, + 0x22, 0xdb, 0xdc, 0x15, 0x2c, 0xc9, 0xc9, 0x54, 0xd3, 0x39, 0x61, 0xf6, 0xe1, 0x6c, 0x48, 0x06, + 0x70, 0xf8, 0xe7, 0x73, 0xc1, 0xf8, 0x3b, 0x72, 0x45, 0x80, 0x23, 0x87, 0x34, 0x28, 0xed, 0x10, + 0x70, 0x70, 0x48, 0xec, 0x62, 0x03, 0xe2, 0x5b, 0x33, 0x9a, 0xea, 0x72, 0xa1, 0x20, 0x5f, 0x60, + 0x7e, 0x0f, 0xc0, 0xf8, 0x3f, 0x03, 0xf0, 0x03, 0x3c, 0xa4, 0x87, 0x67, 0x71, 0x2a, 0x25, 0x21, + 0x00, 0x01, 0x61, 0xb5, 0x61, 0x7c, 0x6c, 0x47, 0xba, 0x3d, 0xba, 0x3b, 0x5c, 0x42, 0xd7, 0x8e, + 0x8c, 0xe2, 0xb3, 0x20, 0x0d, 0x14, 0x0b, 0x6b, 0x95, 0x91, 0x80, 0x4d, 0x74, 0x86, 0x41, 0x97, + 0x14, 0xb9, 0x72, 0xeb, 0x77, 0xd4, 0x8e, 0x6e, 0xe5, 0xba, 0x3b, 0xe6, 0x83, 0x28, 0xa4, 0xd0, + 0x57, 0x9f, 0xc9, 0x04, 0x3a, 0x71, 0xf3, 0xa4, 0x1b, 0xf5, 0x32, 0xfd, 0x20, 0x36, 0x0d, 0x48, + 0xd3, 0x76, 0x46, 0x67, 0x17, 0xed, 0x1c, 0x1c, 0x38, 0x3c, 0x1e, 0x0f, 0x87, 0x87, 0x87, 0x83, + 0xe1, 0xe5, 0xce, 0x1e, 0x07, 0xae, 0x46, 0xc6, 0x79, 0x46, 0x26, 0xaa, 0x9e, 0x61, 0x4a, 0xef, + 0x81, 0xa6, 0x18, 0xc3, 0xa3, 0x6b, 0xb8, 0x09, 0xf0, 0x3f, 0x01, 0xfc, 0x0f, 0x87, 0xc2, 0x03, + 0x1c, 0xa4, 0x87, 0x67, 0x71, 0x2a, 0x55, 0x79, 0x05, 0xc2, 0x3c, 0xe5, 0x45, 0x6c, 0xe7, 0x10, + 0x4e, 0xd9, 0xe5, 0x84, 0x46, 0x9c, 0x3f, 0x9c, 0x5b, 0x14, 0xe8, 0x9d, 0xd7, 0xf5, 0x7f, 0xd1, + 0x0d, 0x54, 0x3f, 0xca, 0x46, 0x33, 0xf2, 0xc0, 0x0c, 0xfc, 0x2c, 0x7b, 0xd0, 0xb0, 0xf0, 0xa6, + 0xad, 0x21, 0x47, 0x74, 0x16, 0xb2, 0xa6, 0x37, 0x18, 0xfc, 0x2b, 0x65, 0x57, 0x2e, 0xec, 0x69, + 0x08, 0x72, 0x41, 0x29, 0xcf, 0x2c, 0xf1, 0x5d, 0x9d, 0x78, 0x02, 0xe2, 0x7d, 0x86, 0x83, 0x19, + 0x0e, 0xc3, 0x8c, 0x87, 0x83, 0xc3, 0xdd, 0x0d, 0x0c, 0x40, 0xb6, 0x0f, 0xdc, 0x82, 0x5c, 0x09, + 0x6a, 0x42, 0x75, 0x02, 0x0e, 0x47, 0x6b, 0x00, 0xe6, 0x26, 0x13, 0xa8, 0xe2, 0xfa, 0x1a, 0x0f, + 0x0f, 0xc0, 0xf8, 0x3f, 0x07, 0x83, 0xf0, 0x84, 0x1c, 0xa4, 0x87, 0x67, 0x71, 0x2a, 0x45, 0x01, + 0x19, 0xad, 0x36, 0xf5, 0xc8, 0x09, 0xde, 0x74, 0x71, 0x9e, 0xf3, 0x33, 0x31, 0x6a, 0x35, 0xad, + 0x7c, 0xdd, 0xea, 0xa3, 0x79, 0x54, 0x4f, 0xdb, 0x1b, 0x15, 0x41, 0xb0, 0xf9, 0xf6, 0x07, 0xfd, + 0xe7, 0xcb, 0xe2, 0x24, 0x4f, 0xf1, 0x53, 0x0f, 0x0a, 0xd8, 0xc1, 0xdf, 0xdc, 0x0f, 0x47, 0x2a, + 0x18, 0x0d, 0x2b, 0x0b, 0x78, 0x34, 0x82, 0x11, 0xd7, 0x4d, 0x35, 0x03, 0xeb, 0xce, 0x70, 0x1a, + 0xf5, 0xfd, 0x70, 0x71, 0xf5, 0x2e, 0x3c, 0x3c, 0x3f, 0x03, 0xc3, 0xc3, 0xe1, 0xf0, 0xf8, 0x1d, + 0x6c, 0x9d, 0x2b, 0x22, 0x3c, 0x18, 0x0d, 0x2a, 0x8c, 0xe8, 0x06, 0x16, 0xd6, 0x9c, 0x15, 0x40, + 0x16, 0x06, 0xad, 0xea, 0x9d, 0x0b, 0x8a, 0x83, 0xf3, 0x83, 0xf0, 0x7e, 0x30, 0x7c, 0x0e, 0xc3, + 0xfc, 0xa0, 0x37, 0x47, 0x71, 0x3a, 0x15, 0x01, 0x05, 0xc2, 0x3f, 0x59, 0xce, 0x7c, 0x6c, 0x44, + 0xf7, 0x52, 0xb7, 0x2b, 0x89, 0x80, 0x09, 0x61, 0xd7, 0x77, 0x57, 0x63, 0x87, 0x7b, 0x88, 0xc8, + 0xa5, 0x72, 0xed, 0x94, 0x0c, 0x84, 0x47, 0xdc, 0xc7, 0x89, 0x7d, 0xef, 0x8d, 0x2a, 0xf4, 0x06, + 0xbd, 0x21, 0x6e, 0x3c, 0x50, 0x9b, 0xcc, 0x01, 0x93, 0xa0, 0xac, 0x4a, 0x38, 0xb6, 0x58, 0xdd, + 0x62, 0x84, 0x87, 0x22, 0x90, 0xb1, 0xa6, 0xa9, 0x91, 0xaf, 0xd8, 0x90, 0xcc, 0x0b, 0xb1, 0x20, + 0xf0, 0xe1, 0x86, 0x66, 0x1c, 0x3c, 0x78, 0xe1, 0x1e, 0x76, 0xd8, 0xf5, 0xe4, 0x57, 0xbd, 0xee, + 0xe6, 0x9f, 0x95, 0x13, 0x10, 0x35, 0xcb, 0x1e, 0x84, 0x14, 0x69, 0x8c, 0x06, 0xa6, 0x7c, 0x3e, + 0x0f, 0xc0, 0xfc, 0x0f, 0xc0, 0xfc, 0x0e, 0x05, 0x1c, 0xa0, 0x37, 0x47, 0x71, 0x2a, 0x64, 0xc9, + 0x05, 0xc2, 0x2d, 0xbf, 0x94, 0x18, 0x2b, 0x9e, 0x1e, 0xff, 0x82, 0x28, 0x5f, 0x6c, 0x46, 0x76, + 0x50, 0x29, 0x5e, 0x59, 0x73, 0xfd, 0x6b, 0x8e, 0x64, 0x33, 0xf6, 0xf6, 0x84, 0x2e, 0x95, 0xba, + 0xb2, 0x8d, 0x72, 0xbb, 0x17, 0x71, 0x91, 0x96, 0xae, 0xab, 0x89, 0xa5, 0xa4, 0xad, 0xaa, 0x48, + 0xe9, 0xdc, 0x69, 0xba, 0x16, 0x99, 0xde, 0x56, 0x69, 0x30, 0xfe, 0xe6, 0xab, 0x1c, 0xe4, 0x50, + 0x71, 0x75, 0x5d, 0xd3, 0x09, 0xa2, 0x13, 0xdc, 0x67, 0x3c, 0x3e, 0x3c, 0x3c, 0x3c, 0x1e, 0x1e, + 0x1d, 0xe7, 0x09, 0x3a, 0x24, 0x66, 0xe1, 0xbe, 0x1b, 0x4f, 0x2a, 0xd3, 0x0b, 0xed, 0xd4, 0xbf, + 0x54, 0xf5, 0x4e, 0x5b, 0x71, 0x7a, 0xe8, 0x0f, 0x07, 0xe0, 0x3e, 0x0f, 0x81, 0xe1, 0xf0, 0x06, + 0x1c, 0xa0, 0x37, 0x47, 0x71, 0x2a, 0x24, 0xd9, 0x19, 0xa1, 0x2c, 0x66, 0x90, 0xb6, 0x0a, 0x0d, + 0x39, 0xb6, 0x11, 0x69, 0x65, 0x6e, 0x92, 0x1c, 0x0d, 0xaf, 0x1a, 0x82, 0x29, 0x7f, 0xbb, 0x9c, + 0x8b, 0x12, 0x8b, 0x66, 0x8d, 0xd7, 0x61, 0xad, 0xa1, 0x5c, 0x47, 0x2d, 0x62, 0x01, 0x0f, 0xe3, + 0xb6, 0xdd, 0x68, 0xee, 0x2b, 0x8c, 0xed, 0xf9, 0xea, 0x43, 0x61, 0x65, 0x57, 0xa3, 0xfd, 0xd9, + 0xcb, 0x10, 0xf9, 0x3a, 0xcc, 0x87, 0x09, 0x8f, 0x10, 0xfe, 0xb1, 0x7f, 0x4f, 0xa2, 0xc7, 0xfc, + 0x1c, 0x38, 0x7e, 0x07, 0xe0, 0x7e, 0x07, 0xe0, 0x3f, 0x81, 0x7e, 0x3f, 0xd1, 0xee, 0xb8, 0xad, + 0xf8, 0x0f, 0x28, 0x0f, 0x58, 0x84, 0x12, 0xac, 0x21, 0x96, 0x78, 0x7a, 0xbb, 0x76, 0x06, 0x26, + 0x38, 0x63, 0x3b, 0xc0, 0xe4, 0x1c, 0x0e, 0xc5, 0xfc, 0xa0, 0x0e, 0x47, 0x71, 0x3a, 0x46, 0x29, + 0x00, 0x00, 0x0f, 0x6f, 0xb2, 0x94, 0x5d, 0x10, 0x2f, 0xca, 0x99, 0xc5, 0xc6, 0x84, 0xa9, 0xd4, + 0xe0, 0x81, 0x3e, 0xbf, 0x51, 0x7a, 0x44, 0xdb, 0xc4, 0xf9, 0x33, 0xa3, 0x59, 0xae, 0x80, 0x5b, + 0x47, 0xee, 0x2d, 0xe4, 0xf8, 0xec, 0xcf, 0x46, 0xc5, 0x9f, 0xb2, 0xa4, 0xb2, 0x11, 0xee, 0xaf, + 0x77, 0xbe, 0x76, 0xf4, 0xac, 0xd8, 0x28, 0xe9, 0xf3, 0x5b, 0x93, 0x59, 0x1f, 0xb5, 0x29, 0xf6, + 0xb7, 0xe5, 0xc5, 0x6f, 0xa2, 0x51, 0xe1, 0xf8, 0x7e, 0x0f, 0xc0, 0x7e, 0x07, 0xe0, 0x7c, 0x38, + 0x1d, 0xeb, 0xc8, 0xea, 0xc6, 0x3e, 0x6b, 0xa1, 0xac, 0xfa, 0xdf, 0xa8, 0xf8, 0xc2, 0x6f, 0x1d, + 0x39, 0xa2, 0x89, 0x2a, 0xb0, 0x6b, 0x2e, 0x3d, 0x40, 0x7c, 0x0f, 0xe0, 0x7c, 0x1f, 0x98, 0x07, + 0x1a, 0x68, 0xc9, 0xf7, 0x71, 0x2a, 0x04, 0x79, 0x04, 0x80, 0xfc, 0x37, 0x46, 0x6c, 0xbf, 0xeb, + 0x78, 0xa1, 0xbc, 0x1e, 0x54, 0x0c, 0x33, 0x62, 0x9f, 0x55, 0x6e, 0x5b, 0x00, 0xb2, 0x38, 0x41, + 0x97, 0x66, 0xc6, 0x45, 0x8b, 0xa7, 0x2c, 0xb9, 0xe7, 0x90, 0x7f, 0x40, 0x99, 0x1a, 0x55, 0x84, + 0xc9, 0x0b, 0x80, 0xe8, 0xea, 0xe0, 0x5d, 0x84, 0xc0, 0x56, 0x70, 0xb8, 0x1b, 0x23, 0x82, 0xe7, + 0xff, 0x70, 0xe6, 0x3c, 0xef, 0xb8, 0x9c, 0x87, 0x7b, 0x35, 0xc9, 0x38, 0xd0, 0xec, 0xeb, 0x0f, + 0x0f, 0xc1, 0xf0, 0x3f, 0x03, 0xf0, 0x78, 0xf8, 0xe2, 0xe2, 0x14, 0x96, 0xc0, 0x57, 0x68, 0x89, + 0x74, 0xb7, 0xc1, 0xb2, 0xd6, 0xa9, 0x7e, 0x26, 0xde, 0x28, 0xf0, 0x13, 0xce, 0x07, 0x0f, 0xc3, + 0xe0, 0x7e, 0x07, 0xe0, 0x7e, 0x07, 0xc2, 0x08, 0x1a, 0x68, 0xc9, 0xf7, 0x71, 0x2a, 0x05, 0x21, + 0x00, 0x00, 0x60, 0xee, 0x8d, 0x54, 0xb8, 0xbc, 0x11, 0xe4, 0x59, 0xa0, 0xac, 0xee, 0x13, 0x3d, + 0x28, 0xb3, 0xa0, 0x3b, 0x69, 0x42, 0xe1, 0xb9, 0xe0, 0x71, 0xdf, 0x4f, 0x17, 0xfc, 0x0c, 0xd5, + 0x79, 0x28, 0x28, 0xfe, 0x04, 0xf9, 0x79, 0xa7, 0x6f, 0xea, 0x6f, 0xdd, 0x6a, 0x46, 0x72, 0xc4, + 0x13, 0x8c, 0x1e, 0x91, 0x34, 0x09, 0xc3, 0xb1, 0x61, 0x48, 0xbc, 0xe6, 0x1c, 0x69, 0x51, 0xff, + 0xd2, 0xb7, 0xf5, 0xc4, 0x0c, 0x21, 0x98, 0x7c, 0x0f, 0x83, 0xc0, 0xfc, 0x0f, 0x87, 0xc7, 0xe8, + 0xec, 0x7e, 0x23, 0xa1, 0x7d, 0x07, 0x0c, 0x40, 0xbf, 0x0c, 0x50, 0xf4, 0x95, 0xce, 0xe2, 0x97, + 0x1a, 0x49, 0x1b, 0x38, 0x14, 0xc0, 0x4b, 0x37, 0xe0, 0xfc, 0x0f, 0x81, 0xf0, 0x78, 0xf0, 0x09, + 0x1a, 0x68, 0xc9, 0xf7, 0x71, 0x2a, 0x14, 0xf9, 0x00, 0x00, 0x62, 0x61, 0xf7, 0x2f, 0x30, 0xbc, + 0x28, 0xbc, 0x28, 0x65, 0x7a, 0x47, 0xd7, 0x8f, 0x22, 0xf4, 0xb5, 0x5f, 0x97, 0xcf, 0x28, 0x51, + 0x42, 0x1f, 0x9b, 0x83, 0x7e, 0x50, 0xbb, 0xf0, 0x6d, 0x6a, 0x62, 0x59, 0x3d, 0x99, 0x05, 0x14, + 0xeb, 0x3a, 0xb1, 0x88, 0xf8, 0xdb, 0x8b, 0x3e, 0xb1, 0x24, 0x58, 0xd6, 0x1f, 0xd0, 0x56, 0xa1, + 0x8c, 0x7a, 0x37, 0xd4, 0x03, 0xd8, 0x0e, 0x9d, 0x8b, 0xe2, 0xf1, 0x53, 0x90, 0x31, 0x87, 0x87, + 0xc1, 0xf0, 0x7c, 0x07, 0xe0, 0x7e, 0x07, 0x86, 0x06, 0xfb, 0x6d, 0xf6, 0x0b, 0x19, 0x9c, 0x5a, + 0x65, 0xfb, 0x3c, 0xf5, 0xd8, 0x15, 0xa1, 0xc3, 0xbd, 0x01, 0x8d, 0x64, 0xd1, 0x51, 0xaf, 0xc3, + 0xf0, 0x3f, 0x81, 0xf8, 0x1f, 0x87, 0xe0, 0x0a, 0x1a, 0x68, 0xc9, 0xf7, 0x71, 0x2a, 0x44, 0x59, + 0x05, 0xc0, 0x9d, 0xa7, 0x4c, 0x88, 0x55, 0x01, 0xc8, 0x85, 0xaa, 0xbb, 0x7c, 0xb5, 0x2c, 0x5d, + 0xce, 0x53, 0x94, 0x4f, 0x0d, 0xa6, 0x09, 0x22, 0x42, 0x9e, 0xef, 0xff, 0xfb, 0xcb, 0x4f, 0xa2, + 0xe8, 0xc7, 0xc9, 0x5c, 0xa1, 0x27, 0x9f, 0xfc, 0x47, 0xcb, 0x4d, 0x52, 0xfe, 0x6d, 0x37, 0xc9, + 0x55, 0x15, 0xba, 0xb4, 0xf4, 0xf0, 0xc8, 0xef, 0x07, 0x52, 0xc6, 0xe9, 0x3f, 0xcc, 0xf4, 0xff, + 0x99, 0x32, 0x60, 0x89, 0x07, 0x4d, 0xe3, 0x1e, 0x07, 0x81, 0xf8, 0x1f, 0x07, 0x8f, 0xc1, 0x19, + 0x10, 0x21, 0x44, 0x9a, 0x82, 0x82, 0xb8, 0x65, 0x94, 0xc8, 0x13, 0x9d, 0x8e, 0xdd, 0x32, 0xc4, + 0xd2, 0x4c, 0xa9, 0xc2, 0xa0, 0x43, 0xe1, 0xf8, 0x0f, 0xc0, 0xfc, 0x0f, 0xc0, 0x7e, 0x06, 0x0b, + 0x1a, 0x68, 0xc9, 0xf7, 0x71, 0x2a, 0x24, 0x71, 0x05, 0xc0, 0x29, 0x32, 0x84, 0x40, 0x4b, 0xb4, + 0xb8, 0xf8, 0xd6, 0xa6, 0xec, 0x18, 0xb0, 0xaa, 0x08, 0xbf, 0x29, 0x3f, 0x51, 0xbe, 0xe3, 0x8c, + 0x18, 0xb9, 0x76, 0xe0, 0xe8, 0x18, 0x4d, 0x1f, 0x99, 0x41, 0x25, 0x1c, 0x65, 0x5c, 0x2c, 0x0e, + 0x44, 0x04, 0x9f, 0x4d, 0x70, 0x89, 0x16, 0xf1, 0xe6, 0xc9, 0xc4, 0x51, 0x0a, 0x40, 0x90, 0x0a, + 0xa8, 0x00, 0x5f, 0x3a, 0xca, 0x1f, 0x42, 0xdc, 0x31, 0xd5, 0x47, 0x16, 0x1f, 0x8d, 0xcf, 0x0f, + 0x07, 0x81, 0xf0, 0x3e, 0x07, 0xe0, 0x78, 0x78, 0x89, 0x16, 0xf6, 0xbb, 0x98, 0x92, 0x3d, 0x56, + 0xa6, 0xb5, 0xff, 0x76, 0x03, 0x89, 0x04, 0xcf, 0x1e, 0xfc, 0x72, 0x3b, 0x80, 0x54, 0xf8, 0x7c, + 0x07, 0xf0, 0x3f, 0x03, 0xf0, 0x3f, 0x06, 0x0c, 0x0a, 0x68, 0xc9, 0xf7, 0x71, 0x2a, 0x34, 0xd9, + 0x00, 0x00, 0x17, 0xa1, 0xff, 0x37, 0x32, 0x54, 0xf2, 0x35, 0xaa, 0xbc, 0x3d, 0x44, 0x8c, 0x73, + 0xeb, 0xa4, 0x59, 0x99, 0xa1, 0xcf, 0x35, 0x8b, 0x40, 0xc4, 0xb5, 0x6c, 0xa2, 0x1f, 0x25, 0x4e, + 0x8f, 0x2f, 0xca, 0x57, 0x8c, 0x06, 0xae, 0xce, 0xcc, 0x52, 0x45, 0x6b, 0x6b, 0xe6, 0x72, 0x66, + 0x4d, 0x58, 0x5d, 0x70, 0xb4, 0x7c, 0xbf, 0xeb, 0x84, 0x5e, 0x17, 0x42, 0x4a, 0x37, 0x1a, 0x27, + 0x66, 0x74, 0x80, 0xf2, 0x2f, 0x53, 0xb7, 0x06, 0x79, 0xc3, 0xc1, 0xf0, 0x3e, 0x0f, 0xc0, 0xf8, + 0x3f, 0x0e, 0x1e, 0xfb, 0xa4, 0x49, 0xea, 0x48, 0x10, 0x32, 0x23, 0x18, 0xd7, 0xa7, 0x29, 0xb3, + 0x7c, 0xf1, 0xc4, 0xab, 0x9c, 0xdb, 0xcf, 0x9c, 0x1e, 0x0f, 0xc0, 0xfc, 0x0f, 0x83, 0x82, 0x0e, + 0x0a, 0x68, 0xc9, 0xf7, 0x71, 0x2a, 0x34, 0xd9, 0x05, 0xc0, 0x28, 0xf5, 0x8d, 0xd8, 0x07, 0x04, + 0xd3, 0x2e, 0x17, 0x79, 0x42, 0x9b, 0x5b, 0x69, 0x9b, 0xb8, 0xee, 0xe0, 0x97, 0xdb, 0x2a, 0x6b, + 0x94, 0xbe, 0xca, 0x5d, 0x74, 0x7a, 0x45, 0x21, 0xc5, 0x46, 0x9c, 0x7a, 0x6f, 0x80, 0xf6, 0x6c, + 0x26, 0xcb, 0xa9, 0xee, 0x25, 0xd1, 0xd5, 0x23, 0xb5, 0x01, 0x13, 0xae, 0x47, 0xb3, 0xb7, 0x76, + 0x88, 0x52, 0x40, 0x18, 0xa4, 0xf9, 0xa1, 0x11, 0xc1, 0x39, 0xed, 0x9f, 0xf6, 0x33, 0xc7, 0x87, + 0x80, 0xfc, 0x1f, 0x81, 0xf8, 0x1f, 0x0f, 0x0f, 0xf7, 0xbf, 0x33, 0xec, 0xe9, 0x9f, 0x66, 0x64, + 0xd1, 0xe7, 0xe5, 0xd3, 0x27, 0x20, 0x57, 0xe2, 0x08, 0x36, 0x1d, 0xaa, 0x4d, 0x4e, 0x60, 0xf0, + 0x7e, 0x07, 0xe0, 0x7e, 0x07, 0xc0, 0xf8, 0x0f, 0x0a, 0x68, 0xc9, 0xf7, 0x71, 0x2a, 0x34, 0x99, + 0x05, 0xc2, 0x3c, 0xe5, 0x45, 0xc1, 0x14, 0xf5, 0x9f, 0x92, 0x87, 0x2b, 0x4f, 0x8f, 0x46, 0xf7, + 0x90, 0x7f, 0x33, 0x60, 0xf1, 0xa6, 0xbc, 0xd0, 0x0e, 0xbb, 0x47, 0xdb, 0xbe, 0xb2, 0xe5, 0x2a, + 0x2c, 0x90, 0xc3, 0x1f, 0x2c, 0xa6, 0xbd, 0x4f, 0x10, 0x7a, 0x4f, 0x0e, 0xe6, 0xdc, 0xfa, 0xef, + 0x51, 0x99, 0xeb, 0x94, 0x13, 0x73, 0xaa, 0xdc, 0x4c, 0xc9, 0xa7, 0x35, 0x7d, 0xd7, 0x00, 0x00, + 0x02, 0x65, 0xd2, 0x97, 0xea, 0x16, 0x68, 0x32, 0x97, 0x29, 0xe1, 0xf1, 0xf0, 0x7c, 0x3c, 0x1e, + 0x28, 0xf8, 0x3f, 0x2a, 0x64, 0xb1, 0x82, 0xe4, 0x95, 0xab, 0xb6, 0xb8, 0xcb, 0x1c, 0xba, 0x03, + 0x6e, 0x9d, 0xf4, 0x0b, 0x15, 0xa8, 0x63, 0xf0, 0x3f, 0x80, 0xfc, 0x0f, 0xc0, 0xfc, 0x0e, 0x11, + 0x0a, 0x28, 0x8c, 0x57, 0x71, 0x2a, 0x66, 0x29, 0x00, 0x00, 0x20, 0x84, 0xdc, 0x03, 0x04, 0xeb, + 0x4f, 0xb6, 0x88, 0x4a, 0xe0, 0x3f, 0x33, 0x8e, 0xdc, 0x7d, 0x6f, 0xee, 0xf6, 0x84, 0xeb, 0xbf, + 0x91, 0x69, 0x4b, 0xce, 0x33, 0xfb, 0x0a, 0x66, 0x8e, 0x79, 0xd6, 0x11, 0x63, 0x25, 0x95, 0xcd, + 0x58, 0x73, 0x02, 0xa7, 0xb6, 0x01, 0x06, 0xc4, 0xd3, 0xfa, 0xbf, 0x4c, 0xc1, 0xc3, 0xb6, 0xd3, + 0xc4, 0x33, 0x99, 0x3f, 0xb1, 0x72, 0xe8, 0xd1, 0xed, 0xd5, 0xad, 0x20, 0x95, 0x84, 0x9c, 0x39, + 0xf0, 0x7e, 0x07, 0xe0, 0x7f, 0x07, 0xe0, 0xf0, 0x7e, 0x9b, 0xb9, 0x9d, 0x29, 0xca, 0x3b, 0x35, + 0xd9, 0xc6, 0x3a, 0xf0, 0x09, 0x69, 0xcd, 0xbd, 0xd6, 0xda, 0xf0, 0x91, 0x3d, 0xcd, 0xb3, 0x73, + 0x81, 0xe0, 0x7e, 0x07, 0xe0, 0x7c, 0x4c, 0x12, 0x0a, 0x68, 0xcf, 0xf7, 0x71, 0x2a, 0x04, 0xf1, + 0x07, 0x82, 0x14, 0xfc, 0x2b, 0x0d, 0x9f, 0xbe, 0xb2, 0xbe, 0x70, 0x4e, 0x05, 0x14, 0x2f, 0x36, + 0xc4, 0x7a, 0x3e, 0xe7, 0xd9, 0xf8, 0x64, 0xde, 0xce, 0x4a, 0x9c, 0x6a, 0xbd, 0xd1, 0x46, 0x78, + 0x18, 0x7a, 0xd8, 0x4c, 0x5f, 0x4d, 0x16, 0xfe, 0xca, 0xee, 0x57, 0x0d, 0x32, 0x27, 0xe9, 0x70, + 0x3b, 0x6a, 0xb4, 0xce, 0xc5, 0x67, 0x35, 0x00, 0xbf, 0x31, 0x34, 0xb6, 0xf1, 0xff, 0x92, 0x83, + 0x10, 0x69, 0x98, 0x04, 0xed, 0x5c, 0x3e, 0x1f, 0x83, 0xf0, 0x7e, 0x07, 0xc1, 0xe1, 0xf7, 0x01, + 0x89, 0x86, 0x9a, 0xec, 0x1a, 0xcc, 0x2a, 0xa6, 0xdf, 0x0a, 0x77, 0x4d, 0x19, 0x7b, 0xdf, 0xd0, + 0xdd, 0xf3, 0xbd, 0x78, 0x71, 0x87, 0x07, 0xe0, 0x3f, 0x03, 0xf0, 0x1f, 0x81, 0xfc, 0x0e, 0x14, + 0x0a, 0x68, 0xcf, 0xf7, 0x71, 0x2a, 0x33, 0xc1, 0x07, 0x82, 0x13, 0x5b, 0xf5, 0x2d, 0xee, 0xfd, + 0x7f, 0xfb, 0x76, 0x44, 0x85, 0x6c, 0xdd, 0x4c, 0xa6, 0x95, 0xa9, 0x01, 0x31, 0x90, 0x49, 0xc4, + 0x3d, 0x4b, 0x96, 0xce, 0x4b, 0x00, 0xc9, 0x69, 0x94, 0xca, 0xd2, 0x72, 0xc6, 0xe5, 0xa5, 0x12, + 0x69, 0x52, 0x37, 0x74, 0x64, 0x8f, 0x89, 0x5a, 0x1e, 0x97, 0x9a, 0x00, 0x55, 0x45, 0x78, 0x0a, + 0x72, 0xff, 0x94, 0x26, 0x4e, 0xcd, 0x20, 0x36, 0xb5, 0x7f, 0x77, 0x3a, 0x3d, 0x38, 0x4a, 0x75, + 0x2e, 0x7c, 0x3e, 0x07, 0xc1, 0xf0, 0x78, 0x71, 0xc0, 0xa6, 0x75, 0x7f, 0xe9, 0x8a, 0x8b, 0xd1, + 0x33, 0x41, 0x0d, 0xcc, 0xd1, 0x18, 0x5d, 0x23, 0x57, 0x1b, 0x09, 0x38, 0x8c, 0x1f, 0x9c, 0x0f, + 0xc0, 0x7e, 0x07, 0xf0, 0x3f, 0x03, 0xf0, 0x16, 0x0a, 0x28, 0x8c, 0x57, 0x71, 0x2a, 0x56, 0x11, + 0x05, 0xc0, 0x9b, 0x63, 0x39, 0x73, 0x53, 0x95, 0x15, 0xe7, 0x15, 0xe0, 0x44, 0x4d, 0x15, 0xbf, + 0xde, 0x98, 0x1a, 0x4b, 0xb0, 0x85, 0x5f, 0x68, 0xb2, 0x5b, 0x4d, 0x6a, 0x3d, 0x83, 0xd4, 0xd4, + 0xe4, 0xd8, 0x47, 0x67, 0x80, 0x3b, 0xe3, 0xad, 0xfe, 0x78, 0xba, 0x10, 0x3c, 0x9f, 0x82, 0x30, + 0xf6, 0x8a, 0xbc, 0x1b, 0xf6, 0xab, 0x50, 0x0a, 0x6a, 0x96, 0xf5, 0x29, 0x24, 0xde, 0x06, 0x3b, + 0xf7, 0x9f, 0x93, 0xcf, 0x66, 0x29, 0xec, 0x7c, 0x3c, 0x0f, 0xc0, 0xfc, 0x1f, 0x0f, 0x91, 0xc3, + 0x1f, 0xad, 0x34, 0xc0, 0x86, 0xc4, 0x44, 0xcb, 0xae, 0xc7, 0x9d, 0xc9, 0x21, 0xf0, 0xa1, 0x6b, + 0xb0, 0x94, 0x45, 0x63, 0x08, 0x8f, 0x9e, 0x07, 0xe0, 0x7e, 0x03, 0xe0, 0x7f, 0x01, 0xf8, 0x19, + 0x0a, 0x68, 0xcf, 0xf7, 0x71, 0x2a, 0x34, 0x51, 0x00, 0x00, 0x00, 0x37, 0x6e, 0x5c, 0x01, 0x8c, + 0x3f, 0xff, 0x62, 0x2d, 0x0d, 0x9e, 0x43, 0x75, 0x69, 0xb0, 0x78, 0x55, 0x7e, 0x0f, 0x78, 0x26, + 0x7c, 0xd5, 0xb4, 0x5c, 0x1a, 0x30, 0x27, 0x9d, 0x48, 0x73, 0x70, 0x77, 0x0f, 0xf5, 0x30, 0x53, + 0xbc, 0x63, 0x38, 0x99, 0x77, 0x69, 0x3d, 0xd1, 0xa6, 0xad, 0x22, 0xf7, 0xc2, 0x6b, 0x53, 0x45, + 0xe5, 0x19, 0x13, 0x44, 0x4f, 0x02, 0x32, 0xfd, 0x03, 0x6f, 0x29, 0xac, 0x78, 0xae, 0x20, 0x62, + 0x9c, 0xf8, 0x3e, 0x0f, 0x81, 0xf8, 0x3f, 0x07, 0xc7, 0x07, 0x5d, 0x8f, 0x14, 0x34, 0xdc, 0xee, + 0xd5, 0xd4, 0x64, 0xbd, 0x7f, 0x9d, 0x45, 0x5f, 0xa1, 0x9c, 0xa3, 0x05, 0xe9, 0x23, 0xa2, 0x05, + 0x1b, 0x38, 0x7e, 0x07, 0xe0, 0x7c, 0x0c, 0x1b, 0x0a, 0x28, 0x8c, 0x57, 0x71, 0x2a, 0x36, 0x39, + 0x05, 0xc2, 0x2d, 0xb6, 0x06, 0x49, 0x18, 0xb9, 0xe1, 0x64, 0xf4, 0x2a, 0x15, 0xeb, 0xac, 0x33, + 0xea, 0xcb, 0x6d, 0x69, 0x4f, 0x5c, 0x10, 0x44, 0xbd, 0x31, 0xce, 0x3c, 0xba, 0xb9, 0xf0, 0x83, + 0x0b, 0x3e, 0x14, 0x7a, 0x56, 0x51, 0x5e, 0xcb, 0x95, 0x39, 0x71, 0xed, 0xd3, 0x33, 0x9a, 0x4d, + 0xa3, 0x8b, 0x9b, 0xcd, 0x16, 0xa3, 0x25, 0xae, 0x6c, 0x9f, 0x00, 0x00, 0x00, 0x91, 0xba, 0xd0, + 0x02, 0x44, 0x89, 0xfa, 0xbf, 0xa2, 0xf1, 0x11, 0x1d, 0x4e, 0x0f, 0x81, 0xf8, 0x1f, 0x03, 0xe1, + 0xe1, 0x35, 0x2d, 0x5d, 0x61, 0xc5, 0x78, 0xe4, 0xea, 0x5c, 0x86, 0x9b, 0x8e, 0x92, 0x54, 0xce, + 0x63, 0x30, 0xc1, 0xce, 0xd1, 0x4f, 0x87, 0xc1, 0xf0, 0x3f, 0x03, 0xf0, 0x3f, 0x81, 0xf0, 0x1f, + 0x0a, 0x70, 0xbc, 0x77, 0x71, 0x2a, 0x56, 0x11, 0x00, 0x00, 0x02, 0x46, 0x64, 0x63, 0x12, 0xa4, + 0x19, 0xda, 0x38, 0xd9, 0x99, 0xf8, 0xc7, 0xd6, 0x5a, 0xaf, 0x79, 0x14, 0x40, 0xbf, 0xda, 0xcc, + 0x59, 0xed, 0xff, 0xc4, 0x6e, 0x25, 0xa8, 0x83, 0x2f, 0x91, 0xbf, 0xf4, 0xb5, 0x60, 0x1f, 0x44, + 0x1c, 0x53, 0x27, 0x71, 0x4c, 0x3a, 0x84, 0x6d, 0x59, 0xfd, 0x68, 0x72, 0x16, 0x24, 0xc8, 0x22, + 0x04, 0xfd, 0x9d, 0xc3, 0x00, 0x0f, 0xc3, 0x4f, 0xf6, 0x9b, 0x99, 0x66, 0xe5, 0xe8, 0x9c, 0x13, + 0x63, 0x83, 0xe0, 0xf8, 0x1f, 0x81, 0xf0, 0x7e, 0x1c, 0x00, 0xdc, 0x6e, 0x2b, 0xe7, 0x9b, 0xa9, + 0xaa, 0x33, 0xb6, 0x37, 0xea, 0xdc, 0x11, 0xbb, 0xf4, 0xeb, 0x30, 0xd2, 0xf1, 0x65, 0x11, 0x5b, + 0xf0, 0xf8, 0x3e, 0x07, 0x83, 0xc7, 0xe0, 0x22, 0x0a, 0x70, 0xbc, 0x77, 0x71, 0x2a, 0x46, 0x31, + 0x00, 0x00, 0x00, 0x05, 0xc7, 0x20, 0x0c, 0x68, 0x5d, 0xb4, 0xd7, 0x65, 0xe2, 0x7e, 0x64, 0x69, + 0xc0, 0x79, 0x17, 0x8c, 0x04, 0xa0, 0xcd, 0xc7, 0x6c, 0x20, 0x96, 0x7c, 0x1a, 0x70, 0x8c, 0xdc, + 0x26, 0x89, 0x28, 0xfa, 0xca, 0x49, 0x17, 0xe8, 0x28, 0xa2, 0x5f, 0xa2, 0xfb, 0xd5, 0xc1, 0x91, + 0x6a, 0x18, 0x89, 0xe7, 0x92, 0x05, 0x50, 0x0f, 0xef, 0x5a, 0x5a, 0xdd, 0x0f, 0x6b, 0x9a, 0xd7, + 0x27, 0x98, 0x13, 0x4f, 0x94, 0x5e, 0xe4, 0xd0, 0xf0, 0xf0, 0xfc, 0x0f, 0xc1, 0xf8, 0x1f, 0x81, + 0xf0, 0x78, 0x7c, 0x93, 0x14, 0x0e, 0x50, 0xbd, 0x13, 0x0f, 0x7f, 0x25, 0x3c, 0x11, 0x04, 0x81, + 0x1c, 0x7f, 0xe7, 0x25, 0x7d, 0xe6, 0xe3, 0x8c, 0x61, 0x27, 0xc1, 0xf8, 0x3c, 0x70, 0xf0, 0x26, + 0x0a, 0x6f, 0x43, 0x77, 0x71, 0x2a, 0x25, 0x19, 0x05, 0xc0, 0x26, 0x36, 0xf3, 0x8a, 0xec, 0x1c, + 0xd5, 0x9c, 0x29, 0xf5, 0xb1, 0xb9, 0xc8, 0xb0, 0x3b, 0xa8, 0xc3, 0xe3, 0x2d, 0xca, 0x7b, 0x90, + 0xe6, 0x7d, 0x9a, 0xa6, 0x40, 0xd2, 0xd8, 0xda, 0x56, 0xf7, 0xfe, 0x56, 0xad, 0xfc, 0x3b, 0xae, + 0xd3, 0x95, 0x6d, 0xba, 0xde, 0x8c, 0x0b, 0x76, 0x9d, 0xe7, 0x56, 0xe3, 0x97, 0x14, 0x2c, 0x3c, + 0xb8, 0xa7, 0x7c, 0x9e, 0x00, 0xfc, 0x43, 0xaa, 0xed, 0x58, 0x9b, 0xc5, 0xf2, 0x01, 0xd6, 0x3c, + 0x7c, 0x1f, 0x03, 0xe0, 0x7e, 0x07, 0x87, 0x87, 0x86, 0x3c, 0xd1, 0xf4, 0xb5, 0x4a, 0x29, 0x93, + 0xad, 0x53, 0x30, 0x85, 0x95, 0x26, 0x4f, 0x45, 0xb5, 0xc3, 0x51, 0x31, 0xa5, 0x7a, 0x18, 0xc1, + 0xf0, 0x7e, 0x07, 0xe1, 0xf0, 0x3c, 0x06, 0x0e, 0x0a, 0xde, 0x40, 0xa7, 0x71, 0x2a, 0x24, 0x71, + 0x0d, 0xc1, 0xee, 0xba, 0xbd, 0x82, 0x50, 0xa0, 0x25, 0x0a, 0xed, 0x97, 0xce, 0x60, 0x2d, 0xf9, + 0xa6, 0x97, 0x2f, 0xe8, 0x05, 0xda, 0x37, 0x2b, 0x0e, 0xd5, 0x67, 0x48, 0x29, 0xb1, 0x94, 0x6f, + 0x1a, 0x31, 0xb4, 0x72, 0xba, 0xeb, 0x59, 0x91, 0xb7, 0xbc, 0x5e, 0xeb, 0xb1, 0xae, 0xa8, 0xd5, + 0x1c, 0xf8, 0x47, 0x27, 0x9c, 0x73, 0xb9, 0x80, 0xc9, 0xcd, 0x77, 0x0a, 0x99, 0x00, 0xa9, 0x04, + 0x4f, 0xe6, 0xb3, 0x10, 0x46, 0x70, 0xf0, 0x7e, 0x07, 0xe0, 0xfc, 0x1e, 0x0e, 0x3c, 0x26, 0x00, + 0xa0, 0xe7, 0x02, 0x0e, 0x19, 0x0b, 0x90, 0xa8, 0xbb, 0x24, 0x11, 0xb4, 0x13, 0xe2, 0x6d, 0xb9, + 0xec, 0x1f, 0x38, 0xd7, 0x64, 0xf0, 0x7e, 0x03, 0xf8, 0x1f, 0x81, 0xf8, 0x1f, 0x83, 0xf0, 0x11, + 0x0a, 0xde, 0x40, 0xa7, 0x71, 0x2a, 0x44, 0x31, 0x00, 0x00, 0x00, 0x5c, 0x89, 0x73, 0x30, 0x0e, + 0xb1, 0x92, 0xb9, 0x1e, 0xb0, 0x56, 0x34, 0x72, 0x4f, 0x7d, 0x1b, 0xca, 0x05, 0x95, 0xd5, 0xc5, + 0x98, 0xee, 0x37, 0x97, 0xa8, 0xfb, 0xb8, 0x61, 0xb1, 0x99, 0x00, 0x90, 0x96, 0xee, 0x1a, 0x6a, + 0x24, 0x6e, 0xeb, 0x9f, 0x53, 0xdc, 0x09, 0xaa, 0xfb, 0xc3, 0x8d, 0x1d, 0xa1, 0xee, 0x48, 0x97, + 0x60, 0xd2, 0xdd, 0x3c, 0x7f, 0xf4, 0xee, 0x11, 0x12, 0x9c, 0xdc, 0xa6, 0xba, 0x61, 0xc3, 0xe0, + 0x7e, 0x0f, 0xc0, 0xfc, 0x0f, 0x81, 0xe0, 0x99, 0x7d, 0xa2, 0xcc, 0x85, 0x43, 0xc5, 0xe5, 0xd6, + 0x64, 0xb5, 0x78, 0x70, 0xd0, 0xe9, 0x70, 0xe6, 0x75, 0x84, 0x3f, 0x0a, 0x7c, 0x86, 0x39, 0x88, + 0x88, 0x7f, 0x03, 0xe0, 0xf8, 0xf8, 0xf2, 0x15, 0x0b, 0x58, 0xca, 0xf7, 0x71, 0x2a, 0x04, 0xb9, + 0x05, 0xc2, 0x71, 0x5c, 0x02, 0x99, 0xdc, 0x5e, 0xb9, 0x6c, 0x6f, 0xdf, 0x52, 0x9e, 0x2d, 0x5b, + 0x67, 0x0e, 0xb4, 0x18, 0x43, 0x89, 0x6a, 0x8f, 0xa6, 0xe6, 0xbc, 0x96, 0xf0, 0x9f, 0x9d, 0x79, + 0x3d, 0x03, 0x25, 0xfe, 0x2b, 0xa3, 0xf9, 0xca, 0x64, 0x77, 0xe7, 0x2c, 0x96, 0x69, 0x99, 0xa6, + 0xbe, 0x13, 0xcb, 0xa2, 0x0a, 0x6f, 0xa1, 0xc7, 0x36, 0xcc, 0xae, 0xd1, 0xba, 0x39, 0x05, 0xd0, + 0x9c, 0x17, 0xa2, 0xec, 0xff, 0x1c, 0x3e, 0x1f, 0x03, 0xf0, 0x3f, 0x07, 0xc0, 0xf0, 0xeb, 0xd0, + 0x52, 0x02, 0xe5, 0x4b, 0x24, 0x82, 0x0e, 0x6f, 0x8b, 0x2a, 0x88, 0x86, 0xb2, 0xaf, 0x77, 0x56, + 0xc3, 0xaf, 0xbe, 0x54, 0x80, 0x4f, 0x81, 0xf0, 0x7e, 0x0f, 0xc1, 0xf8, 0x1f, 0x03, 0xf0, 0x19, + 0x0b, 0x58, 0xca, 0xf7, 0x71, 0x2a, 0x23, 0xc9, 0x37, 0xe7, 0x14, 0xf3, 0xd2, 0xc0, 0xce, 0x02, + 0x93, 0x8f, 0x9b, 0x1a, 0x50, 0x5a, 0x47, 0x8c, 0xdc, 0x53, 0x4d, 0x5c, 0xb4, 0xb1, 0x18, 0x31, + 0x8b, 0xad, 0x6f, 0xe6, 0x94, 0xbf, 0x01, 0x34, 0x04, 0x61, 0x26, 0xd3, 0xe1, 0xdb, 0x07, 0xf9, + 0xfd, 0x7f, 0x33, 0xf4, 0x54, 0x09, 0xfa, 0x10, 0x08, 0x85, 0x92, 0xb6, 0xe1, 0x32, 0x49, 0x94, + 0xa8, 0xd2, 0xb9, 0x34, 0x33, 0x34, 0x18, 0x72, 0x56, 0xdd, 0x19, 0x80, 0x50, 0xc0, 0x9c, 0x3e, + 0x0f, 0x87, 0xe0, 0x7e, 0x03, 0xf8, 0x1c, 0x01, 0x4b, 0x4b, 0xe6, 0x6c, 0x9d, 0x29, 0x01, 0xf6, + 0x9c, 0x38, 0x1d, 0x4c, 0x42, 0xaf, 0x61, 0xda, 0x8a, 0xe2, 0x6f, 0xb4, 0x32, 0x38, 0x4a, 0x44, + 0x03, 0x1b, 0xc6, 0x33, 0x03, 0xbc, 0x0e, 0xc8, 0x0b, 0x58, 0xca, 0xf7, 0x71, 0x39, 0xf4, 0x31, + 0x05, 0xc7, 0xf5, 0x2a, 0x9f, 0x0e, 0x68, 0x80, 0x79, 0xe7, 0x0f, 0xd5, 0x1c, 0xbc, 0x9a, 0x6d, + 0xd6, 0x2a, 0x2e, 0xc9, 0x11, 0x80, 0xc7, 0xba, 0x44, 0x31, 0x0e, 0xf3, 0x02, 0xe4, 0x5b, 0x80, + 0x77, 0x70, 0x52, 0x7e, 0x49, 0x7e, 0xa1, 0xad, 0xff, 0xbe, 0xa0, 0x1b, 0x3b, 0xf6, 0x72, 0x30, + 0x1d, 0xdd, 0x5b, 0xe8, 0x64, 0xd4, 0x65, 0x2e, 0x94, 0xa3, 0xae, 0xb2, 0x67, 0xff, 0x16, 0x70, + 0x52, 0xc5, 0x0c, 0x7f, 0x70, 0x78, 0x1f, 0x81, 0xf8, 0x0f, 0xe0, 0x7c, 0x3f, 0x00, 0x41, 0xc3, + 0x29, 0x1b, 0x12, 0xb0, 0xe8, 0xe8, 0x03, 0xa2, 0x09, 0x02, 0x2e, 0xa9, 0x2c, 0xa9, 0x81, 0x6a, + 0xce, 0xe1, 0xe2, 0x51, 0xd9, 0xfd, 0xc0, 0x7c, 0x0f, 0xc0, 0xf0, 0x7c, 0x1f, 0x0f, 0x0e, 0x0d, + 0x0b, 0x58, 0xca, 0xf7, 0x71, 0x2a, 0x14, 0x21, 0xb0, 0xd1, 0xfe, 0x02, 0x0c, 0xb3, 0xb6, 0x83, + 0x75, 0x81, 0xa0, 0x4b, 0x9d, 0x3a, 0x23, 0x6f, 0x51, 0x41, 0x4d, 0x7f, 0x12, 0x44, 0xf4, 0x60, + 0x50, 0x45, 0x95, 0x2f, 0x88, 0x02, 0xda, 0x5f, 0x55, 0x46, 0xe4, 0xcd, 0x0d, 0x60, 0xd7, 0xd5, + 0x8e, 0x46, 0xc2, 0x3b, 0x89, 0xe0, 0x4b, 0xd0, 0xe4, 0x97, 0x98, 0x58, 0xae, 0x7a, 0xca, 0x3e, + 0x36, 0xc8, 0x83, 0x54, 0xd5, 0x46, 0x39, 0xc6, 0xd6, 0xca, 0x29, 0x4a, 0x4e, 0x58, 0xf1, 0xe0, + 0xfc, 0x07, 0xf0, 0x1f, 0x81, 0xf8, 0x0f, 0xc3, 0xfe, 0xb0, 0x8d, 0xff, 0xed, 0xd6, 0xf0, 0xe5, + 0xc7, 0x8e, 0x3d, 0x4a, 0xa6, 0xb3, 0xe9, 0x92, 0xa1, 0xd3, 0xc6, 0x95, 0x0b, 0x66, 0xcf, 0xa4, + 0x2b, 0xe0, 0x7d, 0xe4, 0xfb, 0x9a, 0x73, 0x12, 0x0b, 0x58, 0xca, 0xf7, 0x71, 0x3a, 0x34, 0x51, + 0x69, 0xf1, 0xe5, 0x5c, 0x4a, 0x49, 0xd5, 0xe9, 0xe1, 0x77, 0xd2, 0xa7, 0x0f, 0xaa, 0x5a, 0x24, + 0xe2, 0x43, 0xa0, 0xa7, 0xdb, 0x58, 0xfe, 0xeb, 0xe8, 0x14, 0x7d, 0x48, 0xda, 0x99, 0x7a, 0x03, + 0x9b, 0x72, 0x29, 0x8d, 0x06, 0xc2, 0x06, 0x3b, 0x4f, 0xa9, 0xc1, 0xc5, 0x40, 0x92, 0x93, 0xed, + 0xe8, 0x14, 0x4d, 0x2e, 0x89, 0x73, 0x03, 0x83, 0xdb, 0xee, 0xe3, 0xe2, 0x4b, 0x59, 0xef, 0xcb, + 0x0e, 0x14, 0xe8, 0x91, 0xc2, 0xb8, 0xf8, 0x3e, 0x07, 0xc1, 0xf0, 0x3f, 0x03, 0xf1, 0x10, 0x04, + 0xe0, 0x02, 0x43, 0x60, 0xa3, 0x65, 0xb9, 0xe2, 0x7e, 0xbe, 0x52, 0x1f, 0xcc, 0x0f, 0x33, 0x44, + 0x9c, 0xfa, 0x8a, 0x58, 0xf2, 0x60, 0xb9, 0x5a, 0x51, 0xbd, 0xe2, 0x1a, 0xf8, 0x6e, 0x06, 0xda, + 0x0b, 0x58, 0xca, 0xf7, 0x71, 0x3a, 0x04, 0xf1, 0x69, 0xd4, 0x41, 0x0b, 0x57, 0xdc, 0xd0, 0x46, + 0x81, 0xf4, 0xba, 0xa0, 0x3b, 0x8a, 0xd5, 0x3f, 0x15, 0x89, 0x23, 0x10, 0x82, 0xcb, 0x6a, 0xe6, + 0x2a, 0x95, 0x3f, 0xfa, 0x5b, 0x0b, 0x07, 0x41, 0xd6, 0x3d, 0x40, 0x29, 0x99, 0x8a, 0x79, 0x56, + 0x9b, 0xb3, 0x6c, 0x58, 0x21, 0x02, 0x01, 0x3b, 0xf1, 0x7c, 0x62, 0x56, 0x94, 0xdb, 0x3a, 0x3b, + 0x02, 0xae, 0x17, 0xb0, 0xea, 0xe7, 0xc2, 0x8d, 0x71, 0x0f, 0x54, 0xa3, 0x99, 0xa3, 0x8f, 0x87, + 0xc1, 0xf8, 0x1f, 0x81, 0xf8, 0x1f, 0x81, 0xfe, 0x08, 0xe2, 0x50, 0x52, 0xe4, 0x31, 0xa3, 0x20, + 0x0c, 0x49, 0xd7, 0xc6, 0x46, 0x60, 0xf2, 0xe1, 0xa2, 0x10, 0x96, 0xfe, 0x6a, 0xba, 0x1c, 0x2a, + 0x41, 0x03, 0x3e, 0x3a, 0xbf, 0x7c, 0x1e, 0xe6, 0x0b, 0x58, 0xca, 0xf7, 0x71, 0x3a, 0x04, 0xe9, + 0xaa, 0xf6, 0x07, 0x75, 0x88, 0x63, 0x97, 0x76, 0xb2, 0x9f, 0x74, 0x03, 0x59, 0x45, 0x41, 0x64, + 0x44, 0xea, 0x56, 0xdd, 0x86, 0x5a, 0x08, 0x90, 0x09, 0xc2, 0xb0, 0x32, 0x2b, 0x21, 0x2d, 0xcd, + 0x6a, 0x7b, 0x10, 0x67, 0x57, 0xd0, 0x81, 0x62, 0x51, 0x53, 0x3e, 0x3b, 0x8c, 0x66, 0x1d, 0xe1, + 0xff, 0x9b, 0x9d, 0x50, 0xfe, 0x4b, 0x58, 0xc7, 0xe7, 0x69, 0xb9, 0xda, 0x2d, 0x04, 0x00, 0xaa, + 0xd7, 0xd5, 0x32, 0x17, 0x09, 0x87, 0x87, 0xc3, 0xe0, 0x7e, 0x07, 0xe0, 0xfc, 0x0f, 0x83, 0xec, + 0x3c, 0x60, 0x68, 0x2e, 0x87, 0x02, 0x42, 0x92, 0xf6, 0xb0, 0xe6, 0xab, 0x37, 0x16, 0xdc, 0x6d, + 0xdb, 0x1c, 0x9c, 0xc9, 0x39, 0x92, 0x09, 0xe9, 0x46, 0x9f, 0xc9, 0xb1, 0x69, 0x83, 0xf1, 0x35, + 0x4a, 0xde, 0x40, 0xa7, 0x71, 0x3a, 0x15, 0x49, 0xaa, 0xf5, 0xa7, 0x07, 0x1a, 0x24, 0xd7, 0x61, + 0x47, 0x97, 0x6d, 0xc7, 0xc2, 0xc0, 0x26, 0xe0, 0x2c, 0x82, 0x92, 0x48, 0x4b, 0x73, 0x2b, 0x20, + 0x89, 0x48, 0xd6, 0x5f, 0x35, 0x8e, 0xa8, 0xe1, 0xb9, 0x2f, 0x76, 0xc1, 0x24, 0x1f, 0xaf, 0xea, + 0x46, 0x96, 0x6c, 0x6f, 0xa1, 0x60, 0x3d, 0xb2, 0x9e, 0x5d, 0xe4, 0xdb, 0xe3, 0x20, 0x66, 0x06, + 0x79, 0x24, 0xa9, 0xfa, 0x90, 0x59, 0x7d, 0x95, 0x7e, 0x56, 0x56, 0x60, 0x00, 0x4f, 0xb7, 0xf0, + 0xf0, 0xf0, 0x3f, 0x07, 0xe0, 0x7c, 0x0f, 0xc0, 0xf1, 0xc2, 0xd4, 0x7e, 0x7f, 0x1f, 0x15, 0x02, + 0x91, 0x30, 0xa8, 0xcf, 0xe1, 0xd3, 0xbe, 0x39, 0x18, 0xa7, 0xd8, 0x27, 0x07, 0xe0, 0x8e, 0xba, + 0x64, 0x2c, 0xe3, 0x4e, 0x38, 0x93, 0xf1, 0x00, 0x0a, 0xde, 0x40, 0xa7, 0x71, 0x3a, 0x25, 0x49, + 0xaf, 0xdd, 0x49, 0xd0, 0x00, 0x2f, 0x1f, 0x73, 0x84, 0xbf, 0xb1, 0x1c, 0xd3, 0x01, 0xac, 0x45, + 0x65, 0xbf, 0xc2, 0xf9, 0x94, 0x70, 0xbd, 0x72, 0x2f, 0xeb, 0x2f, 0xed, 0xff, 0x1d, 0x00, 0x29, + 0x63, 0xa9, 0xa4, 0x2a, 0x32, 0x19, 0xc5, 0x17, 0xb8, 0x44, 0x9d, 0x35, 0x26, 0x80, 0x22, 0xc2, + 0xbd, 0x0f, 0x41, 0xea, 0x16, 0x51, 0x4d, 0x03, 0xcc, 0xaf, 0xb2, 0x4f, 0xe9, 0xa9, 0x48, 0xf9, + 0xed, 0x8f, 0xbd, 0xeb, 0xb8, 0x70, 0x7c, 0x0f, 0xe0, 0x7e, 0x03, 0xf0, 0x1f, 0x20, 0x3f, 0xc7, + 0x17, 0x44, 0x2c, 0x38, 0x3b, 0x6e, 0xa3, 0xbb, 0x95, 0xe6, 0x5a, 0xb0, 0x4a, 0xdb, 0xf1, 0xeb, + 0x06, 0x37, 0x12, 0x64, 0x90, 0xac, 0x4d, 0xef, 0x41, 0x0c, 0xb3, 0x81, 0xcc, 0x97, 0x87, 0x40, + 0x1b, 0x58, 0xca, 0xf7, 0x71, 0x39, 0xf4, 0x61, 0x69, 0xd4, 0x41, 0xd9, 0xdd, 0xe2, 0xaa, 0xbb, + 0x30, 0x4b, 0x61, 0x43, 0x0d, 0xcd, 0x67, 0x0a, 0x07, 0x99, 0x18, 0xa5, 0xf7, 0x78, 0x7d, 0x2a, + 0xaf, 0x8d, 0xda, 0xae, 0x4c, 0x0e, 0x07, 0x2b, 0x45, 0x54, 0x80, 0x0f, 0xd4, 0x4b, 0x87, 0x78, + 0x0b, 0x91, 0xb1, 0x2e, 0x37, 0x35, 0x62, 0xd7, 0xc6, 0x3f, 0xcf, 0x54, 0x66, 0xbc, 0xe8, 0x38, + 0xe6, 0xf9, 0xab, 0x8e, 0xda, 0x31, 0x2b, 0x01, 0x9b, 0x8b, 0x4e, 0x50, 0x91, 0x71, 0xe4, 0x61, + 0x4b, 0x87, 0x83, 0xe0, 0xfc, 0x1f, 0x81, 0xf8, 0x3f, 0x01, 0xff, 0xd5, 0x67, 0xbe, 0x3a, 0x6e, + 0xa3, 0xd6, 0x25, 0x10, 0xe6, 0x36, 0xca, 0xc3, 0xb4, 0xcd, 0xfd, 0xe9, 0xf0, 0xdd, 0xed, 0x7c, + 0xbd, 0xb9, 0x58, 0x95, 0xa7, 0xf3, 0xc8, 0xfc, 0x4a, 0xde, 0x40, 0xa7, 0x71, 0x1a, 0x35, 0xb1, + 0x69, 0x22, 0x08, 0x97, 0x59, 0xc6, 0xef, 0xda, 0x00, 0x19, 0xde, 0x54, 0x54, 0xea, 0xcd, 0xb9, + 0x7e, 0x65, 0x42, 0x94, 0x20, 0x3f, 0x4b, 0xa9, 0xfb, 0x31, 0xd5, 0x9e, 0x68, 0xa0, 0xc5, 0x27, + 0x24, 0xa4, 0x5e, 0x36, 0xd5, 0xe1, 0x64, 0x88, 0x08, 0xd4, 0xe5, 0xae, 0x1e, 0x3f, 0x37, 0x3d, + 0xcf, 0x5d, 0x03, 0x9a, 0x4e, 0xa2, 0x2e, 0xb6, 0xf5, 0x47, 0x01, 0x46, 0xb4, 0x3b, 0x84, 0x66, + 0x4c, 0x87, 0xfb, 0x3b, 0x01, 0xd9, 0x87, 0x87, 0x87, 0xe0, 0xf8, 0x1f, 0x81, 0xf8, 0x03, 0xfd, + 0xb2, 0x4c, 0x82, 0xd6, 0xce, 0x40, 0x2d, 0x5e, 0xfc, 0x72, 0x70, 0x29, 0x92, 0xc9, 0xe7, 0xd0, + 0x2d, 0xd9, 0x44, 0x87, 0x97, 0x1c, 0xf4, 0xe7, 0x59, 0x1c, 0xfc, 0xf0, 0xcc, 0x73, 0xe1, 0x77, + 0xec, 0xac, 0xa7, 0x07, 0x59, 0x3a, 0x34, 0xd1, 0x33, 0xd7, 0xfa, 0x76, 0x00, 0xee, 0xf2, 0xed, + 0xf8, 0x94, 0x94, 0xc0, 0xb9, 0xa4, 0x3d, 0x73, 0x2e, 0xd2, 0x6c, 0x0a, 0xbe, 0x1d, 0xb1, 0x2d, + 0xee, 0xa3, 0x3e, 0x04, 0x14, 0xc0, 0xfa, 0xd6, 0xc1, 0xad, 0x3a, 0xd5, 0x3a, 0x08, 0x3a, 0x82, + 0xed, 0xeb, 0x60, 0xab, 0x90, 0xb0, 0x5c, 0xd0, 0x9e, 0xec, 0xe7, 0xf3, 0x32, 0x70, 0x21, 0x8e, + 0xb4, 0xe7, 0x55, 0x09, 0xc3, 0x7a, 0xb9, 0x51, 0x5c, 0xe4, 0x03, 0x68, 0x1f, 0x80, 0xfe, 0x07, + 0xc1, 0xf6, 0x33, 0x12, 0x00, 0x69, 0xc8, 0xe7, 0x7c, 0x01, 0xd8, 0x78, 0x52, 0xef, 0x20, 0xde, + 0xd5, 0x6c, 0xfc, 0x67, 0xaf, 0x12, 0x8d, 0x3c, 0x17, 0x6d, 0x00, 0x3e, 0x0f, 0x90, 0x0f, 0xe0, + 0x1f, 0xc0, 0xfc, 0x1f, 0x81, 0xfc, 0x0f, 0x44, 0x19, 0x59, 0x4e, 0x0e, 0xb2, 0x6a, 0x13, 0x2c, + 0xa8, 0x0b, 0x9b, 0x86, 0xe8, 0xe9, 0x76, 0x98, 0xdc, 0xb9, 0x70, 0x9c, 0xac, 0xe8, 0xb2, 0xe0, + 0x03, 0x3c, 0xf9, 0xe9, 0x7e, 0xdc, 0x5f, 0x5b, 0x4e, 0x7c, 0xe8, 0x5c, 0xfc, 0xff, 0x23, 0x5e, + 0x64, 0x01, 0x67, 0x29, 0x2e, 0x85, 0x07, 0xf0, 0x11, 0x30, 0xc3, 0xc1, 0xa4, 0xfa, 0x3b, 0x7f, + 0x15, 0xa9, 0x98, 0x19, 0x76, 0x6c, 0x77, 0x61, 0x5f, 0x64, 0x7c, 0x7c, 0x74, 0x82, 0xbe, 0x76, + 0xb3, 0x6c, 0xcf, 0xca, 0xf1, 0xc0, 0xfe, 0x03, 0xf8, 0x1f, 0x0e, 0xf3, 0x21, 0x46, 0x9e, 0x63, + 0x18, 0x71, 0x2a, 0x07, 0x74, 0x18, 0x38, 0x57, 0x8a, 0x15, 0x1b, 0xdf, 0xb5, 0x4a, 0x5d, 0xad, + 0xe8, 0x07, 0xbe, 0x00, 0xf0, 0x7e, 0x07, 0xf0, 0x1f, 0xc0, 0x7e, 0x0f, 0xc1, 0xfc, 0x0f, 0x2a, + 0x19, 0x59, 0x4e, 0x0e, 0xb2, 0x6a, 0x43, 0x34, 0x69, 0xd5, 0x7a, 0xea, 0x8d, 0xa6, 0x94, 0x80, + 0xd3, 0x10, 0x5b, 0x5b, 0x86, 0xad, 0x0d, 0x0b, 0x31, 0xee, 0x21, 0xef, 0x0c, 0xd5, 0x0e, 0xf2, + 0x6d, 0x34, 0xd6, 0x6a, 0x11, 0xaf, 0x64, 0x96, 0xff, 0x14, 0x50, 0x9d, 0xd5, 0xe2, 0x07, 0xf4, + 0x00, 0x63, 0x2e, 0x2c, 0x94, 0xfc, 0xc5, 0x87, 0xfb, 0x73, 0x2e, 0xe3, 0xfd, 0xfe, 0xfe, 0xea, + 0x88, 0xc9, 0xb3, 0x3f, 0x38, 0xb7, 0x65, 0xc2, 0x48, 0xb1, 0xf2, 0x57, 0x78, 0xf0, 0x3e, 0x0f, + 0xc0, 0x7f, 0x03, 0xfe, 0x38, 0xbc, 0x78, 0x67, 0x36, 0xb0, 0xbf, 0x00, 0xa1, 0x93, 0x04, 0xfa, + 0x55, 0x44, 0xb8, 0xfb, 0xc8, 0xc3, 0xf7, 0x42, 0x67, 0x50, 0x79, 0x6a, 0x4e, 0x80, 0xbe, 0xc5, + 0xeb, 0xa2, 0x8c, 0xc3, 0x87, 0x21, 0xf9, 0x0f, 0x0c, 0xac, 0xa7, 0x07, 0x59, 0x3a, 0x04, 0x69, + 0x69, 0xd4, 0x3e, 0x17, 0xb0, 0x98, 0x04, 0x05, 0x75, 0x62, 0x2f, 0x8f, 0x3f, 0x5e, 0x54, 0x3e, + 0x5a, 0x21, 0x5e, 0xcb, 0xd7, 0x50, 0x7b, 0x89, 0x50, 0x16, 0xdb, 0x47, 0x9f, 0x8a, 0xf0, 0xa3, + 0x12, 0xe8, 0x0e, 0xf3, 0x32, 0x6b, 0xf4, 0x10, 0x12, 0xa8, 0x3d, 0x2b, 0x69, 0x26, 0xe1, 0x02, + 0x3f, 0x22, 0xd7, 0x13, 0x22, 0x67, 0x8b, 0x5d, 0x8f, 0x1c, 0x8c, 0x56, 0x22, 0x0c, 0x93, 0x19, + 0xb0, 0x83, 0xff, 0x31, 0x2b, 0x3c, 0x36, 0x31, 0xc6, 0x3e, 0x0f, 0xc0, 0xfc, 0x0f, 0xc0, 0x7c, + 0x0f, 0xfe, 0xd4, 0xc0, 0xa2, 0x0d, 0xa1, 0x10, 0xf3, 0xaf, 0xae, 0x98, 0x30, 0xe0, 0x4d, 0xb0, + 0xc3, 0x08, 0x7d, 0x39, 0x00, 0x47, 0xac, 0xaa, 0xfd, 0xe1, 0xc8, 0x3b, 0x8c, 0x7c, 0x0e, 0xc9, + 0x1c, 0xac, 0xa7, 0x07, 0x59, 0x3a, 0x25, 0xc9, 0xb0, 0xd2, 0xbf, 0x90, 0x45, 0xba, 0xcf, 0x4f, + 0x87, 0x7e, 0x31, 0x8d, 0xf2, 0xc5, 0x31, 0x44, 0x7f, 0x49, 0x8b, 0x3f, 0xd4, 0xde, 0xf5, 0x31, + 0x66, 0x82, 0xe2, 0xbf, 0x2d, 0x87, 0xbd, 0x21, 0xb4, 0xb1, 0x56, 0x42, 0x74, 0xfd, 0x5a, 0x44, + 0x03, 0x98, 0x1a, 0x22, 0x91, 0x2d, 0x63, 0x2a, 0xac, 0x87, 0x61, 0x2d, 0x26, 0xe9, 0x1a, 0xa5, + 0xff, 0xdf, 0x65, 0xe6, 0xfb, 0x97, 0x16, 0x3d, 0xcb, 0x01, 0xe3, 0x46, 0x4b, 0x26, 0xe7, 0x87, + 0xc0, 0xfc, 0x0f, 0xc0, 0xfc, 0x1f, 0x81, 0xff, 0x01, 0x0e, 0x43, 0xa4, 0x08, 0x8e, 0x02, 0xe1, + 0xf9, 0x47, 0x77, 0xd6, 0xe0, 0x31, 0x67, 0x40, 0x2f, 0xf9, 0xe0, 0x93, 0x68, 0xb8, 0x61, 0xea, + 0xb1, 0xc0, 0x9e, 0x49, 0x85, 0x83, 0x89, 0x06, 0x1c, 0x32, 0x1c, 0xb7, 0x59, 0x3a, 0x25, 0x71, + 0x69, 0xd5, 0x7a, 0x69, 0x7a, 0x00, 0x00, 0x00, 0x5e, 0xcd, 0x5d, 0x5d, 0x9f, 0xe1, 0x34, 0x7f, + 0x41, 0x1f, 0x3e, 0x58, 0x11, 0xd7, 0x0b, 0xc5, 0xff, 0x81, 0x59, 0x5d, 0x18, 0x0f, 0x3a, 0xc4, + 0x1d, 0x36, 0x73, 0x5a, 0x43, 0x92, 0xf7, 0x4c, 0x58, 0x75, 0xba, 0x19, 0x39, 0xeb, 0x22, 0x49, + 0x03, 0xd5, 0x9a, 0xa0, 0xec, 0x9a, 0x77, 0xd4, 0x59, 0x8a, 0x8a, 0x86, 0x6e, 0x73, 0x42, 0x25, + 0x5f, 0xe9, 0x15, 0x7e, 0x51, 0x3c, 0x07, 0xc7, 0x91, 0xc7, 0x87, 0x83, 0xf0, 0x3e, 0x07, 0xe0, + 0x78, 0x00, 0x2b, 0x98, 0xf9, 0x3e, 0xe7, 0x5d, 0x8b, 0xe1, 0x46, 0x29, 0x6d, 0xb1, 0x9c, 0xaf, + 0x4c, 0x0e, 0x49, 0x7c, 0xe9, 0xc1, 0x22, 0x17, 0x17, 0xa4, 0x60, 0x47, 0x09, 0xef, 0x85, 0x03, + 0x1c, 0x32, 0x1c, 0xb7, 0x59, 0x3a, 0x15, 0xb1, 0x66, 0x56, 0xfc, 0x34, 0x6c, 0x0a, 0x7c, 0x00, + 0x31, 0xe7, 0x9b, 0x3e, 0x8b, 0xe6, 0x8e, 0x9b, 0x9f, 0x19, 0x61, 0x3a, 0xd0, 0x2d, 0xca, 0xba, + 0x73, 0xc6, 0xf2, 0x04, 0x09, 0x48, 0x28, 0x24, 0x67, 0xbe, 0x51, 0xf8, 0xc4, 0x8c, 0xdc, 0x81, + 0x46, 0x13, 0x86, 0x85, 0x4d, 0x25, 0x2b, 0xb4, 0x64, 0x23, 0x77, 0x62, 0x64, 0xf0, 0x52, 0x6e, + 0xd6, 0x59, 0x17, 0xdc, 0xd7, 0x44, 0x07, 0xd7, 0x05, 0x6f, 0x6e, 0x66, 0x81, 0x15, 0x11, 0x60, + 0x67, 0x8f, 0x83, 0xf0, 0x3f, 0x01, 0xf0, 0x78, 0x3e, 0x00, 0x1c, 0x54, 0x4e, 0x17, 0x85, 0x28, + 0x30, 0x08, 0xc8, 0xa3, 0x18, 0xab, 0x25, 0x2a, 0x03, 0x7d, 0x4d, 0xc4, 0x73, 0x7a, 0xdb, 0xdc, + 0xdc, 0x39, 0x15, 0x4b, 0x45, 0x31, 0xf1, 0x01, 0x1c, 0x32, 0x8b, 0xb7, 0x59, 0x3a, 0x36, 0x29, + 0xb0, 0xdc, 0x58, 0x9c, 0x3d, 0xf8, 0x63, 0x7f, 0xcc, 0xc6, 0x86, 0xb4, 0x12, 0xbb, 0xc1, 0xa6, + 0x45, 0x22, 0x34, 0xe9, 0xcb, 0x2d, 0xf6, 0x45, 0x0a, 0x74, 0x9a, 0x04, 0xaa, 0x90, 0xfa, 0xfe, + 0x2e, 0xc2, 0xb7, 0x5b, 0x04, 0x95, 0x5b, 0x1c, 0xbb, 0x27, 0x4c, 0x23, 0x74, 0x29, 0x65, 0xb3, + 0x29, 0x83, 0x0c, 0xff, 0xca, 0x2c, 0x9b, 0x02, 0x71, 0x97, 0x97, 0xfc, 0x2a, 0x5e, 0xe8, 0xa5, + 0xcb, 0x5b, 0xf4, 0xf5, 0x3e, 0x3e, 0x1f, 0x1f, 0x0f, 0xc1, 0xf0, 0xf8, 0x38, 0x39, 0xf7, 0xed, + 0xfd, 0xb5, 0xbf, 0x3d, 0xc6, 0xe4, 0x97, 0x53, 0xd5, 0xdb, 0x24, 0x1a, 0x2d, 0x59, 0x46, 0xd2, + 0x78, 0xcf, 0x44, 0x64, 0xc8, 0x97, 0x87, 0x00, 0x00, 0x5b, 0x76, 0x23, 0x1e, 0x3e, 0x0f, 0x40, + 0x1c, 0x31, 0xa2, 0xb7, 0x59, 0x3a, 0x44, 0xc1, 0x33, 0xd3, 0x8d, 0x2f, 0x14, 0xf2, 0x6a, 0x70, + 0xdb, 0x8e, 0x7a, 0xb3, 0x95, 0xcb, 0x81, 0x5c, 0xf8, 0x5c, 0xb0, 0x30, 0xb8, 0x50, 0xb8, 0xcd, + 0x5f, 0x61, 0xe5, 0xfc, 0x54, 0xd0, 0xcc, 0xb0, 0x32, 0xa3, 0x79, 0x23, 0x30, 0xbf, 0xa6, 0x60, + 0xb0, 0x91, 0x48, 0x28, 0xdb, 0xa6, 0x6d, 0x06, 0x7d, 0x8c, 0x41, 0x4d, 0x9d, 0x79, 0xec, 0xde, + 0x45, 0xf9, 0xb2, 0x3b, 0x8c, 0x84, 0x4f, 0x89, 0xca, 0x2f, 0xa9, 0xfb, 0x6a, 0x83, 0xf0, 0x3e, + 0x1c, 0x7c, 0x68, 0x4e, 0x04, 0x06, 0x2e, 0x0b, 0xf1, 0x9b, 0x10, 0x41, 0x34, 0xde, 0x34, 0x46, + 0xc1, 0x25, 0x43, 0x02, 0xe8, 0xaa, 0x72, 0x89, 0xa2, 0xb8, 0x99, 0xe1, 0xf8, 0x1f, 0xc0, 0x7e, + 0x03, 0xf8, 0x07, 0xe0, 0x7e, 0x07, 0xe2, 0x98, 0x38, 0x63, 0x2d, 0x6e, 0xb2, 0x6a, 0x13, 0x7c, + 0xa7, 0x93, 0xab, 0x53, 0x7c, 0x44, 0xa6, 0xa3, 0x5c, 0x6e, 0x15, 0x16, 0xc0, 0x70, 0x24, 0x37, + 0x5e, 0xed, 0x86, 0x81, 0x07, 0x22, 0x6d, 0xfa, 0x2b, 0xb4, 0xbc, 0x96, 0x97, 0x5d, 0xf1, 0x41, + 0x46, 0x6b, 0x74, 0x19, 0x83, 0x62, 0xb5, 0xf6, 0x5a, 0x82, 0x66, 0x62, 0x21, 0x40, 0x53, 0xb6, + 0x3e, 0x02, 0xf0, 0xe1, 0x78, 0x1d, 0x7d, 0x09, 0x1d, 0x32, 0x2c, 0x03, 0xac, 0x48, 0x36, 0xfd, + 0x00, 0x00, 0x62, 0x87, 0x11, 0x9d, 0xee, 0x1f, 0x81, 0xf8, 0xe3, 0x98, 0x09, 0x2a, 0x02, 0xf1, + 0x43, 0xba, 0xc3, 0x0f, 0xe8, 0x3a, 0xb6, 0x16, 0x3e, 0x19, 0xd3, 0xca, 0x0d, 0xac, 0x66, 0x44, + 0x29, 0x66, 0x02, 0x11, 0xc3, 0xe1, 0xf8, 0x0f, 0xe0, 0x3f, 0x81, 0xfc, 0x0f, 0x8c, 0xe2, 0x94, + 0x38, 0x63, 0x2d, 0x6e, 0xb2, 0x6a, 0x04, 0xfc, 0x33, 0x99, 0x90, 0x39, 0x20, 0x30, 0xff, 0xb4, + 0x30, 0xb8, 0xc4, 0x12, 0xb1, 0xe9, 0x0f, 0x96, 0xdb, 0x03, 0xcd, 0x52, 0xe2, 0x14, 0x56, 0xf6, + 0x04, 0x3c, 0x4a, 0x5e, 0x8f, 0x15, 0xee, 0xc2, 0x67, 0x8b, 0x94, 0xf7, 0xdc, 0x90, 0x0b, 0xf3, + 0x4e, 0x58, 0xf1, 0x50, 0x5c, 0xa2, 0x6f, 0xa7, 0xa2, 0x7e, 0xb3, 0xf3, 0x5f, 0x90, 0x15, 0x67, + 0xd4, 0xeb, 0xa4, 0x7f, 0x2b, 0x1c, 0xb9, 0x0c, 0x41, 0xc5, 0x02, 0x16, 0xa8, 0xf1, 0xe0, 0xfc, + 0x0f, 0x87, 0x82, 0x1b, 0xdf, 0x89, 0x5e, 0x36, 0x79, 0xbe, 0x67, 0xef, 0xfc, 0x10, 0x3b, 0x67, + 0x30, 0x8e, 0xc5, 0x3f, 0x39, 0x00, 0x2c, 0x4f, 0xf8, 0xe4, 0x46, 0x5d, 0x83, 0xf0, 0x3f, 0x03, + 0xf0, 0x3f, 0x03, 0xf0, 0x3c, 0x3c, 0x1e, 0x90, 0x38, 0x63, 0x2d, 0x6e, 0xb2, 0x69, 0xf3, 0xd4, + 0x33, 0xd8, 0x0e, 0xc2, 0x9f, 0x37, 0x79, 0x60, 0x9a, 0xfc, 0xf2, 0x74, 0xf3, 0x6f, 0x3a, 0x72, + 0x71, 0x2d, 0xb0, 0xd3, 0xf7, 0x25, 0x57, 0x4a, 0x2f, 0xeb, 0xcf, 0x94, 0xce, 0x06, 0x4e, 0x2c, + 0x72, 0xbc, 0xf8, 0xf4, 0x26, 0xde, 0xb9, 0x51, 0xea, 0xba, 0xe8, 0x09, 0x79, 0x57, 0xa0, 0x97, + 0xbf, 0xf5, 0x41, 0xfb, 0x9b, 0x94, 0x77, 0x67, 0x5e, 0xfc, 0xb8, 0xc1, 0xe8, 0x27, 0x86, 0x12, + 0x09, 0x3c, 0xf9, 0xba, 0x0f, 0x4c, 0xe0, 0x7e, 0x0e, 0x1c, 0x42, 0x9e, 0x7d, 0x1d, 0xfa, 0x47, + 0x21, 0xa5, 0xa7, 0x83, 0xdb, 0x4b, 0x22, 0x0f, 0xda, 0x11, 0x07, 0x36, 0x97, 0x0d, 0x1a, 0x4a, + 0x3e, 0x42, 0x58, 0xfc, 0x70, 0x3f, 0x03, 0xf8, 0x1f, 0x81, 0xfc, 0x0f, 0xc1, 0xf0, 0x3e, 0x8c, + 0x38, 0x63, 0x2d, 0x6e, 0xb2, 0x6a, 0x23, 0x6c, 0x69, 0xd4, 0x3e, 0x17, 0xac, 0x21, 0x55, 0x93, + 0x90, 0xdc, 0x64, 0xe3, 0x94, 0x46, 0x58, 0x16, 0x64, 0x08, 0x07, 0x57, 0xea, 0xe7, 0x8d, 0xe6, + 0x3c, 0xff, 0x72, 0xe9, 0xee, 0x44, 0xa1, 0x91, 0xe0, 0xa5, 0x8d, 0xf8, 0x00, 0x42, 0xf4, 0x4f, + 0x12, 0xaa, 0x8d, 0x53, 0xe5, 0x04, 0x23, 0x9a, 0xb0, 0xdf, 0x36, 0x57, 0x8d, 0x80, 0xce, 0x61, + 0x42, 0x79, 0x4e, 0x9a, 0x98, 0x80, 0x36, 0x76, 0xb1, 0x12, 0x52, 0x09, 0x04, 0x3b, 0xc3, 0x07, + 0x83, 0xc3, 0xc1, 0xce, 0xe7, 0x38, 0xd9, 0x76, 0x6f, 0x6f, 0x4d, 0xf7, 0xca, 0xf3, 0x15, 0x07, + 0xf4, 0xa4, 0x45, 0x43, 0xe6, 0x1e, 0x2b, 0x38, 0x95, 0x22, 0x62, 0x7e, 0x09, 0x2a, 0x75, 0x4d, + 0xbe, 0x8a, 0xb3, 0xf8, 0xe7, 0x28, 0xf1, 0x45, 0x15, 0x36, 0xf0, 0xaa, 0x59, 0x3a, 0x05, 0x61, + 0x17, 0x53, 0xba, 0x39, 0x92, 0x10, 0x28, 0x29, 0x42, 0x01, 0x0d, 0x63, 0x30, 0xf6, 0xa2, 0x2e, + 0x2e, 0x94, 0x22, 0x45, 0x69, 0x24, 0x9c, 0xed, 0xc9, 0x03, 0xbb, 0xfa, 0x1b, 0x87, 0x07, 0x18, + 0x7b, 0x1c, 0x81, 0xcc, 0x46, 0x10, 0x0c, 0x05, 0x37, 0xa8, 0xc9, 0xf0, 0x54, 0x77, 0x46, 0xbb, + 0x32, 0x7e, 0xad, 0x89, 0x17, 0xdb, 0x80, 0x3b, 0xcb, 0x56, 0x1c, 0xc4, 0x60, 0x62, 0x11, 0x1b, + 0x0d, 0x2b, 0x8a, 0xfa, 0x5f, 0x9b, 0x03, 0xe3, 0xc3, 0xe3, 0x08, 0x19, 0x41, 0xf9, 0xb0, 0x75, + 0x90, 0x35, 0xf1, 0x6b, 0xde, 0x52, 0x86, 0xb0, 0xa8, 0x45, 0xf5, 0x31, 0x38, 0xbc, 0x42, 0x74, + 0x11, 0x0e, 0x67, 0x07, 0xc0, 0xfc, 0x07, 0xf0, 0x1f, 0xc0, 0x7e, 0x07, 0xc0, 0xf8, 0x1e, 0x88, + 0x2a, 0x6d, 0xe1, 0x54, 0xb2, 0x69, 0xf4, 0x84, 0x33, 0x99, 0x90, 0x14, 0xce, 0x01, 0x5d, 0xb0, + 0x5e, 0x96, 0x0e, 0x6e, 0xab, 0x5c, 0xe5, 0x6d, 0xbb, 0x37, 0x38, 0xb9, 0xb2, 0x1b, 0x05, 0x8c, + 0x78, 0x2c, 0x60, 0xcb, 0xf6, 0x63, 0xc2, 0xaa, 0xcf, 0x45, 0xe3, 0xe7, 0x83, 0xfc, 0x3b, 0xd6, + 0x02, 0x76, 0x96, 0x16, 0x4c, 0xf2, 0xdb, 0x01, 0x14, 0xee, 0x3d, 0x4f, 0xfa, 0x79, 0xe6, 0xee, + 0xcf, 0x2e, 0x8b, 0x05, 0x95, 0xce, 0x11, 0xdd, 0x00, 0x06, 0x76, 0xa4, 0xd0, 0x72, 0xe6, 0x0f, + 0x83, 0xcf, 0x01, 0x37, 0xba, 0xad, 0xa4, 0x76, 0x0e, 0xf2, 0x49, 0xa9, 0xf3, 0xf3, 0xdf, 0xa4, + 0x60, 0x91, 0x77, 0xd7, 0x02, 0x6d, 0x81, 0x16, 0xc1, 0x6a, 0x3f, 0x11, 0xdc, 0x78, 0x1f, 0x81, + 0xfc, 0x07, 0xf0, 0x3f, 0x07, 0x87, 0x86, 0x84, 0x2a, 0x6d, 0xe1, 0x54, 0xb2, 0x69, 0xf5, 0x2c, + 0x33, 0xd3, 0x8c, 0x58, 0xe1, 0x9c, 0xb2, 0x59, 0xfc, 0xdc, 0xd0, 0xc0, 0xf3, 0xe2, 0x7b, 0x0d, + 0x82, 0x03, 0x79, 0xc8, 0x02, 0x05, 0xa5, 0xc0, 0xa3, 0x32, 0x5e, 0xa7, 0x59, 0x35, 0x90, 0x72, + 0xba, 0x77, 0x62, 0x47, 0x75, 0xe5, 0xe7, 0x87, 0xff, 0x6f, 0xf6, 0x54, 0x3c, 0x3c, 0x04, 0xa5, + 0x61, 0x6b, 0x51, 0xb2, 0xef, 0x43, 0xfc, 0xe5, 0x5a, 0x49, 0xd8, 0xa2, 0x90, 0x2d, 0xf4, 0xc9, + 0x92, 0x34, 0x04, 0x4d, 0xbc, 0x44, 0x1b, 0x3c, 0x1f, 0x0f, 0x07, 0xe7, 0x1e, 0x4c, 0x8e, 0x93, + 0x84, 0xc3, 0x84, 0xf0, 0x53, 0xdf, 0x8f, 0x39, 0x31, 0xeb, 0x80, 0xfb, 0x07, 0xa7, 0xc4, 0x62, + 0xdb, 0xe9, 0xe8, 0x64, 0x1e, 0x0f, 0x80, 0xfc, 0x07, 0xe0, 0x7e, 0x07, 0x83, 0x81, 0xe2, 0x82, + 0x2a, 0x6d, 0xe1, 0x54, 0xb2, 0x69, 0xd5, 0x14, 0xa7, 0x9c, 0xd9, 0x8f, 0xdd, 0x6b, 0x3d, 0x76, + 0xf7, 0xc3, 0x0e, 0x97, 0x50, 0x17, 0x2a, 0xf3, 0xb1, 0xc9, 0x00, 0x11, 0x47, 0x58, 0xb6, 0x37, + 0x42, 0x00, 0x82, 0x81, 0xef, 0x39, 0xd7, 0x5c, 0xd4, 0x53, 0xa8, 0x2e, 0xf6, 0xbf, 0x6b, 0x6b, + 0xed, 0xbb, 0x79, 0x5f, 0x4e, 0x7f, 0x5c, 0x9c, 0x36, 0xde, 0xd0, 0xc3, 0xe0, 0xa2, 0x2e, 0xf6, + 0xdc, 0x8b, 0x53, 0x7a, 0x9c, 0xb5, 0xd2, 0xd7, 0x00, 0x00, 0x00, 0x00, 0x86, 0xe7, 0xe0, 0xe7, + 0x03, 0xae, 0x3b, 0xcf, 0xdc, 0xa2, 0x6e, 0x9d, 0x9c, 0x27, 0xe3, 0x71, 0x00, 0x53, 0xcf, 0x51, + 0x41, 0xab, 0x75, 0x93, 0x63, 0x0f, 0x17, 0x53, 0x8f, 0x43, 0xc1, 0xf9, 0x01, 0xfb, 0x08, 0x3f, + 0xc0, 0xfc, 0x07, 0xc0, 0xfc, 0x07, 0xe2, 0x82, 0x38, 0x37, 0x7f, 0xee, 0xb2, 0x6a, 0x05, 0x04, + 0xaf, 0xdd, 0x47, 0xae, 0x91, 0xb9, 0x15, 0x00, 0x00, 0x35, 0x1c, 0x0e, 0xf4, 0x88, 0x7b, 0x3b, + 0x20, 0x11, 0x45, 0xff, 0x9b, 0xc9, 0x49, 0x92, 0x5c, 0xa8, 0x15, 0xc6, 0x2f, 0x00, 0x65, 0xd9, + 0x0c, 0xa6, 0xc1, 0x57, 0x59, 0xfe, 0x6c, 0xa8, 0xb9, 0xca, 0x85, 0x17, 0x43, 0x10, 0x50, 0x89, + 0x2a, 0x32, 0xf0, 0xe9, 0x21, 0xb0, 0x76, 0x84, 0xd6, 0x2c, 0x02, 0x2d, 0xca, 0x00, 0xe4, 0xe7, + 0x70, 0xfc, 0x0d, 0x62, 0x61, 0x29, 0x9b, 0x87, 0x1f, 0x0f, 0xc1, 0xf8, 0x1f, 0x83, 0xe0, 0xe3, + 0x86, 0x05, 0x8b, 0x60, 0x65, 0xfa, 0x56, 0x07, 0xe6, 0x3c, 0x06, 0x1a, 0x85, 0xda, 0x16, 0xa8, + 0xe5, 0x5d, 0x56, 0x66, 0x21, 0xce, 0x99, 0xa2, 0xd4, 0xeb, 0x17, 0x0b, 0xe6, 0x20, 0x53, 0x48, + 0x15, 0xa9, 0xc6, 0x9a, 0x59, 0x3a, 0x15, 0x19, 0xa8, 0x0a, 0xd8, 0xfb, 0x8e, 0x91, 0xcf, 0x81, + 0xf5, 0x95, 0x4a, 0x3c, 0xbf, 0x7b, 0x07, 0x47, 0x4c, 0x06, 0xfb, 0xb8, 0x8e, 0x89, 0x7a, 0xe4, + 0x77, 0xd5, 0xfe, 0xa2, 0x5d, 0x91, 0x3b, 0x3a, 0x4e, 0x73, 0x87, 0x6e, 0x9e, 0xb1, 0x18, 0x3f, + 0x20, 0x0f, 0x97, 0xc7, 0x92, 0xbd, 0x38, 0xa4, 0x5a, 0xdf, 0x04, 0x0d, 0xd6, 0xee, 0xe5, 0x37, + 0x91, 0x4d, 0xd6, 0xf1, 0x39, 0x0a, 0x77, 0xf4, 0x28, 0x18, 0xd6, 0x4e, 0x1b, 0x1f, 0x07, 0x30, + 0x0d, 0x89, 0xf3, 0xe2, 0xa3, 0x96, 0x01, 0xfa, 0x00, 0x69, 0x46, 0x83, 0x58, 0xf8, 0x7d, 0x50, + 0xe5, 0x1c, 0x72, 0x20, 0x12, 0x0a, 0x40, 0x31, 0x94, 0x3f, 0xe1, 0xe0, 0x7e, 0x07, 0xf0, 0x1f, + 0xc0, 0x7e, 0x07, 0xe0, 0x7e, 0x07, 0xe2, 0x8e, 0x31, 0x44, 0x9f, 0x94, 0xb2, 0x6a, 0x04, 0x14, + 0x62, 0xa1, 0x41, 0x6d, 0x58, 0xb3, 0xd6, 0x54, 0x5d, 0x8e, 0x1b, 0xf9, 0xf7, 0xe1, 0xdc, 0xb2, + 0x0a, 0x45, 0xcd, 0xfa, 0x6e, 0x8d, 0x63, 0x73, 0x21, 0x99, 0x55, 0x5c, 0x2c, 0x3a, 0xbf, 0x9c, + 0xe7, 0xad, 0xb0, 0xa9, 0x88, 0xcb, 0x00, 0xd0, 0x1b, 0x3b, 0x87, 0xe4, 0x34, 0x74, 0xd6, 0x41, + 0x01, 0x5a, 0x90, 0x50, 0xd8, 0x61, 0x22, 0xb8, 0xdf, 0xbe, 0xab, 0xa6, 0xf9, 0xd2, 0x05, 0x81, + 0xe6, 0x82, 0x20, 0x7c, 0x3c, 0x60, 0x18, 0x64, 0x7d, 0x2c, 0x7c, 0xc3, 0xf1, 0xfb, 0xbb, 0x77, + 0x59, 0xf4, 0x7b, 0xf2, 0x06, 0x8d, 0x50, 0x8d, 0x9f, 0x4c, 0xc1, 0xa1, 0x0f, 0x69, 0x56, 0x91, + 0xee, 0x6c, 0x3c, 0x0f, 0xc0, 0x7f, 0x01, 0xfc, 0x07, 0xf0, 0x3f, 0x00, 0xfe, 0x03, 0xe2, 0x8c, + 0x31, 0x44, 0x9f, 0x94, 0xb2, 0x6a, 0x04, 0x2c, 0x33, 0xd7, 0xfb, 0x2c, 0x1a, 0x47, 0x41, 0x14, + 0xaa, 0xbb, 0x2f, 0x89, 0x27, 0x2c, 0x14, 0x19, 0x47, 0x2c, 0x09, 0x2b, 0xb7, 0x86, 0x2a, 0x41, + 0xcd, 0xea, 0x0a, 0xc0, 0x62, 0x0d, 0x1a, 0xfd, 0xf2, 0x27, 0x4f, 0x87, 0xfa, 0x66, 0x41, 0x22, + 0xf0, 0xc0, 0x7d, 0x12, 0x3c, 0xff, 0xd8, 0x37, 0x5b, 0x53, 0x07, 0x9b, 0x31, 0x48, 0x1e, 0x74, + 0xa3, 0xf6, 0x2c, 0x3f, 0x81, 0xf5, 0x8a, 0xaa, 0xa1, 0xdc, 0x84, 0x92, 0x7d, 0x56, 0x0f, 0x83, + 0x8f, 0xf0, 0x45, 0x63, 0x5e, 0x0b, 0x34, 0x10, 0x60, 0xc9, 0x8b, 0xf9, 0x00, 0x0b, 0x35, 0xf6, + 0x63, 0xf4, 0x00, 0xc7, 0x64, 0x11, 0xef, 0x57, 0xa0, 0x76, 0x84, 0xe1, 0xf0, 0x1f, 0x81, 0xf8, + 0x1f, 0x80, 0xfc, 0x0f, 0xc0, 0xfc, 0x1e, 0x8a, 0x31, 0x44, 0x9f, 0x94, 0xb2, 0x69, 0xf4, 0x24, + 0x37, 0xdf, 0x74, 0xd5, 0xec, 0x89, 0x25, 0xf8, 0x06, 0x62, 0xdb, 0x69, 0xec, 0x25, 0xdc, 0x0f, + 0x00, 0xff, 0x4e, 0x2f, 0xa4, 0xfa, 0x75, 0x06, 0x49, 0x05, 0xde, 0xc4, 0x47, 0x9a, 0x70, 0x2d, + 0xa8, 0xbf, 0x43, 0xb5, 0x73, 0xb5, 0x6b, 0xbd, 0x7f, 0xd3, 0x51, 0xd3, 0x4a, 0xd9, 0x29, 0xfc, + 0x69, 0xd6, 0xdc, 0x20, 0xa8, 0x28, 0x3f, 0xa6, 0x59, 0x57, 0x81, 0xa7, 0x2f, 0x3e, 0x61, 0xaf, + 0x9f, 0xa5, 0x61, 0x1f, 0xb9, 0x0d, 0x44, 0xf7, 0xee, 0x5e, 0xd9, 0xd7, 0x0a, 0x59, 0xe6, 0x09, + 0x6d, 0xc8, 0xd8, 0xe2, 0x42, 0x98, 0xa5, 0x7b, 0x7e, 0xcc, 0xcc, 0xe9, 0x1b, 0x0b, 0xc5, 0x35, + 0x31, 0x73, 0xa5, 0x75, 0x96, 0xa6, 0x00, 0x1c, 0x3e, 0x1e, 0x07, 0x1c, 0xf1, 0xe0, 0x3e, 0x08, + 0x31, 0x44, 0x9f, 0x94, 0xb2, 0x79, 0x95, 0xcc, 0x33, 0x9e, 0x5d, 0x41, 0x8f, 0x8a, 0x96, 0xc7, + 0xe1, 0x70, 0x65, 0xe7, 0xdb, 0x04, 0xd5, 0xd1, 0x32, 0xef, 0x93, 0xc9, 0x18, 0x8f, 0xe0, 0xe1, + 0x65, 0x45, 0x99, 0x6e, 0x1c, 0x2b, 0xc9, 0x31, 0x1c, 0x79, 0x1b, 0x83, 0x4e, 0xff, 0xda, 0x66, + 0x7e, 0x8c, 0xe7, 0x4e, 0x49, 0x2a, 0x1d, 0x4f, 0x7a, 0x6a, 0xb4, 0xe7, 0xa0, 0x05, 0x0c, 0xc2, + 0x46, 0xd2, 0x31, 0x87, 0xa6, 0x36, 0x6c, 0x25, 0x7e, 0x12, 0xfb, 0x1c, 0x24, 0xc3, 0xe0, 0xf1, + 0xee, 0x58, 0x4a, 0x5e, 0xa5, 0x27, 0x85, 0xc0, 0x61, 0xcd, 0xf2, 0xbc, 0xb1, 0x17, 0xc3, 0xd6, + 0xd6, 0x54, 0xc7, 0xff, 0xa1, 0xe7, 0xc1, 0x0f, 0xbf, 0xf9, 0x4a, 0x23, 0xc3, 0xf0, 0x3f, 0x03, + 0xf8, 0x0f, 0xe0, 0x78, 0x7c, 0x0e, 0x1e, 0x86, 0x31, 0x44, 0x9f, 0x94, 0xb2, 0x69, 0xe4, 0x34, + 0x37, 0xdf, 0x74, 0x6e, 0x24, 0x93, 0x69, 0xca, 0xf0, 0x42, 0x18, 0xc9, 0x65, 0x85, 0x6f, 0x58, + 0x9b, 0xba, 0x9a, 0x97, 0xd0, 0x62, 0xc1, 0xac, 0x90, 0xd2, 0x42, 0x31, 0x2d, 0x7c, 0xc0, 0x2b, + 0xa1, 0x0b, 0xc8, 0x50, 0xf9, 0xbb, 0xa5, 0x7d, 0x4b, 0x87, 0xe8, 0x2f, 0xd0, 0xbb, 0x82, 0xfd, + 0x16, 0x10, 0x19, 0x1f, 0x93, 0x96, 0xb8, 0x62, 0x32, 0xd6, 0x75, 0xbb, 0x2d, 0x8c, 0x48, 0x20, + 0xcc, 0xa6, 0xef, 0x97, 0x6d, 0x51, 0xe5, 0x73, 0x65, 0x9c, 0xdd, 0x79, 0x7c, 0xee, 0x7b, 0xc3, + 0xb7, 0xbf, 0xe4, 0x8f, 0x24, 0xf3, 0x6a, 0x48, 0x7a, 0x33, 0x35, 0x97, 0x37, 0x57, 0x7f, 0x5e, + 0x61, 0x75, 0x1c, 0x3e, 0xdb, 0x57, 0xc4, 0x85, 0x0d, 0xc3, 0xe1, 0x87, 0x81, 0xc6, 0x7d, 0x07, + 0x91, 0x44, 0x9f, 0x94, 0xb2, 0x39, 0xa5, 0xdc, 0x69, 0xd4, 0x53, 0xa1, 0xf2, 0xb1, 0x90, 0x83, + 0xe6, 0x47, 0x9c, 0xb0, 0x39, 0x1c, 0xa0, 0x8e, 0xd1, 0x26, 0xbe, 0xaa, 0x8e, 0xab, 0xad, 0x5b, + 0x71, 0x66, 0xc4, 0xf1, 0xd4, 0x0b, 0x50, 0x92, 0xb0, 0xd3, 0x44, 0xe3, 0x56, 0x3f, 0xb0, 0x84, + 0xc8, 0xdf, 0x80, 0xf9, 0x66, 0xd9, 0x19, 0x17, 0xe0, 0xe2, 0x12, 0x84, 0x1c, 0xcf, 0x57, 0xa9, + 0x56, 0x79, 0x70, 0x7f, 0xb9, 0xa7, 0x58, 0x53, 0xea, 0x65, 0xe9, 0x91, 0x5c, 0x3b, 0x1c, 0xe7, + 0xa4, 0xff, 0xac, 0xa9, 0xfb, 0xde, 0xf9, 0xfc, 0x3c, 0x45, 0x36, 0x2d, 0x7c, 0xdc, 0x83, 0x69, + 0x12, 0x6a, 0xb1, 0x6a, 0x29, 0x02, 0x12, 0xd0, 0x00, 0x93, 0x93, 0xe8, 0x90, 0xbb, 0x5c, 0xa5, + 0x8c, 0xf6, 0x08, 0x7c, 0x37, 0x86, 0x3e, 0x07, 0x98, 0x44, 0x69, 0x6e, 0xb2, 0x39, 0xc6, 0x3c, + 0x69, 0xd4, 0x53, 0xa1, 0xf2, 0xa1, 0xf1, 0xaa, 0xf4, 0x4c, 0x39, 0xb2, 0xc2, 0xa4, 0xa6, 0xf1, + 0xcf, 0x85, 0xb4, 0xd3, 0xc9, 0xc7, 0xa3, 0x33, 0xf3, 0x5a, 0x04, 0xbb, 0x04, 0x8f, 0x8f, 0x80, + 0x7a, 0x24, 0x12, 0x88, 0x2b, 0xb9, 0x56, 0xbe, 0x39, 0x92, 0xf1, 0xb4, 0x80, 0x4b, 0xc1, 0xb3, + 0x7b, 0x23, 0xfc, 0x48, 0x7e, 0x7f, 0xea, 0x3d, 0x49, 0xc4, 0x32, 0x04, 0x69, 0x36, 0xed, 0x68, + 0x03, 0x75, 0x5d, 0x79, 0xc1, 0xcc, 0xa3, 0x21, 0x3d, 0x84, 0xd4, 0x23, 0x16, 0x48, 0x67, 0x80, + 0x3c, 0x76, 0x4e, 0x57, 0x39, 0x4f, 0x1a, 0xbf, 0x6e, 0xf7, 0x2a, 0xac, 0xb9, 0x3d, 0x1c, 0xf1, + 0x72, 0x6b, 0xff, 0x78, 0xec, 0xff, 0x15, 0xe1, 0x35, 0x44, 0x5e, 0x07, 0xc1, 0xfc, 0x61, 0xf8, + 0x98, 0x44, 0x69, 0x6e, 0xb2, 0x39, 0xc6, 0x3c, 0x37, 0xe7, 0x3d, 0xc9, 0x8e, 0xff, 0xc4, 0x6e, + 0x98, 0x6d, 0x0c, 0xe7, 0x5b, 0xa2, 0x9d, 0x70, 0xf9, 0x49, 0x65, 0x08, 0x3c, 0x9d, 0x4c, 0xbe, + 0xab, 0x06, 0x7f, 0x44, 0xcd, 0x5c, 0x3c, 0x0f, 0x45, 0x11, 0x44, 0xa6, 0x5c, 0x39, 0x10, 0xe4, + 0x5e, 0xaa, 0xff, 0x83, 0x97, 0xbb, 0x26, 0x41, 0x9f, 0x65, 0xc0, 0x70, 0x59, 0xea, 0x44, 0xd1, + 0x9d, 0x60, 0x8b, 0x95, 0xdc, 0xee, 0xa5, 0x97, 0x57, 0xb9, 0xc8, 0x53, 0x6b, 0x50, 0x93, 0xef, + 0x46, 0x29, 0xd1, 0x37, 0x23, 0xc8, 0xb8, 0x72, 0x83, 0xd8, 0x10, 0xde, 0xe4, 0x5d, 0xde, 0xc5, + 0xb0, 0x95, 0x28, 0x52, 0xe5, 0x78, 0xea, 0x33, 0xff, 0x45, 0x02, 0x67, 0x5e, 0x1d, 0x80, 0x1e, + 0x2a, 0x64, 0xe0, 0x17, 0x1f, 0x0d, 0x81, 0xf5, 0x98, 0x44, 0x69, 0x6e, 0xb2, 0x39, 0xb6, 0x34, + 0xaf, 0xdd, 0x5d, 0x72, 0x51, 0x9c, 0xbc, 0x0c, 0xcc, 0x10, 0xab, 0x8c, 0xc2, 0x7d, 0x59, 0x42, + 0x30, 0xe9, 0x9d, 0x1a, 0x5c, 0x84, 0x23, 0x4e, 0x22, 0xd6, 0x5f, 0x48, 0x7b, 0x28, 0x9c, 0x30, + 0x8e, 0x91, 0x70, 0xc9, 0x7a, 0x47, 0x8e, 0x19, 0xee, 0xbf, 0x26, 0xbe, 0x14, 0x32, 0xda, 0x90, + 0xa9, 0xb1, 0x01, 0x31, 0x7b, 0x70, 0x6f, 0x7a, 0x92, 0xb9, 0x20, 0x11, 0x61, 0x36, 0xf1, 0x68, + 0x3b, 0x55, 0x89, 0xbc, 0x57, 0x9b, 0xa1, 0x25, 0xf6, 0x2a, 0x0d, 0xbf, 0x06, 0x3c, 0x04, 0x81, + 0x70, 0xc1, 0xc2, 0xc1, 0x75, 0x90, 0xfe, 0x28, 0x0e, 0xf3, 0x46, 0x00, 0xd2, 0xc0, 0xb0, 0x25, + 0xa9, 0x95, 0xba, 0x98, 0x32, 0xc6, 0x64, 0xa8, 0x42, 0xac, 0x6c, 0x1e, 0x6c, 0x3c, 0x91, 0xf8, + 0x98, 0x44, 0xa5, 0x6e, 0xb2, 0x39, 0xf6, 0x2c, 0xaf, 0xdd, 0x5d, 0x70, 0x12, 0x34, 0x02, 0x21, + 0x2e, 0x2a, 0xa5, 0x29, 0x16, 0x21, 0x2b, 0x6b, 0xa6, 0x00, 0x62, 0x1a, 0x85, 0x11, 0xfe, 0x27, + 0x96, 0xc0, 0xe3, 0xca, 0xf9, 0x46, 0xdf, 0x0f, 0x6e, 0x7b, 0x04, 0xb5, 0x60, 0x0b, 0xd7, 0x23, + 0x62, 0x79, 0xd6, 0x0c, 0x1a, 0xd2, 0xed, 0x99, 0xc4, 0x11, 0x6a, 0x80, 0x3a, 0x1f, 0x6c, 0x4a, + 0x47, 0xa4, 0xc2, 0x1c, 0x5b, 0x94, 0x64, 0x8c, 0x26, 0x04, 0xfb, 0xfd, 0x16, 0xc5, 0x1f, 0x97, + 0x58, 0xcd, 0x2c, 0xec, 0xa5, 0xe7, 0x78, 0x58, 0xa7, 0x88, 0x7e, 0xb5, 0xaa, 0x2c, 0xbf, 0x1d, + 0x7d, 0xf1, 0xe0, 0x41, 0x8e, 0x4d, 0x3a, 0x58, 0x34, 0x6e, 0x28, 0x41, 0x75, 0x15, 0xeb, 0xc8, + 0xf2, 0x43, 0xc7, 0x21, 0x6d, 0xe3, 0x9e, 0x07, 0x78, 0x44, 0xa5, 0x6e, 0xb2, 0x39, 0xc6, 0x3c, + 0xb0, 0xdc, 0x12, 0xcc, 0x4c, 0xcc, 0x48, 0xed, 0x80, 0x64, 0xa3, 0x51, 0xff, 0x3d, 0xf0, 0x22, + 0xd1, 0x9b, 0xd6, 0xd3, 0x68, 0x90, 0x43, 0x3f, 0x1b, 0x71, 0x66, 0xd9, 0xa2, 0xbf, 0xc9, 0xe5, + 0xeb, 0x73, 0x46, 0xc1, 0xad, 0x24, 0xfd, 0xf3, 0x39, 0x11, 0x8f, 0xaa, 0x4c, 0x5e, 0xb6, 0x4e, + 0x11, 0xa1, 0xb4, 0xdb, 0x1a, 0xe4, 0xa5, 0xe5, 0xc5, 0xb7, 0xec, 0x9c, 0x1d, 0x17, 0xb7, 0x75, + 0xc5, 0x7e, 0x7d, 0xf1, 0x28, 0xa2, 0x14, 0x9f, 0x10, 0xde, 0x56, 0xb4, 0xe1, 0x83, 0xef, 0x57, + 0x87, 0xda, 0x25, 0x28, 0x35, 0x38, 0x90, 0x50, 0xa4, 0xb5, 0x5d, 0x7d, 0x94, 0xc3, 0xda, 0x73, + 0xdb, 0xe7, 0x28, 0x29, 0xbb, 0x59, 0x5c, 0xb5, 0x83, 0x72, 0x3b, 0x45, 0xc2, 0x56, 0xc7, 0x79, + 0x98, 0x44, 0xa5, 0x6e, 0xb2, 0x39, 0xc6, 0x1c, 0xb0, 0xdc, 0x62, 0x63, 0x93, 0x7b, 0xc3, 0x48, + 0xe7, 0x95, 0x2c, 0x81, 0x44, 0x14, 0xd3, 0xad, 0xf5, 0x39, 0x80, 0x5e, 0xee, 0x45, 0xc0, 0xbd, + 0x79, 0xc3, 0x00, 0x4b, 0x0a, 0xe2, 0x40, 0x24, 0xbc, 0xc5, 0xf6, 0x61, 0x16, 0xa6, 0x76, 0xa2, + 0x59, 0xaa, 0x1c, 0xe5, 0x07, 0x22, 0x89, 0x27, 0xce, 0x4a, 0x3d, 0xd3, 0x95, 0x29, 0x8f, 0xd4, + 0xc9, 0xa4, 0x9c, 0xfd, 0x00, 0x8f, 0x51, 0x80, 0x2a, 0xc8, 0xaa, 0xed, 0xf5, 0xb1, 0x54, 0xf3, + 0x42, 0xd4, 0x2b, 0xa0, 0x34, 0xd0, 0x01, 0x44, 0xf8, 0x28, 0x78, 0x1f, 0x77, 0xf4, 0xf1, 0x9a, + 0xc7, 0x75, 0x42, 0xbd, 0x06, 0xf8, 0x0c, 0xba, 0x99, 0xc7, 0xd4, 0xa9, 0xdd, 0x9b, 0xb6, 0xd0, + 0x86, 0x02, 0x31, 0xe3, 0x18, 0x7c, 0x00, 0xfc, 0x78, 0x44, 0xa5, 0x6e, 0xb2, 0x39, 0xc6, 0x24, + 0x69, 0xd5, 0x7e, 0xf4, 0x56, 0xff, 0xd6, 0xb8, 0x39, 0x42, 0xb8, 0xea, 0x1e, 0x44, 0x7d, 0xdb, + 0x3a, 0xb6, 0x27, 0xe9, 0xc5, 0xe9, 0xce, 0x0b, 0x27, 0x53, 0x53, 0x03, 0x18, 0x9b, 0x40, 0xa5, + 0xd1, 0x72, 0x39, 0x94, 0x3c, 0xb2, 0x50, 0x91, 0x4f, 0x84, 0xa1, 0xa4, 0x88, 0x6e, 0x7b, 0x48, + 0x4a, 0x99, 0x55, 0x38, 0xab, 0x70, 0x69, 0x53, 0x6f, 0xe9, 0x2d, 0xec, 0x15, 0xc8, 0x2f, 0xf6, + 0x1f, 0x48, 0x7d, 0xdf, 0x34, 0x16, 0xc3, 0x6f, 0x06, 0x64, 0x26, 0x9c, 0x20, 0xd0, 0x1c, 0xb0, + 0x6c, 0x57, 0x24, 0xc7, 0xa9, 0x5d, 0xea, 0x8e, 0xd1, 0xeb, 0x56, 0xfc, 0x10, 0x4d, 0xbd, 0xa4, + 0xe4, 0xa0, 0xac, 0xe2, 0xcc, 0x79, 0xb0, 0x7f, 0xae, 0x41, 0xcf, 0x9a, 0x1e, 0x61, 0x81, 0xfc, + 0x99, 0x23, 0x32, 0x8e, 0xb2, 0x39, 0xd5, 0x34, 0xae, 0xec, 0x1e, 0xe4, 0xe0, 0xd5, 0xb6, 0x00, + 0x00, 0xa5, 0x9f, 0x96, 0xcd, 0x72, 0xe7, 0x6b, 0xbd, 0x30, 0xbc, 0x87, 0x98, 0xed, 0xa5, 0x60, + 0x96, 0x46, 0x0e, 0xdb, 0xda, 0x89, 0x3e, 0x73, 0xed, 0xb8, 0x31, 0x33, 0x96, 0xfc, 0x5f, 0xe5, + 0x7f, 0xe9, 0xad, 0x25, 0x07, 0x2c, 0xec, 0x4c, 0xc4, 0x0f, 0x9c, 0x76, 0xe8, 0xaf, 0x0b, 0x62, + 0x23, 0xd7, 0xb2, 0x23, 0xaf, 0x62, 0x5c, 0xb4, 0xdd, 0x13, 0x51, 0x25, 0x86, 0x0c, 0xec, 0x91, + 0x22, 0x56, 0xaf, 0x7b, 0xe0, 0x30, 0x4c, 0x66, 0x14, 0x01, 0xfa, 0x42, 0x04, 0x4b, 0x91, 0xf9, + 0x65, 0xf4, 0x63, 0xd8, 0x58, 0xfb, 0xbb, 0xbe, 0x96, 0xe2, 0xdc, 0x0a, 0x9e, 0x43, 0xba, 0xd2, + 0xe4, 0xa9, 0x23, 0x01, 0xe7, 0x33, 0xb1, 0xe4, 0x78, 0x44, 0xa5, 0x6e, 0xb2, 0x39, 0xc6, 0x34, + 0x69, 0xd5, 0x7e, 0xef, 0x47, 0x1d, 0x1a, 0x06, 0x63, 0xd2, 0xd7, 0x56, 0x12, 0x77, 0x40, 0x88, + 0x00, 0xfd, 0x53, 0xa5, 0x52, 0x98, 0xd9, 0xf7, 0xd4, 0x97, 0xa1, 0x06, 0x7e, 0xc6, 0x9d, 0x5f, + 0x2c, 0x45, 0x27, 0x10, 0xee, 0x32, 0x36, 0xeb, 0x5e, 0x8a, 0x42, 0x23, 0x8b, 0x9c, 0x4b, 0x5d, + 0x14, 0x0a, 0x16, 0x2c, 0xfa, 0x6d, 0x9a, 0x64, 0xe8, 0xc2, 0xeb, 0x23, 0x51, 0x74, 0xe2, 0xbe, + 0x86, 0x3e, 0x9e, 0x4e, 0x3d, 0xf4, 0x10, 0xea, 0xb8, 0xc8, 0x0f, 0x35, 0xee, 0xba, 0x1f, 0x85, + 0xed, 0x2b, 0x5c, 0xe0, 0x65, 0xfc, 0x7f, 0xe3, 0xb5, 0x4c, 0xa2, 0x16, 0x68, 0xfc, 0xf0, 0x41, + 0x22, 0x2a, 0xea, 0x8e, 0x3f, 0xb2, 0x73, 0x66, 0x9e, 0xfe, 0x60, 0x66, 0x29, 0x86, 0x81, 0xf8, + 0x99, 0x23, 0x32, 0x8e, 0xb2, 0x39, 0xb6, 0x3c, 0x66, 0x3c, 0x02, 0x2d, 0xef, 0xe3, 0x94, 0xd8, + 0x80, 0x92, 0x4a, 0x95, 0x73, 0x76, 0x38, 0xc1, 0x72, 0x0b, 0xdd, 0xdd, 0x56, 0x98, 0x8c, 0xc6, + 0x13, 0x03, 0xdd, 0x3a, 0xd6, 0x0f, 0x63, 0xbb, 0xde, 0x18, 0x3a, 0x07, 0x21, 0xf8, 0x9d, 0xe8, + 0xb6, 0xca, 0x75, 0x31, 0x2e, 0x28, 0x6b, 0x1b, 0xd9, 0x19, 0x49, 0xe6, 0xf0, 0x1c, 0x54, 0xa8, + 0x10, 0xeb, 0xc2, 0x27, 0x50, 0x22, 0x03, 0x7a, 0x64, 0xbd, 0xf9, 0x0e, 0xdf, 0x80, 0xec, 0xd4, + 0xa3, 0xac, 0x4c, 0x0f, 0xb6, 0xc0, 0xe4, 0xb0, 0x8b, 0x74, 0x6c, 0xf0, 0x14, 0x5a, 0xa7, 0x55, + 0xb6, 0x2e, 0xdd, 0xdb, 0x0e, 0x29, 0xed, 0x6f, 0x93, 0x9c, 0x51, 0x14, 0x41, 0x34, 0xa8, 0x4f, + 0x62, 0x0e, 0x31, 0xb1, 0x71, 0x64, 0x87, 0xf0, 0x99, 0x23, 0x32, 0x8e, 0xb2, 0x39, 0xa5, 0xfc, + 0xb0, 0xdc, 0x62, 0x57, 0xd3, 0x36, 0xf2, 0xac, 0x75, 0xf7, 0xe4, 0x7e, 0xad, 0xe3, 0x52, 0x9d, + 0x36, 0x68, 0xd7, 0xde, 0xa5, 0xd5, 0x2e, 0xbd, 0x2a, 0x54, 0x3c, 0xe7, 0x64, 0xec, 0x4f, 0xb8, + 0x89, 0xba, 0x8e, 0xf0, 0x3d, 0x8f, 0x1c, 0xc5, 0x36, 0xec, 0x31, 0x31, 0x1c, 0x18, 0x72, 0x55, + 0xb0, 0x48, 0x18, 0x4a, 0xef, 0xb9, 0xe6, 0xc9, 0xdc, 0xe9, 0x60, 0x61, 0x64, 0x90, 0x85, 0x22, + 0x55, 0x9f, 0x06, 0x3c, 0xd1, 0xde, 0x8f, 0x2a, 0xa2, 0xbf, 0x80, 0x84, 0x58, 0x33, 0x0f, 0x28, + 0x57, 0x88, 0x40, 0x90, 0x88, 0x22, 0xf2, 0xf8, 0xfc, 0x27, 0x10, 0x78, 0x52, 0x79, 0xb5, 0x27, + 0x9a, 0x79, 0xcb, 0x0e, 0x23, 0xfe, 0x8f, 0x80, 0x53, 0x20, 0x61, 0xf3, 0xc1, 0x9d, 0xfe, 0x07, + 0x99, 0x23, 0x32, 0x8e, 0xb2, 0x39, 0xd6, 0x2c, 0x69, 0xd4, 0x6a, 0x42, 0x75, 0xb2, 0x56, 0x45, + 0xdb, 0x97, 0x98, 0x7c, 0xf8, 0x26, 0x81, 0xdd, 0x03, 0x6f, 0xd2, 0x5b, 0x85, 0x92, 0xb5, 0x9c, + 0x5b, 0x60, 0x4d, 0xaf, 0x25, 0x78, 0xce, 0xfd, 0x38, 0xc0, 0xd1, 0xf1, 0x1e, 0x99, 0xa7, 0xb2, + 0xf1, 0xae, 0x19, 0x59, 0x9a, 0xba, 0x97, 0x57, 0xcf, 0x6b, 0xee, 0x95, 0xdf, 0xa5, 0x95, 0xc3, + 0xa3, 0xa5, 0x93, 0xc3, 0x19, 0xd3, 0x48, 0x1a, 0x2a, 0x82, 0xe7, 0x5e, 0xdd, 0xff, 0x66, 0xd6, + 0xc1, 0xae, 0xa2, 0xcf, 0xff, 0x86, 0x08, 0x85, 0x94, 0x41, 0xc5, 0x17, 0xf6, 0xfa, 0x02, 0x3b, + 0x16, 0xe1, 0xa5, 0x38, 0x0d, 0x9c, 0x86, 0xef, 0x05, 0x9b, 0x96, 0x9c, 0x24, 0x07, 0x9c, 0xff, + 0x82, 0xf7, 0x07, 0x13, 0x38, 0xec, 0xf2, 0xda, 0x99, 0x23, 0x32, 0x8e, 0xb2, 0x39, 0xa5, 0xe4, + 0x69, 0xd4, 0x53, 0xbf, 0x32, 0xf9, 0xec, 0x78, 0xf3, 0x36, 0xd1, 0xaa, 0xac, 0x07, 0x21, 0xd3, + 0x6c, 0x15, 0x8f, 0xbc, 0x88, 0xa1, 0x7e, 0x52, 0xef, 0xd6, 0xf4, 0x15, 0xf5, 0x35, 0x93, 0xb7, + 0xd8, 0x36, 0x6f, 0xa5, 0xbe, 0xe0, 0x06, 0xf8, 0x9d, 0x49, 0x5a, 0x27, 0x40, 0x03, 0x09, 0xdf, + 0x34, 0x47, 0x3d, 0x32, 0xab, 0x10, 0x19, 0x0c, 0x43, 0x54, 0x2e, 0xda, 0xe5, 0x7b, 0xcd, 0x02, + 0xb8, 0x46, 0x14, 0x10, 0x05, 0xc7, 0x6b, 0xac, 0x48, 0x9d, 0x1c, 0x1f, 0xc4, 0x49, 0x78, 0x0c, + 0x63, 0xbf, 0x0a, 0x4e, 0xcf, 0x04, 0x3c, 0x65, 0x64, 0x7a, 0x89, 0xe6, 0xd3, 0x77, 0xd6, 0x1f, + 0xcf, 0x43, 0x9c, 0xe5, 0x75, 0xde, 0x16, 0x71, 0x37, 0x61, 0x4c, 0xf6, 0x87, 0x2b, 0xfc, 0x07, + 0x99, 0x23, 0x32, 0x8e, 0xb2, 0x39, 0xd6, 0x2c, 0xaf, 0xdd, 0x8e, 0xee, 0x15, 0xf5, 0x46, 0xb7, + 0xde, 0xd7, 0xa3, 0x50, 0xac, 0x8e, 0xc2, 0x34, 0x02, 0xd2, 0x2a, 0xdd, 0xff, 0xdc, 0xf0, 0xba, + 0x8a, 0x5a, 0x96, 0x77, 0xca, 0x80, 0xa6, 0x60, 0x0a, 0x2a, 0x5b, 0x73, 0x5d, 0x0e, 0xeb, 0x52, + 0x76, 0x6b, 0x67, 0x3b, 0x59, 0x81, 0xc9, 0xfa, 0x8d, 0x82, 0x01, 0x76, 0x2c, 0x29, 0x9a, 0xa6, + 0xbf, 0xd2, 0x9a, 0x8a, 0x0b, 0x0d, 0xfb, 0x29, 0xb9, 0x7b, 0x37, 0x42, 0xa6, 0xe0, 0xbc, 0x13, + 0x45, 0x57, 0x37, 0x60, 0x3f, 0xe0, 0xeb, 0xb5, 0xbf, 0x39, 0x9f, 0x1d, 0xdc, 0x4c, 0xee, 0xea, + 0xb4, 0xb5, 0x1f, 0x80, 0xe6, 0x12, 0xf0, 0x85, 0x54, 0x3d, 0x58, 0x8b, 0x21, 0x8a, 0x8e, 0xdb, + 0xab, 0xf3, 0xf8, 0x26, 0x63, 0x19, 0x61, 0xf8, 0x99, 0x23, 0x32, 0x8e, 0xb2, 0x39, 0xb6, 0x34, + 0xaf, 0xdd, 0x5d, 0x70, 0x77, 0xc6, 0x5b, 0x81, 0x61, 0x35, 0x4d, 0x00, 0x3e, 0x7e, 0x5e, 0x7e, + 0xe4, 0x20, 0x03, 0xc2, 0x6e, 0x06, 0xd4, 0x13, 0x02, 0x05, 0xc9, 0x34, 0xcd, 0x9a, 0x72, 0xaa, + 0x2c, 0x54, 0x83, 0xdc, 0x30, 0x1b, 0xc1, 0xa6, 0x5e, 0xd7, 0x94, 0xae, 0x1a, 0x55, 0xba, 0x28, + 0xa3, 0x28, 0xde, 0xb6, 0x34, 0xa6, 0x34, 0xbb, 0xd1, 0xa1, 0xd2, 0x0d, 0x5f, 0xcd, 0xe2, 0xe8, + 0x5b, 0xb3, 0xe7, 0x07, 0x0b, 0xbf, 0x07, 0xd9, 0x03, 0x10, 0x6b, 0xde, 0x07, 0xbb, 0xc2, 0x30, + 0x5b, 0x34, 0x7f, 0xd6, 0xbe, 0x0e, 0x2f, 0xe9, 0x33, 0xbe, 0x7c, 0x86, 0x1f, 0x5f, 0xae, 0x34, + 0xe0, 0xad, 0x7e, 0xa2, 0x02, 0x7e, 0x10, 0x2f, 0x91, 0x19, 0x94, 0xc3, 0x3c, 0xe6, 0x0f, 0x1e, + 0x99, 0x23, 0x32, 0x8e, 0xb2, 0x39, 0xa5, 0xfc, 0xaf, 0xdd, 0x5d, 0x72, 0x40, 0x99, 0x6f, 0xc2, + 0x1b, 0xde, 0x55, 0x98, 0xc8, 0xd0, 0x3c, 0x25, 0xd4, 0xe3, 0x93, 0x2c, 0x6e, 0x62, 0xaf, 0xb2, + 0xdb, 0xab, 0xd4, 0xaf, 0x14, 0x09, 0x1e, 0x1a, 0xde, 0x12, 0xba, 0xc8, 0x63, 0x9d, 0xa2, 0x67, + 0x75, 0xd8, 0x3e, 0xe6, 0xe2, 0x8c, 0xf7, 0xd2, 0xcd, 0x83, 0x33, 0x09, 0x95, 0xea, 0x42, 0x51, + 0x17, 0xad, 0x45, 0xbe, 0x80, 0xd2, 0x64, 0x18, 0x00, 0x7f, 0x59, 0x56, 0xd6, 0xb8, 0x0d, 0x43, + 0x0a, 0x8e, 0xad, 0xa4, 0x7f, 0x11, 0xc7, 0x8b, 0x90, 0x83, 0x43, 0xed, 0xf1, 0x88, 0x74, 0xd1, + 0x1d, 0x0d, 0x3c, 0xeb, 0xfb, 0x10, 0x0c, 0xed, 0xa0, 0xa5, 0x98, 0xec, 0xa7, 0xdd, 0xab, 0x5c, + 0xd4, 0x63, 0xa2, 0x19, 0x09, 0x4e, 0x7f, 0x03, 0x99, 0x23, 0x32, 0x8e, 0xb2, 0x39, 0xc6, 0x3c, + 0x69, 0x22, 0xe8, 0x73, 0x20, 0x58, 0x38, 0x1d, 0xfd, 0x9e, 0xa2, 0xb7, 0x7b, 0x72, 0x36, 0xfa, + 0x26, 0x3e, 0xc4, 0x03, 0xe2, 0x8f, 0x86, 0x5b, 0xdf, 0xa9, 0x39, 0xcb, 0xac, 0xd4, 0x2e, 0xbd, + 0xeb, 0x4b, 0x27, 0x06, 0xf9, 0xff, 0x26, 0x50, 0xe8, 0x4e, 0xeb, 0xae, 0x9f, 0x93, 0x95, 0xf2, + 0x68, 0xb7, 0xba, 0x84, 0x0d, 0x9c, 0xbe, 0x08, 0x7a, 0x70, 0x62, 0x51, 0x22, 0x27, 0x43, 0x23, + 0xd7, 0x8b, 0x2a, 0x7c, 0xac, 0xe0, 0xa4, 0x6e, 0x1f, 0xde, 0x6b, 0x65, 0x8c, 0x7f, 0xfd, 0x87, + 0x36, 0x40, 0xa8, 0xd5, 0xbb, 0x86, 0xed, 0xf3, 0xd8, 0x0c, 0x1d, 0x0b, 0x8b, 0x5a, 0x80, 0xd4, + 0xca, 0xcb, 0x72, 0x52, 0x95, 0xa7, 0xea, 0xa9, 0xe4, 0xec, 0xed, 0x06, 0xd8, 0xcc, 0x3e, 0x07, + 0x79, 0x23, 0x32, 0x8e, 0xb2, 0x39, 0xb6, 0x2c, 0xb0, 0xd2, 0xdb, 0xe7, 0x6a, 0xb8, 0xa5, 0x31, + 0x37, 0xee, 0x2f, 0x89, 0x78, 0x18, 0xf9, 0x03, 0xd4, 0xab, 0xfb, 0x14, 0x26, 0xf8, 0xe2, 0x1c, + 0x20, 0x4c, 0x35, 0xe8, 0x8c, 0x56, 0x17, 0xaa, 0xb4, 0x68, 0xda, 0xb9, 0x19, 0x39, 0xd2, 0x13, + 0x8d, 0xa6, 0x21, 0xc4, 0xec, 0xd6, 0xcb, 0xa1, 0xb6, 0xc2, 0x06, 0xc1, 0x96, 0xed, 0x18, 0x46, + 0x09, 0x1e, 0x39, 0x1c, 0xeb, 0x36, 0xa1, 0x99, 0x8a, 0xfd, 0x14, 0x33, 0x80, 0x35, 0x31, 0xf1, + 0x24, 0x85, 0x80, 0x1f, 0x90, 0x84, 0x82, 0xa9, 0x32, 0xc3, 0x01, 0xc1, 0xda, 0x1d, 0x43, 0x8f, + 0xed, 0x8b, 0x3e, 0xe9, 0x57, 0xd8, 0x56, 0x0c, 0xc6, 0x77, 0x7d, 0x4b, 0xd0, 0x83, 0x14, 0xf4, + 0x5a, 0x4a, 0x21, 0x05, 0x86, 0x41, 0xa7, 0xc1, 0x99, 0x23, 0x32, 0x8e, 0xb2, 0x39, 0xc5, 0xfc, + 0xae, 0xed, 0x1b, 0x9f, 0x80, 0x9b, 0x46, 0xc9, 0xee, 0xe6, 0xaa, 0x41, 0xa7, 0x40, 0x48, 0xa1, + 0x08, 0x99, 0x82, 0x48, 0x0a, 0xc8, 0x52, 0x66, 0x58, 0x96, 0x70, 0x6e, 0x50, 0xe3, 0x43, 0xa5, + 0x74, 0x31, 0xc7, 0x0c, 0x15, 0x94, 0x74, 0x02, 0xd2, 0x96, 0x3a, 0x15, 0x4a, 0xd3, 0x28, 0x07, + 0x6a, 0x8d, 0x97, 0x21, 0x33, 0xbf, 0xe8, 0x80, 0xaf, 0xec, 0x35, 0xb4, 0x2b, 0xba, 0xad, 0xec, + 0xc8, 0xe4, 0x80, 0x3e, 0x90, 0x19, 0x02, 0x5d, 0x48, 0x47, 0x90, 0xf3, 0xbe, 0x0f, 0x7f, 0xde, + 0x13, 0xbd, 0x72, 0x97, 0xf0, 0x87, 0xbc, 0x4f, 0x1d, 0x7a, 0xa8, 0xd2, 0x06, 0x19, 0xbb, 0xe4, + 0xbe, 0x5d, 0x4d, 0x24, 0x54, 0xaa, 0xa1, 0x4b, 0x27, 0x2f, 0x1b, 0x4b, 0x7c, 0x26, 0x59, 0x58, + 0x99, 0x23, 0x32, 0x8e, 0xb2, 0x39, 0xc6, 0x34, 0xaf, 0xdd, 0x5d, 0x57, 0xcc, 0xa3, 0x86, 0x1d, + 0x6d, 0xdd, 0x40, 0xe6, 0x3a, 0x6c, 0xca, 0x2d, 0xb9, 0xbd, 0xaf, 0xf4, 0x89, 0x12, 0x83, 0x82, + 0xcd, 0x72, 0x04, 0x91, 0xdd, 0xe4, 0x9c, 0xdd, 0x5f, 0x2d, 0x77, 0xf9, 0x7c, 0xa7, 0x5c, 0x9a, + 0xf4, 0x20, 0x33, 0x6b, 0x59, 0x3d, 0xe1, 0xb7, 0x91, 0xa1, 0xac, 0xc3, 0xad, 0x4c, 0xea, 0xec, + 0x6a, 0x06, 0xe4, 0xfa, 0xf2, 0x9a, 0x33, 0xea, 0x18, 0x12, 0xa0, 0xdc, 0xfc, 0x37, 0xd9, 0x4c, + 0xaa, 0x11, 0xe7, 0x03, 0x39, 0x72, 0xbf, 0x1c, 0xca, 0xd3, 0x5f, 0x1b, 0x02, 0xff, 0xa7, 0x67, + 0x7c, 0x14, 0x4f, 0xed, 0x54, 0x77, 0x73, 0x2c, 0x48, 0x48, 0x0f, 0xa6, 0x47, 0x87, 0x08, 0x1f, + 0x41, 0xb2, 0x4f, 0xfc, 0x39, 0x0f, 0x77, 0xc1, 0x99, 0x23, 0x32, 0x8e, 0xb2, 0x39, 0xa6, 0x3c, + 0x69, 0xd4, 0x6a, 0x42, 0x63, 0xb5, 0x97, 0x25, 0xe0, 0xa6, 0x00, 0x93, 0xdc, 0x9c, 0x68, 0xb5, + 0x58, 0x2e, 0x3c, 0x24, 0x05, 0xf7, 0xa7, 0x33, 0xc6, 0x48, 0x94, 0x63, 0xdd, 0x8e, 0xd1, 0xe2, + 0x14, 0x7e, 0x33, 0xfc, 0xec, 0x43, 0x1b, 0x78, 0x02, 0x1b, 0x5a, 0x78, 0xae, 0x2e, 0x2d, 0x95, + 0x7f, 0x41, 0x2f, 0x90, 0x46, 0x57, 0xc0, 0xf0, 0xd3, 0xde, 0x1d, 0xa9, 0x86, 0x4d, 0x5d, 0x76, + 0x58, 0x44, 0x76, 0x1f, 0x47, 0x26, 0x38, 0xf8, 0xc4, 0x9a, 0x02, 0xb7, 0x1c, 0xfc, 0x39, 0xe6, + 0x72, 0x94, 0x78, 0x70, 0x2e, 0x51, 0xfc, 0xf4, 0xba, 0x5c, 0x17, 0xcf, 0x14, 0xc0, 0x2d, 0x7b, + 0xb6, 0x5c, 0x49, 0x72, 0x92, 0xdc, 0x83, 0xa7, 0x90, 0x3b, 0x96, 0xc9, 0x07, 0x8e, 0x7c, 0x63, + 0x99, 0x23, 0x32, 0x8e, 0xb2, 0x39, 0xa6, 0x34, 0xaf, 0xdd, 0x72, 0x00, 0xd7, 0xcf, 0x22, 0x79, + 0xce, 0xce, 0x21, 0xcf, 0x85, 0xd9, 0x2a, 0xd8, 0xd4, 0x1d, 0x00, 0x49, 0xae, 0x4e, 0x01, 0x08, + 0xf8, 0x7e, 0xc2, 0x91, 0x69, 0x68, 0x1d, 0x04, 0xf9, 0x06, 0x30, 0xf3, 0x15, 0x53, 0xd6, 0x08, + 0xf3, 0x0f, 0x96, 0xac, 0x17, 0x9d, 0x42, 0xc5, 0xdb, 0xa2, 0x15, 0xbb, 0x2e, 0xd1, 0x6e, 0x9e, + 0xed, 0x97, 0xd1, 0xb0, 0x2e, 0x89, 0xa8, 0x8e, 0x89, 0x27, 0x2c, 0xfd, 0x9a, 0x22, 0x84, 0x21, + 0x91, 0x6b, 0x64, 0x96, 0x00, 0xfe, 0x5d, 0x07, 0x0b, 0xa2, 0x7e, 0xab, 0xd0, 0xee, 0xeb, 0xb7, + 0x8e, 0xbb, 0x85, 0x78, 0x9f, 0xa0, 0x5e, 0x6c, 0x62, 0x47, 0x5d, 0xe1, 0x65, 0x0e, 0x0e, 0xc7, + 0x1d, 0x00, 0x75, 0x9b, 0x4a, 0x42, 0x5f, 0x01, 0x99, 0x23, 0x32, 0x8e, 0xb2, 0x39, 0xc5, 0xbc, + 0xb0, 0xdc, 0x62, 0x56, 0xd4, 0x50, 0x19, 0x30, 0x62, 0x00, 0x93, 0x48, 0x23, 0xd8, 0x8a, 0x44, + 0xe5, 0xdb, 0x09, 0x9c, 0x08, 0x8d, 0x74, 0xbf, 0x33, 0x1a, 0x33, 0x3e, 0xe3, 0xc0, 0x4c, 0x79, + 0x28, 0x9c, 0x4a, 0x19, 0x27, 0x97, 0x7f, 0x42, 0x74, 0x3f, 0xa5, 0x7c, 0xe0, 0x3e, 0xf4, 0x39, + 0x22, 0xa0, 0x05, 0x2e, 0x0a, 0x83, 0xa0, 0x55, 0x47, 0xc2, 0xed, 0xb1, 0x14, 0x20, 0x5f, 0xff, + 0x7a, 0x32, 0x19, 0x50, 0xdb, 0x16, 0x80, 0x7d, 0x1f, 0x6a, 0x9b, 0xc2, 0x8e, 0xfc, 0x70, 0x40, + 0x1a, 0x91, 0xb0, 0x87, 0xad, 0x8b, 0xb7, 0x8e, 0x44, 0xad, 0x0d, 0x70, 0x7b, 0x7a, 0x40, 0xae, + 0x15, 0x3f, 0x73, 0x02, 0xe0, 0xbe, 0x9f, 0xcf, 0x6d, 0xbf, 0x4a, 0x3a, 0x0c, 0x92, 0x76, 0x1e, + 0x99, 0x23, 0x32, 0x8e, 0xb2, 0x39, 0xb6, 0x3c, 0x69, 0xd4, 0x53, 0xbd, 0x32, 0xc2, 0x82, 0x19, + 0xbf, 0x3c, 0x5c, 0x7a, 0xac, 0x01, 0xfc, 0x94, 0x76, 0xf9, 0x6b, 0x28, 0x39, 0x72, 0xce, 0x1c, + 0x1a, 0x3a, 0x81, 0x04, 0xc8, 0x07, 0x55, 0xca, 0x05, 0x2c, 0x0b, 0xb8, 0x64, 0x65, 0xf5, 0x38, + 0xa7, 0x01, 0x29, 0xd5, 0x6a, 0x00, 0xef, 0x4a, 0xcf, 0x97, 0x8c, 0x1b, 0xd5, 0x27, 0x32, 0x9a, + 0xf3, 0x93, 0x58, 0x30, 0x5c, 0x7e, 0xfb, 0xed, 0x58, 0x6e, 0x8a, 0x96, 0xd0, 0xc6, 0x72, 0x01, + 0xc3, 0x8a, 0x5a, 0x69, 0x19, 0x01, 0xe5, 0xa7, 0xfc, 0x1e, 0x78, 0x3f, 0x98, 0xec, 0xae, 0xe3, + 0x9a, 0x88, 0x1a, 0xea, 0x9e, 0xda, 0x15, 0xf6, 0x85, 0x6c, 0x04, 0x94, 0x57, 0x8e, 0xd7, 0x3f, + 0xca, 0x5c, 0x39, 0xde, 0xe0, 0x63, 0xbc, 0x07, 0x99, 0x23, 0x32, 0x8e, 0xb2, 0x39, 0xc6, 0x2c, + 0x69, 0xd4, 0x8a, 0x58, 0x8e, 0xc0, 0x35, 0x85, 0x61, 0x67, 0xd5, 0x84, 0x18, 0x61, 0xee, 0xc4, + 0xc5, 0x01, 0xe4, 0xca, 0xbb, 0xea, 0xa2, 0x35, 0x61, 0xbb, 0x6b, 0x86, 0x9c, 0x9f, 0xba, 0x0f, + 0x85, 0x76, 0xe5, 0x87, 0x82, 0x79, 0xf5, 0x53, 0x72, 0x58, 0x77, 0x5c, 0xb9, 0x81, 0x0a, 0xe3, + 0xbe, 0xae, 0xd5, 0x6b, 0xe8, 0x4d, 0xdb, 0x08, 0xf6, 0x94, 0xed, 0x5a, 0xe9, 0x55, 0x2d, 0x0f, + 0x54, 0xcd, 0x6f, 0x9f, 0xaa, 0x98, 0x47, 0x84, 0xfb, 0xb8, 0xd9, 0x99, 0x08, 0x0f, 0xe1, 0x1f, + 0x35, 0xad, 0xf7, 0x64, 0x04, 0xf2, 0xb6, 0x5d, 0x90, 0x62, 0x6f, 0xee, 0x7e, 0x62, 0x89, 0xfc, + 0x4e, 0xef, 0x82, 0x8f, 0x03, 0x5a, 0x58, 0x28, 0x22, 0x0d, 0xa3, 0xcc, 0x23, 0xc6, 0x3c, 0x0f, + 0x99, 0x23, 0x32, 0x8e, 0xb2, 0x39, 0xc5, 0xd4, 0x69, 0xd4, 0x53, 0x87, 0x0f, 0xf2, 0x3d, 0xef, + 0xd0, 0x40, 0x99, 0x3c, 0xe2, 0xcc, 0x21, 0x07, 0x34, 0x09, 0x82, 0x32, 0x55, 0x25, 0xd8, 0xe5, + 0xc8, 0xc4, 0x4f, 0x97, 0x27, 0xd0, 0x14, 0x1c, 0x54, 0x88, 0x92, 0xa1, 0x2c, 0xc6, 0xd6, 0xf3, + 0xe3, 0x18, 0x39, 0xa8, 0x79, 0x9f, 0x85, 0x36, 0xb1, 0xa2, 0x66, 0xf2, 0x35, 0xf0, 0xb1, 0x05, + 0x4e, 0xcf, 0x61, 0x4f, 0x7f, 0x77, 0xe8, 0xf5, 0x74, 0xd9, 0x1f, 0x75, 0x7e, 0x12, 0x8e, 0xf7, + 0xd5, 0x65, 0x34, 0xd4, 0x7e, 0x27, 0xbc, 0x6f, 0xe2, 0xb2, 0xf5, 0x2a, 0x7c, 0x36, 0xb0, 0x46, + 0x74, 0x8d, 0x03, 0x3e, 0x50, 0x6b, 0x2e, 0xed, 0xa6, 0xa6, 0x90, 0xee, 0x6b, 0xac, 0xe1, 0x30, + 0x72, 0x6b, 0xff, 0x04, 0xda, 0x9e, 0x38, 0x3e, 0x99, 0x23, 0x32, 0x8e, 0xb2, 0x39, 0xa6, 0x3c, + 0xb0, 0xdc, 0x62, 0x6f, 0xa5, 0x3a, 0x56, 0xe6, 0x06, 0xa8, 0x75, 0x42, 0x00, 0x27, 0x19, 0xf9, + 0xb6, 0xf4, 0x19, 0x6e, 0xb3, 0x73, 0x5b, 0x69, 0x18, 0xc3, 0x23, 0x2d, 0x6c, 0xf2, 0x40, 0x80, + 0xef, 0x26, 0xe6, 0x53, 0xfd, 0xce, 0xbb, 0x47, 0xe5, 0xda, 0x38, 0x82, 0xc0, 0x19, 0x69, 0x0b, + 0xa2, 0xcc, 0x9a, 0x6a, 0x38, 0xb9, 0x18, 0xab, 0x9b, 0xd9, 0x5e, 0x19, 0xec, 0x35, 0x01, 0x9c, + 0x4b, 0x55, 0x2d, 0xec, 0xaa, 0x84, 0x98, 0x2a, 0xe6, 0xb8, 0x03, 0x8e, 0xd9, 0xe5, 0x1b, 0x92, + 0xec, 0x43, 0xf6, 0x50, 0xbf, 0x7f, 0xe9, 0xee, 0x9b, 0x0a, 0x36, 0x68, 0xd4, 0xda, 0xd4, 0x69, + 0x22, 0x56, 0xdb, 0x6c, 0xd7, 0x09, 0x85, 0x10, 0x01, 0xaf, 0xf0, 0x63, 0xc3, 0xe1, 0x9f, 0x07, + 0x9b, 0xc5, 0x37, 0xee, 0xb2, 0x39, 0xc5, 0xe4, 0x00, 0xc0, 0x5f, 0xba, 0x85, 0x0b, 0x4f, 0x32, + 0x77, 0xe0, 0x1b, 0xc9, 0xdf, 0x64, 0x30, 0x0c, 0x39, 0x0f, 0xdd, 0xce, 0x93, 0xfc, 0x85, 0xb9, + 0x62, 0xc4, 0x1b, 0x32, 0x49, 0x0e, 0x04, 0x6d, 0x42, 0x78, 0xfb, 0x7a, 0x3d, 0x7b, 0x26, 0x17, + 0x12, 0xab, 0x24, 0x49, 0x7f, 0xbd, 0xf5, 0x32, 0xa2, 0x24, 0xd7, 0x1e, 0x6f, 0xe0, 0xc2, 0xda, + 0x85, 0xdc, 0x78, 0x1a, 0xf2, 0x76, 0xea, 0x90, 0xa1, 0x32, 0x6d, 0x72, 0x10, 0x2b, 0x20, 0x6c, + 0x1b, 0x91, 0xcf, 0x38, 0x3e, 0x0f, 0x87, 0x86, 0x67, 0xb1, 0xc2, 0xe8, 0xb6, 0x78, 0xe8, 0x36, + 0x1a, 0x2e, 0xa3, 0xb9, 0xdb, 0xe9, 0x02, 0xee, 0x8d, 0xaa, 0xa1, 0x72, 0xbc, 0xb1, 0x32, 0x03, + 0xe0, 0x7e, 0x07, 0xf0, 0x3f, 0x01, 0xe5, 0x83, 0x3d, 0xe2, 0x9b, 0xf7, 0x59, 0x0a, 0x25, 0xca, + 0x37, 0xc7, 0xc2, 0xa2, 0x56, 0x44, 0xb6, 0x00, 0x00, 0x1a, 0x32, 0xe9, 0xbc, 0x47, 0xbe, 0x1c, + 0x9f, 0x82, 0xf7, 0xda, 0xa5, 0x58, 0xa9, 0x04, 0x3c, 0x68, 0xed, 0x36, 0x07, 0x81, 0xe4, 0xc1, + 0x33, 0xbe, 0x92, 0x8b, 0x82, 0xe2, 0x48, 0xc7, 0x44, 0xf2, 0x0f, 0x25, 0xb1, 0x2d, 0xde, 0xbe, + 0xc1, 0x73, 0x0c, 0xb4, 0x8e, 0xe3, 0xcc, 0x70, 0x91, 0xfc, 0xc6, 0x35, 0x94, 0xb3, 0x5c, 0x4b, + 0xd3, 0x99, 0x5b, 0x44, 0xed, 0xf2, 0x94, 0x7f, 0x7c, 0x58, 0x63, 0x1b, 0x93, 0x9e, 0x3c, 0x38, + 0xf8, 0x16, 0x70, 0x29, 0xab, 0xba, 0xfb, 0x2d, 0x5b, 0xa8, 0x10, 0x62, 0xe9, 0xe6, 0x8c, 0xe2, + 0xc0, 0xe8, 0x56, 0xb0, 0x13, 0xc7, 0x73, 0x38, 0x20, 0xf0, 0xd3, 0x67, 0x1c, 0xf0, 0xf8, 0x43, + 0xcd, 0xe2, 0x9b, 0xf7, 0x59, 0x1a, 0x06, 0x32, 0x37, 0xca, 0x74, 0x3f, 0xcb, 0x5e, 0xc6, 0xaa, + 0x00, 0x01, 0xa0, 0xea, 0xed, 0x68, 0x7c, 0x8c, 0x51, 0x4d, 0x94, 0x12, 0x69, 0x2c, 0x00, 0x69, + 0x75, 0xcf, 0x95, 0x54, 0xb5, 0x2d, 0x63, 0x60, 0x5e, 0x9b, 0xbc, 0x51, 0xc0, 0x07, 0xba, 0x61, + 0x87, 0x08, 0xba, 0xe6, 0xfd, 0x98, 0xf2, 0x06, 0x80, 0x0d, 0x20, 0x7c, 0x48, 0x23, 0x3a, 0xb9, + 0x74, 0x59, 0x6f, 0xec, 0x9d, 0x2f, 0xb1, 0x4a, 0xd4, 0xb3, 0x4e, 0xfc, 0x7a, 0x33, 0xb0, 0x9a, + 0x0b, 0xa4, 0xce, 0x61, 0x8c, 0xf1, 0x83, 0xc1, 0xe0, 0xa7, 0x06, 0x41, 0x65, 0xb0, 0xee, 0x18, + 0x34, 0x8f, 0x8a, 0x15, 0x42, 0x71, 0x1d, 0xf7, 0x99, 0xe6, 0x2d, 0x7d, 0x86, 0xf9, 0x5e, 0x3a, + 0x64, 0x8a, 0xe6, 0x32, 0x58, 0xc7, 0x11, 0xc3, 0xdd, 0xe2, 0x9b, 0xf7, 0x59, 0x1a, 0x06, 0x32, + 0xaf, 0xdd, 0x47, 0xaf, 0xed, 0xa3, 0xde, 0x00, 0x00, 0x01, 0x43, 0x12, 0x7e, 0x61, 0xbb, 0x2b, + 0x1d, 0x25, 0xb9, 0x7d, 0x8e, 0x56, 0x64, 0x31, 0xdb, 0x3a, 0xf8, 0x23, 0x8b, 0x55, 0x1c, 0xdd, + 0x2d, 0x44, 0x75, 0x2f, 0xc4, 0x86, 0x11, 0x96, 0x4c, 0xf5, 0xc0, 0x8c, 0x1d, 0xc0, 0x70, 0x85, + 0x01, 0x36, 0x29, 0x4b, 0x30, 0xf9, 0x0c, 0x2e, 0x2e, 0xab, 0x75, 0xca, 0x0f, 0xb5, 0x98, 0x2d, + 0x85, 0x23, 0x95, 0x15, 0xd9, 0x3a, 0xd1, 0x47, 0x38, 0xc1, 0xcf, 0x0e, 0x07, 0xc0, 0xf8, 0x1c, + 0x39, 0x7b, 0xbd, 0x31, 0xda, 0xb7, 0x54, 0xc7, 0xce, 0x1a, 0xf3, 0x62, 0x6d, 0xf2, 0x33, 0x4e, + 0x0c, 0x84, 0x04, 0x14, 0xd1, 0x3b, 0x42, 0xb2, 0x11, 0x3a, 0x3a, 0x48, 0x95, 0xc1, 0x29, 0xfe, + 0x5d, 0xd7, 0x8e, 0xf7, 0x59, 0x1a, 0x16, 0x2a, 0x00, 0x00, 0x00, 0x5c, 0x28, 0x11, 0x53, 0x00, + 0x8c, 0xdc, 0x43, 0x04, 0x31, 0x3f, 0x9d, 0x4a, 0x0b, 0xf6, 0x08, 0xd3, 0x72, 0x9c, 0x3f, 0x79, + 0x25, 0x35, 0x5f, 0x40, 0xdb, 0xae, 0x90, 0xbe, 0x35, 0xf4, 0x76, 0xaa, 0x39, 0xba, 0x07, 0x23, + 0xc6, 0x4c, 0x83, 0xbc, 0xee, 0x94, 0x25, 0x80, 0x2a, 0x8d, 0x1a, 0x7f, 0x80, 0xa7, 0x24, 0x50, + 0x17, 0x5b, 0x24, 0x09, 0xe7, 0x28, 0xf6, 0x9b, 0xcd, 0x57, 0x4f, 0x9c, 0x60, 0xef, 0x16, 0xcc, + 0x16, 0x16, 0x7b, 0x34, 0xc8, 0xe1, 0xf0, 0x88, 0x30, 0xb4, 0xb2, 0xcb, 0x30, 0xc9, 0x44, 0x28, + 0xfa, 0xb3, 0xe0, 0x21, 0x20, 0x00, 0xc0, 0x5a, 0xcb, 0x01, 0x0f, 0x06, 0x34, 0x67, 0x8e, 0xf8, + 0x7c, 0x1f, 0x80, 0xfe, 0x07, 0xc0, 0xf8, 0x32, 0xcb, 0x21, 0x8b, 0x97, 0x59, 0x0a, 0x06, 0x3a, + 0xb0, 0xd2, 0xc2, 0xb5, 0xa3, 0xc7, 0x39, 0x0e, 0x03, 0xf4, 0xb2, 0xef, 0x07, 0xda, 0xb6, 0xfd, + 0xfa, 0x68, 0xc1, 0x01, 0xe1, 0x5a, 0x65, 0xe7, 0x5b, 0x3a, 0xf3, 0x1a, 0xe7, 0x68, 0xda, 0xb9, + 0x19, 0x4d, 0xb4, 0xd8, 0x9f, 0x2d, 0x49, 0xba, 0x8c, 0x34, 0x95, 0x40, 0x35, 0x86, 0xfc, 0xd1, + 0x25, 0x6c, 0x90, 0x81, 0xd5, 0x1c, 0xb9, 0xb7, 0xfa, 0x6e, 0x47, 0xd5, 0xbc, 0x83, 0xcf, 0xdb, + 0x58, 0x54, 0x41, 0xf5, 0x28, 0xe2, 0x40, 0x72, 0x7c, 0x19, 0x98, 0x54, 0xe7, 0x07, 0x9c, 0xfe, + 0x10, 0xe5, 0xd3, 0x45, 0xaf, 0x2c, 0x05, 0x07, 0xe7, 0xca, 0x90, 0x28, 0xe4, 0xb0, 0x44, 0x99, + 0x7a, 0x8a, 0xf2, 0x71, 0x8e, 0x64, 0x8a, 0xf4, 0x21, 0xc0, 0x90, 0x53, 0x7e, 0x78, 0x12, 0x1c, + 0x5b, 0x21, 0x8b, 0x97, 0x59, 0x1a, 0x16, 0x2a, 0xaf, 0xde, 0xcb, 0xf9, 0xc9, 0x12, 0x54, 0xc3, + 0xb6, 0xbf, 0xc6, 0xdd, 0x33, 0xef, 0x43, 0xbb, 0x3f, 0x61, 0x00, 0xdf, 0x78, 0x66, 0x7c, 0x52, + 0x78, 0x22, 0x5a, 0x11, 0x2f, 0xa6, 0x2d, 0x29, 0xd3, 0xf5, 0x2b, 0x54, 0x7d, 0x23, 0xc3, 0x14, + 0x17, 0x5c, 0x47, 0x14, 0x3e, 0x40, 0xf9, 0x87, 0x56, 0x0b, 0x97, 0x3a, 0xa9, 0x71, 0x0f, 0x84, + 0xee, 0xa0, 0xa0, 0xc2, 0xc3, 0xf3, 0x10, 0xbc, 0xa1, 0x1b, 0x7b, 0xcd, 0x21, 0x87, 0x66, 0x05, + 0x87, 0x9e, 0x18, 0x7b, 0x33, 0x26, 0x7c, 0xc5, 0x42, 0xe2, 0x04, 0x2c, 0xfc, 0xd2, 0xcc, 0x09, + 0x39, 0xa3, 0x8c, 0x74, 0xda, 0xc6, 0x4b, 0xa6, 0x53, 0xda, 0xc2, 0x51, 0x5f, 0x77, 0x6a, 0x14, + 0x75, 0x95, 0xe7, 0x9c, 0x0a, 0x26, 0x59, 0x81, 0xdb, 0x21, 0x8b, 0x97, 0x59, 0x1a, 0x26, 0x32, + 0xaf, 0xde, 0xcb, 0xf9, 0xd9, 0x8b, 0x32, 0x47, 0x46, 0x01, 0xfe, 0xdc, 0xee, 0xca, 0xbb, 0x21, + 0xe2, 0x27, 0xf6, 0xc0, 0x74, 0x81, 0xd9, 0xaa, 0xab, 0xf8, 0x70, 0x9d, 0x8d, 0x88, 0xd7, 0x08, + 0x4b, 0x17, 0x2f, 0xd9, 0xa6, 0xe0, 0x2f, 0x93, 0x48, 0xf7, 0x33, 0xb2, 0xb3, 0x2d, 0x19, 0x18, + 0x12, 0xfd, 0x31, 0xb8, 0xcc, 0xfe, 0x64, 0x87, 0x69, 0xdc, 0xe4, 0x5c, 0x65, 0xe5, 0x77, 0xb0, + 0x68, 0xb0, 0x06, 0xb4, 0x3b, 0x59, 0x19, 0x83, 0x3c, 0x38, 0x3c, 0x3c, 0x38, 0x78, 0x83, 0x61, + 0xd0, 0x31, 0x81, 0x97, 0x03, 0xb8, 0xef, 0x01, 0x15, 0x40, 0x82, 0xed, 0x8b, 0x08, 0x4f, 0x71, + 0x32, 0xf5, 0xc9, 0x29, 0x1b, 0x2b, 0xac, 0x4c, 0x10, 0x70, 0xa7, 0x97, 0x07, 0x0e, 0x49, 0xe3, + 0xdb, 0x21, 0x4b, 0x97, 0x59, 0x1a, 0x26, 0x12, 0xae, 0xec, 0x11, 0x26, 0xe8, 0x37, 0x92, 0x31, + 0xe5, 0x7f, 0x28, 0xd9, 0x53, 0x25, 0xa2, 0x66, 0x43, 0xcd, 0x52, 0x54, 0x1d, 0x5b, 0xc6, 0x8a, + 0x80, 0xb8, 0x1c, 0x95, 0x07, 0xbc, 0xd0, 0x16, 0xe2, 0x9d, 0x9e, 0x69, 0x70, 0x19, 0xe3, 0x82, + 0x2c, 0xb5, 0x68, 0xe8, 0x7d, 0x89, 0x1a, 0xcd, 0x5a, 0x2e, 0x31, 0x6a, 0x09, 0x5b, 0xb5, 0x65, + 0x8b, 0xd3, 0x84, 0x69, 0xae, 0xaa, 0xd1, 0xbf, 0x98, 0x54, 0x1f, 0xbe, 0x56, 0xfe, 0x6c, 0x38, + 0x47, 0x8f, 0x73, 0x0c, 0xc7, 0xe0, 0x43, 0x58, 0x7e, 0xba, 0xbf, 0x42, 0x48, 0xe0, 0x02, 0xaa, + 0x07, 0x30, 0xfe, 0x2f, 0xcb, 0xc4, 0xd0, 0xd8, 0x90, 0xf7, 0xab, 0x12, 0xee, 0x44, 0x87, 0x70, + 0x74, 0xa0, 0x63, 0xfb, 0xc1, 0xe2, 0x6c, 0x9e, 0x5b, 0x21, 0x8b, 0x97, 0x59, 0x19, 0xf6, 0x2a, + 0xaf, 0xa6, 0xc8, 0x17, 0x83, 0x85, 0xb2, 0x00, 0x04, 0x26, 0x17, 0x1b, 0xb0, 0x82, 0x3d, 0x92, + 0x55, 0x92, 0x2c, 0xcb, 0x67, 0x59, 0x5d, 0xa4, 0x57, 0xb5, 0xf4, 0x0b, 0xcd, 0x2d, 0x28, 0x50, + 0x40, 0x15, 0x90, 0x80, 0x09, 0xb6, 0x09, 0x0b, 0x90, 0x65, 0xdb, 0xc6, 0xf1, 0x86, 0xd9, 0x38, + 0xd8, 0xa2, 0x03, 0x25, 0xc0, 0x97, 0x38, 0x86, 0xfd, 0x86, 0x46, 0x1a, 0xb9, 0xce, 0xa9, 0x5e, + 0xb6, 0xa4, 0x22, 0x2f, 0x9a, 0x86, 0x38, 0xc2, 0x7b, 0x9e, 0x78, 0x3c, 0x1e, 0x1c, 0x1f, 0x07, + 0x1a, 0x08, 0x32, 0x5b, 0x03, 0x89, 0x1d, 0x5b, 0x9f, 0x94, 0x9e, 0x97, 0xde, 0x51, 0xf2, 0x0d, + 0x17, 0xe9, 0x94, 0xa7, 0xfd, 0x5e, 0xea, 0x1d, 0xe2, 0xa8, 0x0b, 0xc0, 0xc2, 0x00, 0xc1, 0xec, + 0x4b, 0x21, 0x4b, 0x97, 0x59, 0x1a, 0x06, 0x1a, 0xaf, 0xde, 0xcb, 0xf9, 0xbd, 0x13, 0x73, 0x0c, + 0x76, 0x0e, 0x78, 0x17, 0x02, 0x17, 0xd2, 0xd1, 0x02, 0xfc, 0x16, 0xa1, 0x3f, 0x01, 0x7d, 0x07, + 0x4a, 0xc9, 0x36, 0x24, 0x45, 0xff, 0xd4, 0x75, 0x8f, 0x51, 0x98, 0xd1, 0x81, 0x98, 0x2a, 0x87, + 0xdc, 0x6f, 0xb8, 0x72, 0xcc, 0x0f, 0x1f, 0xd1, 0x7b, 0x47, 0x57, 0xe5, 0xd0, 0x37, 0xa1, 0x06, + 0x28, 0x7d, 0x54, 0xeb, 0xca, 0x35, 0xc5, 0x77, 0x08, 0x7a, 0x5b, 0x8e, 0x13, 0x60, 0x93, 0x27, + 0x12, 0x38, 0x61, 0xe7, 0x8f, 0xe2, 0x86, 0x8d, 0x73, 0x04, 0x06, 0xf8, 0xb1, 0x98, 0xe6, 0x3a, + 0x4c, 0x2f, 0x31, 0x97, 0x5d, 0x3d, 0xda, 0xb8, 0xc3, 0x38, 0x03, 0xc6, 0xe1, 0x67, 0x68, 0x23, + 0x75, 0x64, 0x4a, 0x24, 0x80, 0x0c, 0x38, 0x26, 0x5b, 0x21, 0x4b, 0x97, 0x59, 0x19, 0xe6, 0x12, + 0xb0, 0xdc, 0x58, 0x39, 0x3d, 0x8b, 0x23, 0x72, 0x96, 0x1a, 0x93, 0x6a, 0x4f, 0xce, 0x7c, 0x61, + 0x4b, 0xec, 0xc2, 0xd4, 0x2b, 0xbc, 0xbe, 0x07, 0xc6, 0xe1, 0x67, 0x09, 0xbc, 0x3f, 0x3a, 0x43, + 0x0e, 0xc1, 0x55, 0x4e, 0xe1, 0x45, 0xf2, 0x9d, 0x7a, 0x6c, 0x8a, 0x15, 0x85, 0x68, 0xb5, 0x9e, + 0xe4, 0x21, 0xc2, 0x5c, 0x9a, 0x7f, 0xfd, 0x12, 0x4d, 0xdb, 0x57, 0x4a, 0x82, 0x57, 0xf1, 0x15, + 0x9e, 0x9b, 0xa3, 0xeb, 0xf2, 0x9a, 0x16, 0xc3, 0x65, 0x38, 0xe7, 0x38, 0x60, 0xe0, 0xff, 0x5e, + 0xdd, 0x32, 0xfb, 0x28, 0x6a, 0xf7, 0x4e, 0x4c, 0x5e, 0x78, 0x82, 0x5a, 0x6e, 0x9f, 0x99, 0xbf, + 0x21, 0x3f, 0x87, 0x94, 0xf0, 0x70, 0x7c, 0xc9, 0x0e, 0x2b, 0x4c, 0x63, 0x83, 0xce, 0x97, 0xc3, + 0xdb, 0x21, 0x4b, 0x97, 0x59, 0x1a, 0x06, 0x32, 0xb0, 0xdc, 0xac, 0xc2, 0x74, 0xa1, 0x3d, 0x48, + 0x3a, 0x03, 0x09, 0x80, 0x9b, 0x70, 0x44, 0x4f, 0xeb, 0x7d, 0xc6, 0xa5, 0x9f, 0xd8, 0xad, 0x96, + 0x2b, 0xbf, 0x90, 0x15, 0x58, 0x86, 0x2c, 0xec, 0xd1, 0x0a, 0xa1, 0xe6, 0x4e, 0x6a, 0xf4, 0x93, + 0x3e, 0x8c, 0xf0, 0x79, 0x70, 0x49, 0xa2, 0x36, 0x54, 0x72, 0xaf, 0x3f, 0xcd, 0x73, 0xf0, 0x0e, + 0x8c, 0x0f, 0xf0, 0xbc, 0xfe, 0xcf, 0x1e, 0xc7, 0x10, 0xf2, 0x8a, 0x7d, 0xf0, 0xe5, 0x4b, 0x27, + 0x1e, 0x0e, 0x18, 0x0f, 0xea, 0xd8, 0xb6, 0x07, 0x4a, 0x5f, 0xdf, 0x0c, 0x9b, 0x3d, 0xc2, 0x1a, + 0x6f, 0x80, 0xe1, 0x9e, 0xea, 0x44, 0xe5, 0x60, 0x48, 0xb2, 0x83, 0xa4, 0x3c, 0xd6, 0xce, 0xc0, + 0xe6, 0x64, 0xef, 0x11, 0xcf, 0x07, 0x98, 0x63, 0xd3, 0xbf, 0xd0, 0x17, 0x59, 0x19, 0xe6, 0x0a, + 0xaf, 0xa6, 0xca, 0x13, 0xf8, 0x16, 0xcc, 0x00, 0x2e, 0x16, 0x74, 0x2c, 0x96, 0x75, 0x81, 0xc1, + 0x54, 0x0f, 0xd8, 0x5f, 0x66, 0x50, 0xed, 0x38, 0xbc, 0x76, 0xb2, 0x05, 0x47, 0x58, 0xa7, 0xdc, + 0x28, 0x22, 0x37, 0xba, 0x80, 0xc1, 0xce, 0xfc, 0xc3, 0x01, 0xf5, 0xa7, 0x48, 0x74, 0x2b, 0x7a, + 0xf6, 0x3c, 0xed, 0xd3, 0x7a, 0xf7, 0xcf, 0xcd, 0x5a, 0x3a, 0xe2, 0xe7, 0x4a, 0x9e, 0xb8, 0x20, + 0x26, 0x3c, 0xc9, 0x42, 0x4f, 0x84, 0xde, 0x70, 0xe3, 0xe1, 0xf0, 0x7c, 0x1f, 0xf0, 0x08, 0x2b, + 0x86, 0x18, 0x8d, 0x41, 0x97, 0x22, 0x64, 0xd0, 0xe4, 0xf9, 0x77, 0xcc, 0x4d, 0x27, 0x79, 0x60, + 0x8d, 0x40, 0x8f, 0x8e, 0x03, 0x73, 0xd1, 0xe6, 0x27, 0x1f, 0x34, 0xfc, 0x58, 0x09, 0x9e, 0x33, + 0x53, 0xbf, 0xd0, 0x17, 0x59, 0x19, 0xd6, 0x0a, 0xae, 0xec, 0x11, 0x26, 0xb9, 0x70, 0xd6, 0x00, + 0x1d, 0xb3, 0x75, 0x85, 0x2c, 0xf6, 0x85, 0xce, 0x68, 0x9f, 0xd0, 0x02, 0xde, 0x6d, 0xd0, 0xae, + 0x0f, 0x3a, 0x8d, 0x29, 0xf0, 0x62, 0x61, 0x80, 0x25, 0x49, 0x49, 0xcd, 0xa5, 0xad, 0x6e, 0xdb, + 0xb5, 0x0f, 0x50, 0x45, 0x12, 0xb1, 0xae, 0x86, 0xe6, 0xe5, 0x5f, 0x0c, 0x95, 0x17, 0x24, 0xd3, + 0xd6, 0x45, 0x8e, 0x4c, 0x28, 0x38, 0x20, 0xfc, 0x96, 0xea, 0x05, 0xe4, 0x13, 0xd8, 0x90, 0xdc, + 0x31, 0xc3, 0x83, 0xc1, 0xf0, 0xf0, 0xbf, 0x1b, 0x6a, 0x44, 0x76, 0xe5, 0xfd, 0xdf, 0x14, 0xcf, + 0xe3, 0x43, 0x50, 0xa4, 0xe2, 0x8e, 0x4c, 0x46, 0x7a, 0x15, 0xb5, 0xc8, 0x1c, 0xd3, 0x39, 0x23, + 0x21, 0x67, 0x9a, 0xae, 0xf4, 0x0e, 0x19, 0x99, 0xd3, 0xbf, 0xd0, 0x17, 0x59, 0x19, 0xc6, 0x1a, + 0xb0, 0xd3, 0x95, 0x9c, 0x58, 0x00, 0x00, 0x00, 0xf5, 0x3c, 0x01, 0xbc, 0x50, 0x4b, 0x8a, 0x3b, + 0xbe, 0xb0, 0x2c, 0xd8, 0x89, 0x14, 0x24, 0xd0, 0xeb, 0x2b, 0x46, 0x10, 0x67, 0x88, 0xd3, 0xd3, + 0xda, 0x0f, 0x5c, 0x59, 0x59, 0x2c, 0x25, 0x0f, 0x4c, 0x65, 0x0a, 0x9b, 0x0a, 0x21, 0xef, 0xdc, + 0x43, 0xe3, 0x91, 0xf6, 0x38, 0x2d, 0x60, 0xfe, 0x48, 0xec, 0xff, 0x1b, 0xac, 0x69, 0x69, 0x14, + 0x84, 0x18, 0x2d, 0xfb, 0x0d, 0xe8, 0x64, 0xaa, 0x27, 0x87, 0xc7, 0x87, 0xc7, 0xfc, 0x93, 0x00, + 0x84, 0x46, 0xae, 0xd8, 0xb5, 0x8d, 0x59, 0x05, 0xca, 0xd3, 0x74, 0xc9, 0xc5, 0xfb, 0x9c, 0x69, + 0x49, 0xcc, 0xb9, 0xa2, 0x46, 0xca, 0x20, 0xd8, 0xdb, 0xfa, 0xf7, 0xe1, 0x84, 0x8e, 0x35, 0x40, + 0x03, 0xbf, 0xd0, 0x17, 0x59, 0x39, 0xc6, 0x3a, 0xaf, 0xdd, 0x49, 0xd0, 0x58, 0x01, 0x68, 0x7b, + 0x15, 0x25, 0xbc, 0xbd, 0x68, 0xca, 0x4a, 0xaa, 0x1e, 0x7c, 0xca, 0x07, 0xf0, 0x8b, 0xe2, 0x53, + 0xa1, 0xba, 0xcf, 0x90, 0xae, 0xec, 0x67, 0xd5, 0x18, 0xc8, 0xe7, 0xcf, 0xdf, 0x2a, 0x54, 0xef, + 0x84, 0x3c, 0x94, 0x02, 0xc3, 0xc2, 0x71, 0x3b, 0x0e, 0xc5, 0xa1, 0x6d, 0x0a, 0xb9, 0x20, 0xad, + 0xfa, 0xff, 0x3f, 0x40, 0xcf, 0x3a, 0x78, 0x7f, 0x3c, 0xd9, 0x35, 0x70, 0xe3, 0x33, 0xb3, 0x83, + 0xe0, 0xfc, 0x0f, 0xc0, 0xfc, 0x1f, 0x00, 0x73, 0x1f, 0x5f, 0xd1, 0xc7, 0x12, 0x2f, 0xa6, 0x64, + 0x53, 0xbe, 0xe4, 0x8c, 0x0d, 0x97, 0x0f, 0xcd, 0xb3, 0xd2, 0x58, 0xb6, 0xba, 0x18, 0xb8, 0x62, + 0x78, 0x32, 0x88, 0x44, 0x2a, 0xf3, 0x33, 0x33, 0xdb, 0x21, 0x37, 0x97, 0x59, 0x19, 0xf5, 0xca, + 0xaf, 0xdd, 0x49, 0xcf, 0xc5, 0x1e, 0x8a, 0xa2, 0x00, 0xf6, 0x9a, 0xa4, 0x8c, 0x5f, 0xa2, 0x92, + 0x0a, 0x8c, 0x05, 0x2a, 0x5b, 0x3d, 0x0c, 0x7a, 0x22, 0xeb, 0xb9, 0x07, 0xe0, 0x57, 0xc1, 0xd5, + 0x2e, 0x6a, 0x68, 0x8d, 0xcb, 0xd0, 0x32, 0xc8, 0x4a, 0x3f, 0x86, 0x21, 0xc9, 0x08, 0x97, 0x21, + 0x27, 0xa9, 0xb0, 0x38, 0xa1, 0xf3, 0xdd, 0xf5, 0xca, 0x95, 0xab, 0xe6, 0xa9, 0xed, 0x72, 0x36, + 0x30, 0xd1, 0x6f, 0x53, 0xdb, 0xb4, 0x39, 0x64, 0xcc, 0xe3, 0xe0, 0xf8, 0x3c, 0x1e, 0x00, 0x5c, + 0xec, 0xbe, 0xee, 0x62, 0xee, 0x30, 0x47, 0x27, 0x12, 0x4c, 0x50, 0xb1, 0x4b, 0xee, 0xe4, 0x74, + 0x51, 0xf6, 0x91, 0x68, 0xee, 0x17, 0x12, 0xa6, 0xed, 0xdb, 0x20, 0xe8, 0x25, 0xec, 0x72, 0xc9, + 0xdb, 0x21, 0x37, 0x97, 0x59, 0x19, 0xf5, 0x8a, 0xaf, 0xa6, 0xc8, 0x17, 0x7f, 0x81, 0x39, 0x12, + 0x00, 0x8c, 0x3f, 0xc9, 0x35, 0x8a, 0x38, 0x56, 0xa2, 0xee, 0xa0, 0x6a, 0x00, 0x15, 0xde, 0x4d, + 0xd3, 0xca, 0xd3, 0x0a, 0x6e, 0xcd, 0x17, 0xcf, 0x7e, 0x26, 0xde, 0x16, 0x06, 0xdf, 0x37, 0x99, + 0x56, 0xf8, 0x09, 0xf0, 0x77, 0x96, 0xe7, 0xd9, 0x35, 0xf0, 0x67, 0xfa, 0x28, 0x1f, 0x04, 0xa7, + 0x80, 0x95, 0x55, 0xfa, 0xd0, 0x3f, 0x07, 0x1c, 0x82, 0x18, 0x34, 0x74, 0x9c, 0x1e, 0x3c, 0x1f, + 0x07, 0xc0, 0xfe, 0x07, 0xe0, 0xe7, 0x99, 0xdc, 0x6f, 0x24, 0xe4, 0x59, 0xd0, 0x63, 0x86, 0xe2, + 0x7a, 0xa0, 0xa2, 0x48, 0x62, 0x54, 0xff, 0x81, 0x25, 0x64, 0xb8, 0x1f, 0xa0, 0xd6, 0x5c, 0x0b, + 0x23, 0xee, 0xbe, 0x8f, 0x2e, 0xdb, 0x86, 0x41, 0xdb, 0x21, 0x37, 0x97, 0x59, 0x19, 0xe5, 0x7a, + 0xaf, 0xa6, 0xca, 0xa1, 0x55, 0xbe, 0xff, 0xdc, 0x00, 0x04, 0xf7, 0x23, 0x29, 0x46, 0xf6, 0xb4, + 0x53, 0x22, 0x0a, 0x40, 0x7e, 0x6f, 0x58, 0xb9, 0x8c, 0xdb, 0xa1, 0x3c, 0x7b, 0xa5, 0x37, 0xc7, + 0xb3, 0x99, 0xc5, 0x50, 0x17, 0x39, 0x75, 0x8e, 0xb7, 0xfb, 0x7c, 0x3a, 0xd5, 0xa4, 0x7e, 0xd0, + 0x3f, 0xff, 0xe7, 0xb1, 0x37, 0x20, 0x50, 0xf1, 0xb3, 0xef, 0x1b, 0x2f, 0x41, 0x11, 0x82, 0xc1, + 0xa0, 0x6e, 0xdb, 0x4b, 0x76, 0x92, 0x4b, 0x06, 0xb1, 0xc1, 0xf0, 0x7c, 0x0f, 0x83, 0x80, 0x0f, + 0x3f, 0xdd, 0xeb, 0xe5, 0xf6, 0x76, 0x84, 0x46, 0x89, 0x97, 0x5a, 0x4a, 0xa7, 0x01, 0x83, 0xff, + 0x30, 0x0d, 0x1a, 0x37, 0x65, 0xdd, 0x88, 0xa6, 0x32, 0x01, 0x36, 0x2d, 0x96, 0xfb, 0x25, 0xb3, + 0xdb, 0x21, 0x37, 0x97, 0x59, 0x1a, 0x15, 0x6a, 0xaf, 0xdd, 0x47, 0xae, 0x87, 0xb3, 0x6e, 0x00, + 0x2d, 0xd4, 0x97, 0x7a, 0xa6, 0xdf, 0x22, 0x80, 0x85, 0x1b, 0x4f, 0xc2, 0x1f, 0x2c, 0x3c, 0x0b, + 0x5d, 0xbf, 0xc4, 0x84, 0x2b, 0xff, 0x91, 0x11, 0x42, 0x6c, 0xb4, 0xec, 0x24, 0xb7, 0xd3, 0x15, + 0x41, 0xb1, 0x42, 0x15, 0xf2, 0x76, 0x8d, 0x3a, 0x20, 0x9d, 0x6f, 0x84, 0x9f, 0x75, 0x54, 0xe3, + 0x17, 0xbf, 0x03, 0x0f, 0xcb, 0x00, 0xdf, 0x7d, 0x83, 0xeb, 0xa5, 0x5b, 0x09, 0x1c, 0xe3, 0xe0, + 0xf8, 0x0f, 0xc0, 0x7e, 0x07, 0xe1, 0x87, 0x8c, 0x27, 0xc1, 0xfd, 0x79, 0xea, 0xde, 0xdd, 0xa3, + 0x4f, 0xb8, 0x14, 0x51, 0x14, 0xd3, 0x9f, 0x0c, 0x07, 0xa2, 0xaf, 0xcf, 0xb0, 0x5d, 0x13, 0x5a, + 0xa6, 0x97, 0x1a, 0x4c, 0x96, 0x3f, 0xe4, 0x48, 0xdb, 0x21, 0x37, 0x97, 0x59, 0x19, 0xf5, 0x7a, + 0xae, 0xed, 0x18, 0xc3, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x21, 0x1a, 0x23, 0x22, 0x82, + 0xde, 0x56, 0x00, 0x03, 0x39, 0xab, 0x1a, 0x5e, 0x2d, 0x76, 0x3a, 0x8a, 0x3b, 0x7a, 0x9f, 0x90, + 0x8a, 0xba, 0x2c, 0xc0, 0x57, 0xf6, 0x52, 0xbf, 0xc5, 0x90, 0xe2, 0x46, 0x3b, 0x94, 0xfd, 0x1b, + 0x68, 0x50, 0xf6, 0x8c, 0x81, 0x5f, 0x61, 0xa9, 0x06, 0x0a, 0x0b, 0x42, 0x58, 0x0c, 0x8c, 0xfe, + 0x0b, 0xb1, 0x94, 0x78, 0xa0, 0x7e, 0x0f, 0x3c, 0x7c, 0x0f, 0x81, 0xfc, 0x0f, 0xe0, 0xf8, 0xf2, + 0x26, 0x1d, 0x88, 0x44, 0xb8, 0xd3, 0x1d, 0xb4, 0x2b, 0xe8, 0x64, 0x42, 0xb7, 0x2c, 0x72, 0x7d, + 0x93, 0x77, 0xa6, 0xc5, 0x1e, 0x26, 0xfb, 0x7e, 0x40, 0xdf, 0xd0, 0xd5, 0xf4, 0xe7, 0x80, 0xe0, + 0x5b, 0x21, 0x37, 0x97, 0x59, 0x19, 0xf5, 0xd2, 0xae, 0xed, 0x18, 0xc3, 0x34, 0x00, 0x00, 0x00, + 0x0e, 0xd4, 0xbc, 0x15, 0xaa, 0xb6, 0x06, 0x47, 0x8d, 0x6e, 0x00, 0x57, 0x6b, 0xa6, 0xed, 0xff, + 0xdf, 0xc2, 0x48, 0x94, 0x1a, 0xbb, 0xb6, 0xb7, 0x18, 0xd1, 0x28, 0xac, 0x2e, 0x52, 0x81, 0xc1, + 0xa9, 0xa0, 0x62, 0x11, 0xeb, 0xf2, 0xdf, 0xb5, 0xb9, 0x5e, 0xd4, 0x85, 0x94, 0x5a, 0x46, 0xe4, + 0xde, 0x7e, 0xdb, 0x7b, 0xe1, 0x37, 0x57, 0x31, 0x46, 0xd4, 0x02, 0xca, 0x34, 0xe1, 0xfc, 0x70, + 0xf0, 0x3f, 0x01, 0xf0, 0x3e, 0x07, 0x9f, 0x21, 0xd3, 0x9c, 0x19, 0xb1, 0x91, 0x52, 0xbf, 0xf7, + 0xbb, 0x6e, 0xf1, 0x68, 0x99, 0xec, 0x8c, 0x3a, 0x2d, 0x5f, 0x1a, 0x16, 0xaa, 0x97, 0xa7, 0xad, + 0xfd, 0x72, 0x17, 0x32, 0x6f, 0x42, 0xd4, 0x0f, 0xcb, 0x21, 0x37, 0x97, 0x59, 0x19, 0xf5, 0xda, + 0xae, 0xec, 0x0f, 0xb3, 0x42, 0x12, 0xd3, 0x00, 0x00, 0x00, 0xdc, 0x94, 0x9d, 0x84, 0xb1, 0xa5, + 0x70, 0x6a, 0xdb, 0xef, 0x0a, 0xe3, 0xcb, 0x15, 0x2e, 0xb4, 0x56, 0x8f, 0xbd, 0x51, 0xc2, 0x83, + 0x91, 0xa7, 0x98, 0xc0, 0xf5, 0xee, 0xdb, 0x79, 0x1d, 0xb2, 0x13, 0x9d, 0x23, 0x3c, 0xaa, 0x66, + 0x7e, 0x45, 0x17, 0xf3, 0x2c, 0x5f, 0x2c, 0x3b, 0x5d, 0xa5, 0x8a, 0x1c, 0x37, 0x62, 0x8c, 0xaa, + 0x8f, 0x52, 0xa3, 0x35, 0x94, 0x57, 0x34, 0xcd, 0xa6, 0xe4, 0xe1, 0xc3, 0xc3, 0xf8, 0x1f, 0x07, + 0x00, 0x08, 0xe5, 0x13, 0x34, 0x5a, 0x6e, 0x33, 0x24, 0xe6, 0xc1, 0x17, 0xab, 0xfa, 0x52, 0x10, + 0x78, 0x33, 0x95, 0xa6, 0xec, 0x53, 0x1e, 0x72, 0xe2, 0x91, 0x85, 0x51, 0x96, 0x6f, 0x99, 0xa4, + 0xdb, 0x22, 0x97, 0x17, 0x59, 0x1a, 0x06, 0x3a, 0xb0, 0xdc, 0xac, 0x99, 0xfc, 0xa7, 0x25, 0x91, + 0xff, 0x02, 0x20, 0x74, 0x42, 0x2a, 0x7a, 0x0c, 0x09, 0x7f, 0xbf, 0x91, 0x04, 0x4f, 0x0d, 0xe0, + 0xe9, 0xc9, 0xf2, 0x79, 0x05, 0xbc, 0x3c, 0xb1, 0x5d, 0x4b, 0x07, 0xfc, 0xc4, 0xa6, 0x05, 0x94, + 0x12, 0xf3, 0x70, 0xf6, 0x4a, 0xf1, 0x4c, 0x1f, 0x04, 0xe3, 0x43, 0x14, 0xed, 0x08, 0xaa, 0x75, + 0xe0, 0x9d, 0xb4, 0xe2, 0x3b, 0x03, 0xeb, 0x98, 0x58, 0xd1, 0xf1, 0xc0, 0xf6, 0x1a, 0x1e, 0x71, + 0xc1, 0xf0, 0x7f, 0x03, 0xc1, 0xc3, 0x82, 0xb1, 0xdc, 0x01, 0xc1, 0xd3, 0x82, 0x68, 0x7e, 0x1f, + 0xa1, 0xd1, 0x19, 0xa8, 0x64, 0xc8, 0x03, 0x1b, 0x0f, 0x1d, 0x3b, 0x85, 0xf2, 0x4a, 0x1f, 0xc4, + 0x77, 0x35, 0xc2, 0x0e, 0x3e, 0x44, 0x1b, 0xc9, 0x5b, 0x22, 0x97, 0x17, 0x59, 0x1a, 0x06, 0x0a, + 0xaf, 0xde, 0xcb, 0x94, 0xe0, 0xe7, 0x7a, 0x12, 0x00, 0x00, 0x3b, 0xd0, 0x3d, 0xc1, 0x34, 0x00, + 0x00, 0x25, 0xbc, 0xbe, 0x5e, 0x36, 0xae, 0xc3, 0xf9, 0xb2, 0xec, 0x2f, 0x96, 0x83, 0xd5, 0xaf, + 0xce, 0x9f, 0x73, 0xd2, 0xc1, 0xc4, 0x36, 0x12, 0x01, 0x35, 0xe4, 0x0f, 0x7f, 0x74, 0x91, 0xeb, + 0xec, 0x1c, 0x6e, 0x7d, 0x17, 0x17, 0xd1, 0x8a, 0x02, 0xb0, 0xbb, 0x49, 0x62, 0x7f, 0x96, 0xfd, + 0x74, 0xd9, 0xcf, 0x5b, 0x74, 0x84, 0xc1, 0xb3, 0x3c, 0x70, 0x7c, 0x0f, 0x81, 0xf8, 0x1c, 0x20, + 0xc5, 0xa2, 0x58, 0x94, 0xe3, 0xd8, 0xe3, 0x14, 0xd8, 0x70, 0x08, 0xda, 0x59, 0x77, 0x30, 0x9c, + 0x39, 0x8a, 0x54, 0xce, 0xb1, 0x23, 0x5d, 0x90, 0xbc, 0xe5, 0x2c, 0xb7, 0x25, 0x0f, 0x08, 0x40, + 0xdb, 0x22, 0x97, 0x17, 0x59, 0x1a, 0x16, 0x12, 0xaf, 0xde, 0xcb, 0xe0, 0x87, 0x0d, 0x93, 0x07, + 0x00, 0x04, 0x00, 0x29, 0x9b, 0x99, 0x97, 0x35, 0x52, 0x0d, 0x40, 0x00, 0x00, 0x10, 0x0d, 0x7a, + 0x70, 0x35, 0x2f, 0x80, 0x3c, 0x14, 0xca, 0x10, 0x3f, 0x6a, 0x18, 0x6d, 0x29, 0xa9, 0x72, 0xf6, + 0xbe, 0xd4, 0x19, 0xd1, 0xc4, 0x29, 0x16, 0x24, 0xb3, 0x02, 0xa9, 0x72, 0x9b, 0xe3, 0xe8, 0xdd, + 0x71, 0x5d, 0xb6, 0x83, 0xae, 0x26, 0x28, 0x23, 0xb5, 0x52, 0xad, 0x16, 0x29, 0x84, 0xbf, 0x6a, + 0x3c, 0xae, 0x51, 0x03, 0xe3, 0xe0, 0xf8, 0x3f, 0x07, 0xe1, 0xe6, 0x67, 0xad, 0xc4, 0x79, 0x2e, + 0xfe, 0xc0, 0x72, 0x34, 0xde, 0x5c, 0xc6, 0x5b, 0xc1, 0xcb, 0xb0, 0x38, 0x50, 0x02, 0x89, 0xd4, + 0x18, 0xdf, 0x30, 0x71, 0x56, 0x27, 0xfe, 0x57, 0x5b, 0x22, 0x97, 0x17, 0x59, 0x1a, 0x15, 0xf2, + 0xaf, 0xdd, 0x49, 0xcf, 0xcc, 0xa4, 0x07, 0x3f, 0x00, 0x08, 0xba, 0xea, 0x33, 0x83, 0xf2, 0x1d, + 0x4a, 0xe8, 0x2b, 0x00, 0x26, 0x46, 0xff, 0xc5, 0x59, 0xdc, 0x04, 0x76, 0xc7, 0x1a, 0x70, 0x6c, + 0xb1, 0x71, 0xe6, 0xd7, 0xc3, 0x71, 0xb8, 0x85, 0x8e, 0xf7, 0x24, 0x6f, 0x6d, 0x8b, 0xde, 0x37, + 0xc9, 0x4c, 0x48, 0xd6, 0x0e, 0x2a, 0x29, 0x33, 0x56, 0x9b, 0xcd, 0x28, 0xb4, 0x62, 0x82, 0x9e, + 0x70, 0x2a, 0x16, 0x0e, 0xfb, 0x6c, 0x82, 0x8b, 0x30, 0x71, 0xe1, 0xf8, 0x3f, 0x07, 0xc1, 0xf8, + 0x3b, 0xb8, 0x9b, 0x2f, 0x22, 0x79, 0x7d, 0x71, 0x14, 0x41, 0x6d, 0x70, 0x84, 0x45, 0x44, 0x06, + 0xa4, 0x86, 0xc9, 0x36, 0x7d, 0x80, 0xda, 0xcc, 0xf2, 0xc1, 0x2d, 0x16, 0x31, 0x2e, 0x7a, 0x8e, + 0x5b, 0x22, 0x97, 0x17, 0x59, 0x1a, 0x15, 0xaa, 0xae, 0xec, 0x11, 0x26, 0xb7, 0x2f, 0x3f, 0xb4, + 0xb4, 0x00, 0x6e, 0x1a, 0x2b, 0xc2, 0xbc, 0x22, 0x6e, 0xf3, 0xf2, 0x6b, 0x3d, 0xec, 0x29, 0x95, + 0x53, 0xdd, 0xaa, 0x8c, 0x3d, 0xce, 0x81, 0x97, 0x61, 0x19, 0x2f, 0x5e, 0x13, 0xf1, 0x9c, 0xb6, + 0x3f, 0xcd, 0x77, 0x53, 0xf5, 0x90, 0x47, 0x07, 0xda, 0x9b, 0x63, 0x02, 0x4a, 0x30, 0xff, 0x3a, + 0x76, 0xe8, 0x42, 0x96, 0x6d, 0x1a, 0x64, 0xe4, 0xee, 0x86, 0x6d, 0xeb, 0x05, 0x66, 0x6c, 0xc3, + 0x8f, 0x81, 0xf8, 0x1f, 0x80, 0xfc, 0x1e, 0x07, 0xfe, 0x22, 0xc0, 0x2b, 0x82, 0x22, 0xa5, 0x60, + 0x5e, 0x4f, 0xef, 0x5c, 0x4a, 0xd8, 0x42, 0x5b, 0xca, 0xbc, 0xf0, 0x6b, 0xaa, 0xc3, 0x69, 0x6f, + 0x6b, 0xbe, 0xc8, 0x18, 0x3f, 0x00, 0x19, 0x8d, 0xcb, 0x22, 0x97, 0x17, 0x59, 0x19, 0xd5, 0x8a, + 0xaf, 0xa6, 0xc8, 0x6c, 0x5a, 0x28, 0x8f, 0x78, 0xe5, 0x00, 0x52, 0x7c, 0x34, 0x94, 0xa7, 0x12, + 0x1d, 0x1d, 0x0f, 0x27, 0x84, 0x09, 0xab, 0xd8, 0xc5, 0xf7, 0x69, 0xde, 0xcd, 0xf0, 0xbd, 0x50, + 0xdc, 0x4a, 0x32, 0xc3, 0x92, 0x6c, 0xb5, 0xa8, 0xd2, 0x87, 0x56, 0x5d, 0x57, 0x63, 0x68, 0x13, + 0x24, 0x2f, 0xdd, 0x92, 0x9a, 0xc8, 0x90, 0x83, 0x70, 0x09, 0x77, 0x16, 0xc2, 0x76, 0xb3, 0xe1, + 0xc5, 0xc0, 0x9a, 0x5c, 0x63, 0xe3, 0x9c, 0x3e, 0x1f, 0x07, 0xf0, 0x1f, 0x80, 0xfc, 0x1f, 0x0e, + 0xed, 0x87, 0xf2, 0x17, 0xaf, 0x9d, 0xdc, 0x64, 0x12, 0x56, 0x3e, 0x2c, 0x56, 0xd0, 0xe0, 0x92, + 0x09, 0xd3, 0xc4, 0x6d, 0xca, 0x42, 0x7c, 0x72, 0x29, 0x02, 0xc0, 0x40, 0x04, 0x3f, 0xf6, 0x5f, + 0x5b, 0x22, 0x97, 0x17, 0x59, 0x1a, 0x05, 0x9a, 0xae, 0xec, 0x0f, 0x7b, 0x69, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x41, 0xaf, 0xfc, 0x8a, 0xb4, 0xa6, 0x16, 0xf1, 0x30, 0x4a, 0x32, 0x65, 0x7b, 0xb8, + 0x15, 0x84, 0xe4, 0x15, 0x21, 0x24, 0x8e, 0xdc, 0xbd, 0x52, 0xbf, 0x4d, 0x97, 0x48, 0xff, 0xf2, + 0x35, 0x2f, 0xfc, 0x4c, 0xe2, 0x4b, 0x34, 0x66, 0x4b, 0x5b, 0xcf, 0xbc, 0xa3, 0x22, 0x7b, 0xd7, + 0x8b, 0x5e, 0xc5, 0x3b, 0x1d, 0xca, 0x9b, 0x63, 0x47, 0x36, 0x0c, 0x80, 0x64, 0xec, 0x6d, 0x26, + 0xb8, 0xe3, 0xe3, 0xf0, 0x0f, 0x81, 0xf8, 0x1e, 0x03, 0xbd, 0xe3, 0xe9, 0x7c, 0x73, 0xd5, 0xff, + 0xed, 0x9b, 0xb6, 0xa5, 0xdd, 0x0a, 0xa0, 0x88, 0xf8, 0xad, 0x8f, 0x0a, 0xc5, 0x85, 0x2f, 0x57, + 0x52, 0x60, 0xd9, 0x9f, 0x66, 0xd3, 0x7b, 0xa6, 0xdb, 0x22, 0x97, 0x17, 0x59, 0x19, 0xf5, 0xc2, + 0xaf, 0xde, 0xcb, 0x85, 0xa7, 0x00, 0x00, 0x00, 0x01, 0x55, 0xe8, 0x5f, 0x8a, 0x56, 0xbc, 0x0c, + 0x12, 0x0a, 0x2a, 0x1e, 0xa9, 0xdc, 0x71, 0xef, 0x73, 0xb5, 0x83, 0x0c, 0x00, 0x5a, 0x54, 0xc1, + 0xe2, 0x96, 0x5a, 0xfe, 0xd4, 0x70, 0xb8, 0x8d, 0x0f, 0x9e, 0xdd, 0xad, 0x2d, 0x24, 0x27, 0x8e, + 0xba, 0xe4, 0xfe, 0x43, 0xab, 0x43, 0x7a, 0x80, 0x27, 0x7e, 0x02, 0x55, 0x17, 0x88, 0x51, 0xcb, + 0x8e, 0x29, 0x97, 0x2f, 0x25, 0x2d, 0xd3, 0x54, 0x9e, 0x3c, 0x3e, 0x0f, 0xc0, 0xf8, 0x1f, 0x07, + 0xfc, 0x61, 0x65, 0xc8, 0x2a, 0x81, 0xda, 0x49, 0x4e, 0x23, 0xec, 0x61, 0xb4, 0xb1, 0xb2, 0xf1, + 0x65, 0x61, 0xad, 0x53, 0x22, 0xda, 0x54, 0x33, 0x9b, 0x86, 0xbe, 0x86, 0xb6, 0xa0, 0x06, 0x55, + 0x5b, 0x22, 0x97, 0x17, 0x59, 0x19, 0xe5, 0x9a, 0x69, 0xd4, 0x3b, 0x63, 0x50, 0x77, 0xfb, 0x38, + 0x00, 0x00, 0x14, 0x4a, 0x4e, 0xe5, 0x7e, 0x3d, 0x1b, 0x13, 0x1f, 0x00, 0x28, 0x86, 0x0d, 0x5c, + 0x8f, 0xf8, 0x26, 0xd1, 0x0c, 0xc6, 0x10, 0x54, 0x78, 0xb4, 0xc4, 0xc9, 0x7a, 0xe7, 0xb0, 0xf1, + 0x91, 0xc8, 0x4e, 0x69, 0x0f, 0x4d, 0xd6, 0x43, 0x2b, 0x58, 0x3c, 0x66, 0x06, 0x07, 0x9c, 0x09, + 0xed, 0x1c, 0x1d, 0x0a, 0x74, 0x0d, 0xb6, 0xcf, 0x0e, 0x81, 0x13, 0xdd, 0x35, 0x6b, 0x34, 0x0f, + 0x97, 0xc7, 0x1e, 0x1e, 0x1f, 0x81, 0xf8, 0x3f, 0x07, 0xe1, 0x04, 0xa5, 0xd0, 0xff, 0x03, 0x33, + 0xab, 0xe3, 0xbe, 0xaa, 0x3f, 0xf1, 0x26, 0x29, 0x16, 0x61, 0xf8, 0x67, 0x5e, 0x48, 0x9d, 0x6a, + 0x57, 0x3d, 0xd8, 0xcd, 0x89, 0xe1, 0x97, 0x45, 0xeb, 0x22, 0x97, 0x17, 0x59, 0x39, 0xf5, 0xc2, + 0xae, 0xed, 0x18, 0xc3, 0x35, 0x47, 0xf3, 0x82, 0x00, 0x00, 0x0a, 0x8d, 0xee, 0x0c, 0x3f, 0x00, + 0x00, 0x00, 0x02, 0x78, 0xdb, 0x9b, 0xa0, 0xe1, 0xe2, 0x22, 0xb6, 0x06, 0x3f, 0xbe, 0xc7, 0x5f, + 0x62, 0xb0, 0x15, 0x12, 0xec, 0xcf, 0x7c, 0xf8, 0x92, 0x96, 0x5a, 0x4a, 0xbd, 0xf4, 0xb6, 0xc0, + 0xcd, 0xd6, 0x83, 0x6d, 0xbf, 0x39, 0xae, 0x56, 0x6c, 0xf6, 0x06, 0x1e, 0xe0, 0xe8, 0x78, 0xa1, + 0x50, 0x9b, 0x7f, 0xba, 0xa0, 0xc7, 0xed, 0xfa, 0x03, 0xa9, 0x0c, 0x7c, 0xf8, 0x7c, 0x1f, 0x03, + 0xf0, 0x7e, 0x1e, 0x03, 0x0b, 0x87, 0xe4, 0x16, 0x30, 0x8f, 0x2f, 0xf4, 0x6d, 0x82, 0xd1, 0x5e, + 0xd9, 0x3a, 0xe5, 0x38, 0x99, 0x56, 0xe7, 0x76, 0x89, 0x6c, 0x8c, 0x0a, 0x4c, 0xf1, 0x9f, 0x8e, + 0xcb, 0x23, 0x63, 0x97, 0x59, 0x19, 0xe6, 0x32, 0xaf, 0xe4, 0xc5, 0x79, 0xc2, 0x5a, 0xff, 0x30, + 0x6b, 0x09, 0x2f, 0xdb, 0x49, 0x80, 0xa7, 0xdc, 0xb8, 0x00, 0x00, 0x00, 0x0a, 0xb2, 0x5f, 0x67, + 0x82, 0x1a, 0x72, 0xdf, 0xfc, 0x95, 0xe3, 0xa4, 0xcf, 0xa3, 0x4e, 0x2b, 0x05, 0x71, 0x98, 0x3b, + 0x08, 0xcc, 0xd8, 0xe0, 0xa3, 0x34, 0xf9, 0xa9, 0xfd, 0xeb, 0xea, 0xfc, 0x18, 0xb7, 0x98, 0x1a, + 0x74, 0x61, 0xb8, 0xc6, 0xf9, 0x99, 0x25, 0x7d, 0x6b, 0xfd, 0xbf, 0x91, 0x58, 0xef, 0x0d, 0x14, + 0xce, 0x61, 0xc0, 0xfe, 0x07, 0xc0, 0xf8, 0x3e, 0x1f, 0xc8, 0xa0, 0x38, 0x93, 0x48, 0x9e, 0x2f, + 0x32, 0x57, 0x4f, 0x26, 0x9f, 0x8e, 0x99, 0xe5, 0x02, 0xa4, 0x48, 0x5a, 0x3d, 0xf7, 0xe5, 0x54, + 0x79, 0x3b, 0xae, 0xcf, 0x6c, 0x5d, 0x20, 0x8a, 0x5b, 0x23, 0x63, 0x97, 0x59, 0x1a, 0x06, 0x0a, + 0xaf, 0x07, 0x59, 0x7c, 0x19, 0x03, 0xa9, 0x3c, 0x00, 0x14, 0x24, 0x32, 0xde, 0x23, 0x1e, 0x64, + 0x00, 0x00, 0x00, 0x02, 0x78, 0x2b, 0x20, 0xce, 0x2f, 0x68, 0xf5, 0xbf, 0x05, 0xeb, 0x26, 0x55, + 0x29, 0x53, 0x4c, 0x7e, 0x61, 0xf9, 0xad, 0x8f, 0xc2, 0x8a, 0x41, 0x34, 0x8d, 0xc9, 0x28, 0xc6, + 0xf8, 0x8b, 0x08, 0xa3, 0xd4, 0x35, 0x7a, 0x7e, 0x53, 0xa0, 0x52, 0x5d, 0x56, 0xd6, 0xd1, 0xdf, + 0xc9, 0xc4, 0x58, 0x68, 0x78, 0x86, 0xf0, 0xa8, 0x62, 0x31, 0x98, 0xf0, 0xe0, 0xf8, 0x3c, 0x1f, + 0x87, 0x8f, 0x00, 0x18, 0x31, 0x02, 0x8c, 0x85, 0xa0, 0xa6, 0x11, 0x2b, 0x61, 0x36, 0xdf, 0x97, + 0xc1, 0x2b, 0x02, 0xba, 0xad, 0xc2, 0x2b, 0xd3, 0x85, 0xe4, 0x28, 0x75, 0xaa, 0xa9, 0x20, 0x72, + 0x5b, 0x23, 0x63, 0x97, 0x59, 0x1a, 0x16, 0x32, 0xaf, 0xde, 0xcb, 0xe0, 0xab, 0x2b, 0xe8, 0xed, + 0x50, 0xe3, 0x86, 0x47, 0xe5, 0x26, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x4f, 0xb5, 0xa6, + 0x0f, 0x22, 0x99, 0x27, 0x10, 0x6e, 0x3f, 0x2c, 0x8c, 0xa3, 0x70, 0xa0, 0x31, 0x5f, 0xec, 0xd2, + 0x6b, 0x19, 0x59, 0x24, 0x59, 0x31, 0xe6, 0x5c, 0x7b, 0x58, 0x91, 0xf2, 0x1f, 0xe5, 0xef, 0xe1, + 0x69, 0x7c, 0x89, 0x15, 0xd6, 0xf0, 0x90, 0x04, 0xf1, 0x1f, 0x4b, 0x6f, 0xd6, 0x20, 0x0e, 0x9b, + 0xf5, 0xb2, 0x26, 0xce, 0x3c, 0x78, 0xf0, 0x7c, 0x1f, 0x81, 0xf8, 0x1e, 0x0c, 0xc3, 0xb7, 0xec, + 0xcd, 0x3f, 0xa9, 0x4d, 0x80, 0x23, 0x7a, 0x9c, 0x52, 0xec, 0x07, 0xb9, 0xcf, 0x14, 0xfe, 0x1d, + 0x31, 0xaf, 0x97, 0xd8, 0x3c, 0xb4, 0xfc, 0x09, 0xdb, 0x23, 0x63, 0x97, 0x59, 0x1a, 0x16, 0x0a, + 0xaf, 0xde, 0xcb, 0xe0, 0x85, 0xa8, 0x27, 0x59, 0x00, 0x01, 0xbf, 0x14, 0x21, 0x94, 0xb6, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x4a, 0xbe, 0xff, 0x68, 0x3f, 0x33, 0x88, 0xc8, 0xea, 0x78, 0x68, 0x02, + 0x5d, 0x09, 0x28, 0x00, 0x6d, 0x52, 0x33, 0xaf, 0x64, 0x95, 0x5e, 0xa3, 0xed, 0x4c, 0x68, 0x8f, + 0xef, 0x24, 0x88, 0x45, 0xa1, 0x68, 0x3a, 0x1f, 0x25, 0x2d, 0xe7, 0x52, 0x34, 0xd4, 0x24, 0x55, + 0x52, 0x60, 0x48, 0x63, 0xe2, 0x23, 0x1a, 0xca, 0xce, 0x20, 0xc3, 0x87, 0xc1, 0xf8, 0x7c, 0x0f, + 0x06, 0x07, 0x73, 0x81, 0xec, 0x4e, 0x4d, 0x9d, 0x5d, 0x11, 0xfe, 0xf0, 0x4f, 0x32, 0xa4, 0x6e, + 0xc9, 0xf9, 0x47, 0x2a, 0x54, 0x86, 0x1b, 0xa0, 0xa8, 0x64, 0x9e, 0x07, 0x08, 0x36, 0x1b, 0x8c, + 0xdb, 0x23, 0x63, 0x97, 0x59, 0x1a, 0x26, 0x32, 0xae, 0xec, 0x0f, 0x7b, 0x69, 0x00, 0x00, 0x00, + 0x0b, 0x2e, 0x68, 0x94, 0x87, 0x37, 0x64, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x5d, 0xa8, 0xb0, 0x06, + 0x83, 0x1b, 0x2d, 0x62, 0x14, 0xb3, 0x22, 0xb6, 0x22, 0xa3, 0xf7, 0xbe, 0xd0, 0x7c, 0x75, 0xff, + 0x33, 0xcb, 0x97, 0x1d, 0xd4, 0x6e, 0x8d, 0x22, 0xfc, 0xe0, 0x98, 0xba, 0x9a, 0x65, 0x82, 0x5c, + 0x37, 0xe7, 0xd3, 0xa9, 0xdf, 0x0d, 0x69, 0xaa, 0x27, 0xfa, 0x1d, 0x2c, 0x08, 0x75, 0x0c, 0x7b, + 0x01, 0xee, 0x19, 0xe7, 0x0f, 0x87, 0xc1, 0xf8, 0x1f, 0x0f, 0xe6, 0x7d, 0xeb, 0x69, 0xbb, 0xa6, + 0x5f, 0x9f, 0x6a, 0xb2, 0xba, 0xac, 0x84, 0x14, 0xde, 0xe9, 0x6e, 0xd4, 0x31, 0x9a, 0xf3, 0x32, + 0x22, 0xa5, 0xe2, 0xf6, 0x3e, 0x75, 0xe8, 0x4d, 0x4b, 0x23, 0x63, 0x97, 0x59, 0x19, 0xe5, 0xa2, + 0xb0, 0xdc, 0xac, 0x9f, 0x4f, 0x3a, 0xa2, 0xc7, 0x00, 0x02, 0x30, 0x4e, 0x88, 0x25, 0x1c, 0x25, + 0xa7, 0x3a, 0x72, 0xc3, 0xf3, 0x65, 0xb3, 0x05, 0x32, 0x8d, 0x45, 0x6f, 0xba, 0x21, 0x22, 0xb1, + 0x50, 0xd3, 0xf2, 0x53, 0x0e, 0xba, 0xd5, 0x99, 0x07, 0xfb, 0x5b, 0x93, 0x74, 0x90, 0x08, 0xcc, + 0xd2, 0xd9, 0xd4, 0x91, 0x5f, 0x96, 0xef, 0xcd, 0x06, 0xcf, 0x04, 0x0e, 0xa1, 0x73, 0x54, 0xa3, + 0xdc, 0x55, 0xd4, 0xe3, 0xc8, 0xb9, 0xab, 0xb7, 0xf3, 0x38, 0x1d, 0xb3, 0x34, 0x63, 0xe1, 0xf0, + 0x7c, 0x18, 0x3f, 0x6f, 0xe2, 0xc6, 0x1c, 0xbc, 0xca, 0xbb, 0x19, 0x8e, 0x89, 0x8a, 0x83, 0xfa, + 0x2b, 0xac, 0x1e, 0x7f, 0xc1, 0x06, 0x99, 0x54, 0x84, 0x06, 0x90, 0x3e, 0x9e, 0x17, 0xfe, 0x07, + 0xcb, 0x59, 0x68, 0x27, 0x59, 0x1a, 0x26, 0x3a, 0xaf, 0xdd, 0x47, 0xaf, 0x45, 0x72, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf0, 0xa8, 0x00, 0x00, 0x84, 0xa0, 0x2f, 0xbe, 0x6a, 0xff, + 0x0b, 0xd8, 0xf2, 0x6f, 0x0a, 0x4d, 0x8b, 0xd4, 0xce, 0x90, 0xa5, 0xbe, 0xcd, 0x84, 0x89, 0xc6, + 0xaa, 0xc2, 0xd7, 0xe0, 0xfc, 0xf4, 0x44, 0xb5, 0x78, 0x7e, 0xd7, 0xdb, 0x9e, 0x7e, 0x18, 0x40, + 0xcf, 0x2a, 0xa8, 0x93, 0xa4, 0x57, 0xc8, 0x26, 0xec, 0x8a, 0x1e, 0xb2, 0x61, 0x89, 0xf2, 0xca, + 0xef, 0xdc, 0x63, 0xc3, 0xe1, 0xf8, 0x0f, 0xc1, 0xe3, 0xe1, 0xbd, 0xd3, 0xfc, 0xee, 0x01, 0x57, + 0xce, 0xa2, 0x20, 0x72, 0xac, 0x90, 0xd7, 0xa3, 0xef, 0x4d, 0x93, 0x3d, 0x65, 0xaa, 0x03, 0xb8, + 0xbd, 0x28, 0x81, 0xa4, 0xcd, 0x81, 0x22, 0x7f, 0xdb, 0x59, 0x68, 0x27, 0x59, 0x1a, 0x06, 0x1a, + 0xb6, 0xaf, 0xa6, 0xa4, 0x0f, 0xc8, 0x00, 0x00, 0x00, 0x8e, 0x8a, 0x00, 0x00, 0x00, 0x00, 0x1f, + 0x89, 0x3f, 0x1e, 0xe4, 0xbd, 0x9e, 0x69, 0xe4, 0xc8, 0x3f, 0xa1, 0x01, 0x8b, 0x3c, 0xd4, 0x7b, + 0xa3, 0x0a, 0x2b, 0xac, 0x9c, 0x76, 0x1a, 0x93, 0x9f, 0x3e, 0xe8, 0x3a, 0x5c, 0x1c, 0x61, 0x84, + 0xe2, 0xe5, 0x2a, 0xb2, 0x1c, 0x19, 0x45, 0x8c, 0xe1, 0x2b, 0x4f, 0xde, 0xc3, 0xfd, 0x59, 0x25, + 0x92, 0x59, 0xc8, 0xef, 0x02, 0xff, 0x86, 0xd5, 0x7e, 0x61, 0x71, 0x9c, 0x3e, 0x1f, 0x07, 0xe0, + 0x7e, 0x1c, 0x61, 0xc4, 0xe7, 0xf9, 0x13, 0xe5, 0x97, 0x8c, 0x19, 0xcf, 0x4b, 0xdd, 0xca, 0xa0, + 0x45, 0xc7, 0x42, 0x81, 0x85, 0xdb, 0x2c, 0x7b, 0x2c, 0x93, 0x4d, 0xbe, 0x0f, 0xab, 0x60, 0x66, + 0x5b, 0x59, 0x68, 0x27, 0x59, 0x1a, 0x05, 0xfa, 0x69, 0x22, 0xde, 0xdd, 0xd2, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8c, 0xcd, 0x03, 0xa3, 0x66, 0x74, 0x51, 0x0c, 0xfd, + 0x96, 0x0e, 0xc4, 0xa1, 0xa5, 0x02, 0x16, 0x3e, 0x54, 0xdc, 0x7b, 0xbf, 0xd1, 0x7f, 0x34, 0xe2, + 0xfc, 0x41, 0x33, 0xf9, 0xe8, 0x4c, 0x0a, 0x66, 0xfb, 0x40, 0x24, 0xd7, 0x1a, 0x5e, 0x80, 0xa4, + 0xa8, 0x60, 0x8b, 0x47, 0x99, 0xd3, 0xa4, 0x7c, 0x01, 0x58, 0x1a, 0x51, 0x8b, 0x43, 0xba, 0xb4, + 0x0a, 0x01, 0x31, 0x8f, 0x0f, 0x0f, 0xc0, 0xf8, 0x1f, 0x87, 0x9f, 0x0e, 0x62, 0x3d, 0xe5, 0x1b, + 0x23, 0x29, 0x1b, 0x32, 0x0d, 0x49, 0xc9, 0x8c, 0x2a, 0x31, 0x17, 0x14, 0x1d, 0x7b, 0x26, 0x54, + 0x07, 0x46, 0xb5, 0x00, 0x2f, 0x97, 0x96, 0x00, 0x5b, 0x59, 0x68, 0x27, 0x59, 0x19, 0xf6, 0x32, + 0xaf, 0xdd, 0x4a, 0x8e, 0x8a, 0x00, 0x00, 0x04, 0x16, 0x72, 0x00, 0x00, 0x00, 0x01, 0x3c, 0x65, + 0x00, 0x00, 0x06, 0xc2, 0x8d, 0x61, 0x32, 0xec, 0x63, 0x9f, 0xd5, 0x3b, 0x41, 0x19, 0x48, 0x92, + 0x5b, 0x79, 0xdf, 0x4e, 0xe0, 0x56, 0xab, 0x10, 0xad, 0xb6, 0x70, 0x26, 0xd8, 0x3b, 0x04, 0x1a, + 0x26, 0x3f, 0x1e, 0xfb, 0x61, 0x9b, 0x2c, 0xcd, 0xc3, 0x1a, 0x45, 0xbe, 0x86, 0xb5, 0x80, 0xbf, + 0x58, 0xe5, 0xf1, 0xc4, 0xfa, 0x70, 0xc3, 0x28, 0xe1, 0x66, 0xe6, 0x3e, 0x1f, 0x1f, 0x1f, 0x07, + 0xc1, 0x86, 0x07, 0x3f, 0x01, 0x4a, 0x24, 0x08, 0xb1, 0x9d, 0x34, 0x0f, 0xd4, 0x9a, 0x67, 0xa5, + 0x2c, 0x41, 0xcc, 0xd6, 0xb1, 0x4d, 0xb6, 0x30, 0x9e, 0x87, 0x1b, 0x81, 0x9b, 0x8a, 0x1b, 0x1f, + 0xdb, 0x59, 0x68, 0x27, 0x59, 0x1a, 0x06, 0x2a, 0x69, 0xab, 0xe1, 0x95, 0x02, 0xf7, 0x56, 0xf1, + 0x00, 0x00, 0x6f, 0x0a, 0x1d, 0x00, 0x00, 0x00, 0x85, 0x49, 0x3a, 0xc8, 0xa2, 0xa7, 0xd2, 0x5a, + 0xa9, 0xdf, 0xe8, 0x8c, 0x63, 0x9f, 0xa4, 0x30, 0xad, 0x60, 0xc9, 0xeb, 0x68, 0x08, 0x85, 0xc7, + 0x58, 0x80, 0x08, 0xa1, 0xb6, 0x36, 0xd8, 0xe9, 0x6a, 0x7b, 0x0b, 0xc1, 0xd6, 0x5e, 0x3f, 0x82, + 0x55, 0x55, 0x9c, 0x24, 0x89, 0x0d, 0x17, 0xf5, 0x4e, 0xf7, 0x62, 0x1a, 0x50, 0xb6, 0x11, 0xe5, + 0x96, 0xa1, 0xea, 0xc7, 0xf3, 0xc7, 0x87, 0xc3, 0xe0, 0xf8, 0x3e, 0x0f, 0x1f, 0x71, 0x01, 0x0a, + 0x69, 0x82, 0xa7, 0xe9, 0x15, 0xa2, 0xb7, 0xd0, 0x26, 0x0c, 0x4d, 0x9f, 0xd9, 0x37, 0x1f, 0x09, + 0x3f, 0x68, 0x19, 0xcc, 0xf5, 0xec, 0x70, 0x2b, 0x4b, 0x59, 0x68, 0x27, 0x59, 0x19, 0xe6, 0x3a, + 0xaf, 0xa6, 0xc8, 0x17, 0x7f, 0x00, 0x00, 0x00, 0x17, 0x06, 0xee, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x11, 0x90, 0x4d, 0x7e, 0x2d, 0x3b, 0x28, 0x83, 0xe1, 0x07, 0x76, 0x76, 0xcf, 0xba, 0x15, 0x34, + 0xb2, 0x39, 0x94, 0xdb, 0x89, 0xe9, 0x6d, 0x1a, 0xaf, 0xd6, 0x16, 0xa8, 0x64, 0x82, 0xb0, 0x29, + 0x5e, 0x24, 0xdd, 0x6b, 0x36, 0x83, 0xba, 0x3a, 0xf6, 0x36, 0x7a, 0x39, 0xd7, 0x81, 0xb2, 0x27, + 0xaf, 0x4c, 0x76, 0xc9, 0x2d, 0x17, 0x4c, 0x66, 0x99, 0x8d, 0x36, 0x38, 0xf0, 0xf8, 0x1f, 0x83, + 0xe1, 0xe0, 0xf8, 0x50, 0x30, 0xfe, 0x6c, 0x6f, 0x1c, 0x5a, 0x7b, 0x2e, 0x88, 0x59, 0x3b, 0xec, + 0xca, 0xde, 0x54, 0x84, 0xc2, 0x74, 0xc8, 0xa9, 0x40, 0x21, 0x70, 0x1d, 0x4f, 0xb4, 0xea, 0x06, + 0xcb, 0x59, 0x68, 0x27, 0x59, 0x19, 0xf6, 0x0a, 0xaf, 0xdd, 0x47, 0xae, 0x79, 0x00, 0x1f, 0x83, + 0x5d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, 0xdb, 0x11, 0x71, 0xcf, 0xbd, + 0x91, 0x1c, 0x8e, 0xc5, 0x83, 0xc4, 0xe6, 0x94, 0xef, 0x6e, 0x0e, 0x9e, 0x6a, 0x42, 0xa9, 0x2a, + 0x2a, 0xd0, 0x12, 0xae, 0x29, 0x75, 0xa5, 0xbf, 0xd1, 0xa3, 0x08, 0x7e, 0xee, 0xfc, 0xaa, 0x6b, + 0x9e, 0xfa, 0x66, 0x0f, 0x9d, 0xef, 0x40, 0x26, 0xe0, 0x10, 0x37, 0x20, 0x7b, 0x47, 0x23, 0xa4, + 0x2a, 0xb7, 0x61, 0xc7, 0x0f, 0x0f, 0x83, 0xe0, 0x7c, 0x0f, 0x83, 0xc0, 0xfd, 0xbe, 0xb6, 0xff, + 0xfa, 0x50, 0x5b, 0x22, 0x16, 0xc5, 0x40, 0x94, 0x44, 0x34, 0x24, 0x3b, 0xc8, 0xa3, 0x46, 0x42, + 0xa9, 0xf3, 0xb0, 0x22, 0x4b, 0xa8, 0x02, 0x1d, 0x4b, 0x59, 0x68, 0x27, 0x59, 0x19, 0xe6, 0x22, + 0xaf, 0xdd, 0x47, 0x5c, 0xb0, 0x00, 0x00, 0x00, 0x09, 0xa7, 0x33, 0xfc, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x51, 0x3a, 0x47, 0x73, 0x14, 0xdc, 0x14, 0x55, 0x01, 0xad, 0xc9, 0x84, 0xf5, 0x04, 0xca, + 0x57, 0xf3, 0x4d, 0xa5, 0x4e, 0x52, 0x7c, 0x3c, 0xb4, 0xac, 0x71, 0xe4, 0x05, 0x1f, 0x32, 0xd5, + 0x66, 0xee, 0x2e, 0x65, 0x11, 0x2b, 0xf8, 0x17, 0x9f, 0x1c, 0x31, 0xc1, 0x45, 0x92, 0xf7, 0xec, + 0x52, 0x11, 0xaf, 0xf8, 0x38, 0xe2, 0x4f, 0x46, 0x0e, 0xa7, 0x7d, 0x8c, 0x61, 0xe0, 0xf0, 0x1e, + 0x1f, 0x1f, 0x80, 0x20, 0x74, 0x20, 0x33, 0xd0, 0x97, 0xf4, 0x65, 0xe5, 0x0f, 0x72, 0x9a, 0xf8, + 0x6a, 0x30, 0x93, 0x48, 0x44, 0x87, 0x45, 0x57, 0x15, 0x89, 0x56, 0xf2, 0x61, 0x92, 0xcb, 0x2f, + 0x5b, 0x59, 0x68, 0x27, 0x59, 0x19, 0xe6, 0x3a, 0xb0, 0xdc, 0x57, 0x1e, 0x7c, 0x00, 0x00, 0x3f, + 0x74, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x39, 0xc0, 0xa6, 0x1f, 0xdd, 0xdd, 0xf7, + 0x8b, 0x46, 0x51, 0xe9, 0xbf, 0x18, 0x60, 0x29, 0x50, 0x4f, 0x93, 0x93, 0xcd, 0x14, 0x7b, 0x2a, + 0x53, 0x8f, 0xca, 0x5a, 0xa7, 0xe9, 0xb6, 0xb2, 0xa0, 0x81, 0x52, 0x7a, 0x5d, 0x89, 0xfd, 0xde, + 0x59, 0x8a, 0x16, 0xa5, 0xe5, 0x2c, 0x17, 0xb3, 0x89, 0xde, 0x88, 0x0c, 0xd6, 0xbe, 0x89, 0x47, + 0xdd, 0x4d, 0x03, 0xe0, 0x70, 0xf8, 0xf8, 0x7c, 0x3c, 0x78, 0xf7, 0x83, 0xda, 0x69, 0x3e, 0x11, + 0xbc, 0x3f, 0x2e, 0x0e, 0x4e, 0x55, 0x11, 0xdd, 0x4a, 0xd8, 0xd2, 0xbc, 0xe0, 0x9e, 0x70, 0xf9, + 0x06, 0x5c, 0x0d, 0xe9, 0x1a, 0x5c, 0x8a, 0xfd, 0x5b, 0x53, 0xe8, 0xa7, 0x59, 0x1a, 0x36, 0x3a, + 0xb6, 0xae, 0x86, 0x8b, 0xba, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xaf, 0x71, 0xb2, 0x01, 0x10, 0x2f, 0x58, 0xa8, 0xda, 0xb2, 0x6b, 0xea, 0x17, 0x82, 0x2a, 0xbc, + 0x17, 0x6c, 0xb8, 0xd7, 0x60, 0xec, 0xac, 0x27, 0x51, 0x63, 0xbd, 0x84, 0xe8, 0x16, 0x96, 0xd8, + 0x10, 0x67, 0xce, 0x90, 0xe4, 0x82, 0x54, 0x9c, 0xab, 0x44, 0x53, 0x78, 0x5c, 0xb3, 0x3e, 0x1f, + 0xf6, 0x95, 0x2a, 0x8a, 0x8f, 0xed, 0x7d, 0x66, 0x2a, 0xf5, 0xb8, 0xe3, 0xe1, 0xc7, 0xc7, 0x1f, + 0x1e, 0x1e, 0x38, 0xfe, 0x01, 0x07, 0x40, 0x10, 0x17, 0x93, 0xba, 0x8e, 0x86, 0xb0, 0x0f, 0x29, + 0x1f, 0xd8, 0x67, 0x5b, 0x07, 0xb3, 0x8b, 0x89, 0x4e, 0xbe, 0xde, 0xc6, 0xad, 0xf3, 0x18, 0x25, + 0xdb, 0x53, 0xe8, 0xa7, 0x59, 0x19, 0xf6, 0x3a, 0x69, 0xd4, 0x3d, 0x80, 0x5f, 0x44, 0xf0, 0x1b, + 0x03, 0x78, 0x03, 0xdd, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x9c, 0x1f, 0xba, 0x9f, 0x49, 0x68, + 0x95, 0xbb, 0xa2, 0x6e, 0x80, 0xcc, 0x35, 0xdc, 0xff, 0xc9, 0x1f, 0x10, 0x2c, 0xdc, 0x79, 0x16, + 0x99, 0xef, 0xf3, 0xd4, 0x9a, 0x9a, 0x00, 0x44, 0x82, 0x10, 0x10, 0x24, 0x3a, 0xd1, 0x86, 0x0e, + 0x4b, 0xa7, 0xb0, 0x31, 0x0d, 0xbb, 0x79, 0xd0, 0xc0, 0xe9, 0x30, 0xf2, 0x9f, 0xcc, 0x2a, 0x67, + 0xad, 0xec, 0x1e, 0x0f, 0x81, 0xf1, 0xf8, 0x7c, 0x1c, 0x3c, 0x1e, 0x1f, 0x1c, 0x00, 0x02, 0x87, + 0x80, 0xd1, 0x3c, 0xd8, 0x47, 0xbf, 0xc9, 0xec, 0x76, 0x76, 0xe5, 0xcd, 0x14, 0x99, 0x89, 0xe5, + 0x7a, 0xd2, 0x9b, 0x22, 0xc2, 0xc2, 0x13, 0xc3, 0x4b, 0x53, 0xe8, 0xa7, 0x59, 0x19, 0xe6, 0x32, + 0xaf, 0xa6, 0xca, 0x13, 0x93, 0x00, 0xeb, 0x83, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x03, 0x80, 0x9d, 0xf7, 0xc3, 0x46, 0x0b, 0x53, 0x53, 0x73, 0x89, 0xc2, 0x97, 0x55, + 0x72, 0x5c, 0xff, 0x9a, 0xdc, 0x02, 0xf7, 0xf0, 0xcf, 0x21, 0x75, 0x66, 0xe6, 0x6c, 0x3b, 0xba, + 0x79, 0x7c, 0xcc, 0x09, 0x13, 0xba, 0xb1, 0x7e, 0x92, 0x48, 0x08, 0xfb, 0xcc, 0x16, 0xb3, 0xbf, + 0x95, 0x42, 0x12, 0x23, 0x7b, 0x8b, 0xc4, 0xa1, 0xe7, 0x05, 0x3f, 0xc7, 0x86, 0x1c, 0x3c, 0x7e, + 0x1f, 0x0f, 0x0f, 0x0c, 0x0f, 0x37, 0xcb, 0xcd, 0x3b, 0x4b, 0x74, 0x4e, 0xa6, 0x1f, 0x4b, 0x8a, + 0x9e, 0xfb, 0x19, 0x56, 0xfd, 0xc8, 0x31, 0x86, 0x38, 0xf0, 0x61, 0xef, 0x30, 0x56, 0x57, 0xb9, + 0xcb, 0x53, 0xe8, 0xa7, 0x59, 0x19, 0xf6, 0x3a, 0xaf, 0xa6, 0xc8, 0x17, 0x7f, 0x00, 0x00, 0x00, + 0x00, 0x05, 0x62, 0x75, 0x00, 0x00, 0x69, 0x8c, 0xb5, 0x9f, 0x6d, 0x91, 0x16, 0xec, 0x45, 0x2d, + 0xd7, 0x21, 0x0a, 0xd3, 0x74, 0x15, 0x95, 0x67, 0x89, 0x8f, 0xb7, 0x07, 0x97, 0xb4, 0x98, 0x68, + 0x61, 0xec, 0x05, 0xc5, 0x91, 0x0b, 0x6f, 0x0f, 0xd6, 0x08, 0xbf, 0x6d, 0x57, 0x68, 0xb3, 0x3e, + 0xd6, 0x22, 0x91, 0x89, 0x3d, 0xd3, 0xcf, 0x0f, 0x02, 0x68, 0x0c, 0xc5, 0xd9, 0x61, 0xb5, 0x6c, + 0xa3, 0x68, 0x38, 0xc3, 0xc3, 0x83, 0xe7, 0x83, 0xc3, 0x8c, 0x1d, 0xc9, 0xc7, 0x32, 0x2b, 0x70, + 0x8e, 0x87, 0x12, 0x53, 0x43, 0x41, 0x24, 0xe9, 0x59, 0x03, 0xa3, 0xc4, 0x4b, 0xf9, 0x63, 0xd3, + 0x86, 0x6f, 0x28, 0x60, 0xe1, 0x17, 0xdb, 0x42, 0x0b, 0x53, 0xe8, 0xa7, 0x59, 0x3a, 0x16, 0x0a, + 0xae, 0xec, 0x11, 0x26, 0xb5, 0x00, 0x00, 0x00, 0x00, 0x40, 0x35, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xbc, 0x19, 0x14, 0x6e, 0x12, 0xa1, 0x3a, 0xba, 0x04, 0x5e, 0xea, 0x69, 0x8d, + 0xb1, 0x09, 0xf8, 0xfb, 0x64, 0x6a, 0x78, 0x8d, 0x47, 0x40, 0x96, 0x40, 0xa1, 0x65, 0x8c, 0x09, + 0x2a, 0xa1, 0x36, 0x57, 0x11, 0x6e, 0x99, 0x4b, 0x31, 0x58, 0x23, 0x85, 0x8e, 0x38, 0x0f, 0x57, + 0x47, 0xee, 0x44, 0x32, 0x6f, 0x04, 0x5c, 0xbf, 0xd2, 0xf1, 0xf8, 0x3e, 0x1f, 0x03, 0x87, 0x1e, + 0x1f, 0x07, 0x83, 0x8e, 0x1f, 0xfe, 0xe2, 0x0b, 0xe9, 0x36, 0x03, 0xae, 0x74, 0xa7, 0x7f, 0x11, + 0x66, 0xc6, 0x9a, 0xe9, 0xdc, 0x9c, 0x99, 0xba, 0xd6, 0x42, 0xb8, 0x3a, 0x9e, 0x95, 0xee, 0x41, + 0xcb, 0x53, 0xe8, 0xa7, 0x59, 0x19, 0xf6, 0x3a, 0xb0, 0xd2, 0xbf, 0x90, 0x28, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x01, 0x4f, 0x00, 0x03, 0x1f, 0x9c, 0x00, 0x00, 0x00, 0x24, 0x0d, 0x60, 0x8b, 0x80, + 0x3b, 0x7a, 0x02, 0x8e, 0xea, 0x5e, 0xa6, 0xc9, 0x36, 0x07, 0xac, 0xae, 0x7e, 0x91, 0xd7, 0x6e, + 0xdc, 0xa1, 0x54, 0xc9, 0x75, 0x9c, 0xce, 0x7d, 0x7d, 0x04, 0xc1, 0xd1, 0x71, 0x1c, 0xbf, 0x8c, + 0x27, 0xb8, 0x20, 0xc9, 0xba, 0xa3, 0x8f, 0xfa, 0x44, 0xc3, 0x2f, 0x0a, 0xb3, 0x56, 0xa0, 0xab, + 0x6e, 0x1f, 0xc7, 0x8e, 0x3e, 0x1e, 0xf8, 0xf0, 0xf8, 0x78, 0x70, 0x0f, 0xfe, 0x78, 0x15, 0xb8, + 0xcf, 0x1d, 0xb9, 0x69, 0x24, 0x7a, 0x50, 0x85, 0x62, 0x26, 0xf7, 0x93, 0x2b, 0x00, 0x75, 0x4f, + 0x16, 0xdc, 0x23, 0x06, 0x99, 0xb0, 0x06, 0x1f, 0xdb, 0x53, 0xe8, 0xa7, 0x59, 0x1a, 0x06, 0x32, + 0xaf, 0xde, 0xcb, 0x94, 0xcb, 0x00, 0x12, 0x26, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x28, 0xc0, 0x55, 0xea, 0xd5, 0x22, 0xd8, 0x60, 0xe5, 0xa1, 0xab, 0x14, 0x67, + 0x2f, 0x34, 0x1c, 0x63, 0x68, 0xe1, 0x58, 0x09, 0x83, 0x4d, 0x6d, 0x27, 0xaa, 0xa9, 0x2a, 0x23, + 0x93, 0xea, 0x4e, 0x52, 0x55, 0xd3, 0x9e, 0x04, 0xf0, 0x69, 0xa2, 0x55, 0xa1, 0x20, 0x84, 0xe8, + 0xed, 0x95, 0x73, 0x9a, 0x67, 0x25, 0x84, 0xc8, 0x8e, 0x7e, 0x0f, 0x83, 0xf0, 0x78, 0xf0, 0xf3, + 0xc3, 0xc7, 0x04, 0x1d, 0x3a, 0xbf, 0xfe, 0xcd, 0xd6, 0x67, 0xb0, 0xfb, 0x4b, 0x60, 0x83, 0x17, + 0x32, 0x8f, 0x84, 0xcb, 0xf4, 0xe2, 0xec, 0x57, 0xe9, 0xf4, 0xd9, 0x00, 0x50, 0x34, 0xc4, 0x8f, + 0xeb, 0x53, 0xe8, 0xa7, 0x59, 0x1a, 0x26, 0x32, 0xae, 0xec, 0x11, 0x27, 0x19, 0xd0, 0x62, 0x4b, + 0x9f, 0x92, 0x14, 0xbc, 0x07, 0x1c, 0xcd, 0x60, 0x00, 0x3f, 0x57, 0x72, 0x78, 0xb6, 0x2b, 0xb9, + 0x23, 0xf9, 0xf4, 0x88, 0x94, 0xe5, 0xdd, 0x61, 0xef, 0x21, 0x28, 0x38, 0x79, 0x91, 0x0a, 0xcb, + 0x97, 0xa2, 0x5d, 0xa7, 0x18, 0x3b, 0x3a, 0x52, 0xac, 0xfe, 0xc5, 0x69, 0x48, 0x07, 0xf0, 0xa5, + 0xf4, 0x06, 0xed, 0xbb, 0x6c, 0x5a, 0xae, 0x56, 0x4b, 0x1e, 0xf1, 0x21, 0xc2, 0xf6, 0xb5, 0xc8, + 0xfa, 0x2f, 0xa3, 0x9c, 0xe1, 0xe3, 0xe7, 0xb0, 0xb1, 0x50, 0xdc, 0xe2, 0x49, 0x0b, 0x91, 0x08, + 0xdc, 0x4d, 0x8b, 0xf2, 0xb8, 0x83, 0xcc, 0x45, 0x26, 0xb3, 0xc9, 0x08, 0x1c, 0x71, 0xe9, 0x75, + 0xff, 0x16, 0x10, 0x2e, 0x83, 0x32, 0x45, 0xc4, 0x48, 0x34, 0x8f, 0xe7, 0x79, 0x19, 0xa5, 0xca, + 0x69, 0x22, 0x06, 0xbe, 0xb8, 0x00, 0x00, 0x55, 0x5b, 0xef, 0x00, 0x00, 0x00, 0x65, 0x5b, 0x53, + 0x00, 0x00, 0x00, 0x01, 0xe4, 0x3c, 0x66, 0x44, 0xb7, 0x31, 0x12, 0x8e, 0xf8, 0x46, 0x36, 0x48, + 0xa3, 0x84, 0xae, 0x9a, 0xde, 0xcf, 0xbe, 0x67, 0xa1, 0x24, 0x81, 0xa9, 0x4c, 0xfd, 0x11, 0x1a, + 0xca, 0xbb, 0x75, 0x5e, 0x95, 0x2b, 0xda, 0xc3, 0xd6, 0x2e, 0x7c, 0xc1, 0x9a, 0x98, 0x7a, 0xf9, + 0xe6, 0xb3, 0x4d, 0x7e, 0x50, 0xd3, 0x9c, 0x0e, 0x8d, 0xa1, 0xe2, 0x87, 0xcf, 0xc7, 0xc3, 0xc3, + 0xc0, 0xf0, 0x79, 0xff, 0x33, 0xfa, 0x2b, 0xe2, 0x2e, 0x7c, 0xcd, 0xee, 0x04, 0xd5, 0xae, 0xd3, + 0x49, 0x0a, 0x97, 0x36, 0x42, 0x31, 0xd5, 0xcc, 0xa3, 0xe5, 0x35, 0xcc, 0x6a, 0xe0, 0xfb, 0x61, + 0x5b, 0x53, 0xe8, 0xa7, 0x59, 0x19, 0xe6, 0x22, 0xb0, 0xd2, 0xc2, 0xb5, 0x9b, 0x5e, 0x0d, 0x49, + 0xbb, 0x31, 0x14, 0xd0, 0x16, 0x61, 0xd1, 0x9a, 0x00, 0x16, 0x0e, 0x09, 0x69, 0x56, 0xae, 0x13, + 0x2b, 0x91, 0x7b, 0xe0, 0x64, 0x29, 0xff, 0xfd, 0xdc, 0x02, 0x5e, 0xde, 0xc4, 0x61, 0x77, 0x7b, + 0xe0, 0xe9, 0xcf, 0xeb, 0x5e, 0x2d, 0x46, 0x50, 0x6c, 0xd3, 0x95, 0xd8, 0x14, 0x31, 0xc5, 0x72, + 0xce, 0xc4, 0xde, 0x03, 0x51, 0xb6, 0xd0, 0xd5, 0xc2, 0x7f, 0x5d, 0xa8, 0xcc, 0x34, 0x3c, 0xad, + 0x33, 0x75, 0x5a, 0x65, 0x96, 0x22, 0x18, 0x78, 0xf1, 0x80, 0x42, 0x04, 0xf5, 0x2f, 0x00, 0xda, + 0x4e, 0x5f, 0x29, 0xbb, 0xeb, 0x49, 0x53, 0x4c, 0x90, 0x29, 0x99, 0x37, 0xe0, 0x2c, 0xe3, 0xdc, + 0x40, 0x0a, 0x29, 0xc4, 0x2b, 0x81, 0x1a, 0x64, 0x48, 0x34, 0x8f, 0xe7, 0x79, 0x19, 0xb6, 0x32, + 0x00, 0x00, 0x7b, 0x8a, 0x4f, 0xb1, 0xcd, 0x72, 0xeb, 0x2f, 0x0c, 0x8d, 0x21, 0x4d, 0xce, 0xba, + 0xa1, 0x37, 0x98, 0x35, 0xd6, 0x85, 0xed, 0x39, 0x22, 0x9c, 0x85, 0x49, 0x87, 0x8a, 0xcf, 0x4c, + 0xab, 0x48, 0x69, 0x6b, 0xbc, 0x6a, 0x38, 0x4e, 0xe0, 0x93, 0x9b, 0xe2, 0x8d, 0x23, 0x54, 0x0e, + 0x4b, 0x6f, 0x17, 0x7d, 0x05, 0x5a, 0xc2, 0x02, 0x5a, 0x10, 0x0f, 0x6e, 0xf2, 0x94, 0x81, 0x7a, + 0x99, 0xc7, 0x9b, 0xe5, 0xff, 0xf9, 0xc7, 0x27, 0x37, 0x80, 0x2a, 0x98, 0x98, 0x71, 0xce, 0x07, + 0x0d, 0x5d, 0x01, 0xdf, 0x03, 0x24, 0xc2, 0xd0, 0x47, 0xab, 0x5c, 0xb6, 0x57, 0x2f, 0x08, 0xb8, + 0x6c, 0xbf, 0xef, 0x56, 0x4d, 0x98, 0xc7, 0x1c, 0x78, 0x1f, 0x03, 0xf8, 0x38, 0x3e, 0x11, 0x2a, + 0xc8, 0x34, 0x8f, 0xe7, 0x79, 0x09, 0x95, 0x9a, 0xaf, 0xa6, 0xca, 0xa0, 0xc4, 0x9c, 0x8d, 0xe3, + 0xce, 0xbf, 0xbc, 0x6a, 0x2e, 0xe0, 0xbe, 0xbd, 0xa2, 0x3a, 0x6d, 0x84, 0x19, 0x2d, 0x7e, 0xe4, + 0x7a, 0x69, 0x85, 0x11, 0xc4, 0x7e, 0x27, 0x96, 0x4a, 0x91, 0x96, 0x58, 0x21, 0xa8, 0x30, 0xe8, + 0xd4, 0x07, 0xe5, 0x04, 0x9c, 0x80, 0x4d, 0x07, 0x26, 0x1f, 0xcf, 0x74, 0xc9, 0x1e, 0x0a, 0xf9, + 0xe9, 0x4f, 0x23, 0xd1, 0x6f, 0x46, 0x7f, 0x5a, 0x5a, 0x27, 0x9e, 0x9b, 0x72, 0xca, 0xea, 0x6f, + 0x38, 0x4b, 0x43, 0x70, 0xc3, 0xc3, 0x83, 0xc3, 0x9b, 0x60, 0x7e, 0x06, 0xb3, 0xc4, 0x53, 0x16, + 0x70, 0xf3, 0xb0, 0x8d, 0x02, 0x50, 0x97, 0x83, 0x55, 0x2d, 0x4c, 0xbc, 0xc8, 0x1b, 0x25, 0xb6, + 0xdc, 0x79, 0x75, 0xfc, 0xf3, 0x32, 0xcb, 0x1a, 0x48, 0x34, 0x8f, 0xe7, 0x79, 0x19, 0x75, 0xaa, + 0xb0, 0xd2, 0xbf, 0x90, 0x50, 0xd0, 0xf0, 0x42, 0x44, 0x70, 0x24, 0x60, 0x1a, 0x2c, 0xbd, 0x2a, + 0x5f, 0x4b, 0x37, 0x70, 0x95, 0x79, 0xff, 0x07, 0xad, 0x00, 0x68, 0x44, 0xfe, 0xde, 0x89, 0x98, + 0x3c, 0x3d, 0x96, 0x3c, 0x08, 0x2d, 0x2f, 0xfc, 0xa9, 0xe7, 0xce, 0x1d, 0x91, 0x3e, 0xb1, 0x89, + 0xdc, 0x7d, 0xbd, 0x2f, 0x0d, 0x56, 0x15, 0x6c, 0xde, 0x0e, 0x57, 0x29, 0x67, 0x78, 0x41, 0xfb, + 0xf7, 0x2d, 0xea, 0xab, 0x5f, 0x85, 0xce, 0x39, 0xd1, 0x9d, 0xfb, 0x96, 0xec, 0x70, 0xf8, 0x61, + 0xe1, 0x9d, 0x87, 0xa3, 0x56, 0x63, 0x78, 0x7b, 0x40, 0x6b, 0x5f, 0x1e, 0x7e, 0x33, 0x23, 0x0c, + 0xd9, 0xc4, 0x2d, 0xf2, 0x0d, 0x32, 0x15, 0x7c, 0x10, 0xef, 0xd1, 0x52, 0xd8, 0x22, 0x2b, 0xd7, + 0x48, 0x34, 0x8f, 0xe7, 0x79, 0x19, 0x86, 0x02, 0x00, 0x00, 0x00, 0x5c, 0x4f, 0x5c, 0x9d, 0xdd, + 0x23, 0xea, 0x8f, 0x47, 0xb9, 0xed, 0xc2, 0x20, 0x63, 0x74, 0x8e, 0x6e, 0x88, 0x0f, 0xdf, 0x76, + 0x0a, 0xac, 0x64, 0xc4, 0x55, 0x19, 0x4a, 0xb7, 0x7a, 0xeb, 0xf9, 0xa0, 0xcf, 0x58, 0x59, 0xd6, + 0xe8, 0xc0, 0xee, 0x3b, 0x7e, 0xb1, 0x30, 0x26, 0x9b, 0x33, 0x1a, 0x56, 0xc7, 0x15, 0xe5, 0xa2, + 0x7c, 0xf3, 0x54, 0xff, 0x8f, 0x7a, 0xd6, 0xf0, 0x84, 0x6c, 0xeb, 0xcd, 0xe1, 0x80, 0x5e, 0x45, + 0x8b, 0x8c, 0x2e, 0x9e, 0x71, 0xe3, 0xc3, 0x1f, 0xb2, 0x18, 0x0e, 0x45, 0x1a, 0x22, 0x77, 0xcf, + 0x03, 0x41, 0xd7, 0x84, 0x37, 0x88, 0x4f, 0xf3, 0x87, 0xec, 0x9b, 0xd1, 0x0d, 0x1b, 0xab, 0x01, + 0x8f, 0x81, 0xf8, 0x3f, 0x03, 0xe1, 0xe7, 0x17, 0x48, 0x34, 0x8f, 0xe7, 0x79, 0x09, 0xb5, 0x9a, + 0xae, 0xed, 0x19, 0x12, 0xa7, 0xec, 0xb5, 0x78, 0xea, 0x3c, 0x5f, 0x3c, 0x65, 0x32, 0xc1, 0x96, + 0x17, 0x53, 0xb5, 0x8a, 0xc8, 0xa4, 0xbc, 0x00, 0x16, 0xff, 0x66, 0xad, 0x27, 0x95, 0x20, 0x99, + 0xe4, 0x92, 0x8e, 0x0d, 0x73, 0x94, 0xbe, 0xed, 0x8b, 0xb9, 0x83, 0xa8, 0x30, 0xc6, 0xc3, 0x6e, + 0xb3, 0xa6, 0xe5, 0x1b, 0x7a, 0xd0, 0x90, 0x5a, 0x70, 0x05, 0x7e, 0x13, 0xb0, 0xb5, 0xf4, 0x50, + 0xa3, 0xb3, 0x42, 0x45, 0x57, 0x1f, 0x3c, 0x4d, 0x1b, 0xbd, 0xa8, 0x8c, 0x65, 0xb7, 0x27, 0x07, + 0x07, 0x8f, 0x85, 0x0f, 0x51, 0x5c, 0x2d, 0x32, 0x33, 0x61, 0x39, 0x8b, 0x92, 0x23, 0x9e, 0x2f, + 0xa2, 0x19, 0x4c, 0x65, 0xb1, 0xc5, 0xdb, 0x79, 0x58, 0x18, 0x2a, 0x26, 0x3e, 0x81, 0x44, 0x63, + 0xc8, 0x34, 0x8f, 0xe7, 0x79, 0x19, 0x96, 0x0a, 0x00, 0x00, 0x00, 0x5c, 0x4f, 0x57, 0xe1, 0xe3, + 0xbc, 0x37, 0x2a, 0xaf, 0x44, 0x7a, 0xf6, 0x6e, 0x08, 0x0a, 0x68, 0xf8, 0xea, 0x64, 0x83, 0x2c, + 0xd9, 0xce, 0x39, 0xce, 0xa9, 0x4e, 0xd4, 0xae, 0x45, 0xe9, 0x30, 0xab, 0x44, 0xb3, 0x4e, 0xa0, + 0xde, 0x8c, 0x5b, 0x17, 0x8d, 0xd0, 0xb8, 0xcf, 0x93, 0xd4, 0xa8, 0x7e, 0xbc, 0x40, 0x1c, 0x52, + 0x3b, 0x05, 0x69, 0x0a, 0x0f, 0xba, 0x99, 0xc6, 0x07, 0xce, 0x7a, 0xc5, 0x00, 0x49, 0x8c, 0xf9, + 0x57, 0xce, 0x01, 0x47, 0x1e, 0x38, 0x78, 0xf0, 0x3d, 0xd5, 0x46, 0x8b, 0x19, 0x01, 0xd8, 0xdd, + 0xe5, 0x1a, 0xac, 0x3b, 0xff, 0x51, 0xb2, 0x89, 0x2e, 0x41, 0xfc, 0x4f, 0xdd, 0x9b, 0x88, 0x1c, + 0x3f, 0x01, 0xf8, 0x1e, 0x0f, 0x87, 0x8e, 0x11, 0x48, 0x34, 0x8f, 0xe7, 0x79, 0x09, 0x95, 0xda, + 0xb0, 0xd2, 0xc2, 0xb4, 0xcd, 0x00, 0x67, 0xfa, 0x11, 0xab, 0x00, 0x06, 0x12, 0x0c, 0xca, 0x82, + 0x9f, 0xb2, 0x61, 0x98, 0x46, 0x1f, 0xb7, 0x04, 0x6c, 0x91, 0x49, 0xa9, 0xd4, 0xbe, 0x87, 0xf6, + 0xdd, 0xf6, 0x4c, 0x82, 0x4f, 0x2b, 0xea, 0xbf, 0x67, 0x6b, 0x86, 0x96, 0x4e, 0x33, 0x2a, 0xbb, + 0x52, 0x29, 0x73, 0x7d, 0x2b, 0x2d, 0x15, 0xb3, 0x84, 0x68, 0x93, 0x06, 0x94, 0x0a, 0x05, 0x5f, + 0x8f, 0x9c, 0xd1, 0x77, 0xa1, 0x4f, 0x5c, 0x1d, 0xfd, 0xaf, 0xec, 0x3e, 0x3c, 0x1e, 0x1e, 0x0f, + 0x0d, 0x22, 0xc0, 0x41, 0x0b, 0x7c, 0x0a, 0xc3, 0x3e, 0x29, 0x3e, 0x1b, 0x8e, 0xf8, 0xc0, 0xb0, + 0x66, 0x2e, 0x45, 0xea, 0xea, 0xa3, 0x0a, 0x1a, 0x6b, 0xa3, 0x9b, 0x40, 0x78, 0x48, 0x7a, 0xd7, + 0xd8, 0x34, 0x8f, 0xe7, 0x79, 0x19, 0x85, 0xe2, 0xaf, 0xa6, 0xc8, 0x17, 0x7f, 0x07, 0xd7, 0x80, + 0x85, 0x13, 0x00, 0x01, 0xd1, 0x39, 0x98, 0xdf, 0x2f, 0x6d, 0x9a, 0x18, 0x38, 0xbd, 0xfd, 0x90, + 0xc0, 0xd5, 0x26, 0x43, 0x07, 0x65, 0x0a, 0x21, 0x38, 0x54, 0xe0, 0x51, 0x55, 0x53, 0x11, 0xe7, + 0x46, 0x6c, 0x32, 0x98, 0x69, 0xe2, 0x99, 0x27, 0x20, 0x1d, 0xab, 0x1e, 0x3b, 0x0d, 0x20, 0x08, + 0xaf, 0x40, 0xa3, 0x69, 0x19, 0xb5, 0xa4, 0x97, 0x85, 0xd3, 0xb9, 0x10, 0x45, 0x45, 0x95, 0x76, + 0x55, 0x2d, 0x20, 0xc5, 0x1e, 0x8e, 0x3c, 0x3c, 0x1e, 0x1f, 0x2e, 0xf4, 0x8f, 0x52, 0xf3, 0x11, + 0x12, 0x09, 0x55, 0x8d, 0x65, 0x73, 0x76, 0x12, 0x0a, 0x31, 0x30, 0x99, 0x63, 0x6a, 0x70, 0x82, + 0xda, 0x1b, 0xca, 0xa0, 0xc6, 0x1f, 0x48, 0x30, 0x48, 0x34, 0x8f, 0xe7, 0x79, 0x19, 0x76, 0x3a, + 0xb0, 0xd2, 0xc2, 0xb4, 0xe8, 0x03, 0xc5, 0x58, 0xf9, 0x16, 0x0c, 0x7d, 0x98, 0xd8, 0xc6, 0x8b, + 0x15, 0x7a, 0x10, 0x1e, 0xd9, 0xf5, 0xda, 0x2e, 0x55, 0x0e, 0x00, 0x1e, 0xf8, 0x72, 0x0c, 0xa5, + 0xe0, 0xe7, 0x31, 0x5b, 0xf7, 0xe7, 0x17, 0x85, 0x0f, 0x3c, 0x37, 0x27, 0xff, 0xef, 0x9f, 0xee, + 0xd9, 0xba, 0x49, 0xac, 0xb8, 0xaf, 0x82, 0xc8, 0x3c, 0x3a, 0x40, 0x41, 0xfb, 0x93, 0x48, 0x9a, + 0x75, 0x8c, 0x74, 0x6f, 0xaf, 0xbc, 0x29, 0x1d, 0x0d, 0xa2, 0x17, 0xc2, 0x78, 0xf4, 0xe8, 0x4c, + 0x71, 0xf8, 0x08, 0x01, 0x4b, 0x48, 0x10, 0xb8, 0x82, 0x41, 0xc9, 0x98, 0xca, 0xb5, 0x20, 0x00, + 0x4f, 0x46, 0xed, 0x59, 0x64, 0xfc, 0x57, 0x0a, 0x50, 0xb5, 0x52, 0x7d, 0x46, 0xd1, 0xe2, 0x79, + 0xc9, 0x18, 0x7f, 0xb7, 0x79, 0x19, 0x86, 0x3a, 0xaf, 0xdd, 0x47, 0xaf, 0xd9, 0x97, 0xb6, 0x49, + 0x9c, 0xea, 0x94, 0x11, 0x6e, 0x68, 0xd4, 0xbc, 0x72, 0xbe, 0xc1, 0xe3, 0xbe, 0xfe, 0x53, 0x05, + 0x2b, 0x0f, 0x14, 0x1f, 0xa1, 0xcd, 0x19, 0xfd, 0x44, 0x78, 0x5d, 0x0e, 0xb6, 0x7a, 0x0b, 0x07, + 0xbf, 0xae, 0x97, 0x1c, 0x4f, 0x97, 0xa1, 0x92, 0xcb, 0x5a, 0xea, 0x36, 0xc3, 0xdf, 0x33, 0x5c, + 0x12, 0xc9, 0x14, 0x25, 0x7b, 0x9a, 0x35, 0xea, 0x63, 0x00, 0xa4, 0x6e, 0x9d, 0x7c, 0x14, 0x25, + 0xe2, 0x9e, 0x43, 0x5f, 0xca, 0x8c, 0x78, 0x7c, 0x3e, 0x3e, 0x1e, 0x62, 0x7f, 0x36, 0x1b, 0xb5, + 0x3e, 0x9e, 0x03, 0xce, 0x27, 0x63, 0xca, 0x5a, 0xd5, 0x4d, 0x72, 0x6b, 0x4f, 0xfb, 0xa1, 0xf2, + 0xc2, 0x65, 0x11, 0x02, 0x41, 0x87, 0x90, 0xc6, 0x48, 0x34, 0x8f, 0xe7, 0x79, 0x19, 0x96, 0x12, + 0xaf, 0xa6, 0xca, 0xa0, 0xd1, 0x87, 0xbe, 0x89, 0xd0, 0xce, 0x85, 0x59, 0x7a, 0x65, 0x23, 0x50, + 0xc8, 0x53, 0x5c, 0xd8, 0x14, 0x4f, 0x2e, 0xb5, 0x66, 0x49, 0x0f, 0x52, 0x12, 0x21, 0xfb, 0x7f, + 0x6d, 0xa6, 0x80, 0x20, 0x95, 0x30, 0xdc, 0xfc, 0xee, 0x23, 0xd5, 0x30, 0xa7, 0x9e, 0x11, 0x2b, + 0x52, 0xf2, 0x3e, 0x5b, 0x9e, 0xeb, 0x6b, 0xa0, 0x5f, 0x15, 0x68, 0x8e, 0xe9, 0x78, 0x59, 0xd9, + 0xe6, 0xc9, 0x05, 0x0d, 0x73, 0x26, 0xf8, 0x3b, 0x34, 0x2f, 0x1f, 0x91, 0x9e, 0x99, 0x63, 0x8c, + 0x33, 0xf4, 0x84, 0x0e, 0x27, 0x25, 0xb6, 0x1b, 0x98, 0x0e, 0xee, 0xcf, 0xd8, 0x15, 0xd5, 0xaa, + 0xd9, 0xbf, 0x82, 0xfb, 0x5a, 0x91, 0x4c, 0xa3, 0x6b, 0x4a, 0x17, 0x07, 0x99, 0xcc, 0x7a, 0x01, + 0xd9, 0x18, 0x7f, 0xb7, 0x79, 0x19, 0x96, 0x2a, 0xb6, 0xba, 0x94, 0x47, 0x96, 0x0a, 0x24, 0x0e, + 0x1d, 0x13, 0x4c, 0xd0, 0x98, 0x46, 0x8e, 0xe9, 0x00, 0x09, 0xa0, 0x5f, 0x54, 0x00, 0x0a, 0x27, + 0xd9, 0x45, 0xcf, 0xcf, 0x1a, 0xb1, 0xb9, 0x23, 0xd3, 0x8f, 0x2b, 0xa0, 0x6c, 0xf0, 0x94, 0xc5, + 0xec, 0xa0, 0x25, 0x4c, 0x03, 0x95, 0x9a, 0xb0, 0xe8, 0x17, 0x31, 0xcc, 0x58, 0xae, 0x26, 0xd5, + 0x19, 0x74, 0xd0, 0x5d, 0x2a, 0xcf, 0x73, 0xb2, 0xd0, 0xf2, 0x0e, 0x6e, 0x20, 0xef, 0xb2, 0x5d, + 0x74, 0xc2, 0x33, 0x9d, 0x8c, 0xe3, 0x8f, 0x1e, 0x0f, 0x0f, 0x87, 0x9c, 0x5a, 0x72, 0x8c, 0x3d, + 0x84, 0x9d, 0x8c, 0xf9, 0x92, 0x6a, 0x27, 0x11, 0xb6, 0x7c, 0x1f, 0x5c, 0x20, 0xa5, 0x31, 0x10, + 0x53, 0xfa, 0x70, 0xc1, 0x57, 0x77, 0x41, 0x9c, 0xd8, 0x34, 0x8f, 0xe7, 0x79, 0x19, 0x95, 0xf2, + 0xae, 0xec, 0x0f, 0xb3, 0x25, 0xd2, 0x48, 0x45, 0xcc, 0x96, 0x18, 0x73, 0x3f, 0x05, 0xf8, 0xf1, + 0x77, 0x06, 0xb8, 0x84, 0x9f, 0x94, 0x3a, 0x01, 0x59, 0xef, 0x5e, 0x07, 0xb8, 0x44, 0x7c, 0xb5, + 0x08, 0xdd, 0xae, 0x57, 0x5b, 0x81, 0x1a, 0xc7, 0x62, 0x6c, 0xf9, 0x0a, 0x4a, 0xb6, 0xf3, 0x44, + 0x11, 0x93, 0xb8, 0x1e, 0xb8, 0xa9, 0x4f, 0xbc, 0x79, 0xf6, 0x95, 0xfd, 0xfb, 0xf3, 0x57, 0x4b, + 0xb9, 0xe9, 0xb5, 0xcd, 0x8d, 0xd4, 0x39, 0x21, 0x88, 0x43, 0xda, 0x37, 0xb8, 0x78, 0xfc, 0x1e, + 0x0f, 0x87, 0x04, 0x2d, 0x7e, 0xf0, 0xad, 0x32, 0xd2, 0xef, 0x5c, 0xa7, 0xd6, 0x56, 0x84, 0xcc, + 0xbc, 0x3b, 0x95, 0x32, 0x8b, 0xaa, 0x20, 0xb2, 0x89, 0x90, 0x61, 0x00, 0xc9, 0xe9, 0xe9, 0x42, + 0xc8, 0x34, 0x8f, 0xe7, 0x79, 0x39, 0x86, 0x0a, 0xaf, 0xdd, 0x49, 0x47, 0x93, 0x57, 0xb2, 0x73, + 0x98, 0x0a, 0x4a, 0x00, 0x02, 0xdc, 0x10, 0x12, 0x0d, 0xa8, 0x69, 0xb4, 0xff, 0xbb, 0xd4, 0x79, + 0x00, 0x10, 0x9a, 0xd9, 0x29, 0x03, 0x07, 0x8d, 0xe2, 0xeb, 0x51, 0x78, 0xff, 0x8f, 0xde, 0x43, + 0xb8, 0x6b, 0x59, 0xf8, 0xa5, 0x52, 0x56, 0x92, 0xa2, 0x86, 0xb2, 0x2d, 0x49, 0xf6, 0x12, 0x4b, + 0x9a, 0xf3, 0x65, 0x5c, 0xb3, 0x2c, 0xc1, 0x2f, 0x02, 0x43, 0x35, 0xe5, 0xab, 0x9b, 0xa6, 0x19, + 0xf3, 0xd4, 0x73, 0xc1, 0x83, 0x07, 0x1c, 0xc5, 0xb7, 0x8f, 0x20, 0xc2, 0xa4, 0x18, 0x21, 0x83, + 0xc0, 0x58, 0xea, 0xb3, 0xcf, 0x90, 0x80, 0x92, 0x34, 0xd0, 0xc6, 0x2f, 0x39, 0x13, 0xbf, 0x92, + 0xbd, 0x02, 0x92, 0x14, 0x88, 0x75, 0x17, 0x8f, 0x58, 0x31, 0x9e, 0xe7, 0x79, 0x19, 0x96, 0x32, + 0x00, 0x00, 0x00, 0x17, 0xce, 0xd6, 0x4b, 0x99, 0x74, 0x49, 0x5b, 0xfd, 0x44, 0xe4, 0xd0, 0xf0, + 0x28, 0x47, 0x5e, 0xff, 0x1b, 0xc0, 0xe7, 0x04, 0x71, 0x3d, 0x0d, 0xd6, 0xca, 0x4c, 0x60, 0xc4, + 0x25, 0xe3, 0xef, 0x6b, 0xc8, 0x44, 0xdf, 0x67, 0xf4, 0xa2, 0x3c, 0x99, 0xf2, 0xeb, 0x63, 0x2b, + 0x4f, 0x57, 0xb0, 0xb4, 0xd3, 0x15, 0x11, 0xd9, 0x4a, 0x4d, 0xe0, 0xfc, 0x8d, 0x7e, 0xbb, 0xdf, + 0x51, 0x9b, 0xd6, 0x78, 0x46, 0x08, 0x84, 0x21, 0x19, 0x9a, 0x9e, 0x1c, 0x26, 0x98, 0x45, 0xfa, + 0x96, 0xd6, 0xe3, 0xe3, 0x86, 0x79, 0x95, 0xa4, 0x90, 0x73, 0xe5, 0x0c, 0x93, 0xed, 0x60, 0x04, + 0x16, 0x48, 0x1c, 0x2d, 0xe0, 0xf3, 0x18, 0x2f, 0xc9, 0x87, 0x8f, 0x0f, 0x0e, 0x0e, 0x35, 0x04, + 0x0a, 0xa2, 0x25, 0xbe, 0x79, 0x29, 0xd6, 0x22, 0xaf, 0xdd, 0x49, 0xd0, 0x01, 0x07, 0x26, 0x24, + 0x1a, 0x30, 0xf7, 0x6a, 0x7c, 0x6d, 0x9b, 0x33, 0x48, 0x02, 0x8d, 0x03, 0x92, 0x80, 0x00, 0x00, + 0x00, 0x9b, 0x5f, 0x92, 0xdf, 0x60, 0x50, 0x67, 0x44, 0xa0, 0xed, 0xb2, 0xaa, 0xdf, 0x6f, 0xfc, + 0x8d, 0x08, 0xfb, 0xb1, 0x55, 0x21, 0x9c, 0x5d, 0x89, 0xc5, 0x0f, 0x69, 0x54, 0xaa, 0x9b, 0x7c, + 0x6e, 0x86, 0x21, 0x29, 0xb8, 0x84, 0xa3, 0xd5, 0x82, 0x0b, 0xdc, 0xe0, 0x0f, 0xa8, 0x5e, 0x5d, + 0x77, 0xdb, 0x0f, 0x83, 0x83, 0xc3, 0x8c, 0x27, 0x38, 0x79, 0x87, 0x31, 0x4c, 0xcc, 0xa5, 0x12, + 0x52, 0x98, 0x6b, 0x9b, 0x18, 0x09, 0x51, 0x91, 0x73, 0x8f, 0x76, 0xe2, 0x04, 0x4c, 0x4c, 0x19, + 0xc5, 0x7b, 0xd6, 0x24, 0x31, 0x97, 0xf9, 0x53, 0x4a, 0xa2, 0x25, 0xbe, 0x79, 0x39, 0xb6, 0x22, + 0xaf, 0xdd, 0x47, 0x5c, 0xd4, 0x87, 0xe9, 0x38, 0x67, 0x02, 0xb6, 0xd5, 0x9e, 0x32, 0x3e, 0x50, + 0x4e, 0x41, 0x80, 0xeb, 0x01, 0x11, 0x93, 0x00, 0x00, 0xc1, 0x6f, 0x39, 0x60, 0x40, 0xe1, 0x8f, + 0xe0, 0xde, 0x4a, 0x1c, 0x46, 0x43, 0x6c, 0xd0, 0x4d, 0x6f, 0x87, 0xfd, 0x26, 0xc9, 0xac, 0xef, + 0x65, 0x1f, 0x08, 0xd4, 0x2d, 0xe3, 0xbb, 0x95, 0x06, 0x98, 0x02, 0x6f, 0xc3, 0x4b, 0x70, 0xb5, + 0xd4, 0x1d, 0xcc, 0x12, 0x9e, 0xd0, 0x4b, 0xc0, 0x83, 0x5e, 0x5c, 0x43, 0xe0, 0x61, 0xfc, 0x70, + 0x85, 0xb9, 0xe1, 0xce, 0x81, 0x81, 0x74, 0x0f, 0x71, 0x24, 0x04, 0xe7, 0x0b, 0x3d, 0x89, 0x87, + 0x1f, 0x22, 0x73, 0xef, 0x71, 0xca, 0x0e, 0xac, 0x13, 0x9a, 0xab, 0x6f, 0x08, 0x10, 0x58, 0x63, + 0xda, 0xa2, 0x25, 0xbe, 0x79, 0x19, 0xb6, 0x2a, 0xaf, 0xde, 0xcb, 0xf9, 0xda, 0x75, 0x22, 0xeb, + 0x42, 0x79, 0x4d, 0xf9, 0x26, 0x61, 0xa1, 0xde, 0x6f, 0x04, 0x69, 0x01, 0x56, 0x71, 0x00, 0x00, + 0x00, 0xc9, 0x21, 0xc5, 0x11, 0x2d, 0x68, 0xb3, 0x00, 0x0d, 0x1b, 0x31, 0x17, 0xa5, 0x05, 0x0b, + 0x0c, 0x4a, 0x5e, 0x20, 0xbf, 0x2c, 0x0d, 0x5c, 0x6c, 0x89, 0x64, 0x68, 0xe2, 0xcd, 0x31, 0xb3, + 0x25, 0x74, 0x83, 0x25, 0x47, 0x80, 0xba, 0x98, 0xa2, 0xaa, 0x5c, 0x20, 0x84, 0x5d, 0x84, 0x77, + 0xa6, 0x57, 0x5f, 0xc0, 0x7e, 0x0f, 0xc0, 0xf0, 0xf1, 0xf9, 0x1c, 0x78, 0x25, 0xe7, 0xf6, 0xbe, + 0x41, 0x60, 0x4b, 0x07, 0xd9, 0x03, 0x1a, 0x7a, 0xfa, 0xc9, 0x8c, 0x49, 0x67, 0x61, 0x68, 0xbe, + 0x6b, 0x94, 0x67, 0xce, 0x01, 0x7f, 0xbd, 0x03, 0xda, 0xa2, 0x25, 0xbe, 0x79, 0x19, 0xb6, 0x32, + 0xb6, 0xae, 0x86, 0x8b, 0xf6, 0x97, 0xbd, 0x1d, 0x21, 0x8d, 0xd3, 0xc1, 0x14, 0xa5, 0xb4, 0x74, + 0xcb, 0x2c, 0x68, 0x95, 0x58, 0x6e, 0x9d, 0xd8, 0x67, 0xd7, 0x00, 0x28, 0x59, 0xe1, 0x22, 0x0f, + 0x08, 0x16, 0x8c, 0xbc, 0x39, 0x08, 0xc8, 0xf2, 0xd5, 0x63, 0x96, 0x2a, 0x4d, 0xe4, 0xb8, 0x45, + 0x8d, 0xe0, 0xe6, 0x7e, 0x09, 0xe7, 0xba, 0xdb, 0x8c, 0x84, 0x06, 0xd1, 0xa0, 0xcf, 0x15, 0xd8, + 0xe6, 0x6e, 0x30, 0x2c, 0xf3, 0x92, 0xe8, 0x69, 0xbf, 0xdb, 0xe0, 0xe2, 0x18, 0xe5, 0x38, 0x7c, + 0x70, 0x58, 0xab, 0x5a, 0xb3, 0x41, 0xa2, 0x39, 0x1d, 0xe8, 0x60, 0x13, 0x37, 0xa0, 0xea, 0x94, + 0xa9, 0x3f, 0xc2, 0xa8, 0x02, 0xa8, 0xc9, 0xc9, 0x5b, 0x82, 0x58, 0xa0, 0x7e, 0x58, 0xc0, 0xbc, + 0xda, 0xa2, 0x25, 0xbe, 0x79, 0x19, 0x85, 0xe2, 0x33, 0xd8, 0x04, 0x09, 0x22, 0xac, 0x4b, 0x30, + 0x26, 0xa5, 0xce, 0x2b, 0x8b, 0xe4, 0xdd, 0x49, 0xde, 0xf3, 0x71, 0xdb, 0x41, 0x0b, 0x9c, 0x9e, + 0x37, 0x87, 0x37, 0x00, 0x30, 0x51, 0x30, 0xf8, 0x07, 0x9d, 0xd5, 0xaf, 0x2d, 0xa0, 0x72, 0x91, + 0xf5, 0xf6, 0xff, 0x28, 0xe7, 0x8c, 0x19, 0x61, 0xc9, 0x90, 0x69, 0xd0, 0xb6, 0x18, 0x57, 0x2b, + 0xbb, 0x7d, 0x94, 0xbd, 0xbb, 0x1b, 0xd1, 0xf3, 0xe2, 0x7b, 0x00, 0x00, 0x00, 0x5e, 0xb5, 0x7d, + 0x88, 0x13, 0x70, 0x37, 0xc7, 0x09, 0xf1, 0xff, 0x00, 0xf4, 0xda, 0xfd, 0xf8, 0xc8, 0xeb, 0x4e, + 0x20, 0x64, 0x24, 0xe8, 0x83, 0x33, 0xdd, 0x21, 0xf1, 0x98, 0xa9, 0x4a, 0x2a, 0x22, 0x38, 0xd0, + 0x50, 0x44, 0x3e, 0x12, 0x97, 0xf5, 0x0a, 0x4f, 0xb5, 0x45, 0x00, 0xbc, 0xf2, 0x39, 0x96, 0x24, + 0xb6, 0xaf, 0xa6, 0xf9, 0xcd, 0x37, 0xd5, 0x1c, 0x78, 0xf8, 0x77, 0x78, 0xdd, 0x48, 0x14, 0x86, + 0x42, 0xb8, 0xa5, 0x3f, 0x61, 0x53, 0x26, 0x14, 0x48, 0x00, 0x3a, 0x99, 0xa8, 0xc0, 0x35, 0x0d, + 0x65, 0x76, 0x0d, 0x54, 0x20, 0x78, 0x1f, 0xf5, 0x28, 0xdd, 0x90, 0x38, 0xb0, 0xae, 0x63, 0xe6, + 0x31, 0x7b, 0xd9, 0x68, 0x06, 0x49, 0x53, 0xda, 0x75, 0x93, 0x00, 0x15, 0x70, 0x7f, 0xa1, 0x2f, + 0x4d, 0xf6, 0xb4, 0x42, 0x29, 0xfd, 0xfd, 0xa7, 0x50, 0xf9, 0x4e, 0xb1, 0x67, 0x06, 0x3c, 0xc0, + 0x6f, 0x38, 0x79, 0x0b, 0x3e, 0x0e, 0x94, 0x82, 0x42, 0x70, 0x9a, 0xc5, 0x1b, 0x63, 0x61, 0x3e, + 0x4b, 0xb3, 0x17, 0xbb, 0x40, 0x09, 0x2a, 0xff, 0x7e, 0xe5, 0x44, 0xdf, 0x48, 0x4a, 0x75, 0x8b, + 0x5a, 0xa2, 0x80, 0x5e, 0x79, 0x19, 0x96, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x28, 0x6d, 0x73, 0x7c, + 0x9f, 0x67, 0xa0, 0xef, 0xa0, 0xa7, 0xeb, 0xe2, 0xe1, 0x85, 0x96, 0x6a, 0xe4, 0x5b, 0xa3, 0xc6, + 0x67, 0x86, 0xd3, 0x74, 0x6c, 0x13, 0xb2, 0x27, 0x47, 0x70, 0x4c, 0x11, 0x7f, 0x31, 0xa6, 0xc0, + 0x2d, 0x9f, 0xc1, 0x91, 0x91, 0x1b, 0xa9, 0xb6, 0xee, 0x29, 0x8d, 0x51, 0xbf, 0xab, 0xad, 0xed, + 0x28, 0x95, 0xf9, 0x44, 0x3d, 0x92, 0x01, 0x45, 0x09, 0x32, 0xb3, 0x82, 0x55, 0xf4, 0x7b, 0x46, + 0x43, 0x48, 0xac, 0x84, 0xd9, 0x86, 0xd3, 0x0f, 0xc2, 0xa5, 0x42, 0x20, 0x89, 0x96, 0x99, 0xba, + 0xe6, 0x22, 0x7b, 0x43, 0x99, 0xa0, 0x7a, 0xce, 0x14, 0x67, 0x08, 0x47, 0x76, 0xe0, 0xf9, 0x4d, + 0xd4, 0x42, 0xd1, 0xe0, 0xf0, 0x78, 0x71, 0xb6, 0x3a, 0xa2, 0x80, 0x5e, 0x79, 0x09, 0xc6, 0x22, + 0x35, 0x16, 0xd8, 0x03, 0xc2, 0xd2, 0x32, 0x65, 0x0f, 0x49, 0xb5, 0x22, 0x2f, 0x98, 0x3e, 0x96, + 0x6b, 0x25, 0xef, 0xf6, 0x08, 0x01, 0xc4, 0xf3, 0xf1, 0xf2, 0x31, 0xf1, 0xa5, 0x00, 0x3b, 0x24, + 0x7d, 0x52, 0x00, 0xe5, 0x7e, 0xbe, 0xb5, 0x73, 0xf3, 0xe8, 0x4b, 0xbf, 0x91, 0xf5, 0x54, 0x7f, + 0x21, 0x72, 0x51, 0xd8, 0xe1, 0x31, 0xa6, 0x40, 0x8a, 0xcc, 0x5f, 0xfb, 0x40, 0x94, 0x61, 0x54, + 0x7d, 0x74, 0x71, 0x5e, 0xc4, 0x00, 0x10, 0x92, 0x02, 0x93, 0x30, 0x37, 0x6f, 0xac, 0xf4, 0xad, + 0xe6, 0x90, 0xc0, 0x9c, 0x32, 0xc4, 0x42, 0x2b, 0x38, 0x99, 0x1c, 0x60, 0xa8, 0x5e, 0x49, 0xb0, + 0x0f, 0x27, 0xab, 0x4c, 0x98, 0x81, 0x8e, 0x77, 0x3b, 0xd3, 0x1c, 0xb4, 0xfd, 0x1f, 0x3a, 0xa7, + 0x95, 0x45, 0x00, 0xbc, 0xf2, 0x39, 0x65, 0x94, 0x33, 0x99, 0xa3, 0x6b, 0xc6, 0x11, 0xc8, 0xea, + 0xb8, 0x61, 0x56, 0x62, 0x54, 0xef, 0x09, 0xac, 0xa7, 0x9c, 0xad, 0x88, 0x72, 0xaf, 0xf2, 0xa8, + 0x81, 0x9f, 0x94, 0x00, 0x00, 0x02, 0xf0, 0xb9, 0xf9, 0xc6, 0xf8, 0x3d, 0x1a, 0x27, 0x3f, 0xf5, + 0xb9, 0xac, 0x99, 0xf8, 0x85, 0x99, 0xcf, 0x49, 0x9f, 0xaf, 0x12, 0x30, 0x09, 0xfe, 0xd0, 0xbd, + 0x86, 0x1a, 0xac, 0xfa, 0xbb, 0x6a, 0x66, 0x24, 0xed, 0x00, 0x00, 0x03, 0x54, 0xca, 0x7c, 0x4a, + 0xfa, 0xe6, 0xc8, 0x40, 0x26, 0x05, 0x34, 0x56, 0x3b, 0x79, 0x50, 0xcf, 0x27, 0x43, 0x18, 0xb1, + 0xc0, 0x8a, 0xf1, 0x82, 0x94, 0x12, 0x71, 0xba, 0x16, 0x61, 0x76, 0x5c, 0x54, 0x36, 0x73, 0xc6, + 0x31, 0x89, 0x38, 0x20, 0x3f, 0x47, 0x1b, 0xb1, 0xa7, 0x98, 0x05, 0x3c, 0xf2, 0x39, 0x76, 0x2c, + 0xa7, 0x93, 0xb3, 0x3a, 0x0e, 0xd7, 0x1c, 0x1f, 0xf4, 0x4b, 0x21, 0xd0, 0xc4, 0xe0, 0xcc, 0xef, + 0x91, 0x75, 0x3d, 0xa5, 0xb0, 0x40, 0xb3, 0xb9, 0x31, 0x00, 0x6e, 0x00, 0x00, 0x0d, 0x11, 0x8c, + 0xe6, 0x15, 0x6c, 0xb2, 0x90, 0x0e, 0xe8, 0xdc, 0xce, 0xd0, 0x62, 0xb0, 0x91, 0xbe, 0x4b, 0xbd, + 0x94, 0x45, 0x10, 0xa5, 0x09, 0x1f, 0x7f, 0x18, 0xbe, 0xf9, 0xc8, 0x0d, 0x8d, 0xd5, 0xf1, 0x5d, + 0x99, 0x2b, 0xb7, 0xa7, 0x00, 0x00, 0x00, 0xd8, 0x5e, 0x54, 0x19, 0xb5, 0xff, 0x6d, 0x16, 0xdd, + 0xfa, 0xf5, 0x7d, 0x1d, 0xbe, 0x3e, 0x7d, 0x91, 0xd9, 0xaa, 0x2a, 0xcd, 0xe0, 0x6a, 0x90, 0x8b, + 0xc8, 0x0c, 0xad, 0x60, 0xde, 0x00, 0xfd, 0xb4, 0x1c, 0x57, 0xe0, 0x1b, 0x7f, 0x56, 0x68, 0xd6, + 0x87, 0x98, 0x05, 0x3c, 0xf2, 0x39, 0x85, 0xcc, 0x33, 0xd3, 0x9e, 0x22, 0x68, 0x6b, 0xaf, 0xd6, + 0xa4, 0x58, 0xc7, 0xa3, 0xf3, 0x00, 0xe2, 0x5c, 0xf3, 0xf6, 0xdb, 0x75, 0xba, 0x17, 0xd3, 0xc1, + 0xaf, 0x7f, 0x00, 0x00, 0x00, 0x43, 0x84, 0xe7, 0xfc, 0x20, 0xd6, 0xee, 0xb0, 0xb9, 0xed, 0x0a, + 0xf0, 0xde, 0x63, 0x4a, 0xa1, 0x5a, 0x58, 0x07, 0xb1, 0x38, 0x42, 0x56, 0x56, 0xf7, 0xaa, 0x64, + 0x84, 0xab, 0x74, 0xc9, 0xc4, 0xa0, 0x09, 0xdd, 0x00, 0x00, 0x00, 0x03, 0x0d, 0x63, 0x4e, 0xbe, + 0xce, 0x98, 0xb5, 0x50, 0xae, 0x78, 0xc0, 0xb0, 0x5c, 0x0f, 0xca, 0x14, 0x15, 0x68, 0x01, 0x1f, + 0xc6, 0x0d, 0x51, 0x5f, 0x40, 0xe1, 0x48, 0xed, 0x2d, 0xe4, 0x64, 0xd2, 0x7e, 0x16, 0x99, 0x89, + 0x75, 0x25, 0x63, 0x66, 0x12, 0x08, 0xb4, 0x51, 0xa7, 0x98, 0x05, 0x3c, 0xf2, 0x39, 0xa6, 0x24, + 0x33, 0x99, 0xa3, 0x6b, 0xc6, 0x40, 0x4e, 0xf2, 0x28, 0x89, 0x9e, 0x2b, 0x8a, 0x6f, 0xe1, 0x1e, + 0x33, 0x5a, 0x70, 0x73, 0xb0, 0x05, 0xc7, 0xcc, 0xb7, 0x27, 0x00, 0x00, 0x00, 0x0b, 0x3f, 0x43, + 0x7c, 0xa0, 0x5d, 0x2e, 0x1f, 0x82, 0x46, 0x80, 0x39, 0xe0, 0xf3, 0x1a, 0x5f, 0x44, 0xc2, 0x81, + 0x92, 0xb1, 0xa3, 0xf6, 0x56, 0x71, 0x57, 0xf5, 0x30, 0xa1, 0x39, 0x74, 0xbb, 0x23, 0xd9, 0x1d, + 0x5c, 0x49, 0x00, 0x4b, 0xee, 0x8c, 0x85, 0xe2, 0x4c, 0x03, 0x1d, 0x7c, 0xc1, 0x88, 0x32, 0x63, + 0x36, 0xec, 0x9a, 0x8c, 0x20, 0xdc, 0xe8, 0x9c, 0x7d, 0x11, 0x80, 0xda, 0x23, 0xe6, 0x41, 0xfa, + 0x0c, 0x27, 0xa9, 0xb4, 0x8a, 0x26, 0xa9, 0x3c, 0x0b, 0x78, 0x4b, 0xc4, 0x84, 0xa2, 0x32, 0x83, + 0xa7, 0x98, 0x05, 0x3c, 0xf2, 0x39, 0x96, 0x14, 0xa8, 0x0a, 0x97, 0xaf, 0xfe, 0xac, 0xa6, 0x0a, + 0xe1, 0x39, 0xca, 0xb8, 0x3a, 0x4f, 0x2b, 0xe3, 0x36, 0x00, 0x10, 0xcb, 0x27, 0xd9, 0xe2, 0x7c, + 0x79, 0xd0, 0x00, 0x00, 0x04, 0x7c, 0xe0, 0x82, 0xcc, 0x6e, 0x97, 0x2d, 0x88, 0x6e, 0x5b, 0xbd, + 0x20, 0x79, 0x51, 0xc5, 0x6f, 0xff, 0xad, 0xde, 0x5f, 0x02, 0x72, 0x31, 0x96, 0x2a, 0x7c, 0xaa, + 0x94, 0x32, 0x5c, 0xae, 0xa5, 0x49, 0x0b, 0x84, 0x0a, 0x00, 0x1d, 0xbc, 0x9d, 0x0f, 0x9e, 0xa3, + 0x1a, 0xe5, 0xe6, 0x00, 0xc0, 0xf2, 0xb6, 0x6e, 0x9e, 0xf5, 0x6b, 0x0c, 0xfd, 0x92, 0x6c, 0x01, + 0x87, 0xc8, 0x1f, 0xb3, 0x10, 0x81, 0x64, 0xb9, 0xb3, 0x71, 0xa5, 0x36, 0x42, 0x27, 0xdb, 0x79, + 0x41, 0x84, 0x07, 0x08, 0x49, 0xf5, 0x38, 0xae, 0xa7, 0x98, 0x05, 0x3c, 0xf2, 0x39, 0x96, 0x3c, + 0xae, 0xf1, 0x98, 0x15, 0x69, 0xd4, 0x07, 0x00, 0x00, 0x29, 0xde, 0xff, 0x8b, 0xc6, 0x7b, 0x35, + 0xf8, 0x26, 0x07, 0x42, 0xe9, 0x0e, 0xf2, 0x5a, 0xdb, 0x75, 0xd8, 0xbd, 0x00, 0x21, 0xce, 0x65, + 0x8f, 0x1a, 0x4c, 0xfb, 0xcf, 0xaf, 0xba, 0x6d, 0xc4, 0x98, 0x48, 0xd8, 0xa8, 0xf5, 0x3a, 0xbe, + 0x01, 0xb6, 0x93, 0x98, 0x34, 0xae, 0x75, 0x79, 0x26, 0xa4, 0x44, 0xf1, 0x17, 0x4a, 0x2c, 0x6e, + 0x05, 0x29, 0x36, 0x4d, 0xe5, 0x23, 0xb9, 0xff, 0x5b, 0xa2, 0xcc, 0xfe, 0x06, 0x71, 0x48, 0x46, + 0x66, 0xae, 0x88, 0x67, 0x87, 0xa3, 0xd0, 0xb8, 0x67, 0xfa, 0x6f, 0x3a, 0xa2, 0x85, 0xa5, 0xa3, + 0xd5, 0xa5, 0x28, 0x10, 0xe3, 0xed, 0x5b, 0x11, 0x63, 0xa0, 0xb8, 0x1f, 0x1f, 0xdb, 0x47, 0x2c, + 0xa7, 0x98, 0x05, 0x3c, 0xf2, 0x39, 0x66, 0x3c, 0x33, 0xd3, 0xb5, 0xb8, 0x9d, 0xe5, 0x92, 0xaa, + 0x00, 0x2a, 0x00, 0x06, 0x30, 0x9a, 0x3d, 0x97, 0xe8, 0x11, 0x6f, 0x8f, 0xeb, 0x98, 0xa1, 0xc5, + 0x00, 0x00, 0x00, 0xcc, 0x4d, 0x31, 0x19, 0xf2, 0x0a, 0x32, 0x12, 0x5e, 0xce, 0x61, 0xb6, 0x12, + 0xbd, 0xb0, 0xf3, 0xc6, 0xd2, 0xe9, 0x3c, 0xa0, 0x40, 0x98, 0x33, 0x39, 0x4f, 0xf4, 0x5c, 0xdd, + 0x5b, 0x17, 0x1e, 0x26, 0xe1, 0x15, 0xb2, 0xff, 0x2c, 0x00, 0x46, 0xe4, 0xc4, 0xe2, 0x07, 0x2e, + 0x4e, 0xbf, 0x0d, 0xc0, 0x7f, 0xde, 0x73, 0xc6, 0xb4, 0xb8, 0x04, 0xde, 0xb8, 0x16, 0xdb, 0x9e, + 0xa1, 0xa5, 0xd1, 0x25, 0x5b, 0x50, 0x0d, 0xf1, 0x4f, 0xc2, 0xd6, 0xc9, 0x83, 0x58, 0x18, 0x4d, + 0x26, 0x19, 0x1c, 0xa8, 0x0e, 0xd7, 0xcd, 0x38, 0xa7, 0x98, 0x05, 0x3c, 0xf2, 0x39, 0x96, 0x1c, + 0x33, 0xd2, 0xc1, 0x91, 0x36, 0x06, 0x73, 0x74, 0x55, 0x63, 0x0f, 0x0d, 0xc6, 0xc5, 0x37, 0x32, + 0x23, 0x57, 0xa2, 0x52, 0x26, 0xe6, 0x0e, 0x44, 0xbd, 0xf7, 0xe2, 0x00, 0x01, 0x2f, 0x59, 0xed, + 0xea, 0x0b, 0xd5, 0xe1, 0x8c, 0x48, 0x5c, 0x76, 0xc5, 0x26, 0xcf, 0x00, 0x6a, 0x14, 0x55, 0xa5, + 0x7e, 0xef, 0xd8, 0xb0, 0xc1, 0x4a, 0xc1, 0x8f, 0x43, 0x7d, 0xb1, 0xef, 0x32, 0x78, 0x04, 0xfd, + 0x6a, 0xa2, 0x01, 0x16, 0xaf, 0x74, 0x19, 0xe8, 0xc1, 0xce, 0x9f, 0xe0, 0x43, 0xc8, 0x9c, 0xa9, + 0xd0, 0x6e, 0xb0, 0x29, 0xbb, 0x78, 0x31, 0xcc, 0x45, 0xb7, 0x4a, 0xff, 0x80, 0x53, 0xb9, 0x57, + 0x97, 0xe9, 0x60, 0xce, 0x5d, 0x26, 0x0c, 0xd6, 0xe3, 0xd2, 0xd1, 0x59, 0x68, 0x82, 0xd4, 0xc3, + 0xa7, 0x98, 0x05, 0x3c, 0xf2, 0x39, 0x86, 0x14, 0xaa, 0x72, 0x28, 0x1c, 0x23, 0xca, 0x8d, 0x54, + 0x31, 0x9f, 0x7a, 0x0c, 0x0b, 0xf9, 0x00, 0x00, 0x13, 0x8d, 0x44, 0xaa, 0x44, 0x4a, 0x06, 0x00, + 0x00, 0x00, 0x02, 0x62, 0xc7, 0xf0, 0xf8, 0x6a, 0xbd, 0x1d, 0x75, 0x02, 0x11, 0x50, 0xcf, 0x51, + 0x7d, 0x12, 0xa8, 0xfe, 0x93, 0xad, 0x29, 0x0a, 0xbf, 0xbb, 0x3b, 0xf3, 0x63, 0x98, 0x6e, 0x85, + 0x73, 0xc1, 0x02, 0x41, 0x87, 0x9c, 0x53, 0xc7, 0x00, 0x57, 0x04, 0x4a, 0x78, 0xda, 0xcb, 0xe0, + 0xed, 0xe5, 0x3f, 0x3f, 0x8d, 0x1c, 0xc9, 0x28, 0xf5, 0x12, 0xcb, 0x34, 0x68, 0x30, 0x7c, 0xe6, + 0x86, 0xbd, 0xe0, 0x48, 0x40, 0x3f, 0xb5, 0x1f, 0x35, 0x6b, 0x32, 0x3b, 0x61, 0x6c, 0xe4, 0xde, + 0x81, 0x3a, 0x96, 0xc4, 0x20, 0xa9, 0xee, 0x87, 0x87, 0x98, 0x05, 0x3c, 0xf2, 0x79, 0x96, 0x3c, + 0x35, 0x1d, 0x6f, 0xd0, 0x0b, 0xbd, 0x6c, 0x0e, 0x54, 0x6a, 0xbe, 0xdd, 0x5b, 0x56, 0x75, 0x13, + 0xc7, 0x42, 0x28, 0x79, 0xc3, 0xfa, 0x0b, 0xc3, 0xaa, 0x5d, 0x99, 0x23, 0xe8, 0xdb, 0x04, 0x7a, + 0xd8, 0x78, 0x50, 0xab, 0x97, 0x12, 0xff, 0xa6, 0xf5, 0x85, 0xa9, 0xae, 0xd4, 0x57, 0xc2, 0x05, + 0x19, 0x3b, 0x6a, 0xac, 0x1b, 0x78, 0x10, 0xad, 0xde, 0x20, 0xc1, 0xa3, 0xdf, 0x57, 0xc4, 0x8f, + 0x2a, 0x00, 0x00, 0x02, 0x96, 0x4e, 0x79, 0x2b, 0xda, 0x72, 0x78, 0xdc, 0x3b, 0x03, 0x55, 0xd0, + 0xa3, 0xc1, 0xf2, 0x22, 0xee, 0x09, 0xf6, 0x72, 0x47, 0xf1, 0x57, 0x46, 0xd9, 0xc9, 0x0b, 0xa0, + 0xb9, 0x66, 0xaa, 0x7b, 0xea, 0x13, 0xc2, 0x08, 0x01, 0x66, 0x8f, 0xb3, 0x55, 0xe3, 0xe2, 0x89, + 0x85, 0xa6, 0xf0, 0xfe, 0xf2, 0x79, 0x86, 0x24, 0x33, 0x99, 0x9b, 0x83, 0xf8, 0x2a, 0x63, 0x47, + 0xa8, 0x98, 0xe4, 0x80, 0xf9, 0x98, 0x38, 0x29, 0x1a, 0xaf, 0x7e, 0xc1, 0x84, 0xfd, 0xc7, 0x07, + 0x8d, 0xc8, 0x92, 0x14, 0x00, 0x03, 0x50, 0xdf, 0xdd, 0x23, 0xc8, 0xd1, 0xa6, 0xb0, 0xa3, 0x10, + 0xd3, 0xe2, 0xdc, 0x57, 0x83, 0xd5, 0x84, 0xb3, 0x47, 0x04, 0x5b, 0xd2, 0xa9, 0xd1, 0xe3, 0xee, + 0xd3, 0x1c, 0x9c, 0xb1, 0x4f, 0xa0, 0x00, 0x00, 0x39, 0x21, 0xe6, 0x8b, 0xa3, 0xd9, 0xbf, 0x1c, + 0x03, 0x7e, 0x78, 0x7c, 0x39, 0x00, 0xe1, 0x70, 0x03, 0x34, 0x10, 0x6e, 0x42, 0xac, 0x8c, 0x40, + 0x4d, 0xe0, 0x71, 0x80, 0x54, 0x1d, 0x67, 0x43, 0x69, 0x34, 0x8a, 0x16, 0x78, 0x56, 0x85, 0xdd, + 0x91, 0x36, 0x51, 0x79, 0x6b, 0x6f, 0x7e, 0x8c, 0x85, 0xa6, 0xf0, 0xfe, 0xf2, 0x79, 0x96, 0x3c, + 0x35, 0x15, 0x1c, 0x7a, 0xf9, 0xb9, 0x15, 0xe0, 0xbb, 0xd6, 0x30, 0xcd, 0x56, 0x50, 0x2b, 0xc4, + 0x80, 0x2b, 0x4e, 0xa8, 0xd5, 0xf6, 0x54, 0x89, 0xbc, 0xbb, 0xc8, 0xfe, 0xa5, 0xd1, 0x00, 0x2d, + 0xcd, 0xb7, 0x7f, 0xd2, 0x26, 0x62, 0xff, 0xc4, 0x7e, 0xf3, 0x6f, 0xfe, 0x5c, 0x06, 0x09, 0xc2, + 0xf6, 0x16, 0x14, 0x4b, 0xaf, 0x70, 0xc8, 0x3b, 0xca, 0xed, 0x32, 0xb6, 0xff, 0x62, 0x16, 0x0b, + 0x57, 0x57, 0x01, 0x38, 0x00, 0x00, 0x9e, 0x5f, 0xc7, 0xf1, 0x08, 0x01, 0xb6, 0x9e, 0x5f, 0xfb, + 0x2e, 0xbf, 0x72, 0xd3, 0x6c, 0x14, 0x21, 0xfb, 0xa6, 0x0c, 0xa3, 0x7a, 0xa0, 0xe9, 0x91, 0xe7, + 0xa7, 0x90, 0xb3, 0x59, 0x84, 0x67, 0x0b, 0x94, 0x88, 0xce, 0x52, 0xd3, 0xfe, 0x67, 0x95, 0x92, + 0xa7, 0x96, 0x3c, 0xfc, 0xf2, 0x39, 0x76, 0x14, 0x65, 0xdb, 0x77, 0x74, 0x9b, 0xd1, 0x69, 0x04, + 0xa5, 0xab, 0x66, 0x61, 0x14, 0x5a, 0xc4, 0xc2, 0x97, 0x58, 0xb2, 0x79, 0x19, 0xe3, 0x67, 0xad, + 0x01, 0x95, 0x51, 0x52, 0x00, 0x01, 0x1a, 0x75, 0xd4, 0xa2, 0x96, 0x59, 0x20, 0x64, 0x25, 0x05, + 0x13, 0xdb, 0x41, 0xe0, 0x85, 0xa5, 0xb0, 0x6d, 0x5b, 0x3c, 0x6a, 0x4c, 0x6c, 0xa4, 0x4a, 0x66, + 0x37, 0x36, 0xa8, 0x1d, 0x4b, 0x1b, 0x17, 0x3c, 0x43, 0x00, 0x00, 0x0f, 0xf6, 0xf6, 0xb0, 0x3a, + 0xff, 0x2d, 0xc1, 0x2b, 0x8c, 0xf8, 0x20, 0x38, 0xb7, 0x83, 0x49, 0x13, 0x72, 0x58, 0xa3, 0xff, + 0x96, 0x2d, 0xd7, 0x2c, 0x60, 0xe6, 0x23, 0x13, 0xe9, 0x12, 0xdc, 0xc7, 0x29, 0x52, 0x97, 0x61, + 0x27, 0x07, 0x8d, 0xb7, 0x10, 0x12, 0x47, 0x34, 0xa5, 0xa6, 0xf0, 0xfe, 0xf2, 0x39, 0x86, 0x34, + 0x33, 0x99, 0xad, 0xf5, 0xb8, 0x20, 0x69, 0x36, 0xc3, 0x36, 0x38, 0x69, 0x6c, 0x55, 0x45, 0x82, + 0xc1, 0x47, 0xb5, 0x00, 0xe6, 0x9e, 0xec, 0x9f, 0xee, 0x9d, 0xda, 0xd3, 0x2b, 0x6e, 0xd8, 0x0b, + 0xa7, 0xab, 0xca, 0xf5, 0xe8, 0xd6, 0x02, 0xfb, 0xfe, 0xa3, 0x2b, 0x5f, 0x27, 0xa7, 0xd3, 0x6a, + 0x26, 0xfb, 0x88, 0x1c, 0xc5, 0xa4, 0xfa, 0x7f, 0x29, 0xfa, 0xd3, 0x67, 0x91, 0x97, 0xae, 0x84, + 0x47, 0x28, 0x00, 0x01, 0x0c, 0x1c, 0x69, 0x6f, 0xde, 0x2c, 0x8b, 0x31, 0x90, 0x4a, 0x1f, 0x06, + 0x39, 0x85, 0x14, 0x2f, 0xf2, 0x66, 0x4e, 0xff, 0x8a, 0xef, 0x13, 0x03, 0x84, 0xc1, 0x09, 0xb8, + 0x35, 0xd2, 0x8b, 0x54, 0xb9, 0x92, 0x86, 0xbe, 0xa8, 0xa5, 0x7c, 0x1c, 0x42, 0xcd, 0x35, 0x91, + 0xa5, 0xa6, 0xf0, 0xfe, 0xf2, 0x39, 0x86, 0x34, 0xaf, 0xde, 0xd3, 0xde, 0x29, 0xed, 0x28, 0x0d, + 0x99, 0xdd, 0xfa, 0x24, 0x1f, 0x60, 0x23, 0x8f, 0x5b, 0x2b, 0x71, 0x00, 0x00, 0x00, 0x18, 0xb9, + 0xe5, 0xc0, 0x40, 0x00, 0x04, 0x38, 0x27, 0x36, 0x94, 0xd7, 0x17, 0x8b, 0x70, 0x4c, 0x86, 0x34, + 0x7b, 0xef, 0x53, 0x59, 0x91, 0x66, 0x04, 0x41, 0xa7, 0x00, 0xcf, 0x10, 0x27, 0xf0, 0xdf, 0x0b, + 0xe1, 0xdb, 0xf8, 0x57, 0x3b, 0x2b, 0x02, 0x49, 0x2b, 0x98, 0x1f, 0x79, 0x70, 0x42, 0x2b, 0xac, + 0x12, 0x63, 0x0f, 0x91, 0x9c, 0xc0, 0x65, 0x85, 0xa5, 0x63, 0x2c, 0xb0, 0x4c, 0x3b, 0x98, 0x88, + 0x18, 0x71, 0x64, 0x0d, 0xdb, 0x8c, 0xeb, 0x07, 0xd4, 0x36, 0x0f, 0xd4, 0x30, 0x84, 0x61, 0x5c, + 0x1f, 0xd1, 0x8c, 0x7e, 0x0f, 0xdf, 0xb0, 0x9c, 0xa4, 0xa7, 0x0a, 0x7e, 0xf2, 0x39, 0x76, 0x34, + 0x33, 0xd7, 0x8c, 0x35, 0x71, 0x03, 0x71, 0x5c, 0x0e, 0x58, 0xb3, 0xc3, 0x3c, 0x24, 0x94, 0x53, + 0x0f, 0x65, 0x75, 0xd3, 0xbc, 0xae, 0x3c, 0x84, 0xde, 0x62, 0x00, 0x21, 0x7b, 0x79, 0x01, 0x6f, + 0xce, 0x47, 0x16, 0xd8, 0x82, 0x42, 0xe2, 0x1c, 0x52, 0x2e, 0xaf, 0x3b, 0xf7, 0xb5, 0x7f, 0xb9, + 0xd6, 0xe7, 0x8f, 0x84, 0x3f, 0xd2, 0x99, 0x4e, 0x15, 0xe1, 0x00, 0xcf, 0x2d, 0x30, 0x00, 0x1b, + 0x38, 0xa2, 0xc8, 0xeb, 0x02, 0x91, 0xdf, 0xfa, 0x7e, 0x00, 0x09, 0x17, 0x86, 0x70, 0x64, 0x95, + 0xa6, 0xb0, 0x5a, 0x5c, 0x18, 0xf1, 0x52, 0xa9, 0x09, 0x1e, 0xb5, 0x79, 0x35, 0x49, 0xe9, 0xb4, + 0xf5, 0xc7, 0x76, 0xea, 0x2c, 0x8f, 0x8e, 0x58, 0x17, 0xaa, 0x5e, 0xa8, 0x80, 0x7a, 0xdb, 0xf8, + 0xa5, 0xaf, 0x06, 0xfe, 0xf2, 0x39, 0x96, 0x34, 0x69, 0xad, 0x39, 0xda, 0x09, 0x4e, 0x4d, 0x05, + 0x63, 0x35, 0x94, 0xf7, 0x7d, 0xae, 0xdc, 0x29, 0x81, 0xb0, 0xdc, 0xae, 0x0f, 0x94, 0x17, 0x00, + 0xce, 0x1e, 0x72, 0x1b, 0x3d, 0x8b, 0xc9, 0x6a, 0x45, 0x35, 0x59, 0x23, 0x13, 0xf9, 0x28, 0x7b, + 0x2a, 0xb1, 0x88, 0xf3, 0x75, 0x67, 0x46, 0xe3, 0xb2, 0x07, 0x9e, 0xc9, 0x85, 0x55, 0x29, 0x05, + 0x2f, 0x7a, 0x1f, 0xe9, 0xed, 0x67, 0x1d, 0x0f, 0xbe, 0x00, 0x29, 0x71, 0xfc, 0xdb, 0xe3, 0x50, + 0x81, 0x10, 0x8d, 0x27, 0x30, 0x00, 0xcc, 0x63, 0x84, 0x3e, 0xd3, 0xd0, 0x61, 0xbd, 0xe2, 0x5b, + 0x5c, 0x0f, 0x9d, 0xd4, 0x69, 0x7e, 0x1f, 0x78, 0xf7, 0xaa, 0xad, 0xfb, 0x56, 0x92, 0xfe, 0x76, + 0x02, 0x38, 0xf6, 0x61, 0x13, 0x95, 0x07, 0x28, 0x85, 0xaf, 0x06, 0xfe, 0xf2, 0x39, 0x76, 0x14, + 0x35, 0x16, 0xeb, 0x64, 0x8e, 0x38, 0x4c, 0x9d, 0xa2, 0x33, 0x03, 0x67, 0x77, 0x01, 0x8b, 0x94, + 0xda, 0x0d, 0xba, 0x85, 0xab, 0xbb, 0xa7, 0xcd, 0x52, 0xd2, 0x28, 0x48, 0xfd, 0x6a, 0x9e, 0xb3, + 0x97, 0x2a, 0x67, 0x7f, 0x61, 0x7a, 0xd3, 0xc2, 0x95, 0xbc, 0xf3, 0x13, 0xbb, 0x38, 0x2c, 0x5e, + 0xf5, 0x25, 0xd5, 0x35, 0xdd, 0x30, 0xbd, 0x47, 0x6d, 0x7a, 0xdf, 0xbe, 0xe5, 0xf8, 0x87, 0xaa, + 0x00, 0x05, 0x76, 0x4e, 0x2c, 0xfc, 0x61, 0x4a, 0x0a, 0xea, 0xa0, 0xef, 0xe0, 0xce, 0xfd, 0xb2, + 0xca, 0x73, 0xa2, 0x79, 0x6c, 0x79, 0x6b, 0x05, 0xb3, 0x26, 0xd0, 0x6e, 0x98, 0xac, 0x3f, 0x08, + 0xed, 0x75, 0x09, 0xeb, 0xd5, 0xb9, 0xee, 0xd7, 0xca, 0xbe, 0x37, 0xa8, 0x31, 0x09, 0x26, 0xc6, + 0xa5, 0xaf, 0x06, 0xfe, 0xf2, 0x39, 0x76, 0x24, 0x35, 0x7f, 0x23, 0xcf, 0x33, 0x12, 0xde, 0x3c, + 0x10, 0xbc, 0xd5, 0xab, 0xb5, 0x31, 0xde, 0x73, 0xa5, 0xcf, 0xe9, 0xcd, 0xd6, 0xd8, 0xf5, 0x87, + 0x44, 0x23, 0x15, 0x25, 0x51, 0x9e, 0xb2, 0x1f, 0xa3, 0x37, 0xe5, 0x08, 0x12, 0x97, 0xf7, 0x2f, + 0x22, 0x63, 0x53, 0x76, 0x8b, 0x95, 0x50, 0x02, 0x42, 0x2f, 0x94, 0xd5, 0x56, 0x61, 0xa7, 0xde, + 0xa8, 0xcd, 0x25, 0x49, 0x6b, 0xa8, 0x93, 0x33, 0xbd, 0x25, 0x79, 0x9a, 0x79, 0xb9, 0x97, 0xe4, + 0x09, 0xd1, 0x1f, 0xfa, 0x2f, 0xb0, 0x1f, 0x03, 0xc0, 0x79, 0xe0, 0x07, 0x2c, 0xaf, 0x7b, 0xb3, + 0xbf, 0x09, 0x0d, 0x0e, 0x57, 0x8f, 0x5d, 0xa7, 0x79, 0x52, 0x13, 0xf7, 0x24, 0x90, 0x26, 0x9e, + 0x6b, 0xb3, 0x9e, 0x06, 0x3c, 0x1f, 0xd1, 0x2c, 0x85, 0xaf, 0x06, 0xfe, 0xf2, 0x19, 0x96, 0x3c, + 0xaf, 0xdd, 0xec, 0xcd, 0x0b, 0x42, 0x00, 0x00, 0x2e, 0x7a, 0x81, 0xcb, 0x68, 0x5f, 0x8b, 0x27, + 0x5a, 0x66, 0x42, 0x8b, 0xcb, 0xa7, 0xf2, 0x55, 0x8c, 0xf1, 0xbd, 0xff, 0xed, 0x97, 0x68, 0x26, + 0x8d, 0xdc, 0x19, 0x36, 0xc2, 0x4a, 0xa6, 0x3a, 0x55, 0xf0, 0x04, 0x2c, 0xa2, 0x72, 0xac, 0x64, + 0xe9, 0xf3, 0x1c, 0x9d, 0x2d, 0x41, 0xb7, 0x04, 0x2a, 0x28, 0x81, 0x41, 0x4b, 0xf5, 0xc6, 0x12, + 0x71, 0xb9, 0x3a, 0x2b, 0x7d, 0xaf, 0x12, 0xa3, 0xf1, 0xbc, 0x37, 0xb5, 0x78, 0xfe, 0x0f, 0x07, + 0xe1, 0xf1, 0x7f, 0x8d, 0x2e, 0x47, 0x5c, 0x3a, 0x11, 0xa8, 0x02, 0x8a, 0x1f, 0x6b, 0xa3, 0x1e, + 0xa5, 0xb3, 0x7b, 0x04, 0xcc, 0xf9, 0x05, 0xf6, 0xad, 0xe2, 0xe2, 0x27, 0x0f, 0x0f, 0xe5, 0xdc, + 0x85, 0xaf, 0x06, 0xfe, 0xf2, 0x19, 0x96, 0x3c, 0x64, 0x11, 0x5d, 0x4e, 0x5b, 0x2d, 0x0d, 0x23, + 0xf3, 0x0c, 0x6d, 0x9b, 0x66, 0x35, 0x84, 0xb9, 0x6e, 0x3d, 0x59, 0x00, 0x52, 0xfb, 0x2f, 0x5a, + 0x0d, 0x4e, 0x83, 0x36, 0xdb, 0x38, 0xa4, 0x8f, 0x17, 0x70, 0x3f, 0x1c, 0xd9, 0xba, 0xb5, 0x08, + 0x23, 0x42, 0xe0, 0xae, 0x6b, 0xb7, 0xcc, 0x59, 0xc4, 0xdb, 0xeb, 0xc6, 0x06, 0x8c, 0x3e, 0xfc, + 0xf5, 0x86, 0x6d, 0xf7, 0xc9, 0x28, 0xba, 0x5f, 0xee, 0x8f, 0x52, 0xb4, 0x9b, 0xa7, 0xe7, 0xdb, + 0x94, 0x55, 0x09, 0xbf, 0x72, 0x00, 0x7f, 0x00, 0x7e, 0x07, 0xe1, 0xc0, 0x9f, 0xd2, 0x34, 0xad, + 0x0c, 0xcc, 0xc5, 0x71, 0x48, 0x37, 0xfc, 0xaa, 0x0d, 0x1c, 0x8d, 0xf7, 0x4c, 0x98, 0x79, 0x3a, + 0xe7, 0xba, 0x6b, 0x21, 0xc7, 0x87, 0xf7, 0x2c, 0x85, 0xaf, 0x06, 0xfe, 0xf2, 0x19, 0xa6, 0x3c, + 0x37, 0x6c, 0x53, 0x00, 0x6f, 0x00, 0x00, 0x00, 0x4b, 0x8b, 0xf6, 0x32, 0x39, 0x48, 0x5b, 0x22, + 0x4f, 0x00, 0x00, 0x00, 0xff, 0x87, 0x00, 0x75, 0x5c, 0xf4, 0x0c, 0xd0, 0xec, 0x07, 0x73, 0x83, + 0x31, 0x29, 0xdd, 0x09, 0x57, 0xd3, 0x3c, 0xda, 0xa2, 0x04, 0xb9, 0xad, 0x13, 0xa8, 0x88, 0x84, + 0x87, 0x00, 0x7a, 0xbf, 0x83, 0x33, 0x15, 0xb1, 0xb0, 0xfd, 0x78, 0x12, 0x21, 0x3f, 0x1d, 0x6f, + 0x63, 0x17, 0x1f, 0xac, 0x1c, 0xec, 0x49, 0xfd, 0xa9, 0x85, 0x4f, 0x0d, 0x3d, 0x4f, 0xc0, 0xfc, + 0x3c, 0x0f, 0x0b, 0xf2, 0x04, 0x02, 0x90, 0xff, 0x07, 0x0a, 0x8b, 0x80, 0x71, 0x85, 0xc6, 0x69, + 0xb3, 0x10, 0xa1, 0xd2, 0xdb, 0x27, 0x48, 0xc5, 0x5b, 0xbb, 0xf1, 0xe8, 0x87, 0x3c, 0x3c, 0xd5, + 0x85, 0xaf, 0x06, 0xfe, 0xf2, 0x19, 0xa6, 0x3c, 0x35, 0x16, 0xad, 0x1b, 0x11, 0x11, 0x2c, 0x31, + 0x9b, 0x11, 0xa4, 0xb4, 0x21, 0x9f, 0x58, 0xa7, 0x69, 0x72, 0x41, 0xff, 0x6d, 0xd2, 0x08, 0x82, + 0x05, 0x1f, 0x5f, 0x56, 0xb5, 0x4f, 0x9c, 0xe6, 0x63, 0xf0, 0x5f, 0xf3, 0x59, 0x48, 0xba, 0x0f, + 0xba, 0x84, 0x33, 0x25, 0x9a, 0x6a, 0x3d, 0x78, 0x05, 0xbc, 0x2f, 0x04, 0xb7, 0x68, 0xac, 0x54, + 0x2b, 0x74, 0xed, 0x1f, 0xef, 0x85, 0x94, 0xd6, 0x82, 0x33, 0xae, 0xc1, 0x19, 0x5b, 0xed, 0x5d, + 0x93, 0x50, 0xac, 0xba, 0xcf, 0xc1, 0x1f, 0xe0, 0x3f, 0x03, 0xe3, 0xc4, 0x01, 0xd7, 0x00, 0xf6, + 0xdf, 0xa6, 0xb8, 0x30, 0x7a, 0xee, 0x1a, 0x36, 0x7f, 0x38, 0x94, 0xc2, 0x6c, 0xc5, 0xab, 0xbe, + 0xc7, 0x82, 0x6b, 0xc8, 0x61, 0xc5, 0xd6, 0xfe, 0x85, 0xaf, 0x06, 0xfe, 0xf2, 0x19, 0xa6, 0x34, + 0xa7, 0x93, 0xab, 0x17, 0xbc, 0xeb, 0xc1, 0x81, 0x22, 0x09, 0x43, 0x88, 0x90, 0x6f, 0x57, 0xec, + 0x00, 0x00, 0x43, 0x7c, 0x81, 0xea, 0x88, 0x05, 0xb7, 0x66, 0xc1, 0x19, 0xc7, 0xb0, 0xbd, 0x0e, + 0x1f, 0x14, 0xc9, 0x40, 0x05, 0xab, 0x02, 0xdf, 0x36, 0x96, 0xec, 0x3c, 0x43, 0xe9, 0x48, 0xba, + 0x41, 0x77, 0x10, 0x1c, 0xc9, 0xa3, 0x68, 0xa4, 0x3c, 0xf0, 0xcd, 0x87, 0x12, 0xb2, 0xc4, 0xef, + 0xd0, 0x2d, 0x71, 0xe5, 0xe6, 0x4d, 0xbf, 0x17, 0xe1, 0x98, 0xc1, 0x4f, 0x60, 0x1f, 0xc0, 0x7e, + 0x07, 0xe0, 0xf8, 0x80, 0xba, 0xbc, 0x7d, 0xe4, 0x47, 0x11, 0xde, 0xe4, 0x65, 0xe1, 0x9b, 0xc0, + 0x7a, 0x3e, 0x40, 0x76, 0x3c, 0x94, 0xe3, 0x1d, 0x5e, 0x5a, 0x40, 0xdb, 0xe8, 0x18, 0x29, 0x7c, + 0x85, 0xaf, 0x06, 0xfe, 0xf2, 0x19, 0xb6, 0x34, 0x65, 0xca, 0x46, 0xb9, 0x0b, 0x52, 0x79, 0x41, + 0x19, 0xc3, 0x73, 0x41, 0x1c, 0x52, 0xc7, 0x42, 0xc6, 0xcc, 0x7f, 0xb4, 0xf0, 0x18, 0x20, 0x04, + 0x05, 0xc7, 0x3d, 0x84, 0x7a, 0x66, 0xbf, 0x9e, 0xb3, 0x80, 0xf8, 0x8c, 0xb8, 0x90, 0x9a, 0xc0, + 0x59, 0x00, 0x50, 0xa7, 0xf1, 0x3b, 0xf6, 0xbe, 0x59, 0xf8, 0x13, 0xae, 0x02, 0x45, 0xe9, 0xb5, + 0x3c, 0x3d, 0xa3, 0x50, 0xab, 0x50, 0x84, 0x22, 0xfa, 0xc3, 0xc7, 0x70, 0x15, 0x5a, 0x18, 0x73, + 0xae, 0xb3, 0xdb, 0x73, 0x9f, 0x71, 0x55, 0xfc, 0x03, 0xf0, 0x1f, 0x81, 0xc1, 0x4f, 0x75, 0xd8, + 0x5a, 0x3d, 0x42, 0xfc, 0xc3, 0x81, 0x58, 0x1a, 0xb3, 0x61, 0xf4, 0xa5, 0x5d, 0xbd, 0x1c, 0xd3, + 0x7e, 0xfe, 0xbc, 0xf4, 0x1c, 0xe7, 0xda, 0x55, 0x85, 0xaf, 0x06, 0xfe, 0xf2, 0x19, 0x96, 0x3c, + 0x63, 0xc0, 0x39, 0x41, 0x09, 0x13, 0x33, 0xb4, 0x49, 0x82, 0x56, 0xb8, 0x0c, 0xaf, 0x54, 0x24, + 0x61, 0x6b, 0x00, 0x02, 0x55, 0xf8, 0x02, 0x36, 0x24, 0x97, 0x94, 0x17, 0x16, 0xff, 0xc5, 0x5a, + 0x22, 0x7c, 0x45, 0x25, 0xe0, 0x41, 0xe4, 0x40, 0xf9, 0x20, 0x3c, 0xe0, 0x48, 0xbe, 0xa1, 0x54, + 0xef, 0x5d, 0x3a, 0xfb, 0x00, 0xf2, 0x43, 0xda, 0x97, 0x91, 0x47, 0xeb, 0xaf, 0x0a, 0x51, 0x4e, + 0x1c, 0x1d, 0xe5, 0x97, 0x28, 0x4b, 0xa7, 0x23, 0xf4, 0x01, 0xac, 0x53, 0x22, 0x1c, 0xff, 0x07, + 0xf8, 0x0f, 0xc0, 0xfc, 0x1e, 0x02, 0x1d, 0xa7, 0xa3, 0x6b, 0x16, 0x58, 0x99, 0xd1, 0xd9, 0xd7, + 0x5a, 0x5c, 0x25, 0x4f, 0x1b, 0x83, 0x10, 0x9b, 0x65, 0x52, 0xc8, 0xaf, 0x76, 0x22, 0x1c, 0xde, + 0xa5, 0xaf, 0x06, 0xfe, 0xf2, 0x19, 0xb6, 0x3c, 0x65, 0xc6, 0xcd, 0x55, 0x50, 0x3d, 0x97, 0x82, + 0x9f, 0x19, 0x08, 0xd8, 0x1e, 0x75, 0xd2, 0x61, 0xc1, 0x35, 0x05, 0xfb, 0x13, 0xa6, 0x14, 0x63, + 0x87, 0x4d, 0x51, 0x0e, 0x16, 0x3b, 0x43, 0xaa, 0xc2, 0x72, 0xbf, 0x1f, 0x9c, 0xf5, 0xc1, 0x07, + 0xc2, 0xc5, 0xd2, 0x77, 0xe1, 0x39, 0xff, 0x43, 0x15, 0x29, 0x64, 0x5b, 0xa3, 0x44, 0x78, 0x93, + 0x88, 0xc1, 0x82, 0x3a, 0x25, 0x6d, 0x0c, 0xbc, 0x4b, 0xba, 0xca, 0xbe, 0xbb, 0x19, 0xe4, 0x8e, + 0x76, 0x0c, 0xe5, 0x8c, 0x8d, 0xcf, 0xe0, 0x7c, 0x3c, 0xc6, 0x0c, 0xfb, 0xdb, 0x2e, 0x16, 0x35, + 0x91, 0x51, 0x29, 0x18, 0x54, 0xad, 0x0b, 0x07, 0x76, 0x42, 0xd7, 0x55, 0x12, 0x6d, 0xce, 0x2f, + 0x7f, 0xe0, 0x78, 0xe0, 0xfe, 0xe6, 0xb2, 0x27, 0x91, 0x6a, 0xd2, 0xce, 0xf2, 0x19, 0x46, 0x3c, + 0xa7, 0x93, 0xab, 0x44, 0xbe, 0xa7, 0x80, 0x9c, 0xd3, 0xf8, 0xe1, 0x27, 0x07, 0x73, 0x64, 0x42, + 0xc1, 0x1d, 0x6c, 0x8b, 0xe3, 0xc5, 0x99, 0x2d, 0xf9, 0x62, 0x2e, 0xda, 0xf6, 0xb7, 0x19, 0x5a, + 0x06, 0x49, 0x62, 0x8f, 0x30, 0xe9, 0xb1, 0xc4, 0xd1, 0x09, 0x46, 0x15, 0xc2, 0xd6, 0x7e, 0x50, + 0xf7, 0xef, 0x31, 0x82, 0xef, 0xfb, 0xe2, 0xee, 0xd2, 0x20, 0xcb, 0xe4, 0x73, 0x7b, 0x49, 0x44, + 0x67, 0x23, 0x2e, 0xb8, 0x22, 0xa0, 0xd8, 0xe9, 0xbd, 0x30, 0x34, 0x65, 0x51, 0x6c, 0x01, 0xf7, + 0x80, 0x7e, 0x0f, 0x87, 0xc6, 0x78, 0xcf, 0x07, 0x77, 0x6c, 0x92, 0x63, 0xd6, 0xab, 0x53, 0xbd, + 0x59, 0x26, 0x10, 0xd2, 0xbe, 0xc8, 0x61, 0x41, 0xf0, 0x34, 0x63, 0xf1, 0x10, 0x4c, 0xaa, 0x2c, + 0x85, 0xaf, 0x06, 0xfe, 0xf2, 0x19, 0x86, 0x3c, 0xaa, 0x5a, 0xbb, 0xd7, 0xf8, 0xbb, 0x6f, 0xc4, + 0xc0, 0x30, 0x3e, 0x19, 0xe0, 0xf5, 0x55, 0x89, 0x37, 0x28, 0xd4, 0x29, 0x0d, 0x1f, 0xfa, 0xc2, + 0x00, 0x12, 0xad, 0x18, 0xd3, 0x85, 0x03, 0xd1, 0x26, 0xba, 0xc3, 0x95, 0x73, 0x0a, 0xff, 0x05, + 0x55, 0xee, 0x12, 0x41, 0x6d, 0x0c, 0x06, 0xf7, 0x01, 0x63, 0x20, 0xf6, 0xf5, 0x75, 0xcb, 0xf4, + 0x34, 0xf4, 0x0d, 0x55, 0x2e, 0x64, 0x61, 0x96, 0xc1, 0x14, 0x18, 0xf0, 0x06, 0xc1, 0x36, 0xa1, + 0xcb, 0xd5, 0x81, 0x08, 0xa3, 0x8a, 0xc0, 0x7f, 0x01, 0xf8, 0x3e, 0x0e, 0x47, 0x81, 0xc7, 0x8c, + 0xa3, 0xf0, 0x44, 0x41, 0x97, 0x61, 0xbd, 0x28, 0x73, 0x24, 0xa1, 0xfc, 0x76, 0x76, 0x57, 0x68, + 0x00, 0x00, 0x08, 0xc3, 0xc1, 0x08, 0xa3, 0x8e, 0x85, 0xaf, 0x06, 0xfe, 0xf2, 0x19, 0x96, 0x3c, + 0x69, 0xb1, 0xb3, 0x14, 0xc6, 0x0a, 0xef, 0xfa, 0x49, 0x55, 0xc7, 0xd6, 0xd6, 0x6f, 0xca, 0x4d, + 0x80, 0x0c, 0x07, 0x98, 0xef, 0xb9, 0xdd, 0xf0, 0x2c, 0x72, 0xfb, 0x82, 0x00, 0xc4, 0xf9, 0x7a, + 0x77, 0x18, 0xf7, 0x13, 0xcd, 0x32, 0x82, 0x84, 0xf3, 0xde, 0x5d, 0xee, 0xec, 0x4a, 0x5a, 0xca, + 0xcd, 0xe0, 0xbe, 0x24, 0xd0, 0xcf, 0xfa, 0xa2, 0x60, 0x8a, 0x57, 0xa1, 0x74, 0x0e, 0xe1, 0xf9, + 0xc5, 0xe7, 0x75, 0x25, 0xe2, 0x19, 0xb8, 0xab, 0x49, 0xea, 0xe3, 0x48, 0x22, 0x98, 0x7e, 0x0f, + 0x81, 0xf1, 0xc1, 0x70, 0xe7, 0xc4, 0xea, 0x0e, 0x16, 0xd8, 0xfb, 0xb9, 0x93, 0x5c, 0x6d, 0x54, + 0x08, 0x7e, 0xc7, 0x90, 0xb6, 0xe5, 0xa7, 0x1f, 0xf1, 0xea, 0xcf, 0xc7, 0xf1, 0xea, 0x71, 0x4c, + 0x91, 0x6a, 0xd2, 0xce, 0xf2, 0x19, 0x66, 0x3c, 0x66, 0x71, 0x12, 0xfb, 0xfc, 0xc3, 0xd6, 0xee, + 0x81, 0x60, 0xf5, 0x11, 0x13, 0x17, 0xd4, 0xe0, 0x47, 0x5f, 0x2b, 0x34, 0x69, 0x01, 0x01, 0xfa, + 0xe3, 0x71, 0x62, 0xd5, 0xfd, 0xc6, 0xad, 0xa8, 0xa1, 0x71, 0x0d, 0x50, 0x8b, 0x5f, 0x94, 0xa9, + 0xc6, 0x7b, 0xea, 0x99, 0x12, 0x7b, 0xcf, 0x33, 0xe1, 0x70, 0x52, 0x96, 0x14, 0xb9, 0xb6, 0x56, + 0x20, 0xcf, 0x88, 0x7a, 0x3c, 0x00, 0xf5, 0x8d, 0x82, 0xdc, 0x0c, 0xc0, 0x57, 0xfd, 0xb5, 0xb5, + 0x59, 0x4f, 0xd7, 0xde, 0xa0, 0x3e, 0x03, 0xf0, 0x7c, 0x38, 0x2f, 0x82, 0x4a, 0x02, 0x18, 0xcf, + 0xca, 0xe8, 0xd2, 0x49, 0xee, 0x11, 0x96, 0x2e, 0x8a, 0x02, 0xf1, 0x62, 0x10, 0x78, 0x87, 0x8e, + 0x41, 0x1f, 0x08, 0xc1, 0xa7, 0x11, 0xc5, 0xfc, 0x91, 0x6a, 0xd2, 0xce, 0xf2, 0x19, 0x66, 0x3c, + 0xaf, 0xa6, 0xc8, 0x17, 0xa3, 0x84, 0xdd, 0xa9, 0x0a, 0x0e, 0x89, 0xbc, 0x1f, 0xf0, 0x65, 0x09, + 0x6a, 0x1d, 0x56, 0x2f, 0xf0, 0xcd, 0xa6, 0xba, 0xcb, 0xa2, 0x5d, 0xcf, 0xe8, 0x89, 0x91, 0x7d, + 0x62, 0x41, 0x4e, 0xf4, 0x85, 0xf9, 0x49, 0xeb, 0xaa, 0x66, 0xb7, 0xd9, 0x79, 0x47, 0xfd, 0x78, + 0x49, 0x3b, 0x68, 0x11, 0xfb, 0xee, 0x8a, 0x55, 0x05, 0x04, 0x35, 0xb7, 0x0d, 0x1a, 0xe3, 0xdd, + 0x59, 0xbe, 0xf7, 0xfc, 0x1a, 0xac, 0x1c, 0x3d, 0x70, 0xce, 0xfe, 0x98, 0x40, 0xd7, 0x0f, 0xd0, + 0x7e, 0x1f, 0x0c, 0x1c, 0x32, 0xbe, 0x5f, 0x1a, 0xc2, 0xab, 0xfc, 0xb0, 0xbd, 0x6c, 0x64, 0xf5, + 0x7f, 0x9b, 0xd3, 0x42, 0x77, 0x73, 0xe2, 0x04, 0xdc, 0xf5, 0x7f, 0x9e, 0x3e, 0xdc, 0x61, 0xd7, + 0x91, 0x6a, 0xd2, 0xce, 0xf2, 0x19, 0x66, 0x3c, 0x66, 0x6e, 0xc7, 0xba, 0x0b, 0x00, 0x5e, 0x7e, + 0x17, 0x39, 0xe6, 0x76, 0xdb, 0x13, 0xa6, 0x5b, 0x1a, 0x16, 0x1c, 0x88, 0x6f, 0x59, 0x98, 0xe0, + 0x7e, 0x5d, 0xe7, 0xd0, 0xb9, 0x93, 0xdd, 0xf9, 0x87, 0xc2, 0x84, 0xf1, 0xab, 0x86, 0x07, 0x37, + 0x72, 0x2b, 0xcb, 0xb4, 0xe6, 0x9b, 0x62, 0x26, 0x81, 0xde, 0xae, 0xf2, 0x4a, 0x5d, 0xf8, 0xb8, + 0xaa, 0xfa, 0x96, 0x1c, 0x54, 0x35, 0x43, 0xfe, 0xda, 0xeb, 0xc7, 0x9d, 0x8f, 0xbf, 0xc6, 0xb5, + 0x87, 0x7a, 0xc3, 0x90, 0x02, 0x4e, 0xb0, 0x3f, 0x03, 0xf0, 0x78, 0x79, 0x1f, 0x8e, 0x15, 0x14, + 0xa1, 0xae, 0x84, 0x3b, 0x09, 0x62, 0x15, 0x7c, 0x50, 0xf7, 0x78, 0xed, 0x72, 0x41, 0x63, 0xcf, + 0xb3, 0xf0, 0xb0, 0x08, 0x70, 0x26, 0x49, 0xd6, 0x91, 0x6a, 0xd2, 0xce, 0xf2, 0x19, 0x66, 0x2c, + 0x69, 0xd5, 0x7a, 0x69, 0x80, 0x89, 0x16, 0x0e, 0x00, 0x8e, 0xdd, 0xe8, 0xba, 0x4a, 0xb8, 0xd4, + 0x9f, 0x71, 0xd7, 0x2a, 0xd2, 0xf5, 0x0c, 0xc3, 0x4f, 0xfb, 0x22, 0x11, 0x30, 0xb1, 0x93, 0x21, + 0x19, 0x9a, 0xb8, 0x73, 0x51, 0x9e, 0x2a, 0x77, 0x0f, 0x61, 0xbb, 0x18, 0x26, 0x3a, 0x10, 0x35, + 0x4a, 0xa3, 0x35, 0x10, 0x92, 0x56, 0xf5, 0xf5, 0x6e, 0xb8, 0x73, 0x7f, 0xf7, 0x78, 0xd2, 0x36, + 0x2e, 0x72, 0xfa, 0x9d, 0x7a, 0xdd, 0xe3, 0x6a, 0x0e, 0x47, 0x06, 0xa3, 0x23, 0x9f, 0x60, 0x7c, + 0x0f, 0x87, 0x99, 0x1e, 0x63, 0x8f, 0x66, 0xc4, 0x31, 0x76, 0x2d, 0x6a, 0x06, 0xc4, 0xd0, 0x4d, + 0x39, 0x53, 0x65, 0x85, 0x6c, 0xd7, 0x65, 0xdd, 0xf9, 0xa6, 0xf2, 0x18, 0x18, 0x9c, 0x8a, 0xd5, + 0x91, 0x6a, 0xd2, 0xce, 0xf2, 0x19, 0x66, 0x3c, 0xaf, 0xae, 0x7f, 0x37, 0x7c, 0x7e, 0xc8, 0x66, + 0x0c, 0xdb, 0xf9, 0x2a, 0xd1, 0xdc, 0x4b, 0xd9, 0xa3, 0x2d, 0xb4, 0x03, 0xae, 0x50, 0x54, 0x60, + 0xdb, 0xbe, 0x75, 0xe2, 0xb8, 0x20, 0xee, 0x0d, 0x6f, 0x53, 0xaf, 0xce, 0x03, 0x41, 0xc2, 0xc2, + 0xbb, 0xd5, 0x1f, 0xb8, 0x7f, 0x2c, 0xad, 0x56, 0x3b, 0x9b, 0xd7, 0xc9, 0xfc, 0xaf, 0x0a, 0x43, + 0x4c, 0xa2, 0xde, 0x6d, 0xf0, 0x57, 0x61, 0x8a, 0x55, 0x0b, 0x3c, 0x37, 0xbc, 0xf5, 0x9f, 0xda, + 0x35, 0xf9, 0x86, 0x34, 0xd4, 0x57, 0x30, 0x7f, 0x07, 0x83, 0xe1, 0xc0, 0x3e, 0x44, 0x81, 0x64, + 0x89, 0x31, 0xd2, 0xa8, 0x04, 0xe1, 0x52, 0x99, 0x84, 0x7b, 0x8b, 0x4d, 0x00, 0x92, 0x95, 0x49, + 0x52, 0x69, 0x84, 0xf8, 0xc7, 0x9a, 0x89, 0xe7, 0x91, 0x6a, 0xd2, 0xce, 0xf2, 0x19, 0x56, 0x3c, + 0x33, 0xd2, 0xb4, 0x9f, 0x05, 0xe1, 0xfa, 0x45, 0x00, 0x6f, 0x0a, 0x22, 0x3e, 0x60, 0xae, 0xcf, + 0xa0, 0x2f, 0xfc, 0xb6, 0xa8, 0x52, 0x88, 0x72, 0x12, 0xbe, 0xe9, 0xf3, 0xdc, 0xca, 0xa7, 0xe4, + 0xdd, 0x5a, 0x49, 0x6b, 0x42, 0x48, 0xc7, 0xde, 0x5b, 0x86, 0xf8, 0xd1, 0xc3, 0x56, 0x13, 0x97, + 0x12, 0x80, 0x6b, 0xab, 0x24, 0x24, 0x85, 0xb5, 0x76, 0x41, 0x3a, 0xeb, 0xa4, 0x51, 0xfd, 0x78, + 0x00, 0xd0, 0xa4, 0x3c, 0x79, 0xce, 0x54, 0xc2, 0x36, 0x15, 0x99, 0x46, 0xe7, 0x23, 0x00, 0x7f, + 0x01, 0xe0, 0xf8, 0x78, 0x37, 0xe3, 0x44, 0xf0, 0xc0, 0x24, 0xd0, 0xc9, 0x9c, 0x03, 0xe4, 0x7f, + 0x96, 0x92, 0x05, 0x40, 0xdf, 0xdf, 0x5c, 0xe6, 0xd3, 0xb9, 0xb8, 0x09, 0x04, 0x3b, 0x9c, 0x8c, + 0x91, 0x6a, 0xd2, 0xce, 0xf2, 0x19, 0x76, 0x3c, 0xaa, 0x72, 0x73, 0xe5, 0x5b, 0x51, 0x7c, 0xb3, + 0x87, 0x46, 0x40, 0x43, 0xe4, 0x19, 0x48, 0x8a, 0xe9, 0x8c, 0x51, 0x10, 0x86, 0x49, 0x47, 0x2b, + 0xdc, 0x88, 0x66, 0xe1, 0x44, 0x5c, 0x6e, 0x7b, 0xcd, 0x5d, 0xb6, 0x3b, 0xb2, 0xd5, 0x9f, 0x93, + 0xd0, 0x94, 0xef, 0xe0, 0x13, 0x33, 0x83, 0xa1, 0x37, 0xb6, 0xc8, 0xc7, 0x15, 0xdb, 0xbf, 0xac, + 0x97, 0xaa, 0x34, 0xe2, 0x45, 0x35, 0xaf, 0x75, 0x67, 0xf1, 0x7a, 0x71, 0xa6, 0xd1, 0x73, 0xdf, + 0x9f, 0x72, 0x46, 0xf8, 0x20, 0xfe, 0x07, 0xc1, 0xf8, 0x3c, 0x1f, 0xc7, 0x06, 0xc5, 0xe4, 0x52, + 0xd2, 0x6f, 0x92, 0x73, 0x58, 0x22, 0xbb, 0xda, 0x8d, 0xc1, 0xa4, 0xf4, 0xa8, 0x4f, 0x5a, 0xb1, + 0x90, 0x29, 0x48, 0x66, 0x47, 0x8d, 0x3a, 0x0c, 0x91, 0x6a, 0xd2, 0xce, 0xf2, 0x19, 0x66, 0x2c, + 0xaf, 0xdd, 0x47, 0x5c, 0xbe, 0xa2, 0xfd, 0xbc, 0xa0, 0x77, 0xc9, 0x9e, 0x7b, 0xc3, 0x7e, 0x20, + 0xd5, 0x15, 0x36, 0xfd, 0x0d, 0xbd, 0xf2, 0x45, 0xb9, 0x05, 0x4f, 0x58, 0xe0, 0xe6, 0x09, 0x9a, + 0x6a, 0xf0, 0xdc, 0x35, 0x0d, 0xe7, 0x80, 0x71, 0xff, 0x81, 0x7f, 0x77, 0xc4, 0xd4, 0x30, 0x13, + 0xdc, 0x3a, 0x2f, 0x79, 0x06, 0x88, 0x87, 0xe1, 0xb9, 0x0c, 0x54, 0xb7, 0xa9, 0xf8, 0x38, 0xed, + 0xa1, 0x82, 0xdd, 0x87, 0xfd, 0x51, 0x3b, 0xe4, 0x1b, 0xb1, 0x30, 0x4e, 0xb7, 0x9e, 0x03, 0xfc, + 0x3e, 0x07, 0xc3, 0xec, 0x43, 0xb8, 0xb3, 0x8d, 0x19, 0xc6, 0x43, 0x27, 0x8f, 0x09, 0x63, 0xe5, + 0xc4, 0x07, 0x41, 0x6f, 0x13, 0x00, 0x79, 0xdd, 0x09, 0x27, 0xde, 0xc4, 0x71, 0x4b, 0xf7, 0xbc, + 0x91, 0x6a, 0xd2, 0xce, 0xf2, 0x19, 0x56, 0x3c, 0xaa, 0x55, 0xb7, 0x24, 0x58, 0x31, 0x2f, 0x97, + 0x1f, 0x7f, 0x50, 0x76, 0x2c, 0x74, 0x2d, 0xf6, 0xd9, 0xdb, 0xbd, 0x07, 0x39, 0xb5, 0x5a, 0xed, + 0x8d, 0xdc, 0x64, 0x0c, 0x5b, 0x27, 0xc7, 0x96, 0xf2, 0xfc, 0x31, 0x3d, 0x42, 0x39, 0x15, 0x6a, + 0x6b, 0x9d, 0x6e, 0xaf, 0x1e, 0x9a, 0x9c, 0x38, 0x0f, 0xe3, 0x9e, 0xec, 0xd5, 0xed, 0x41, 0x3c, + 0xf8, 0x11, 0xb0, 0x5e, 0x42, 0x46, 0x77, 0xde, 0xb3, 0x5c, 0xd0, 0xba, 0x83, 0xa8, 0xf0, 0x34, + 0x96, 0x44, 0x95, 0xee, 0xfc, 0x07, 0xf0, 0x1f, 0x81, 0xf0, 0xfc, 0x41, 0xfb, 0x1f, 0x47, 0xf8, + 0xcf, 0xef, 0xce, 0xef, 0xaf, 0x96, 0xdf, 0x00, 0x58, 0x72, 0x83, 0xdb, 0x24, 0x20, 0x01, 0xef, + 0x9f, 0x44, 0xb9, 0xa4, 0xe2, 0x91, 0x94, 0xec, 0x91, 0x6a, 0xd2, 0xce, 0xf2, 0x19, 0x66, 0x3c, + 0x66, 0x6e, 0xc7, 0xe6, 0x2e, 0x32, 0x8e, 0x22, 0x9e, 0x55, 0x80, 0x61, 0xe0, 0x8a, 0xa5, 0x3f, + 0x95, 0xe0, 0x55, 0x60, 0x2e, 0xba, 0xaa, 0x4e, 0xd2, 0xfa, 0x76, 0x7c, 0x31, 0xcd, 0x9a, 0xd4, + 0xfc, 0x7d, 0xd3, 0xd3, 0x8c, 0x33, 0x03, 0x2d, 0x76, 0x18, 0xfb, 0x43, 0x89, 0x31, 0xd6, 0x02, + 0xa0, 0x6d, 0x55, 0x10, 0xe8, 0xae, 0x37, 0xe5, 0x60, 0x47, 0xcf, 0xf7, 0x22, 0x25, 0xe6, 0xf7, + 0xcb, 0x99, 0x6d, 0x2d, 0xdb, 0x02, 0x69, 0x16, 0x15, 0x56, 0x6b, 0x07, 0xb1, 0x69, 0xf3, 0x80, + 0xfc, 0x07, 0xf0, 0x7c, 0x70, 0xe6, 0xfd, 0x75, 0x86, 0x94, 0x6b, 0xf8, 0x28, 0x5b, 0x49, 0xf8, + 0x74, 0xc2, 0xba, 0x58, 0xc7, 0x55, 0xb8, 0xc9, 0x9e, 0x2f, 0xfc, 0x03, 0x0f, 0xe2, 0xd3, 0xce, + 0x91, 0x6a, 0xd2, 0xce, 0xf2, 0x19, 0x66, 0x3c, 0xaa, 0x6f, 0x07, 0xbb, 0x3f, 0xd8, 0x79, 0x25, + 0x03, 0x41, 0x4e, 0x0b, 0x33, 0x5a, 0x0b, 0x82, 0x3d, 0xae, 0xe8, 0x10, 0x72, 0xb5, 0x7b, 0x96, + 0xe7, 0xd0, 0xc0, 0x40, 0x2f, 0x17, 0x6a, 0x9e, 0xbd, 0xe2, 0x7f, 0xbb, 0x36, 0x3a, 0xb9, 0x0f, + 0x7f, 0x96, 0xf2, 0xfe, 0x0b, 0x12, 0xe9, 0xca, 0xe8, 0x2f, 0x0f, 0x1e, 0x27, 0xf6, 0x80, 0x27, + 0x01, 0x37, 0x81, 0xfe, 0x86, 0x2a, 0x0e, 0x79, 0x90, 0x70, 0xf5, 0xe4, 0xe9, 0x8e, 0x3c, 0x79, + 0xff, 0x3f, 0xf1, 0xc9, 0x02, 0x0b, 0xf1, 0x1f, 0x81, 0xf0, 0x3e, 0xc1, 0xe1, 0x72, 0x33, 0xaf, + 0x29, 0xd5, 0x37, 0x5e, 0x2b, 0x97, 0xdc, 0x9a, 0x12, 0x5c, 0xaf, 0x19, 0x79, 0x9f, 0xa0, 0xef, + 0x02, 0x66, 0xbf, 0x03, 0x82, 0x96, 0x5a, 0xf1, 0x71, 0x6a, 0xd2, 0xce, 0xf2, 0x19, 0x56, 0x2c, + 0x66, 0x71, 0x55, 0x28, 0xc7, 0xcb, 0x12, 0xbc, 0x67, 0x7c, 0x14, 0xa5, 0xed, 0x35, 0x49, 0x59, + 0x92, 0xd0, 0x51, 0x5d, 0xf1, 0x08, 0x93, 0x64, 0x87, 0xe2, 0x37, 0xe7, 0x02, 0xb8, 0x39, 0xd9, + 0xef, 0xb3, 0x82, 0xd5, 0x1b, 0x32, 0xaa, 0xc6, 0x89, 0x03, 0x80, 0x1c, 0xd4, 0x95, 0x85, 0xc5, + 0xeb, 0x0e, 0x7a, 0x53, 0x7b, 0xfb, 0x24, 0xed, 0x64, 0x1a, 0xe0, 0x87, 0xb8, 0xe5, 0xcf, 0xbe, + 0x6c, 0x17, 0xf2, 0xd6, 0x02, 0x6e, 0x78, 0xa0, 0xc9, 0xfd, 0x8e, 0xd0, 0x00, 0x3f, 0x80, 0xf8, + 0x7e, 0x1f, 0x01, 0x83, 0xe7, 0x04, 0xf8, 0x8c, 0xf0, 0xb5, 0x6f, 0x92, 0xff, 0x8c, 0x32, 0xf8, + 0x12, 0xba, 0xad, 0x59, 0x59, 0x9d, 0x25, 0x6a, 0x6c, 0x4c, 0x81, 0x04, 0xf7, 0x9e, 0xce, 0x80, + 0x71, 0x6a, 0xd2, 0xce, 0xf2, 0x19, 0x66, 0x34, 0x65, 0xc9, 0xf7, 0x20, 0x2d, 0xee, 0x82, 0xd8, + 0x1b, 0xb4, 0x62, 0x09, 0x60, 0x29, 0xa1, 0xe1, 0x0d, 0xa7, 0x29, 0xab, 0x31, 0x41, 0x5d, 0x5b, + 0x6c, 0xdf, 0x28, 0xd1, 0x8f, 0x35, 0xa7, 0x24, 0x46, 0xaf, 0x3d, 0xf8, 0xb1, 0xc8, 0x97, 0x1b, + 0x15, 0xae, 0xc8, 0x97, 0x73, 0x95, 0x1d, 0x45, 0x8b, 0xc9, 0x51, 0xeb, 0x9e, 0x15, 0x5d, 0xc4, + 0x20, 0x6b, 0x11, 0x03, 0x23, 0xb9, 0x7d, 0x95, 0xe5, 0x4a, 0x8b, 0x03, 0x69, 0x3c, 0x1f, 0xbe, + 0x8e, 0xf6, 0xe8, 0x93, 0xb3, 0x07, 0xe0, 0x7e, 0x07, 0x81, 0xe0, 0xf1, 0xc7, 0xcc, 0xc3, 0xb1, + 0x6f, 0x14, 0x01, 0x4d, 0xd9, 0x3c, 0xf1, 0x06, 0x1f, 0x35, 0x98, 0x90, 0xaf, 0x1f, 0x19, 0x61, + 0x82, 0x33, 0xfd, 0xe0, 0xa1, 0x0a, 0x62, 0x63, 0x91, 0x6a, 0xd2, 0xce, 0xf2, 0x19, 0x56, 0x3c, + 0x63, 0xbe, 0x62, 0x88, 0xda, 0xfc, 0x1e, 0x11, 0x29, 0x0c, 0xe5, 0x1b, 0xe5, 0x41, 0xba, 0xb3, + 0xcf, 0x4a, 0xda, 0xa2, 0x7e, 0x6d, 0x8b, 0xf8, 0xfc, 0xf1, 0x9e, 0x17, 0x6c, 0x9d, 0x19, 0xdd, + 0x81, 0x15, 0xa4, 0x32, 0x73, 0x7e, 0xba, 0xc3, 0x7d, 0x0b, 0xbc, 0x10, 0x11, 0x2f, 0x5f, 0xed, + 0xad, 0xc7, 0x7c, 0x0a, 0xc1, 0xb3, 0xef, 0x0a, 0xec, 0x13, 0x08, 0x9e, 0x12, 0x64, 0xce, 0xf8, + 0xe8, 0x23, 0xf6, 0x67, 0xac, 0x53, 0x50, 0xdc, 0x4a, 0xfc, 0xc3, 0xc0, 0x92, 0x0b, 0x2b, 0xf8, + 0x1f, 0xc1, 0xfc, 0x0f, 0x0f, 0x38, 0xf8, 0x91, 0xa0, 0x10, 0x29, 0x4c, 0xb2, 0xd0, 0x3d, 0x2a, + 0x06, 0xbc, 0x8b, 0x82, 0x18, 0x90, 0x62, 0x7f, 0x67, 0x7e, 0x75, 0xc1, 0xf5, 0x2c, 0x82, 0xc3, + 0x91, 0x6a, 0xd2, 0xce, 0xf2, 0x19, 0x76, 0x3c, 0x65, 0xdb, 0x69, 0x4c, 0x00, 0x13, 0x80, 0x00, + 0xa5, 0x3d, 0x13, 0x89, 0x11, 0xac, 0x4b, 0x54, 0xdf, 0x73, 0xd1, 0x09, 0x20, 0xc5, 0xd0, 0xd5, + 0x16, 0x47, 0xd8, 0x32, 0x19, 0x4c, 0xa9, 0x7b, 0xb5, 0x42, 0x72, 0x3c, 0x77, 0x89, 0xad, 0xbc, + 0xc0, 0x34, 0xdd, 0xb3, 0x24, 0x80, 0x12, 0x92, 0x8b, 0x8c, 0x31, 0xe9, 0x75, 0x5d, 0x72, 0xc9, + 0x27, 0x0f, 0x5c, 0xc0, 0xb4, 0xbe, 0x67, 0xa3, 0xcc, 0x0f, 0x48, 0x47, 0xbd, 0x9b, 0x05, 0x1c, + 0xbc, 0xa6, 0x41, 0x21, 0x8c, 0x51, 0x78, 0x0f, 0xc0, 0xfc, 0x3f, 0x87, 0xe3, 0x0e, 0x0e, 0xba, + 0xad, 0x50, 0x32, 0xf1, 0x76, 0xa4, 0xf9, 0x0c, 0x36, 0xc1, 0xdd, 0xbc, 0xbf, 0x68, 0x70, 0x01, + 0xc4, 0xe4, 0x17, 0xe2, 0x12, 0x28, 0xc5, 0x9f, 0x91, 0x6a, 0xd2, 0xce, 0xf2, 0x19, 0x66, 0x3c, + 0x35, 0x0a, 0x9e, 0x71, 0xc2, 0xab, 0x24, 0xaf, 0x16, 0xa5, 0x65, 0x01, 0x3c, 0x0e, 0x39, 0x42, + 0x75, 0xf5, 0x02, 0xf0, 0x1a, 0xf6, 0xec, 0xa3, 0x9d, 0xda, 0x93, 0x3d, 0x5f, 0xa8, 0x95, 0xa8, + 0xd0, 0xc3, 0x2c, 0xa8, 0x3a, 0x02, 0x84, 0x45, 0x79, 0x0a, 0x6f, 0x0f, 0x3c, 0xae, 0x11, 0x18, + 0xd9, 0xfe, 0xf6, 0x1c, 0xb0, 0xe0, 0x09, 0x42, 0xd7, 0xe4, 0xec, 0xd2, 0x47, 0xd4, 0xf6, 0xd7, + 0x6e, 0xe3, 0xdf, 0x4e, 0xa0, 0xd7, 0xb3, 0xaa, 0xf6, 0x28, 0x1a, 0xbb, 0x01, 0xc3, 0xaf, 0xc0, + 0xfe, 0x03, 0xf0, 0x7e, 0x3e, 0x70, 0x7c, 0x66, 0x21, 0xe9, 0x30, 0x96, 0xae, 0x2e, 0x1c, 0x3c, + 0xcc, 0x68, 0xec, 0xb1, 0x25, 0x1f, 0xed, 0xaf, 0xeb, 0xd8, 0x89, 0x3c, 0x27, 0x62, 0x38, 0xb1, + 0x91, 0x6a, 0xd2, 0xce, 0xf2, 0x19, 0x66, 0x3c, 0xaf, 0xd8, 0x66, 0x50, 0x91, 0xce, 0x6e, 0x00, + 0x93, 0x92, 0xf8, 0x3f, 0x41, 0xce, 0x85, 0xf2, 0xea, 0x59, 0x43, 0x74, 0x9f, 0x02, 0x89, 0x7c, + 0xae, 0xc0, 0x18, 0x11, 0x3d, 0x87, 0x63, 0xe9, 0x07, 0xe0, 0xe7, 0x0b, 0x24, 0x7b, 0x46, 0xb2, + 0x3b, 0x4b, 0x21, 0xa9, 0x3e, 0x9b, 0xaa, 0x34, 0x12, 0xa5, 0xbb, 0x35, 0x52, 0xcc, 0x1f, 0xf2, + 0x15, 0x35, 0x3d, 0xa9, 0x0b, 0xd4, 0xbc, 0xbc, 0x06, 0x48, 0x40, 0x53, 0x29, 0x4d, 0x96, 0x1f, + 0xdc, 0x41, 0x94, 0xd4, 0x06, 0x0f, 0xc1, 0xf1, 0xe1, 0xc4, 0x47, 0xc0, 0xf2, 0xb8, 0x9c, 0xc0, + 0x18, 0x92, 0xe2, 0x92, 0x79, 0x25, 0x6a, 0x4e, 0x5c, 0xa5, 0x43, 0x03, 0x9d, 0x56, 0x9e, 0x04, + 0x0c, 0x47, 0xc3, 0x07, 0x86, 0x7d, 0x51, 0xb0, 0x71, 0x72, 0x90, 0x4e, 0xf2, 0x19, 0x36, 0x3c, + 0xaf, 0xde, 0xd9, 0x76, 0xbf, 0xd7, 0xe9, 0x42, 0x20, 0x1c, 0xba, 0xc5, 0xd2, 0x84, 0x1a, 0xc9, + 0xfe, 0xe0, 0xa4, 0x27, 0x91, 0x41, 0x2c, 0x90, 0x21, 0x2f, 0x13, 0xa4, 0x90, 0x44, 0x9c, 0xe3, + 0x21, 0x0b, 0x2f, 0x1b, 0x7a, 0x7c, 0x3d, 0x4b, 0xf1, 0x4d, 0x92, 0x96, 0xea, 0xbe, 0x8b, 0xa2, + 0x21, 0xad, 0x9a, 0x4f, 0x38, 0xb1, 0xe6, 0x7b, 0x70, 0xe0, 0x53, 0xf4, 0xbb, 0x30, 0xf4, 0xa4, + 0xc8, 0x9c, 0x64, 0x84, 0xb5, 0x79, 0xb3, 0x29, 0x8a, 0x99, 0xc4, 0x2c, 0x0e, 0xb8, 0x70, 0xfe, + 0x0f, 0xfc, 0x42, 0x32, 0x6f, 0x4b, 0x8d, 0x8a, 0x00, 0xc9, 0x86, 0x90, 0xbf, 0x0d, 0x82, 0xc1, + 0x3c, 0xc6, 0x77, 0xaa, 0xcc, 0x84, 0xeb, 0xb7, 0xe3, 0x4b, 0xf7, 0x93, 0x88, 0x32, 0x99, 0xf8, + 0x91, 0x72, 0x90, 0x4e, 0xf2, 0x39, 0x26, 0x24, 0x69, 0xd4, 0x3b, 0x66, 0x16, 0x03, 0x00, 0x90, + 0x22, 0x40, 0xfa, 0x1a, 0x04, 0x41, 0xa5, 0xc1, 0xf6, 0xa7, 0x21, 0xd0, 0x0c, 0x43, 0x97, 0x96, + 0x55, 0x0d, 0x1c, 0x01, 0xb6, 0x85, 0x74, 0x0a, 0x78, 0xf3, 0x9b, 0x7c, 0x18, 0x8f, 0x6a, 0x0f, + 0x08, 0x89, 0xbe, 0x3b, 0x7e, 0xe1, 0x0e, 0x27, 0xa2, 0xea, 0xad, 0x9c, 0xcf, 0xd9, 0x4b, 0x40, + 0x73, 0x35, 0x6b, 0xcb, 0x5e, 0x0e, 0xff, 0x17, 0x3c, 0x44, 0x6d, 0xdc, 0x26, 0xbf, 0x28, 0x96, + 0xb2, 0x8d, 0x8d, 0x9e, 0x7d, 0xca, 0x82, 0x51, 0xf0, 0x79, 0xf0, 0xf9, 0x3e, 0x07, 0xff, 0x6c, + 0x30, 0xe9, 0xaf, 0xab, 0x1f, 0x91, 0x02, 0xd7, 0x94, 0xbe, 0x82, 0x8a, 0x58, 0xb6, 0x2c, 0x06, + 0x09, 0x88, 0xfb, 0x99, 0xe3, 0xfd, 0x96, 0xa5, 0x91, 0x72, 0x90, 0x4e, 0xf2, 0x19, 0x56, 0x3c, + 0xaa, 0x55, 0xb7, 0x24, 0x66, 0x3c, 0xcb, 0xe6, 0x01, 0x0d, 0x56, 0xf4, 0x3f, 0x74, 0xbf, 0xfb, + 0x3b, 0x05, 0xdf, 0xcd, 0x00, 0x00, 0x00, 0x00, 0xdd, 0xd3, 0x47, 0x59, 0x30, 0x43, 0xb7, 0x3c, + 0xb8, 0x17, 0xd4, 0x51, 0xe1, 0xa4, 0xb0, 0x52, 0xa9, 0x13, 0xd9, 0xf3, 0x04, 0x48, 0xe2, 0x65, + 0xa7, 0xbb, 0xa8, 0x3c, 0xe1, 0xe7, 0x72, 0x3e, 0x8f, 0x0d, 0xc2, 0x88, 0x6b, 0x25, 0x07, 0x6a, + 0x3c, 0x9b, 0xb7, 0x4e, 0xd7, 0x40, 0x21, 0x03, 0xa6, 0xbb, 0x01, 0x14, 0x4d, 0x59, 0xaf, 0x07, + 0xf0, 0x78, 0x3e, 0x0f, 0xb0, 0x3f, 0x07, 0x2e, 0xca, 0xe0, 0x35, 0xb8, 0x63, 0x37, 0x46, 0xce, + 0x97, 0xb8, 0xcb, 0x3a, 0xce, 0x3e, 0x5b, 0xf9, 0xb6, 0xb2, 0x83, 0x30, 0x70, 0x45, 0x4d, 0xb8, + 0x91, 0x72, 0x90, 0x4e, 0xf2, 0x19, 0x66, 0x3c, 0x69, 0xd4, 0xd7, 0x0f, 0x56, 0xb8, 0x0a, 0x16, + 0xd2, 0xa2, 0x0a, 0xd6, 0x86, 0x63, 0x1d, 0xf5, 0x79, 0x28, 0x93, 0x0f, 0x2e, 0x60, 0x7a, 0x0b, + 0x85, 0x00, 0x03, 0x59, 0x79, 0x93, 0xfb, 0xa4, 0x95, 0xbe, 0xd3, 0x99, 0x09, 0x31, 0x6d, 0xb1, + 0x92, 0xa6, 0x2e, 0x08, 0x89, 0x6a, 0xd8, 0x42, 0x39, 0x62, 0x22, 0x42, 0x9e, 0xb7, 0x0b, 0xbf, + 0xdf, 0xf9, 0xa7, 0x55, 0x5a, 0x0e, 0x93, 0xbe, 0x39, 0x71, 0xb0, 0x97, 0x5d, 0x4f, 0x8e, 0x97, + 0x98, 0xae, 0xd8, 0x3e, 0x94, 0xea, 0x7e, 0x0f, 0x87, 0xe0, 0xe1, 0x8f, 0xe0, 0xff, 0x8e, 0x7d, + 0xc7, 0x5d, 0x99, 0xec, 0x13, 0xf8, 0x27, 0x05, 0x8a, 0x01, 0xb1, 0xd8, 0x84, 0xa4, 0xbd, 0x59, + 0xc6, 0xf6, 0xfe, 0xf7, 0x0e, 0x4d, 0xb4, 0xa8, 0x71, 0x72, 0x90, 0x4e, 0xf2, 0x19, 0x56, 0x3c, + 0xaa, 0x6f, 0xa2, 0xf5, 0xd8, 0xb5, 0x5e, 0xbd, 0x40, 0x81, 0xb1, 0x5e, 0x70, 0x21, 0xab, 0x00, + 0x00, 0x00, 0x00, 0xcd, 0xb9, 0xa5, 0x00, 0xed, 0xc7, 0xf5, 0xf3, 0x79, 0xa1, 0x72, 0xa6, 0xf4, + 0x97, 0x3a, 0x66, 0xf0, 0x06, 0x52, 0xce, 0x4d, 0x40, 0xb0, 0xd7, 0x56, 0x11, 0x36, 0xeb, 0x5f, + 0x76, 0x0e, 0x27, 0x89, 0x4f, 0x90, 0x4e, 0x5f, 0xa4, 0xbb, 0x65, 0x18, 0x7f, 0xbe, 0x5d, 0x33, + 0x3b, 0xf0, 0xee, 0xf3, 0x0c, 0xab, 0x98, 0x21, 0x4f, 0x7f, 0xa8, 0xbd, 0x67, 0xfe, 0x03, 0xf8, + 0x1f, 0xe0, 0x3e, 0x1c, 0x78, 0xc0, 0xfd, 0x3f, 0x79, 0x8b, 0x5c, 0xd1, 0xc2, 0x51, 0x43, 0x45, + 0x1b, 0x0e, 0xeb, 0x9c, 0xc7, 0x1d, 0x54, 0x4d, 0x75, 0x75, 0x30, 0xe8, 0xfc, 0x3c, 0x52, 0xb3, + 0x96, 0xeb, 0x66, 0xaf, 0x72, 0x19, 0x96, 0x3c, 0xaa, 0x6f, 0x27, 0x9f, 0x71, 0x1f, 0xaf, 0xb1, + 0xb2, 0xaa, 0x21, 0x2b, 0x65, 0x0b, 0xb4, 0x98, 0x0f, 0xad, 0x8e, 0x7b, 0xa1, 0xa9, 0x01, 0xf6, + 0x5c, 0x20, 0xcb, 0x10, 0x89, 0x09, 0xdc, 0x57, 0xb2, 0x77, 0x20, 0xc5, 0xa8, 0xd1, 0x2d, 0xa8, + 0xee, 0x9f, 0x47, 0xeb, 0x5e, 0x25, 0x31, 0x90, 0x6b, 0x53, 0x5e, 0x40, 0xda, 0xce, 0x70, 0xc5, + 0x6c, 0xb2, 0xee, 0x9e, 0xfa, 0x48, 0x07, 0x91, 0xdf, 0x85, 0x52, 0x46, 0xc9, 0xd0, 0x4f, 0xb7, + 0xb4, 0xe8, 0x1a, 0x4e, 0xab, 0x03, 0x9e, 0x3e, 0x00, 0x1c, 0x08, 0x5d, 0x0d, 0xa9, 0x97, 0xe4, + 0x32, 0x30, 0x6f, 0x4a, 0xab, 0x3d, 0x4a, 0x09, 0x0a, 0x98, 0xc3, 0x60, 0x4f, 0xb8, 0x7d, 0x0e, + 0x88, 0xb4, 0x68, 0x82, 0xa0, 0x03, 0x5d, 0x9c, 0x96, 0xeb, 0x66, 0xaf, 0x72, 0x39, 0x56, 0x2c, + 0x65, 0xd9, 0x97, 0x01, 0xee, 0x4a, 0x66, 0x11, 0x45, 0x5b, 0xde, 0x86, 0xac, 0xba, 0x65, 0xf1, + 0x3f, 0x56, 0x54, 0x05, 0x5a, 0x39, 0x00, 0x3e, 0x79, 0x2f, 0xbb, 0xcd, 0x63, 0x69, 0xa5, 0x45, + 0x64, 0xab, 0xfe, 0xc9, 0x8f, 0xf9, 0x25, 0xb1, 0x69, 0x21, 0x4b, 0x7f, 0xbb, 0x5c, 0x6b, 0x30, + 0x21, 0xdb, 0x98, 0x32, 0x9e, 0x9f, 0xe5, 0xf3, 0x11, 0x60, 0xeb, 0xc6, 0xcb, 0x74, 0x72, 0xd0, + 0x1c, 0x94, 0xd4, 0xe6, 0xf0, 0x05, 0x5b, 0x02, 0xa4, 0x9f, 0xea, 0x44, 0xb8, 0x0d, 0xf4, 0x73, + 0x08, 0x3c, 0xce, 0x29, 0xf0, 0xb5, 0xe0, 0x48, 0x13, 0xab, 0x4a, 0x47, 0x89, 0xb1, 0x33, 0x8a, + 0xc7, 0xae, 0x39, 0xee, 0xbb, 0x65, 0xb9, 0xe2, 0xa0, 0x72, 0x6e, 0x3e, 0xa0, 0x33, 0x56, 0xa6, + 0x96, 0xeb, 0x66, 0xaf, 0x72, 0x39, 0x76, 0x34, 0x65, 0x57, 0x24, 0xfc, 0x7e, 0x20, 0x8e, 0xb5, + 0x9b, 0x37, 0x73, 0x06, 0x19, 0x9a, 0x84, 0x40, 0x00, 0xeb, 0x19, 0x30, 0xd1, 0x54, 0xd5, 0x11, + 0x6d, 0xaa, 0xac, 0xd6, 0xb9, 0x08, 0xd7, 0x79, 0x4f, 0x4d, 0xe8, 0x27, 0x5b, 0xe1, 0xe6, 0x41, + 0x7b, 0xd4, 0x30, 0x66, 0xc3, 0x67, 0x28, 0x70, 0xaf, 0x1b, 0xcc, 0x6b, 0x7b, 0x12, 0x2a, 0xe6, + 0xfa, 0x7e, 0x23, 0xb9, 0x24, 0x56, 0x92, 0x3b, 0x42, 0xc3, 0xb4, 0x2a, 0x22, 0x3d, 0xae, 0xfb, + 0x8d, 0x73, 0xb5, 0x20, 0x18, 0x5f, 0x63, 0x02, 0x75, 0x91, 0x7d, 0x16, 0xa5, 0xfd, 0x20, 0xe9, + 0x27, 0x80, 0x13, 0xdc, 0xaa, 0xc1, 0x4d, 0xcc, 0x99, 0x00, 0xf8, 0x48, 0x30, 0x2c, 0xb0, 0xa4, + 0x3c, 0x0b, 0x08, 0xbf, 0x63, 0x3d, 0x61, 0xa8, 0xb6, 0xeb, 0x66, 0xaf, 0x72, 0x39, 0x66, 0x34, + 0x63, 0xb3, 0xbd, 0x96, 0xb3, 0x4d, 0xd2, 0xf2, 0xee, 0xa4, 0x40, 0x95, 0x46, 0x7d, 0x46, 0x9e, + 0xa5, 0x6f, 0x5c, 0xe2, 0xfc, 0x70, 0xcf, 0xe0, 0x25, 0xe2, 0x44, 0x10, 0x05, 0x8a, 0xe9, 0xe9, + 0x43, 0xcc, 0x0d, 0x4c, 0x47, 0x14, 0x97, 0xac, 0xf5, 0x79, 0x36, 0x9d, 0xb7, 0xfd, 0xbe, 0xda, + 0x64, 0xa2, 0x70, 0x09, 0x52, 0x83, 0xf9, 0x91, 0xfa, 0x8b, 0x47, 0xd1, 0x2d, 0xee, 0xf4, 0xd9, + 0x41, 0xd9, 0xb2, 0x99, 0xf0, 0x0a, 0x93, 0x8c, 0x30, 0x27, 0xb0, 0x05, 0xfc, 0x58, 0x30, 0x5a, + 0x3f, 0x46, 0x13, 0x90, 0x9a, 0x29, 0x53, 0x60, 0xae, 0x82, 0xad, 0xc1, 0x2b, 0x27, 0x6a, 0x4f, + 0x3e, 0xeb, 0x9b, 0x6e, 0x34, 0x6a, 0x48, 0xf1, 0xb7, 0x33, 0x5a, 0x00, 0x3a, 0x11, 0x4e, 0xea, + 0xb5, 0xe9, 0x62, 0x2f, 0x72, 0x39, 0x66, 0x3c, 0xb6, 0x91, 0xd0, 0xbc, 0x85, 0xad, 0x1c, 0xc1, + 0xc5, 0x74, 0xa3, 0x65, 0x58, 0x79, 0x04, 0x76, 0x1a, 0xba, 0x32, 0xcd, 0xc3, 0xbc, 0x10, 0x62, + 0x17, 0x92, 0x1a, 0x73, 0xac, 0x21, 0xa4, 0xc1, 0x08, 0xc1, 0xfd, 0x0e, 0x4a, 0x33, 0xf2, 0xe8, + 0xfd, 0xab, 0x37, 0x23, 0x66, 0x9d, 0x84, 0xad, 0xa6, 0xc3, 0xf7, 0x8c, 0x0e, 0x73, 0x01, 0x0e, + 0x23, 0xb8, 0x6d, 0x19, 0x5c, 0xed, 0xaf, 0x76, 0xf7, 0x83, 0x0d, 0x7e, 0x89, 0x98, 0x1c, 0x5b, + 0x99, 0x95, 0xb7, 0xe0, 0x48, 0xcf, 0xa0, 0xc6, 0x10, 0x44, 0x89, 0x24, 0xb5, 0x79, 0xc4, 0xfc, + 0xa1, 0xc2, 0x3b, 0x41, 0x53, 0x89, 0xad, 0xce, 0x3e, 0x39, 0xb2, 0x92, 0xea, 0x36, 0xda, 0x4a, + 0xc9, 0x52, 0xc0, 0x19, 0xd9, 0x2a, 0x7d, 0x1e, 0x95, 0xe9, 0x62, 0x2f, 0x72, 0x39, 0x45, 0xe4, + 0x6e, 0xba, 0xba, 0xbc, 0xf5, 0x92, 0xd9, 0x00, 0x2d, 0x18, 0x51, 0x21, 0x42, 0x93, 0x43, 0xce, + 0x38, 0xfb, 0x80, 0x6f, 0x6f, 0x0d, 0x0b, 0x9f, 0xdc, 0x9e, 0x09, 0xb4, 0x68, 0x96, 0xbb, 0x25, + 0x36, 0xe6, 0x05, 0x3b, 0x83, 0xc4, 0x7c, 0x97, 0x04, 0xf0, 0xf0, 0x31, 0x12, 0x53, 0x28, 0xf5, + 0x3a, 0xb3, 0x4b, 0x50, 0xbc, 0xf6, 0x58, 0x53, 0xe1, 0x94, 0xe2, 0xe0, 0xec, 0x61, 0x35, 0x73, + 0x6c, 0xc2, 0xb6, 0x4b, 0xa6, 0x12, 0x7d, 0x28, 0xbc, 0x29, 0x02, 0x74, 0x71, 0x41, 0xeb, 0xe1, + 0xa5, 0x68, 0xbe, 0xac, 0xde, 0xcf, 0x1a, 0x25, 0x79, 0x66, 0x4f, 0x68, 0xdb, 0xb0, 0x67, 0x7f, + 0xc2, 0xfa, 0x52, 0x88, 0xf8, 0x11, 0x75, 0x0c, 0x37, 0x9b, 0x3c, 0x4d, 0xe2, 0x48, 0x17, 0xa6, + 0x95, 0xe9, 0x62, 0x2f, 0x72, 0x39, 0x56, 0x3c, 0xaf, 0xe4, 0xa2, 0x89, 0x12, 0x82, 0x0c, 0x29, + 0xbf, 0x24, 0x3d, 0xce, 0x5e, 0x00, 0x0c, 0xb4, 0xea, 0xf0, 0x83, 0x87, 0x99, 0xd9, 0xda, 0xbb, + 0xe1, 0x31, 0xa9, 0x85, 0xd1, 0xdc, 0x6e, 0xff, 0xba, 0xb1, 0xfd, 0x54, 0x95, 0x64, 0xbb, 0x8f, + 0x9e, 0x6f, 0x2a, 0x8a, 0x85, 0xd5, 0xef, 0x6f, 0x2a, 0xdb, 0xb9, 0x1e, 0x90, 0xd0, 0x3d, 0xb3, + 0xb4, 0xd5, 0x21, 0xf7, 0xcc, 0xa0, 0x56, 0x37, 0xd2, 0x04, 0xac, 0xa6, 0xba, 0x35, 0x9b, 0xf8, + 0x54, 0x4f, 0x56, 0x8e, 0x03, 0xba, 0xb7, 0xbe, 0x42, 0xc4, 0x8b, 0xf1, 0x3b, 0x97, 0x91, 0x6e, + 0xa9, 0x3b, 0x56, 0x63, 0x21, 0xe4, 0x32, 0x00, 0x40, 0x49, 0x96, 0x2d, 0x2f, 0x42, 0x1f, 0xce, + 0x9e, 0x2b, 0x45, 0x5f, 0xba, 0x22, 0x4f, 0x66, 0x95, 0xe9, 0x62, 0x2f, 0x72, 0x39, 0x66, 0x2c, + 0x65, 0xca, 0x4a, 0x9e, 0x20, 0x90, 0xd5, 0xeb, 0xdf, 0xb8, 0x17, 0x31, 0xd9, 0x80, 0x30, 0x3b, + 0x26, 0xd8, 0xa2, 0xbd, 0x5b, 0x02, 0x22, 0x53, 0x50, 0x98, 0xa5, 0x6a, 0x9b, 0x17, 0xd8, 0x89, + 0x3e, 0xf7, 0x00, 0x3d, 0x93, 0xeb, 0x5c, 0x37, 0x12, 0x20, 0x94, 0x6d, 0x2c, 0x0d, 0xcc, 0x20, + 0x04, 0x55, 0xa2, 0x73, 0xbb, 0xc0, 0xaa, 0x95, 0xa2, 0x02, 0x52, 0x9c, 0xf6, 0xb2, 0xd0, 0xc9, + 0xd4, 0x8d, 0xcf, 0xfe, 0xee, 0xa6, 0xc9, 0xf4, 0xd2, 0xd3, 0xca, 0xf8, 0x88, 0x0d, 0xf3, 0xcd, + 0x90, 0xff, 0x03, 0x3e, 0xb9, 0x22, 0x9f, 0x5b, 0x67, 0x40, 0xc7, 0x86, 0x67, 0xba, 0xf2, 0x10, + 0x6a, 0x38, 0xbc, 0x8f, 0x6a, 0x35, 0x69, 0xbf, 0xda, 0xeb, 0xbf, 0x41, 0x56, 0x71, 0x55, 0x4f, + 0x95, 0xe9, 0x62, 0x2f, 0x72, 0x39, 0x56, 0x34, 0xb6, 0x90, 0xce, 0x2f, 0x9f, 0xa6, 0x39, 0xdb, + 0x76, 0xc2, 0x48, 0x94, 0x8c, 0xd3, 0xc2, 0xc0, 0xde, 0xa3, 0x37, 0xc0, 0x1c, 0x11, 0x2c, 0x9b, + 0x06, 0x3a, 0xbf, 0x47, 0x64, 0x38, 0x2c, 0x56, 0x2b, 0x5d, 0x1d, 0xf6, 0x6e, 0xd3, 0x62, 0x89, + 0x10, 0x2b, 0x5d, 0x15, 0x48, 0x2f, 0x03, 0xa8, 0x07, 0xf3, 0x78, 0xcd, 0xb9, 0xb8, 0xce, 0xe7, + 0x69, 0x39, 0x3c, 0x13, 0x14, 0xd6, 0xb8, 0x8c, 0xe0, 0xcd, 0x8a, 0x23, 0x15, 0x89, 0x83, 0x31, + 0x3a, 0x0c, 0x95, 0xc0, 0xe9, 0xbf, 0x9f, 0xbd, 0x05, 0x61, 0x67, 0xe3, 0x3f, 0x10, 0x9a, 0x29, + 0x72, 0x3c, 0x5a, 0x38, 0xe0, 0xf4, 0x9a, 0x59, 0x9f, 0xd5, 0x44, 0x62, 0xcd, 0xed, 0x00, 0x78, + 0xc2, 0x1c, 0x7c, 0x47, 0xf4, 0xb3, 0x55, 0x13, 0x95, 0xe9, 0x62, 0x2f, 0x72, 0x39, 0x56, 0x0c, + 0xaf, 0xe5, 0x67, 0xb2, 0x9d, 0xfd, 0x91, 0xaf, 0x74, 0xcd, 0xd3, 0x13, 0x5c, 0xa8, 0x96, 0x7b, + 0x63, 0x82, 0xa3, 0x3f, 0x19, 0xa9, 0xd5, 0xc7, 0x7c, 0x3c, 0x64, 0x11, 0x80, 0x9b, 0xbc, 0x11, + 0x43, 0xf3, 0x6a, 0x02, 0xb4, 0x70, 0x52, 0x0f, 0xeb, 0xf0, 0x41, 0x9f, 0x15, 0x9e, 0xf5, 0xd7, + 0x72, 0x98, 0x4b, 0x06, 0x1a, 0x74, 0x8f, 0x29, 0x1f, 0x0d, 0x38, 0xf7, 0xea, 0xd8, 0xa4, 0x3e, + 0x37, 0xba, 0x03, 0xa9, 0xef, 0x6d, 0x0b, 0x1b, 0x48, 0x97, 0xd7, 0x76, 0x06, 0x66, 0xf0, 0x7d, + 0x2b, 0xe4, 0x56, 0x38, 0x87, 0x5d, 0xb6, 0x00, 0x64, 0x55, 0xe5, 0x31, 0x11, 0xa1, 0xac, 0x9c, + 0x88, 0x28, 0x04, 0xae, 0x9d, 0x14, 0xc5, 0x61, 0x9d, 0x11, 0x54, 0x3e, 0xb3, 0x46, 0x61, 0x0d, + 0x95, 0xe9, 0x62, 0x2f, 0x72, 0x39, 0x76, 0x34, 0x66, 0x57, 0xfe, 0x3a, 0x35, 0x14, 0xf0, 0x24, + 0x07, 0x8c, 0x8c, 0x9b, 0xdb, 0x06, 0xd7, 0x4c, 0x45, 0xf2, 0x1e, 0x75, 0x12, 0x9a, 0x0e, 0x66, + 0xbe, 0xb8, 0x15, 0x6c, 0x4c, 0xfc, 0x8a, 0x98, 0xac, 0xc0, 0xb0, 0x9c, 0x9a, 0x68, 0xd2, 0xab, + 0x41, 0x7d, 0xb4, 0x82, 0x2c, 0x8f, 0x0f, 0x93, 0xf4, 0xfa, 0x4d, 0x87, 0x76, 0xea, 0x45, 0xe6, + 0x66, 0x05, 0xe3, 0x09, 0x0e, 0x56, 0xf8, 0x16, 0xd6, 0x7e, 0x8f, 0xde, 0x9a, 0x61, 0x67, 0xbd, + 0xe3, 0x77, 0xb9, 0x73, 0x7b, 0xf2, 0x3f, 0x38, 0x88, 0x29, 0x36, 0x88, 0x84, 0x0c, 0x10, 0xd8, + 0x80, 0x6d, 0xbc, 0x26, 0xc8, 0x2c, 0xdd, 0x68, 0xfe, 0x2b, 0x23, 0x73, 0xd2, 0x38, 0x54, 0x63, + 0xc6, 0x57, 0xc7, 0xfe, 0x7e, 0xf7, 0xac, 0xab, 0xb1, 0x2d, 0x5a, 0x8e, 0xf2, 0x39, 0x35, 0x84, + 0xaf, 0xa7, 0x15, 0x3e, 0x78, 0xcd, 0x36, 0xc0, 0x19, 0x4c, 0x1d, 0x8d, 0x0b, 0xc6, 0x83, 0x8e, + 0xcc, 0xc7, 0xb7, 0x14, 0x15, 0x87, 0x95, 0x8b, 0xfb, 0xac, 0x9b, 0xdd, 0x72, 0xdf, 0xef, 0xfe, + 0x15, 0xc7, 0xce, 0xcc, 0xb4, 0x51, 0x23, 0xea, 0x70, 0x2e, 0x1b, 0x60, 0x3e, 0x70, 0x01, 0xb6, + 0xa4, 0xe9, 0xb7, 0x1c, 0x32, 0x64, 0xe3, 0xea, 0x57, 0x1c, 0x65, 0x7f, 0xfd, 0x05, 0x8c, 0xae, + 0x96, 0x79, 0x53, 0x17, 0x42, 0xbf, 0xfd, 0x35, 0x27, 0x6e, 0x3b, 0xd0, 0xb3, 0x3f, 0x90, 0x03, + 0xc4, 0x4a, 0xf3, 0x5a, 0x0f, 0x39, 0xb2, 0x65, 0x8e, 0x4f, 0x0a, 0xb8, 0xfb, 0x03, 0x3e, 0x4f, + 0x8d, 0xf1, 0xa6, 0x2d, 0x8d, 0x85, 0x25, 0x72, 0xe2, 0xcb, 0xec, 0xf7, 0xe1, 0x98, 0xef, 0xe6, + 0x95, 0xe9, 0x62, 0x2f, 0x72, 0x39, 0x76, 0x2c, 0xaf, 0xde, 0xd3, 0xde, 0x29, 0xec, 0xcb, 0xa8, + 0xa4, 0xa7, 0xdb, 0x9f, 0x13, 0xaa, 0x7c, 0xff, 0x2e, 0x7d, 0x26, 0x00, 0xb7, 0xa0, 0x49, 0x04, + 0x6b, 0x78, 0x0b, 0xfe, 0x7c, 0x8c, 0x2c, 0x86, 0x78, 0x04, 0x92, 0xa5, 0x06, 0x05, 0x40, 0xe5, + 0x5f, 0xe8, 0x5e, 0x1b, 0x4b, 0x53, 0x6e, 0xe4, 0x52, 0xeb, 0x96, 0x18, 0x33, 0xa7, 0x3a, 0xf5, + 0x59, 0xa8, 0xb3, 0x81, 0x20, 0xd7, 0x88, 0x92, 0x6a, 0xdb, 0x6e, 0x81, 0xe5, 0x47, 0xda, 0x84, + 0x83, 0x9a, 0x9e, 0x5e, 0x78, 0x8c, 0x12, 0xf0, 0xc0, 0x35, 0x03, 0x58, 0x3f, 0xec, 0x8f, 0xb7, + 0xe8, 0x74, 0xa6, 0xfb, 0xd1, 0xa2, 0xe2, 0x20, 0x18, 0x86, 0x03, 0x22, 0x43, 0x46, 0x23, 0x76, + 0x22, 0x2f, 0x38, 0x83, 0xdb, 0x90, 0xd3, 0x13, 0x95, 0xe9, 0x62, 0x2f, 0x72, 0x39, 0x56, 0x3c, + 0x69, 0x22, 0xe4, 0xca, 0x53, 0x96, 0xc7, 0x1b, 0xed, 0xf3, 0x0a, 0xc8, 0xfc, 0x00, 0x5d, 0xa2, + 0x8c, 0x2b, 0x14, 0x70, 0x6d, 0x84, 0x76, 0x1e, 0x00, 0xcc, 0x13, 0xdb, 0xf3, 0x48, 0xbd, 0x79, + 0x77, 0x56, 0x2e, 0x91, 0x75, 0x37, 0x14, 0x9f, 0x29, 0x9a, 0x4f, 0xb9, 0x0e, 0x77, 0x77, 0x5a, + 0x7a, 0x3d, 0xe3, 0x76, 0x36, 0x61, 0xd5, 0xa9, 0xda, 0x5e, 0x27, 0xa5, 0xb8, 0xc9, 0x27, 0xc8, + 0x4f, 0x50, 0x77, 0x0f, 0x14, 0x1e, 0x80, 0x1b, 0xbf, 0xb1, 0xc5, 0x39, 0xaf, 0xe6, 0x82, 0x60, + 0xb0, 0x5e, 0x32, 0xc1, 0xdf, 0xa8, 0x33, 0x70, 0xaf, 0x78, 0x08, 0x1f, 0xce, 0x63, 0x45, 0xbb, + 0xf0, 0xf9, 0x90, 0x3e, 0x11, 0xf3, 0x7e, 0x5d, 0x44, 0x61, 0xe3, 0xa8, 0xbc, 0xaa, 0x71, 0x33, + 0xb1, 0x2d, 0x5a, 0x8e, 0xf2, 0x39, 0x16, 0x2c, 0x65, 0xc7, 0x3e, 0xca, 0xc3, 0x81, 0xb0, 0xa1, + 0x95, 0xf1, 0x83, 0xb4, 0x2a, 0x9f, 0xd9, 0xed, 0xb6, 0x66, 0x25, 0xcd, 0x41, 0x1d, 0x06, 0x01, + 0x57, 0x3c, 0xb7, 0x75, 0xee, 0x9a, 0x64, 0xd7, 0x83, 0x2c, 0x34, 0x42, 0xae, 0x59, 0x21, 0x9c, + 0xaa, 0xc8, 0xfa, 0xfc, 0x6e, 0xb5, 0x4d, 0x14, 0x8d, 0xe4, 0x5a, 0x85, 0xe9, 0xb7, 0xa1, 0x76, + 0x4b, 0x57, 0x1b, 0x8b, 0xa5, 0x91, 0x48, 0xdd, 0x76, 0x47, 0x3d, 0xdf, 0xe3, 0xbd, 0x5f, 0x54, + 0x14, 0x25, 0x9f, 0x11, 0x81, 0xcc, 0x62, 0x83, 0x8f, 0x20, 0x5c, 0xa7, 0x39, 0x37, 0xcd, 0x5f, + 0xb2, 0x30, 0x10, 0x9e, 0x2c, 0xec, 0xb6, 0x65, 0x45, 0xd2, 0x0c, 0x5b, 0xa2, 0x4f, 0x8b, 0xb6, + 0xa1, 0x0b, 0xc2, 0xbb, 0x8c, 0xa5, 0x15, 0x87, 0xb1, 0x2d, 0x5a, 0x8e, 0xf2, 0x39, 0x25, 0xe4, + 0x65, 0xc6, 0xd3, 0xa6, 0x52, 0x43, 0x2a, 0xef, 0x33, 0x6c, 0x87, 0xeb, 0x3a, 0xcf, 0x5d, 0xf0, + 0xc0, 0x08, 0x10, 0x7e, 0x05, 0xb0, 0x45, 0x65, 0x24, 0xd9, 0xe8, 0xb5, 0xf1, 0x9a, 0xbf, 0xc8, + 0xbf, 0x69, 0x46, 0x6a, 0x23, 0xb9, 0x2e, 0x01, 0xea, 0x4d, 0xdf, 0x67, 0xfa, 0x07, 0x84, 0x2e, + 0x59, 0xa2, 0x09, 0x20, 0xdd, 0xf6, 0x02, 0x98, 0xbd, 0xc7, 0x57, 0x85, 0x72, 0x36, 0x1a, 0x2a, + 0x4f, 0x84, 0x15, 0xa8, 0x47, 0x57, 0x9f, 0x57, 0x23, 0xd6, 0xc0, 0x7c, 0x3e, 0xf6, 0x02, 0x3a, + 0xc4, 0x97, 0x5c, 0xc0, 0x52, 0x4c, 0x05, 0x1f, 0x1a, 0xfb, 0x4c, 0x4f, 0x31, 0x4c, 0xc8, 0x02, + 0xfd, 0x73, 0xed, 0x7b, 0x24, 0xe0, 0xc1, 0x61, 0xb8, 0x52, 0x8d, 0x2c, 0x8a, 0xb3, 0x7e, 0xf8, + 0xb1, 0x2d, 0x5a, 0x8e, 0xf2, 0x39, 0x25, 0x84, 0xaf, 0xdd, 0x74, 0x71, 0x44, 0x68, 0xff, 0x2b, + 0x57, 0x71, 0x24, 0x5c, 0x55, 0xa5, 0x54, 0x83, 0x19, 0xf7, 0x1a, 0xc2, 0xe7, 0xdc, 0x46, 0xf0, + 0x09, 0x8b, 0xf5, 0xf3, 0x91, 0x04, 0x22, 0xa1, 0x27, 0x34, 0x0f, 0x64, 0xeb, 0x1f, 0xe5, 0x9b, + 0xcb, 0x22, 0x0f, 0xc3, 0x54, 0x10, 0x78, 0x8c, 0x61, 0xf9, 0xf4, 0x6f, 0xc9, 0xbb, 0x88, 0x86, + 0x73, 0x8a, 0x4c, 0xff, 0x4e, 0x44, 0xc9, 0x5d, 0x96, 0x9f, 0x80, 0x19, 0xe6, 0x78, 0x1f, 0x6b, + 0x00, 0x0c, 0x9f, 0x04, 0x24, 0x74, 0xf0, 0x3c, 0x53, 0x08, 0x2b, 0x3b, 0x50, 0xa9, 0xe8, 0x65, + 0x87, 0x69, 0xf7, 0xd4, 0x59, 0x0e, 0x0b, 0x9d, 0x1e, 0x11, 0x0a, 0xe6, 0x57, 0x11, 0x78, 0x08, + 0xd0, 0x64, 0x47, 0x05, 0xae, 0x94, 0x89, 0xbc, 0xb1, 0x31, 0xa7, 0x0e, 0xf2, 0x39, 0x15, 0xfc, + 0xb6, 0x85, 0x63, 0x1f, 0x20, 0xc0, 0x06, 0x36, 0xe0, 0xa7, 0x4a, 0xc5, 0xad, 0x13, 0x1f, 0xa7, + 0x8a, 0xd5, 0x1a, 0xab, 0xdc, 0xc1, 0x6b, 0xa9, 0x50, 0xfb, 0x62, 0xc5, 0x48, 0xf1, 0x9b, 0x9b, + 0x2c, 0xe8, 0x56, 0xcf, 0x2a, 0x04, 0xa4, 0x0b, 0xd5, 0x36, 0xda, 0x6a, 0xa8, 0xa7, 0xa9, 0x58, + 0xef, 0xa2, 0x35, 0x74, 0x48, 0xc9, 0xa2, 0xb5, 0x48, 0xeb, 0x2f, 0x99, 0x26, 0x75, 0xf9, 0xeb, + 0x35, 0xc1, 0x92, 0xec, 0xda, 0x01, 0xee, 0x4e, 0xef, 0x15, 0xe6, 0x87, 0x03, 0xf7, 0x73, 0xc5, + 0x6f, 0x02, 0xf5, 0xbe, 0x1f, 0x49, 0x0f, 0x88, 0x0b, 0xe3, 0x24, 0x06, 0xed, 0xe1, 0xa1, 0xe3, + 0x33, 0x5b, 0xbb, 0xae, 0x10, 0x01, 0xd0, 0xd8, 0x63, 0xe2, 0x15, 0x44, 0xdf, 0xd3, 0x7b, 0x5b, + 0xb5, 0xe9, 0x62, 0x2f, 0x72, 0x39, 0x76, 0x0c, 0x69, 0x22, 0x72, 0xe4, 0x98, 0xd5, 0x8a, 0x89, + 0x1c, 0x65, 0xc4, 0x6e, 0x00, 0x17, 0x29, 0x54, 0x3d, 0xd5, 0x58, 0x43, 0xc0, 0x33, 0x85, 0x15, + 0x9d, 0xf1, 0x19, 0x3f, 0x72, 0x51, 0xcf, 0x81, 0xb7, 0x6b, 0xd7, 0x35, 0x69, 0x08, 0xe1, 0x13, + 0x3b, 0x78, 0x0a, 0xe1, 0x1b, 0xa7, 0xe8, 0x72, 0x10, 0x55, 0xb9, 0x20, 0x11, 0x50, 0xa4, 0x17, + 0x87, 0x12, 0xfa, 0xf9, 0xf4, 0x1d, 0x4f, 0x08, 0x95, 0x82, 0x72, 0x9e, 0xc9, 0x0f, 0xe9, 0x01, + 0x21, 0x7f, 0xde, 0xf8, 0x10, 0x38, 0x56, 0x3b, 0x20, 0xa7, 0x02, 0x3f, 0x16, 0x3c, 0x36, 0x81, + 0x69, 0xa6, 0x1a, 0xcc, 0x51, 0xac, 0x6d, 0x79, 0x9a, 0xda, 0x1c, 0xca, 0xa7, 0x96, 0x95, 0x6b, + 0x00, 0xb0, 0x61, 0x1c, 0xce, 0xc3, 0x6f, 0xb7, 0x95, 0xe9, 0x62, 0x2f, 0x72, 0x39, 0x55, 0x84, + 0xaa, 0x56, 0xbf, 0xa9, 0xda, 0x3c, 0x9d, 0xc3, 0xf5, 0xac, 0x60, 0x1e, 0x1a, 0xd8, 0x19, 0xdf, + 0x0a, 0x71, 0x4a, 0xfc, 0xe5, 0xc4, 0x08, 0x23, 0xec, 0x2f, 0x4c, 0x6c, 0xa6, 0x7c, 0x21, 0x4a, + 0xdd, 0xb3, 0xca, 0x0f, 0xbb, 0x13, 0x27, 0x92, 0x69, 0xde, 0x0e, 0xe7, 0x16, 0xd4, 0x62, 0x1a, + 0x7c, 0xd8, 0xef, 0xcd, 0xcd, 0xdd, 0x83, 0xbd, 0x7f, 0xaa, 0x22, 0xc3, 0x04, 0xe2, 0x4d, 0x2b, + 0xe4, 0x6f, 0xd2, 0x4e, 0xb8, 0x46, 0x41, 0x47, 0xbe, 0x19, 0x09, 0xfc, 0x60, 0x43, 0x60, 0x39, + 0x1d, 0xda, 0x13, 0x3e, 0x0d, 0x1d, 0xc8, 0x68, 0xbc, 0x05, 0x49, 0xa7, 0xc1, 0x3b, 0x2a, 0x03, + 0x60, 0x25, 0xba, 0xac, 0xd5, 0x4b, 0x2c, 0x64, 0x83, 0x96, 0x80, 0x4d, 0xa0, 0x66, 0xab, 0x1e, + 0xb5, 0xe9, 0x62, 0x2f, 0x72, 0x39, 0x55, 0xf4, 0xaa, 0x56, 0x81, 0x76, 0xd9, 0xc8, 0x2c, 0x73, + 0x36, 0x0f, 0xea, 0x62, 0xe2, 0x2c, 0x3b, 0x4b, 0x43, 0xdc, 0x2e, 0x7a, 0x64, 0xf5, 0xc9, 0xb4, + 0xd3, 0x00, 0x02, 0x38, 0xc4, 0x99, 0x45, 0x1a, 0x98, 0x04, 0x95, 0xd5, 0xbe, 0x36, 0xa9, 0xd1, + 0x88, 0xf0, 0xc3, 0x1f, 0xe5, 0x6a, 0x61, 0xac, 0x5d, 0x5e, 0x7d, 0xf0, 0xc3, 0x0a, 0x06, 0x20, + 0xde, 0xe4, 0xe3, 0x4a, 0x50, 0xae, 0xea, 0xbd, 0x97, 0xb0, 0xe4, 0xe6, 0x13, 0x25, 0x13, 0x3c, + 0x9d, 0xd1, 0x00, 0xfb, 0x94, 0xff, 0xb8, 0x13, 0x63, 0x79, 0x7c, 0x38, 0xbf, 0x96, 0x4e, 0xec, + 0x8b, 0x24, 0xd3, 0x67, 0xf1, 0x6a, 0x56, 0x7b, 0xca, 0xf1, 0xee, 0x32, 0x3b, 0x01, 0x12, 0x00, + 0x37, 0xa9, 0x23, 0xe6, 0xf7, 0x12, 0x74, 0xe1, 0x95, 0xed, 0xae, 0xab, 0x72, 0x39, 0x65, 0xbc, + 0x65, 0xc7, 0x3e, 0xba, 0x36, 0x09, 0x27, 0x54, 0x8f, 0xf1, 0xe9, 0x4f, 0x64, 0x30, 0xaa, 0x29, + 0x9f, 0x5d, 0x65, 0x00, 0x00, 0x53, 0x82, 0x0f, 0xdd, 0x1c, 0x37, 0x3a, 0xbf, 0xb6, 0xba, 0xf1, + 0xbe, 0x00, 0xc8, 0x58, 0x9b, 0xbf, 0x78, 0xc5, 0xbe, 0x78, 0x7f, 0xd3, 0xb0, 0xdc, 0x2f, 0xd4, + 0xbd, 0x16, 0x7f, 0xbb, 0x36, 0xd3, 0x5f, 0x75, 0x99, 0x27, 0x3c, 0xd8, 0x44, 0xed, 0xbd, 0xb7, + 0xc1, 0xe7, 0x56, 0x27, 0x63, 0x3c, 0xa2, 0x25, 0x5b, 0xc6, 0x93, 0x9d, 0x03, 0x96, 0x19, 0xa4, + 0xd9, 0x58, 0xeb, 0xf9, 0xf4, 0xcb, 0x05, 0xa2, 0x20, 0xac, 0xf4, 0xed, 0x1a, 0xc8, 0x32, 0xa8, + 0x88, 0xc3, 0xad, 0x15, 0xcc, 0x10, 0x65, 0xd1, 0x83, 0xe4, 0x99, 0xf9, 0xfe, 0xaa, 0x44, 0xd0, + 0xb5, 0xe9, 0x62, 0x2f, 0x72, 0x39, 0x76, 0x1c, 0x69, 0x22, 0x06, 0xbe, 0xcf, 0xbb, 0x90, 0x18, + 0x52, 0x80, 0x9a, 0xbc, 0x72, 0x5b, 0x82, 0xed, 0x4f, 0x22, 0x04, 0xca, 0xe6, 0xf0, 0x1d, 0x3e, + 0x19, 0x9d, 0xcc, 0xb2, 0x6a, 0x37, 0x5a, 0xa8, 0x24, 0x0d, 0x27, 0x00, 0xeb, 0x99, 0xa9, 0x6c, + 0x96, 0xd9, 0x30, 0x39, 0x3f, 0xcb, 0x4d, 0x9f, 0x97, 0x8d, 0x5a, 0xd6, 0x71, 0x42, 0x8b, 0x1d, + 0xf5, 0x72, 0x87, 0x7d, 0x4c, 0x2c, 0x80, 0x01, 0x8a, 0x1a, 0x30, 0x68, 0x6f, 0xfb, 0x6c, 0x5b, + 0xc0, 0xe8, 0x73, 0x0f, 0x77, 0xae, 0x69, 0xa2, 0xba, 0x3b, 0x86, 0xf3, 0x22, 0x1e, 0xda, 0x7b, + 0xc8, 0x50, 0xc9, 0x12, 0x89, 0xff, 0xe6, 0x57, 0xe2, 0x50, 0xef, 0x1e, 0x37, 0xda, 0xc5, 0x1d, + 0xcf, 0x63, 0xcf, 0x1c, 0x79, 0x8e, 0xf8, 0xb8, 0xb5, 0xe9, 0x62, 0x2f, 0x72, 0x29, 0x56, 0x2c, + 0x65, 0xca, 0x0c, 0x46, 0xc6, 0x0f, 0x6d, 0xc2, 0xc1, 0x9d, 0x46, 0x6b, 0x63, 0x2f, 0x24, 0x80, + 0xf9, 0x0e, 0x34, 0xbf, 0x1b, 0x00, 0x23, 0x4d, 0xef, 0x2f, 0x3f, 0x36, 0xfc, 0x5e, 0x98, 0x6d, + 0x00, 0xf5, 0x32, 0x7b, 0x17, 0x4e, 0xb7, 0xc8, 0x7f, 0x4f, 0xcb, 0x75, 0x42, 0x94, 0x8f, 0x1c, + 0x77, 0x91, 0x21, 0x58, 0x0a, 0x9f, 0xe2, 0xf0, 0x24, 0x82, 0x60, 0x38, 0x15, 0x9c, 0x66, 0xa4, + 0x0c, 0xce, 0xd7, 0x98, 0x92, 0x21, 0x82, 0xad, 0x64, 0x05, 0x9f, 0x1c, 0x81, 0x78, 0x31, 0x2e, + 0xb3, 0x35, 0xd8, 0x39, 0x26, 0xa0, 0xae, 0x18, 0xdf, 0x9b, 0x15, 0xc8, 0x54, 0x3f, 0x72, 0x73, + 0xaa, 0x6c, 0x99, 0xf3, 0x01, 0x82, 0x3f, 0x06, 0xf9, 0x22, 0x80, 0x50, 0x3f, 0xb4, 0x5d, 0x64, + 0xb5, 0xe9, 0x62, 0x2f, 0x72, 0x39, 0x76, 0x34, 0x65, 0xc7, 0x3e, 0xbd, 0x54, 0x3b, 0x16, 0x90, + 0xdc, 0x7d, 0x82, 0x5b, 0x33, 0x8a, 0xc1, 0x6a, 0x59, 0x44, 0x23, 0x87, 0x50, 0xa1, 0xc5, 0x00, + 0x00, 0x6c, 0xf6, 0x1e, 0x90, 0xfc, 0x00, 0x04, 0x36, 0x8c, 0x59, 0x9a, 0x9d, 0x6a, 0x98, 0x8f, + 0x31, 0xb2, 0x25, 0xe6, 0xca, 0x2c, 0x83, 0x26, 0x7b, 0x52, 0xdc, 0x27, 0x9f, 0xda, 0x74, 0x90, + 0xba, 0xc2, 0x2e, 0x09, 0x02, 0xec, 0xe6, 0xf4, 0x1a, 0x97, 0xc7, 0x82, 0xcf, 0x75, 0x6a, 0x2c, + 0x26, 0x04, 0x81, 0xd3, 0x70, 0xd0, 0x9c, 0x6a, 0x4e, 0x50, 0x87, 0x3f, 0x15, 0x8e, 0x6f, 0x20, + 0x50, 0xa9, 0x84, 0xea, 0xfd, 0xdf, 0x55, 0xd9, 0xb3, 0x49, 0x67, 0xc0, 0x43, 0xd2, 0xf5, 0x68, + 0x0a, 0x65, 0x54, 0x12, 0xcb, 0x7a, 0x6d, 0x50, 0xb5, 0xe9, 0x62, 0x2b, 0x72, 0x39, 0x75, 0xec, + 0xaa, 0x72, 0x28, 0x1c, 0x23, 0xca, 0x8c, 0x31, 0x24, 0xa3, 0x04, 0x8f, 0x88, 0xe2, 0xd0, 0x51, + 0x97, 0x8f, 0x00, 0xee, 0xb9, 0x2c, 0x03, 0xa3, 0x1a, 0x73, 0xd9, 0x42, 0xbc, 0x46, 0x13, 0x46, + 0x00, 0x00, 0xee, 0xc8, 0xb4, 0xc5, 0x3c, 0xe6, 0xa4, 0xe8, 0x67, 0x45, 0xf7, 0xcc, 0x7d, 0xdd, + 0x15, 0x48, 0xcf, 0xc1, 0x49, 0x8c, 0xef, 0x61, 0x96, 0xd6, 0xd9, 0x36, 0x6d, 0xb5, 0x2d, 0x39, + 0x73, 0x56, 0x21, 0xa7, 0x00, 0xf6, 0xe3, 0x6e, 0xc2, 0xf8, 0x82, 0xf9, 0x01, 0x70, 0xd3, 0x0a, + 0x44, 0xed, 0xe6, 0x74, 0xfe, 0xbe, 0xbd, 0xc4, 0xff, 0x43, 0x28, 0x18, 0xa1, 0xa4, 0x95, 0xde, + 0x49, 0x6c, 0x24, 0xc7, 0xcb, 0x7c, 0x5e, 0x71, 0xc1, 0xf9, 0x37, 0xcb, 0x11, 0xc9, 0x4a, 0xa4, + 0x95, 0xe9, 0x62, 0x2b, 0x72, 0x39, 0x65, 0x8c, 0xaf, 0xdd, 0x47, 0x5c, 0xb0, 0x00, 0x49, 0x93, + 0x33, 0x62, 0x33, 0xea, 0x01, 0x96, 0x10, 0xe9, 0xad, 0x31, 0x60, 0x63, 0xf9, 0x70, 0xb5, 0x05, + 0x93, 0x21, 0x00, 0x00, 0x00, 0x1b, 0xf0, 0xb4, 0x11, 0x74, 0xb8, 0x13, 0x3f, 0xe9, 0xa0, 0x87, + 0xa9, 0xeb, 0xf4, 0x90, 0xcd, 0xf1, 0xd5, 0x98, 0xa1, 0xc7, 0xc4, 0xf3, 0x2d, 0xe2, 0x38, 0x12, + 0x1b, 0x59, 0x0c, 0xa0, 0x6f, 0x2d, 0x00, 0xd6, 0xfb, 0xfd, 0x1f, 0x4f, 0xac, 0x83, 0x66, 0xe6, + 0x30, 0xf0, 0xe1, 0xe6, 0x5f, 0xfe, 0x37, 0x82, 0xde, 0x01, 0xe0, 0x63, 0x6f, 0x7a, 0x5b, 0x81, + 0x01, 0xf1, 0x7c, 0x58, 0x9f, 0x4a, 0x7d, 0x11, 0xd2, 0xd3, 0x20, 0x4e, 0xb5, 0xfc, 0xe3, 0x28, + 0xd9, 0x0b, 0xf6, 0x5d, 0x8e, 0x1c, 0x1c, 0xec, 0xb5, 0xed, 0xae, 0xab, 0x72, 0x29, 0x85, 0xcb, + 0xb0, 0xdc, 0x57, 0x20, 0xf0, 0xa7, 0x97, 0x09, 0x74, 0xb4, 0x8e, 0xbb, 0x8a, 0x26, 0x54, 0xe4, + 0xcd, 0x48, 0x58, 0xcc, 0xea, 0xe0, 0x6f, 0x98, 0xb6, 0x00, 0xa4, 0x1b, 0x6d, 0x00, 0x2b, 0x3a, + 0xcf, 0x5b, 0xb7, 0x5e, 0xc5, 0x12, 0x68, 0xd3, 0xaf, 0x2c, 0x53, 0x43, 0x57, 0x1f, 0xe2, 0xb6, + 0x6e, 0xb0, 0xe1, 0x95, 0x7e, 0x6d, 0x63, 0x04, 0x32, 0x58, 0x9d, 0x3a, 0xe8, 0xe2, 0x21, 0xc5, + 0x2e, 0x45, 0x56, 0xec, 0x38, 0x53, 0xe1, 0x0c, 0x98, 0xcd, 0x8f, 0x00, 0xc0, 0x58, 0x8f, 0x80, + 0x4e, 0x14, 0x9d, 0x44, 0x39, 0x0f, 0xa9, 0x8f, 0x67, 0xc8, 0xed, 0xf4, 0x69, 0x45, 0x64, 0x76, + 0x98, 0x5f, 0x96, 0xa1, 0x88, 0x8c, 0xdf, 0x5f, 0x19, 0x7e, 0xc7, 0x26, 0xc1, 0x18, 0x78, 0xdc, + 0xb4, 0x71, 0x61, 0x8b, 0x72, 0x29, 0x85, 0xf3, 0xaf, 0xdd, 0x47, 0x5c, 0xf8, 0xf7, 0x5d, 0x32, + 0xb2, 0x35, 0x24, 0x6f, 0x38, 0xf4, 0x7c, 0x9b, 0x23, 0x39, 0xdd, 0xd4, 0x86, 0x97, 0xff, 0xc8, + 0x61, 0x9b, 0xf3, 0xf2, 0xad, 0x9b, 0xb1, 0x5d, 0x07, 0x94, 0x64, 0x06, 0x3a, 0x87, 0xec, 0x50, + 0x74, 0x21, 0x00, 0xc6, 0x46, 0x09, 0xba, 0xd1, 0x31, 0x47, 0xa6, 0xeb, 0x5f, 0x5a, 0xd6, 0x49, + 0x18, 0xeb, 0x1b, 0x99, 0xf5, 0x21, 0x5a, 0xe8, 0xb0, 0xa7, 0x38, 0xc6, 0xc7, 0xf9, 0x21, 0x4a, + 0x13, 0x0a, 0xf8, 0xe6, 0xae, 0xf9, 0x9f, 0x9f, 0x40, 0x68, 0x50, 0xb8, 0x9f, 0x0c, 0xe8, 0x70, + 0xc4, 0x70, 0x33, 0x08, 0xdd, 0x46, 0x76, 0x76, 0x55, 0x74, 0x43, 0x17, 0xc9, 0xcc, 0xbb, 0x6b, + 0x50, 0x86, 0xda, 0x12, 0x79, 0x9f, 0x04, 0xaf, 0xb4, 0x4d, 0x18, 0x0b, 0x72, 0x29, 0x75, 0x83, + 0x37, 0xe8, 0x78, 0x4c, 0xdd, 0x28, 0xd1, 0xf1, 0xa5, 0x1f, 0xea, 0x9c, 0x2d, 0x1f, 0xfc, 0x29, + 0x3b, 0xca, 0x42, 0xdd, 0x56, 0x2f, 0x55, 0xaa, 0x11, 0x41, 0x23, 0x4b, 0xe0, 0x8a, 0xfe, 0x4d, + 0x49, 0x93, 0x7e, 0xd0, 0x3a, 0x26, 0x94, 0xcf, 0x54, 0xd2, 0x73, 0x43, 0xa5, 0x86, 0x08, 0x3b, + 0xdb, 0x9c, 0x33, 0x0b, 0xde, 0xd1, 0x22, 0x51, 0xa9, 0xff, 0x73, 0xe3, 0xe2, 0x0d, 0x78, 0x3b, + 0xc0, 0x66, 0xc1, 0x2b, 0x3f, 0x97, 0x7e, 0x13, 0xc7, 0x4a, 0x5b, 0x87, 0x8f, 0x43, 0xa4, 0xc2, + 0x3c, 0xad, 0xf1, 0x1a, 0x7c, 0x94, 0xfa, 0x33, 0x6a, 0xa2, 0x0c, 0x5c, 0x62, 0x75, 0x00, 0x42, + 0xab, 0xed, 0x05, 0x25, 0x58, 0x69, 0x4e, 0xc1, 0xcc, 0x53, 0xc6, 0x54, 0xc6, 0x1c, 0xce, 0x94, + 0xb4, 0x4d, 0x18, 0x0b, 0x72, 0x39, 0x55, 0xab, 0xaf, 0xa7, 0x15, 0xa8, 0xfa, 0xa5, 0x34, 0x80, + 0x03, 0xb3, 0x75, 0xe8, 0x13, 0x94, 0x18, 0xdc, 0xd8, 0x42, 0xea, 0x90, 0x95, 0x6b, 0x37, 0x53, + 0x2e, 0x0f, 0xc1, 0x0f, 0xa9, 0x55, 0x71, 0xa2, 0xbe, 0xee, 0xe2, 0x16, 0xb0, 0x47, 0x82, 0x1f, + 0x91, 0x53, 0xc1, 0xa2, 0x19, 0xc8, 0x5e, 0x37, 0x98, 0x7f, 0x20, 0x33, 0x91, 0x1b, 0x8a, 0x12, + 0xc1, 0x67, 0xa5, 0xbf, 0x6a, 0xa6, 0xc2, 0xe9, 0xf2, 0xe6, 0x21, 0x4a, 0xf0, 0xba, 0xed, 0xa3, + 0x9f, 0x8d, 0xe3, 0xc3, 0x54, 0xac, 0x01, 0x62, 0x53, 0x20, 0x7c, 0x7c, 0x53, 0x59, 0x5b, 0xd3, + 0x8a, 0x6d, 0x86, 0x32, 0x50, 0x58, 0xc5, 0xe8, 0xe3, 0xf8, 0xff, 0xc4, 0x91, 0x89, 0x75, 0x2e, + 0x8a, 0xe4, 0x9e, 0x73, 0xda, 0x64, 0x27, 0x83, 0x94, 0x3c, 0x71, 0x0b, 0x72, 0x39, 0x55, 0x6b, + 0xaf, 0xdd, 0x47, 0x5c, 0xc7, 0x48, 0xbf, 0x31, 0x23, 0xf9, 0x44, 0x19, 0xad, 0x87, 0xee, 0x99, + 0xce, 0xdd, 0xbe, 0xba, 0x25, 0x83, 0x36, 0x59, 0x62, 0x45, 0x2f, 0xcc, 0xb3, 0x56, 0xae, 0x24, + 0xc9, 0xf1, 0x9d, 0x05, 0x11, 0x5d, 0x68, 0x98, 0x71, 0xd4, 0xef, 0xa6, 0xc2, 0x21, 0x6e, 0x39, + 0x11, 0x0b, 0x96, 0x04, 0xc0, 0xfc, 0x74, 0xa4, 0xe5, 0x0e, 0xef, 0x05, 0x1a, 0x4d, 0x1e, 0x83, + 0xa8, 0xdd, 0x5f, 0xcd, 0x23, 0x89, 0x26, 0xad, 0x27, 0x0f, 0x14, 0xa0, 0xba, 0x22, 0x87, 0x05, + 0x98, 0xab, 0x84, 0x4e, 0x9f, 0x7d, 0x8e, 0x28, 0x09, 0x8f, 0xf2, 0xe1, 0xe6, 0xbe, 0xa3, 0x9e, + 0xf4, 0xb4, 0xd3, 0x2d, 0x93, 0xb5, 0x8c, 0xe6, 0x3b, 0x7e, 0x27, 0x17, 0x9c, 0x31, 0x26, 0x42, + 0xb4, 0x3c, 0x71, 0x0b, 0x72, 0x29, 0x65, 0x4b, 0xaf, 0xdc, 0xf2, 0xe1, 0x37, 0x69, 0x8f, 0x62, + 0x94, 0xaa, 0x2e, 0x8f, 0x4c, 0x13, 0x76, 0x24, 0xa7, 0xc5, 0x6a, 0xeb, 0xcd, 0xe4, 0x11, 0x6e, + 0xaa, 0x4d, 0x5a, 0xbc, 0x30, 0x81, 0xcb, 0xaf, 0x22, 0x20, 0x00, 0x55, 0x45, 0x25, 0x83, 0xf9, + 0xb2, 0x42, 0x42, 0x5c, 0x7f, 0x20, 0x1c, 0x45, 0x7d, 0x12, 0xa8, 0xfe, 0x93, 0xad, 0x29, 0x9e, + 0xb1, 0xdc, 0xc6, 0xaa, 0xc1, 0xb5, 0x4d, 0xae, 0xe6, 0xe2, 0x50, 0x62, 0x66, 0xb7, 0x13, 0x9e, + 0x84, 0xe3, 0xed, 0x02, 0x90, 0x01, 0x84, 0x09, 0x8e, 0x18, 0x12, 0xe0, 0xf9, 0x0f, 0x38, 0x35, + 0xb1, 0x62, 0x99, 0x3a, 0xc5, 0x21, 0x65, 0xa1, 0x4e, 0xe5, 0x63, 0x3f, 0x9c, 0x43, 0x63, 0xb4, + 0xae, 0xc8, 0x52, 0x31, 0xa2, 0x2a, 0xf5, 0xf3, 0x94, 0x3c, 0x71, 0x0b, 0x72, 0x39, 0x55, 0x53, + 0xaf, 0xa6, 0xca, 0x13, 0x95, 0x17, 0x6c, 0x2d, 0x47, 0x4e, 0xf4, 0x3a, 0xb8, 0xf0, 0x27, 0x55, + 0xf9, 0x78, 0x67, 0x4e, 0x50, 0x6a, 0xc0, 0x2b, 0x9f, 0xe5, 0xda, 0x28, 0xcc, 0x23, 0xae, 0x95, + 0xd0, 0xc0, 0xff, 0x90, 0xcf, 0xf1, 0x89, 0x7e, 0xc9, 0x79, 0x70, 0x48, 0xc4, 0x47, 0x85, 0x26, + 0x37, 0x26, 0xc4, 0x55, 0x42, 0xd7, 0xd3, 0x69, 0x9f, 0x2f, 0xe7, 0xf4, 0x2c, 0x5d, 0x96, 0x37, + 0xb0, 0xb7, 0x47, 0x3d, 0x1e, 0x3d, 0xf3, 0x39, 0xe5, 0xdc, 0xe7, 0x81, 0xf1, 0x7d, 0x22, 0xd7, + 0x09, 0xee, 0x56, 0x19, 0xe7, 0xc6, 0x53, 0x43, 0x0c, 0x8b, 0x37, 0x62, 0x68, 0x9e, 0x90, 0xa8, + 0x88, 0x9b, 0x14, 0x5d, 0x29, 0xdf, 0xaf, 0xfa, 0x7d, 0x7e, 0x0f, 0x63, 0xb3, 0xc7, 0x2e, 0xbf, + 0x94, 0x3c, 0x71, 0x0b, 0x72, 0x29, 0x45, 0x4b, 0x69, 0xab, 0xe4, 0x62, 0x9f, 0xb0, 0x4e, 0xd3, + 0x48, 0xa7, 0xb8, 0xa8, 0x6b, 0x21, 0xd6, 0x1a, 0x0d, 0xcc, 0xe5, 0x36, 0xc5, 0x24, 0xba, 0xad, + 0xdf, 0x35, 0xe1, 0x45, 0xa8, 0xd4, 0x8c, 0x4e, 0x88, 0x37, 0x5f, 0x09, 0x05, 0x0d, 0x8d, 0x14, + 0x44, 0xd7, 0x7e, 0x17, 0x13, 0xa4, 0xd4, 0x74, 0x9d, 0x64, 0x6d, 0x60, 0xd0, 0x4c, 0x82, 0x4e, + 0x3a, 0xb4, 0x3b, 0xd6, 0xe3, 0xa9, 0xe3, 0xda, 0x0b, 0x97, 0xec, 0xc4, 0x1a, 0x65, 0x64, 0x4a, + 0x00, 0x38, 0xf2, 0x3c, 0x3f, 0x09, 0x9e, 0x22, 0x2b, 0x00, 0xaf, 0x4c, 0xac, 0x3b, 0x00, 0x1d, + 0x25, 0xab, 0x0b, 0x1a, 0x56, 0xe1, 0x7b, 0x8e, 0xc8, 0x80, 0x4e, 0x68, 0xcf, 0x18, 0x74, 0x19, + 0x10, 0x2c, 0xa0, 0x8c, 0x42, 0x04, 0x38, 0xf7, 0xb4, 0x4d, 0x18, 0x0b, 0x72, 0x29, 0x65, 0x4b, + 0xb0, 0xd2, 0xbf, 0xfa, 0x22, 0x62, 0xa0, 0x3a, 0xbe, 0x16, 0x43, 0x4e, 0xd1, 0x9e, 0x40, 0x98, + 0x3c, 0x1c, 0x26, 0xe8, 0x69, 0xae, 0x0e, 0x13, 0xa9, 0x1e, 0x42, 0x47, 0x9e, 0x7a, 0x56, 0xf6, + 0xc0, 0xb6, 0xbb, 0x80, 0x00, 0x34, 0xd4, 0x27, 0x3b, 0x31, 0x20, 0xa2, 0xdb, 0x0e, 0x81, 0xe9, + 0x23, 0x27, 0x8c, 0xd2, 0x20, 0xf6, 0x1a, 0x79, 0xe7, 0x23, 0x51, 0xec, 0x6f, 0x15, 0x7c, 0x7f, + 0x7b, 0xce, 0xa9, 0x30, 0xf9, 0xb4, 0x4a, 0x1e, 0x27, 0x3e, 0xc3, 0xe1, 0x10, 0x60, 0xfa, 0xc1, + 0x62, 0x6a, 0x67, 0x43, 0x62, 0xe1, 0x9d, 0x30, 0x75, 0x2a, 0x19, 0xf1, 0x5e, 0xd6, 0x06, 0xaf, + 0x46, 0xb7, 0x1c, 0x47, 0x0d, 0xc8, 0xd3, 0xc3, 0x65, 0xf0, 0x66, 0x83, 0xc5, 0x9e, 0xe3, 0x1c, + 0xb4, 0x3c, 0x71, 0x0b, 0x72, 0x29, 0x45, 0x63, 0xb0, 0xd2, 0xc2, 0x06, 0xf4, 0x6c, 0xfb, 0xc1, + 0x8f, 0x89, 0x8a, 0x74, 0x0a, 0xd2, 0x5f, 0x4a, 0xf9, 0x7c, 0x3c, 0x51, 0xcf, 0x28, 0x07, 0x36, + 0xca, 0xbd, 0x7a, 0xcd, 0xd0, 0x57, 0x1f, 0x54, 0x01, 0x19, 0x8c, 0xd0, 0x8b, 0x1e, 0x40, 0xa5, + 0x76, 0x7f, 0xb0, 0x25, 0x79, 0x3c, 0xa4, 0x51, 0x74, 0xa3, 0x6a, 0x53, 0x44, 0xbb, 0x9a, 0x39, + 0xa7, 0x8b, 0xd4, 0x66, 0xe5, 0x8e, 0x52, 0xc9, 0xbb, 0x9e, 0x2a, 0x19, 0x31, 0x12, 0x15, 0x5d, + 0x4b, 0x8f, 0xfc, 0x08, 0xb2, 0xd3, 0x0a, 0xb8, 0xad, 0xa7, 0x38, 0xba, 0xd6, 0x83, 0xb3, 0xe8, + 0x74, 0x04, 0xd4, 0x19, 0x01, 0xc4, 0xc3, 0x96, 0xe5, 0x8a, 0xe1, 0x17, 0x09, 0xf0, 0xd4, 0x40, + 0x9a, 0xce, 0x1b, 0x1e, 0x1c, 0x9c, 0x3d, 0x0b, 0xb2, 0xfc, 0xd5, 0xcb, 0x72, 0x29, 0x55, 0x43, + 0xaf, 0xdd, 0x92, 0x47, 0xe0, 0x4e, 0xf8, 0xd3, 0x44, 0x79, 0xec, 0x05, 0x38, 0xd5, 0x9d, 0xfe, + 0xec, 0x81, 0xc0, 0xd3, 0x3d, 0xcd, 0x5c, 0x3b, 0x04, 0x92, 0x44, 0x6b, 0x60, 0x15, 0xc9, 0x08, + 0xc9, 0x19, 0xe7, 0xc3, 0x95, 0x00, 0x06, 0xf0, 0x63, 0x39, 0x2f, 0x9d, 0xca, 0xe7, 0xdd, 0x5e, + 0xe8, 0x42, 0x60, 0xae, 0xf7, 0x3d, 0x54, 0x97, 0xc8, 0xf0, 0xae, 0xe7, 0xc9, 0x19, 0xc0, 0xba, + 0xeb, 0xff, 0x21, 0xa9, 0xe4, 0xbd, 0x3f, 0xfb, 0xb8, 0x4a, 0x9c, 0x3e, 0x48, 0x8c, 0x19, 0xc2, + 0x61, 0xcf, 0x94, 0xd6, 0x20, 0x58, 0x2e, 0x7f, 0x00, 0x95, 0x6f, 0x65, 0x5d, 0x45, 0xc6, 0x76, + 0x59, 0x54, 0x9c, 0xa5, 0x52, 0x15, 0x68, 0x05, 0x92, 0x9e, 0xd3, 0x98, 0x75, 0xdc, 0x37, 0x6e, + 0xb2, 0xfc, 0xd5, 0xcb, 0x72, 0x39, 0x45, 0x3b, 0xaf, 0xa6, 0xc8, 0x6c, 0x71, 0xa7, 0x64, 0xc8, + 0x03, 0xf6, 0x41, 0x91, 0xe2, 0xaa, 0x0d, 0x16, 0x53, 0xcc, 0x0b, 0xaf, 0xcf, 0x29, 0x88, 0x88, + 0xc5, 0x52, 0x40, 0x05, 0x03, 0x49, 0xbe, 0xcf, 0x29, 0x47, 0xdf, 0x86, 0x00, 0x00, 0x0d, 0xa8, + 0x9a, 0x70, 0xe5, 0x7d, 0xbc, 0x39, 0xd0, 0xee, 0x27, 0x3b, 0xea, 0xfa, 0xaa, 0xb5, 0x90, 0x9d, + 0xfc, 0xb9, 0x2d, 0x43, 0xa0, 0xb7, 0xc5, 0xb3, 0xb4, 0x38, 0xfa, 0x6c, 0xe8, 0x55, 0x2e, 0xba, + 0xd9, 0xe1, 0xdc, 0xe1, 0x38, 0x0e, 0xf7, 0xe6, 0x8b, 0x29, 0xbc, 0xe9, 0x93, 0x90, 0x6a, 0x66, + 0x5b, 0x06, 0x91, 0x5d, 0x4c, 0xfe, 0x15, 0x15, 0x8f, 0xd5, 0xd3, 0x82, 0xfd, 0x0b, 0xc9, 0x02, + 0x71, 0x31, 0x8d, 0xc7, 0x03, 0x0e, 0x1e, 0x33, 0xb2, 0xfc, 0xd5, 0xcb, 0x72, 0x29, 0x45, 0x43, + 0xaf, 0xdd, 0x49, 0x48, 0xd3, 0x75, 0x5e, 0xb0, 0xd0, 0xb0, 0x73, 0x72, 0x7d, 0x02, 0x7b, 0x87, + 0x8e, 0x21, 0xd1, 0xd1, 0xac, 0x4a, 0xb8, 0x7d, 0x1a, 0x56, 0x42, 0x43, 0x9a, 0x3b, 0xfe, 0xda, + 0x43, 0xb4, 0x11, 0x0a, 0x88, 0x0e, 0x16, 0xf1, 0xfe, 0x0c, 0x9b, 0x62, 0x20, 0x22, 0x25, 0x69, + 0xb6, 0x6d, 0x50, 0x93, 0x3e, 0xa7, 0x40, 0x85, 0x5a, 0xd0, 0x9d, 0x33, 0x8c, 0x92, 0xf5, 0x19, + 0xdd, 0xef, 0x2b, 0x3e, 0xb3, 0xdb, 0xf7, 0x91, 0xd6, 0x0d, 0xd3, 0x21, 0x10, 0xc0, 0xaf, 0x56, + 0x95, 0xac, 0x9e, 0x9c, 0xde, 0xb4, 0x81, 0x1f, 0x47, 0xf9, 0x0f, 0xdd, 0xbe, 0x03, 0xab, 0x3a, + 0x4c, 0x2e, 0x80, 0x3a, 0xc2, 0x27, 0x1c, 0x68, 0x60, 0x65, 0xce, 0x31, 0x43, 0x9d, 0x32, 0x63, + 0xb2, 0xfc, 0xd5, 0xcb, 0x72, 0x29, 0x35, 0x43, 0xaf, 0xdd, 0x47, 0x5c, 0xf9, 0x00, 0xce, 0xda, + 0x72, 0x75, 0xe5, 0xce, 0x0f, 0xda, 0x63, 0xf1, 0xbb, 0x2f, 0x6e, 0x27, 0xaf, 0xc9, 0xf9, 0x05, + 0x2f, 0x3b, 0x77, 0x81, 0x72, 0xfe, 0x1c, 0x01, 0xb7, 0x00, 0xf3, 0x32, 0x27, 0x6c, 0xfa, 0x1e, + 0xeb, 0x80, 0x00, 0x1b, 0xe5, 0x20, 0x2d, 0x53, 0x50, 0xe1, 0x92, 0x72, 0x7d, 0x1d, 0x9b, 0x6f, + 0xaa, 0x9d, 0x8a, 0x3c, 0x5a, 0xa6, 0xa0, 0x19, 0xf7, 0x4b, 0x4f, 0x1a, 0xc7, 0x13, 0xae, 0xcf, + 0xa1, 0x80, 0x05, 0x8a, 0x1b, 0x78, 0x51, 0xe3, 0x70, 0x5e, 0x7f, 0x7a, 0x5b, 0x7b, 0x03, 0x67, + 0x5c, 0x30, 0xb4, 0xbe, 0xc5, 0xf1, 0x4d, 0x2b, 0x9d, 0x95, 0xf2, 0xe0, 0x68, 0x3f, 0x9c, 0x71, + 0xe0, 0x3c, 0x0f, 0x82, 0x06, 0xc1, 0xb1, 0xdc, 0xb2, 0xf7, 0x96, 0xcf, 0x72, 0x29, 0x25, 0x1b, + 0xaf, 0xa7, 0x16, 0x19, 0x40, 0xf1, 0x9c, 0x25, 0x92, 0x3f, 0x33, 0xb2, 0xbf, 0x20, 0xb3, 0xa0, + 0x2d, 0x5d, 0xae, 0x21, 0xf2, 0xc5, 0xb8, 0x11, 0x55, 0x11, 0x4b, 0x02, 0xc7, 0x79, 0x44, 0x5f, + 0x48, 0xb5, 0x1e, 0x16, 0x00, 0x07, 0x9a, 0xbe, 0xf0, 0x4d, 0x7d, 0x00, 0x20, 0x8a, 0x54, 0xf4, + 0x21, 0xf3, 0x81, 0x1d, 0x49, 0x66, 0x9c, 0xb5, 0xf2, 0x32, 0xa6, 0xcb, 0x96, 0xd0, 0x2c, 0xd0, + 0x20, 0x1c, 0xfa, 0xce, 0xa2, 0x43, 0x4a, 0x0f, 0xf1, 0x51, 0x82, 0x6f, 0x87, 0xde, 0x9d, 0x20, + 0x17, 0x72, 0x69, 0x02, 0xe2, 0x8d, 0x0c, 0x3f, 0x68, 0x87, 0x07, 0xaa, 0xf2, 0xd7, 0xec, 0xd4, + 0x8c, 0x01, 0xc2, 0x79, 0x02, 0xbf, 0xfb, 0xc6, 0x29, 0xa4, 0x65, 0x31, 0xdb, 0x5a, 0x65, 0xbc, + 0xb2, 0xf7, 0x96, 0xcb, 0x72, 0x39, 0x55, 0x34, 0xaf, 0xa6, 0xc8, 0x17, 0xb7, 0x7d, 0xd5, 0xca, + 0x74, 0xc2, 0x5c, 0x37, 0x77, 0xf3, 0xf9, 0x9b, 0x22, 0xa2, 0x30, 0x43, 0x24, 0x9d, 0x13, 0xb0, + 0x8c, 0x2c, 0xb4, 0x26, 0x5b, 0x91, 0xcb, 0xd0, 0x02, 0xe9, 0xea, 0x3e, 0xb9, 0xbd, 0xc7, 0xd3, + 0x12, 0x4c, 0x44, 0xcf, 0xfe, 0xee, 0xb3, 0xfc, 0xf8, 0x7d, 0xd0, 0x28, 0xd0, 0xc9, 0x5e, 0xbc, + 0x0a, 0xd6, 0xf6, 0xa7, 0x19, 0x4a, 0x53, 0x3b, 0x45, 0xfb, 0x17, 0x90, 0x9b, 0xd2, 0xf2, 0x03, + 0xea, 0x1f, 0x0f, 0x0a, 0x3d, 0x82, 0xd0, 0x92, 0x50, 0x3c, 0xaa, 0x8f, 0x0c, 0x9c, 0x2a, 0x03, + 0xb0, 0x76, 0x51, 0xab, 0x45, 0x27, 0xa8, 0x00, 0x0e, 0x31, 0xf1, 0x68, 0x25, 0x0d, 0x5f, 0x8a, + 0xf2, 0x87, 0xf8, 0x7c, 0x38, 0xdf, 0x67, 0x04, 0x92, 0xf7, 0x96, 0xcb, 0x72, 0x29, 0x25, 0x4b, + 0x69, 0xd4, 0x6d, 0x1c, 0xb8, 0xb2, 0x19, 0x82, 0x7a, 0xc5, 0x7e, 0x26, 0xbd, 0x0c, 0x51, 0xe1, + 0xb3, 0x8e, 0xe9, 0xf5, 0x0e, 0xec, 0x92, 0x79, 0x9c, 0x5d, 0x5a, 0xec, 0x4d, 0x1f, 0x9d, 0x03, + 0x5e, 0xcf, 0x10, 0x00, 0x00, 0x55, 0xb2, 0xb3, 0x23, 0xfd, 0xa2, 0x86, 0x58, 0xeb, 0xdd, 0xe8, + 0x29, 0xc3, 0x02, 0x4a, 0x66, 0x04, 0x41, 0xa8, 0x85, 0x6d, 0xc4, 0x07, 0xd7, 0x1f, 0xec, 0x46, + 0x3d, 0xbf, 0x8b, 0xf1, 0x3d, 0xb8, 0xf0, 0x7d, 0x6c, 0xd3, 0xaf, 0x80, 0x5a, 0x1b, 0x43, 0xd9, + 0x89, 0xd4, 0x91, 0xbd, 0x3c, 0xf1, 0x53, 0x86, 0x1c, 0x31, 0x38, 0x7f, 0x08, 0x17, 0x77, 0x73, + 0x60, 0x20, 0x4f, 0x4b, 0x66, 0x09, 0x76, 0x38, 0xdf, 0x8e, 0x00, 0x20, 0x19, 0xfb, 0x36, 0xe8, + 0xd2, 0xf7, 0x96, 0xcb, 0x72, 0x39, 0x55, 0x44, 0x69, 0xd5, 0x83, 0xaf, 0xc3, 0x79, 0x09, 0x0e, + 0x52, 0xd2, 0x55, 0x8d, 0x78, 0xcc, 0x3a, 0x6c, 0x65, 0xc1, 0xcc, 0x02, 0xac, 0x02, 0x40, 0x73, + 0x29, 0x63, 0x1f, 0x13, 0x45, 0x67, 0x03, 0xf9, 0x08, 0xa2, 0x20, 0x00, 0x00, 0x91, 0x15, 0xe4, + 0x27, 0x74, 0xe0, 0xf0, 0x90, 0x05, 0x2f, 0xda, 0x12, 0xdd, 0xaa, 0x2d, 0x00, 0x25, 0xf0, 0xd5, + 0xaa, 0x72, 0xa6, 0x30, 0xc6, 0x7f, 0x9d, 0x33, 0xce, 0x22, 0xcd, 0x65, 0x84, 0x35, 0xe8, 0xe2, + 0xb8, 0x0d, 0xf0, 0xa5, 0x40, 0x79, 0x01, 0x28, 0x6b, 0x0c, 0x32, 0x89, 0x4e, 0xc0, 0xe7, 0xef, + 0xb6, 0x85, 0xd9, 0x63, 0x91, 0x85, 0xee, 0x0c, 0xa5, 0x7d, 0x71, 0xf3, 0x29, 0x01, 0xbd, 0x52, + 0x57, 0xd7, 0x48, 0x13, 0x63, 0xb8, 0xb0, 0x09, 0xb2, 0xf7, 0x96, 0xcb, 0x72, 0x39, 0x55, 0x44, + 0x69, 0xd9, 0xef, 0x6c, 0xb2, 0x38, 0xbe, 0x9e, 0x51, 0xd0, 0xd9, 0x42, 0xfd, 0xf2, 0xa0, 0x1d, + 0x83, 0x0d, 0xb8, 0xeb, 0xbe, 0xfd, 0xdd, 0xc4, 0x1b, 0x86, 0xb7, 0xa3, 0x2d, 0x79, 0x91, 0xc5, + 0x58, 0x6c, 0x47, 0x20, 0x4f, 0xe9, 0x53, 0xab, 0x16, 0x22, 0x45, 0x5c, 0xa5, 0xce, 0x7c, 0x0f, + 0xd6, 0xd0, 0xd1, 0x15, 0x95, 0x10, 0xb9, 0xb1, 0x25, 0x79, 0x74, 0x07, 0x2e, 0xb8, 0x2a, 0x55, + 0x42, 0x4f, 0xd6, 0x45, 0x3d, 0x5e, 0x19, 0x86, 0x0a, 0x28, 0xc1, 0x36, 0xf7, 0xeb, 0x9e, 0x8e, + 0xe0, 0x34, 0x21, 0x87, 0x47, 0xdb, 0x03, 0x3f, 0x4a, 0x88, 0x12, 0x43, 0x86, 0x68, 0x7a, 0x1c, + 0x55, 0x66, 0x1d, 0x6b, 0x0a, 0xb3, 0x03, 0x12, 0x7e, 0x30, 0xd2, 0xc4, 0x89, 0x6a, 0xc8, 0x71, + 0xb2, 0xf7, 0x96, 0xcb, 0x72, 0x39, 0x35, 0x2c, 0x04, 0x80, 0xcf, 0x6e, 0xba, 0x53, 0x7e, 0xfc, + 0x48, 0x13, 0xb0, 0xb2, 0xe0, 0x4a, 0x27, 0x0a, 0x77, 0x12, 0x5e, 0x41, 0x52, 0xd7, 0xe2, 0x25, + 0x8a, 0x30, 0x0a, 0x64, 0x05, 0x9b, 0x60, 0x62, 0x7f, 0x5a, 0x06, 0x2a, 0x60, 0x8f, 0x2d, 0xbd, + 0x03, 0xc8, 0xaf, 0xcb, 0x2b, 0x0c, 0x6e, 0x17, 0x2d, 0x8b, 0x4d, 0xf9, 0x2d, 0x9f, 0x50, 0x28, + 0x0e, 0x87, 0x60, 0xa5, 0x32, 0x00, 0x1c, 0x80, 0x4a, 0x6b, 0x1a, 0xf1, 0x7b, 0xe5, 0x0c, 0x36, + 0x6f, 0x09, 0xe1, 0xf1, 0x39, 0x0c, 0x14, 0x43, 0xa0, 0x85, 0x69, 0x0c, 0x4d, 0x63, 0xcc, 0x13, + 0x2e, 0x06, 0x29, 0x29, 0x3e, 0x62, 0xeb, 0xea, 0xf9, 0xb3, 0x6d, 0x39, 0x82, 0x04, 0xf8, 0xe3, + 0xdc, 0xe0, 0xf8, 0x7c, 0x67, 0x13, 0x84, 0xf2, 0xab, 0x26, 0x2d, 0xe5, 0x72, 0x09, 0x55, 0x3c, + 0x00, 0x02, 0x0b, 0xfd, 0x34, 0x96, 0xcd, 0x2c, 0x13, 0xf5, 0x15, 0x62, 0xb3, 0x0c, 0xbc, 0xb0, + 0xf2, 0x55, 0x65, 0x77, 0x8a, 0x88, 0x33, 0xde, 0x29, 0xdc, 0xa7, 0xaa, 0xf1, 0x3b, 0xb7, 0xe1, + 0xf0, 0x3f, 0x7e, 0x0b, 0xd3, 0xc2, 0xca, 0x1c, 0x82, 0x29, 0x75, 0xd3, 0x40, 0x44, 0x2c, 0x35, + 0x60, 0x0b, 0xe3, 0x7c, 0xf0, 0x8d, 0x92, 0x6b, 0xa1, 0xad, 0x23, 0x83, 0x51, 0x37, 0xe4, 0x7e, + 0xdf, 0x43, 0xf8, 0xb0, 0xac, 0x3a, 0x03, 0x9d, 0xad, 0xcd, 0x2f, 0x0c, 0xc0, 0xca, 0x10, 0x80, + 0xb6, 0x78, 0x9d, 0x02, 0x39, 0xd5, 0x1b, 0xa6, 0x4b, 0x1c, 0x4b, 0x13, 0xf0, 0xf2, 0xf0, 0x3e, + 0x83, 0xc4, 0x95, 0x57, 0xc3, 0x9a, 0x38, 0xf0, 0x7c, 0x1f, 0x1c, 0x1e, 0x73, 0x25, 0x99, 0xe1, + 0xcb, 0x26, 0x2d, 0xe5, 0x72, 0x09, 0x65, 0x44, 0x00, 0x00, 0x5c, 0x72, 0x41, 0xbd, 0xd3, 0x72, + 0xc5, 0x97, 0xa1, 0x09, 0x85, 0xb7, 0xb5, 0xcd, 0x87, 0xb2, 0x14, 0xf7, 0xe4, 0xa2, 0x56, 0xf3, + 0x24, 0xd9, 0x78, 0xeb, 0x77, 0x74, 0x15, 0x2d, 0x80, 0xee, 0xd7, 0xd1, 0x9b, 0x8f, 0xd9, 0x48, + 0xcf, 0x65, 0x14, 0x8b, 0xd3, 0xed, 0x61, 0x71, 0xd3, 0x58, 0x6d, 0x8f, 0xb9, 0x3a, 0x12, 0xb8, + 0x11, 0xf0, 0x7f, 0x98, 0x0f, 0xf7, 0x0d, 0xf0, 0x6a, 0x30, 0x63, 0xc4, 0xa3, 0xf7, 0x6f, 0x30, + 0x1e, 0x7a, 0x8f, 0x5f, 0x02, 0x0a, 0xa1, 0x76, 0x95, 0x11, 0x0e, 0xb3, 0x25, 0xc1, 0x24, 0xed, + 0x84, 0x1a, 0xa0, 0x02, 0x74, 0x91, 0x93, 0xe5, 0x53, 0x6a, 0x01, 0xdb, 0x68, 0x00, 0x70, 0xec, + 0xc7, 0x0f, 0x8f, 0x3f, 0x87, 0x33, 0xd4, 0x3b, 0xab, 0x26, 0x2d, 0xe5, 0x72, 0x09, 0x65, 0x3c, + 0x00, 0x00, 0xa8, 0xe7, 0x3f, 0x87, 0x15, 0x13, 0x4d, 0x2e, 0xb6, 0x5d, 0x73, 0x44, 0x5c, 0x0f, + 0x96, 0xbd, 0x9a, 0x07, 0xe4, 0xe8, 0x25, 0x9e, 0x4e, 0xb8, 0xec, 0x83, 0xac, 0xd8, 0x21, 0x8c, + 0x49, 0xb6, 0x03, 0xf8, 0x10, 0x7d, 0x94, 0x7c, 0x00, 0xb2, 0xad, 0x2c, 0xfa, 0x1e, 0xd2, 0x5a, + 0x4d, 0xa3, 0x3e, 0x84, 0x85, 0x6e, 0x6a, 0x75, 0x12, 0x86, 0x12, 0xed, 0xfe, 0x12, 0xb6, 0x7f, + 0x44, 0x20, 0x88, 0x9f, 0x74, 0xcc, 0x4b, 0x8f, 0x8c, 0xed, 0xf2, 0x1e, 0x2e, 0xd2, 0x25, 0x93, + 0x1f, 0x5c, 0xd2, 0x6c, 0xcb, 0x4e, 0x4a, 0x01, 0xd7, 0xe0, 0xb9, 0x6d, 0x4a, 0x95, 0xcb, 0x98, + 0x5b, 0x12, 0x7c, 0x7e, 0xa4, 0x37, 0x87, 0x99, 0xc7, 0x87, 0x87, 0xc3, 0xc1, 0x87, 0x1b, 0x3b, + 0xab, 0x26, 0x2d, 0xe5, 0x72, 0x09, 0x65, 0x4c, 0x00, 0x00, 0x49, 0x66, 0xcd, 0x0f, 0xe2, 0x90, + 0x44, 0x22, 0xa7, 0xe4, 0x98, 0x09, 0x9e, 0xc8, 0x8e, 0x98, 0xff, 0x70, 0x84, 0xb0, 0x2b, 0xaf, + 0xd0, 0x13, 0xb2, 0xa3, 0xc1, 0xd0, 0xe2, 0x9a, 0xac, 0xf5, 0xeb, 0x1e, 0xa4, 0x99, 0x49, 0x97, + 0x16, 0x6d, 0x1f, 0xcc, 0x78, 0x57, 0xec, 0x44, 0x2a, 0x18, 0x86, 0x60, 0x85, 0x9d, 0x9e, 0x14, + 0x7b, 0x1b, 0x42, 0xa8, 0x40, 0x17, 0xa1, 0x89, 0xc8, 0xe9, 0xd8, 0x98, 0x78, 0x56, 0x8a, 0x32, + 0x00, 0x46, 0x03, 0x4d, 0x13, 0x13, 0x5f, 0x7c, 0x7f, 0xb6, 0x03, 0x8f, 0x67, 0x95, 0x59, 0xcf, + 0xf4, 0xc6, 0x21, 0x57, 0x38, 0x2b, 0x78, 0x77, 0x88, 0x07, 0x66, 0x1c, 0x38, 0x60, 0x39, 0xf1, + 0xf0, 0xf0, 0xf0, 0x7d, 0xe1, 0xeb, 0x5c, 0x48, 0xb2, 0xf7, 0x8a, 0xcb, 0x72, 0x09, 0x35, 0x3c, + 0xb6, 0xba, 0x95, 0xeb, 0x8c, 0xcb, 0x32, 0x16, 0x68, 0x08, 0xe8, 0xf3, 0x54, 0xed, 0xd0, 0x23, + 0xb8, 0xd8, 0xfe, 0x83, 0x49, 0x8a, 0x2c, 0xed, 0x74, 0x11, 0x5a, 0xe3, 0xe9, 0x3a, 0x74, 0x01, + 0x6f, 0x93, 0xa5, 0x68, 0xf6, 0xc2, 0xb0, 0x27, 0xab, 0xed, 0x83, 0xfe, 0x73, 0x59, 0x33, 0xf2, + 0x9a, 0xa0, 0x43, 0xd5, 0xce, 0x9d, 0xbc, 0xe6, 0x06, 0x13, 0x52, 0x2e, 0xaf, 0x50, 0x10, 0x02, + 0xb8, 0xf8, 0x78, 0x81, 0xf8, 0x21, 0xb2, 0xe7, 0xbd, 0x7c, 0x79, 0x56, 0x1d, 0xc1, 0x9f, 0x98, + 0xd9, 0x81, 0xd6, 0x38, 0x54, 0x41, 0x32, 0xa1, 0x1c, 0x62, 0x3e, 0x1e, 0x25, 0x7f, 0xb8, 0xbd, + 0x34, 0x93, 0x90, 0x08, 0x27, 0xc1, 0xe0, 0xf8, 0xf0, 0x7e, 0x1e, 0x1e, 0x1f, 0xb3, 0x62, 0x33, + 0xa6, 0x97, 0x6d, 0x65, 0x72, 0x19, 0x55, 0x4c, 0x00, 0x00, 0xad, 0xf5, 0xb8, 0x70, 0x1c, 0x3d, + 0x42, 0x6e, 0x7f, 0x08, 0x9a, 0x82, 0x46, 0x2b, 0x81, 0x4c, 0xbe, 0xaa, 0x01, 0xdb, 0x75, 0x89, + 0x79, 0x95, 0xc3, 0xbc, 0x16, 0x20, 0x87, 0x3c, 0xca, 0x15, 0xee, 0x26, 0xcf, 0x22, 0xce, 0x43, + 0xc0, 0xd3, 0x55, 0xd6, 0xac, 0x9c, 0x24, 0x66, 0xb5, 0xb0, 0x59, 0x76, 0x60, 0x23, 0xd4, 0xc8, + 0x62, 0xa3, 0x10, 0xe4, 0x25, 0x8e, 0x35, 0x1a, 0xd1, 0x49, 0x59, 0x1b, 0x8a, 0x54, 0xfc, 0x01, + 0x1a, 0xa8, 0xdf, 0x01, 0x51, 0x54, 0x5f, 0x58, 0x65, 0x22, 0xcc, 0xca, 0x31, 0xcd, 0x5f, 0xd2, + 0x6e, 0x5c, 0xbe, 0x4f, 0xc7, 0x6c, 0x0a, 0x6d, 0xc4, 0x26, 0x42, 0x1e, 0xbd, 0x86, 0x20, 0x8e, + 0x18, 0x73, 0x9e, 0x7b, 0xc0, 0x31, 0xa2, 0x2d, 0xb2, 0xf7, 0x8a, 0xcb, 0x72, 0x09, 0x45, 0x54, + 0xb7, 0x90, 0x1e, 0x6d, 0xf4, 0xf7, 0xba, 0x1c, 0x9d, 0x28, 0xa9, 0x49, 0xa0, 0xd4, 0x89, 0xa5, + 0xbb, 0x2d, 0xb1, 0xe6, 0xb5, 0x6f, 0x41, 0x76, 0x40, 0x59, 0x6b, 0x67, 0x1f, 0x5d, 0xae, 0x4c, + 0xbf, 0x68, 0x0c, 0xdc, 0x06, 0xa1, 0x0c, 0xf6, 0x02, 0xf9, 0xc2, 0x57, 0xe0, 0x02, 0xb6, 0x81, + 0x80, 0xac, 0x8b, 0x94, 0x6b, 0x89, 0xb2, 0x6d, 0x54, 0xa3, 0xf1, 0xb7, 0x49, 0x0f, 0x12, 0xc7, + 0xf2, 0x84, 0x97, 0x89, 0xf2, 0x63, 0x9f, 0x11, 0xcb, 0xbe, 0x0f, 0x91, 0x12, 0x80, 0x8a, 0x40, + 0xde, 0x5e, 0x9a, 0x92, 0xb6, 0x7b, 0xd1, 0x42, 0xf6, 0xa5, 0xef, 0x98, 0xc2, 0x4b, 0x74, 0x4e, + 0xe2, 0x39, 0x84, 0x78, 0x86, 0x3e, 0x0f, 0x1e, 0x3c, 0x38, 0xf8, 0x39, 0xd6, 0x7a, 0xf1, 0xf8, + 0xb2, 0xf7, 0x8a, 0xcb, 0x72, 0x19, 0x45, 0x5c, 0xb7, 0x8e, 0x57, 0xf0, 0x5a, 0xe1, 0xbe, 0x1d, + 0xde, 0x3a, 0xfc, 0x59, 0x2f, 0x95, 0x9a, 0x2e, 0xa3, 0x5a, 0xc6, 0xed, 0x24, 0x61, 0x10, 0xc8, + 0xff, 0x18, 0xef, 0xaa, 0x5b, 0xbc, 0xd9, 0x6e, 0xd7, 0x71, 0xb8, 0x95, 0x91, 0x0f, 0x74, 0xf3, + 0xa9, 0x87, 0x80, 0x37, 0xff, 0x65, 0xef, 0x3a, 0x46, 0x7e, 0xa1, 0x15, 0xd4, 0x23, 0x3e, 0xa5, + 0xb4, 0x7a, 0x13, 0x60, 0x61, 0xb8, 0x5d, 0xb5, 0x2b, 0xf5, 0x73, 0xb0, 0xd0, 0x20, 0x38, 0x0a, + 0x37, 0xce, 0xad, 0x7b, 0xc6, 0x3c, 0x15, 0x9e, 0x16, 0xfd, 0x0b, 0x97, 0x2f, 0x26, 0xbd, 0x18, + 0x98, 0xb9, 0xc9, 0x30, 0x13, 0x5c, 0x35, 0xf2, 0x58, 0xf2, 0x1d, 0xfa, 0xc0, 0x00, 0xf8, 0x7c, + 0x3c, 0x7c, 0x3c, 0x3e, 0x0f, 0xd7, 0x8e, 0xa9, 0xa6, 0x97, 0x6d, 0x65, 0x72, 0x19, 0x55, 0x5c, + 0x00, 0x00, 0x4a, 0xaa, 0xdf, 0xc3, 0xea, 0xc1, 0x91, 0xcc, 0x7b, 0x65, 0x32, 0xc1, 0xdf, 0x7c, + 0x26, 0xcf, 0xc7, 0xcc, 0x1c, 0x96, 0x4c, 0x19, 0xaa, 0x8e, 0x4b, 0xed, 0x33, 0xf8, 0x71, 0xfe, + 0xe8, 0x69, 0xbf, 0x44, 0x25, 0x77, 0x34, 0xe9, 0x85, 0xfc, 0xa4, 0xfb, 0xef, 0xd2, 0xaf, 0xe5, + 0x2e, 0xcb, 0xe8, 0x6f, 0x56, 0x61, 0xa8, 0x92, 0xa7, 0x6d, 0x0f, 0xd5, 0x4b, 0xc9, 0x7b, 0x9a, + 0x1d, 0x09, 0x73, 0x8f, 0x2f, 0x3d, 0xed, 0x1f, 0xf2, 0xad, 0xfc, 0x4a, 0x1e, 0x13, 0x00, 0x3a, + 0x92, 0x23, 0xce, 0x82, 0xa6, 0xca, 0xce, 0xef, 0x49, 0xb9, 0x0c, 0x13, 0x96, 0x63, 0x95, 0x58, + 0xf8, 0x90, 0xde, 0xc3, 0xc1, 0xe1, 0xe1, 0xc0, 0xf8, 0x78, 0x39, 0xde, 0x61, 0xf3, 0xcc, 0x93, + 0xc6, 0x97, 0x6d, 0x65, 0x72, 0x09, 0x55, 0x5c, 0x00, 0x00, 0x04, 0x64, 0xc2, 0x65, 0xa5, 0x9b, + 0x1b, 0xf5, 0x1e, 0x7c, 0x69, 0x02, 0x66, 0x02, 0xf5, 0x67, 0x3d, 0x74, 0xc1, 0x94, 0x28, 0x45, + 0xee, 0xf2, 0x61, 0xd7, 0x6c, 0x4f, 0xc3, 0xf7, 0xf6, 0x7c, 0x0a, 0xf2, 0xe1, 0xad, 0x80, 0xab, + 0x29, 0xb5, 0xb6, 0x0e, 0x9c, 0xc8, 0xb9, 0x73, 0xa3, 0xa4, 0x9b, 0x08, 0x78, 0x46, 0x33, 0x05, + 0x59, 0x73, 0x38, 0x7e, 0x53, 0x82, 0xab, 0xb4, 0xd8, 0x3e, 0xc0, 0xd0, 0xf4, 0x6f, 0xf1, 0x37, + 0xbc, 0x62, 0xfb, 0xf8, 0x14, 0x2f, 0x8f, 0xc0, 0xf5, 0xdc, 0xb0, 0x69, 0x43, 0x1e, 0x1f, 0x70, + 0x33, 0xad, 0xd1, 0x5e, 0xd1, 0x5a, 0x2b, 0xfb, 0xff, 0x2c, 0x90, 0x03, 0x8f, 0x31, 0xce, 0x1f, + 0x07, 0xc1, 0xf8, 0x70, 0xee, 0x79, 0xe1, 0x77, 0xc4, 0x4f, 0xee, 0x21, 0x72, 0x09, 0x55, 0x5c, + 0x00, 0x00, 0x51, 0xd6, 0xd8, 0xe3, 0xc4, 0x8c, 0x8e, 0x67, 0xea, 0x5f, 0xa8, 0xf3, 0x29, 0x5f, + 0x08, 0x8d, 0x93, 0x99, 0x5e, 0x36, 0xe5, 0x76, 0x06, 0x6a, 0x30, 0xa4, 0x32, 0x32, 0xfc, 0xce, + 0xab, 0x13, 0x89, 0xa5, 0xe1, 0x82, 0xfb, 0xd5, 0x65, 0x45, 0xa6, 0x17, 0x87, 0x51, 0xbc, 0x8a, + 0xce, 0x5a, 0xf2, 0x1a, 0xba, 0x33, 0xf1, 0x3c, 0x75, 0x96, 0x66, 0xe7, 0x9c, 0x47, 0xa8, 0x75, + 0xc4, 0xb0, 0x6c, 0x56, 0x50, 0xcf, 0xe9, 0xa7, 0xdf, 0x0d, 0xf0, 0xf8, 0x41, 0x91, 0xfe, 0x21, + 0x76, 0x2c, 0xb4, 0x59, 0x22, 0x27, 0x1f, 0x33, 0x15, 0xdd, 0x33, 0xb4, 0xf6, 0x0d, 0xb1, 0x1f, + 0x64, 0x94, 0x6f, 0x8c, 0x63, 0x87, 0x0f, 0x0f, 0x87, 0xc1, 0xe0, 0x61, 0x85, 0xde, 0x1b, 0x23, + 0xc4, 0x4f, 0xee, 0x21, 0x72, 0x09, 0x55, 0x64, 0xaf, 0xde, 0xaf, 0x87, 0x46, 0xfd, 0x1e, 0xf4, + 0xe9, 0x93, 0x89, 0xda, 0x9f, 0xac, 0x1b, 0x3a, 0x4c, 0x26, 0x6c, 0x39, 0x5b, 0x6d, 0xe6, 0x29, + 0xdb, 0x44, 0x8c, 0xe6, 0x6c, 0x78, 0x88, 0xac, 0x59, 0xea, 0xdf, 0x09, 0xef, 0x2a, 0x0c, 0x2f, + 0x2e, 0x58, 0x29, 0x55, 0xbf, 0xa4, 0xa5, 0xdc, 0xc4, 0x26, 0xde, 0x68, 0xa1, 0x2c, 0x20, 0x26, + 0xa9, 0xa6, 0xe2, 0x39, 0x2c, 0xd9, 0x0e, 0xfb, 0xb4, 0x3e, 0x3d, 0x57, 0xb4, 0xb4, 0xd7, 0xcc, + 0x19, 0x89, 0x27, 0x7d, 0xfb, 0xaa, 0x2e, 0x9c, 0x63, 0x57, 0x49, 0x39, 0x88, 0xcb, 0xb4, 0xca, + 0x52, 0x0e, 0x56, 0xea, 0xfc, 0x78, 0xfe, 0x6b, 0x73, 0xff, 0x04, 0xf1, 0xc3, 0x8f, 0x87, 0xc3, + 0xe0, 0xfb, 0x46, 0x92, 0xf0, 0x9d, 0xc8, 0xec, 0xa4, 0x4f, 0xee, 0x21, 0x72, 0x19, 0x25, 0x54, + 0x38, 0x63, 0x03, 0x45, 0x3f, 0x0d, 0x4f, 0x28, 0xdb, 0x46, 0xb1, 0x7d, 0xf8, 0x2a, 0xbb, 0xb6, + 0x9f, 0xa9, 0x15, 0xb0, 0xb3, 0x12, 0x6b, 0xe8, 0xe5, 0x1e, 0x74, 0x70, 0x91, 0x13, 0x34, 0x4d, + 0x4a, 0xb8, 0x7b, 0xe6, 0x6d, 0xfe, 0x85, 0x4e, 0xba, 0xac, 0x12, 0xff, 0x58, 0x16, 0x10, 0xc1, + 0x70, 0x7e, 0x89, 0xb4, 0x84, 0x21, 0xc7, 0x7a, 0x35, 0x56, 0x2e, 0x6a, 0x02, 0xb0, 0xa0, 0x10, + 0x49, 0x33, 0xd6, 0x57, 0x4b, 0x4a, 0x66, 0xcb, 0x3b, 0x00, 0xdc, 0xeb, 0x5f, 0x41, 0xdc, 0x40, + 0x3b, 0x3f, 0xa4, 0xf9, 0x56, 0x0c, 0x33, 0xa2, 0x2f, 0x1c, 0x8a, 0x42, 0x54, 0xae, 0xf7, 0xbb, + 0xf1, 0x2b, 0xcb, 0x91, 0x95, 0xa0, 0xf4, 0x1e, 0x19, 0xc2, 0x10, 0xe7, 0x18, 0x70, 0xfb, 0x88, + 0xa6, 0x97, 0x6d, 0x65, 0x72, 0x29, 0x35, 0x64, 0xaf, 0xdd, 0x47, 0x5d, 0x46, 0xc5, 0xfd, 0x81, + 0x82, 0x41, 0x59, 0xad, 0x3b, 0x24, 0x2f, 0x86, 0x49, 0x9b, 0xfb, 0x82, 0xb6, 0xdf, 0xf1, 0x54, + 0x52, 0xca, 0x10, 0xfd, 0x91, 0x73, 0x58, 0xbc, 0xb4, 0x47, 0x3f, 0xb9, 0x2f, 0xe5, 0x54, 0x1f, + 0xcf, 0x61, 0x2e, 0xba, 0xd3, 0x78, 0x64, 0x12, 0xb2, 0xdc, 0x19, 0xa7, 0x89, 0xd3, 0x00, 0x56, + 0x61, 0x09, 0x75, 0x8b, 0x0f, 0xa7, 0xa1, 0xdc, 0xd0, 0x15, 0xe5, 0xf5, 0x8c, 0x75, 0x21, 0x41, + 0x82, 0x9e, 0x49, 0xf0, 0xb2, 0xd8, 0xf3, 0x28, 0xf0, 0x5e, 0x11, 0x39, 0x88, 0x2e, 0xfe, 0x2f, + 0xb7, 0x8e, 0xd2, 0x1e, 0x93, 0xf1, 0x00, 0x27, 0x3a, 0x98, 0x72, 0x3e, 0x1c, 0x70, 0xc7, 0xc7, + 0x83, 0x81, 0xc8, 0xd3, 0x62, 0x23, 0x32, 0x26, 0xa4, 0x4f, 0xee, 0x21, 0x72, 0x19, 0x35, 0x6c, + 0x00, 0x06, 0x98, 0x1d, 0x78, 0x1c, 0x4f, 0xae, 0x3c, 0x0b, 0xfd, 0x61, 0x38, 0x3e, 0x2f, 0x10, + 0x1b, 0x48, 0x6c, 0x3e, 0x43, 0x08, 0x25, 0x07, 0xa7, 0xb0, 0x4f, 0x1b, 0xa4, 0xca, 0x9d, 0x68, + 0xd0, 0x2a, 0x22, 0x3e, 0x04, 0xd4, 0xe6, 0x76, 0x8c, 0xac, 0x74, 0xdb, 0x71, 0x53, 0xe8, 0x71, + 0xc9, 0x0d, 0x24, 0xb5, 0x27, 0xe4, 0xaa, 0xb5, 0xc3, 0x7f, 0xf6, 0x52, 0x81, 0xaf, 0x30, 0xf0, + 0xe6, 0x88, 0x65, 0xa9, 0xf4, 0x6a, 0x7d, 0xb6, 0x06, 0x87, 0xc4, 0x6c, 0x1a, 0x71, 0x0b, 0x20, + 0x60, 0x82, 0x24, 0xe2, 0x57, 0x3d, 0x6d, 0x5e, 0xbe, 0x37, 0xab, 0xa1, 0xa7, 0x37, 0xf7, 0x3d, + 0x5e, 0x80, 0x1c, 0xc6, 0x0c, 0x1c, 0x1c, 0x3e, 0x07, 0xc3, 0xe1, 0xe1, 0xe7, 0x36, 0xa6, 0x50, + 0xc4, 0x4f, 0xee, 0x21, 0x72, 0x09, 0x45, 0x64, 0xb0, 0xd2, 0xbf, 0xf9, 0x4d, 0xc8, 0xe1, 0x95, + 0x22, 0x86, 0x89, 0x6c, 0x3a, 0xdb, 0x05, 0x25, 0xcd, 0x73, 0x92, 0xe3, 0x20, 0xdd, 0x46, 0xff, + 0x1b, 0xb2, 0x0b, 0xc3, 0x29, 0x0b, 0xf2, 0x78, 0x08, 0xca, 0x9b, 0xfe, 0xd5, 0x80, 0xc4, 0xfc, + 0x56, 0xb7, 0xcf, 0x1e, 0x15, 0xd5, 0xab, 0x9b, 0x18, 0x7a, 0xa8, 0xcb, 0x92, 0x08, 0x39, 0x55, + 0xc6, 0x5b, 0xa6, 0xa4, 0x23, 0x76, 0x1f, 0xaa, 0xdf, 0x5c, 0xe6, 0x90, 0x38, 0xbc, 0x65, 0x6d, + 0xe8, 0x92, 0x37, 0x8c, 0x0c, 0x04, 0xec, 0x5b, 0x52, 0xce, 0x90, 0x10, 0x84, 0x3a, 0x32, 0x7a, + 0x2d, 0xdd, 0x6a, 0xed, 0x0d, 0xe2, 0xf7, 0xba, 0xbc, 0xe3, 0xce, 0x48, 0x8e, 0x38, 0x70, 0xf0, + 0xf8, 0xf0, 0x78, 0x3e, 0x65, 0x58, 0x92, 0x1e, 0xa4, 0x4f, 0xee, 0x21, 0x72, 0x19, 0x45, 0x6c, + 0x04, 0x80, 0xe4, 0x10, 0x35, 0x6d, 0x65, 0x13, 0x4b, 0xc1, 0x05, 0x47, 0x8f, 0x67, 0xa9, 0x43, + 0x6e, 0x6a, 0x3f, 0x3b, 0xa7, 0x8f, 0x82, 0xad, 0x0e, 0x6b, 0x96, 0xfe, 0xb4, 0xe7, 0x35, 0x3a, + 0x23, 0x38, 0xbf, 0x16, 0x7a, 0xea, 0x0d, 0x55, 0x7d, 0x79, 0x89, 0x69, 0xb4, 0xd4, 0x93, 0xae, + 0xfe, 0xb4, 0xed, 0x25, 0xcc, 0x22, 0xd7, 0x89, 0xf6, 0xbf, 0xff, 0x87, 0x81, 0xf5, 0xf3, 0xe3, + 0xca, 0x90, 0xb8, 0xf0, 0xc8, 0xcc, 0x49, 0x36, 0x60, 0x54, 0x98, 0x6f, 0x16, 0xeb, 0xc7, 0x5e, + 0xc1, 0x49, 0x30, 0xea, 0x12, 0xdd, 0xfa, 0x44, 0x78, 0xa4, 0xe0, 0x42, 0xc3, 0xd7, 0xcb, 0x7b, + 0x55, 0x86, 0x43, 0xb8, 0xe3, 0xcc, 0x78, 0xf0, 0x3e, 0x1e, 0x63, 0x8c, 0x78, 0xe0, 0x8a, 0x73, + 0xc4, 0x4f, 0xee, 0x21, 0x72, 0x09, 0x35, 0x74, 0x00, 0x00, 0x24, 0x08, 0x30, 0xb0, 0xd7, 0x30, + 0xa7, 0x09, 0xff, 0xd2, 0x36, 0x01, 0x9a, 0x80, 0xe8, 0x35, 0x7b, 0xa9, 0x39, 0xe9, 0x64, 0x79, + 0x72, 0x11, 0xe1, 0xc1, 0x58, 0x57, 0xc1, 0x5a, 0x8d, 0xe9, 0x3e, 0x51, 0x42, 0x9a, 0x7a, 0x76, + 0x1f, 0x1b, 0xbb, 0x9f, 0xd4, 0xa3, 0x80, 0x9d, 0xc9, 0x76, 0x9f, 0xef, 0x19, 0x52, 0xd6, 0xd9, + 0x65, 0x25, 0x59, 0x40, 0x8c, 0x26, 0x72, 0x99, 0x0b, 0xb4, 0x85, 0x4f, 0xa1, 0xd9, 0x98, 0x08, + 0x9d, 0xb0, 0xf7, 0x9d, 0xd1, 0x7c, 0x16, 0xf2, 0x54, 0x61, 0xab, 0x18, 0xf9, 0xbe, 0x9f, 0xa6, + 0x64, 0x3d, 0x79, 0x71, 0x20, 0xf1, 0x9d, 0x2f, 0xfb, 0x1f, 0xd1, 0xe7, 0x83, 0xe1, 0xfc, 0x0e, + 0x3e, 0x38, 0xdf, 0x46, 0x78, 0x7e, 0x34, 0x98, 0xc2, 0x08, 0x6e, 0xe5, 0x72, 0x09, 0x25, 0x74, + 0x00, 0x00, 0x28, 0x94, 0x58, 0x2b, 0x0d, 0xc2, 0x12, 0xc0, 0x7b, 0x14, 0x6d, 0xe5, 0x12, 0xfc, + 0x91, 0xd4, 0x8e, 0xe4, 0x6f, 0x2b, 0x95, 0xe0, 0xc6, 0xa3, 0x98, 0xee, 0x3a, 0x76, 0x26, 0x2b, + 0xaa, 0xea, 0x23, 0x52, 0xc9, 0xab, 0xb5, 0x86, 0x09, 0xf3, 0xbc, 0x38, 0x9e, 0xef, 0x63, 0x58, + 0xbc, 0x23, 0xbf, 0x52, 0xa0, 0x5c, 0x8f, 0x69, 0x25, 0x1b, 0x8f, 0x66, 0xa2, 0xb1, 0x27, 0x91, + 0x74, 0x3c, 0x6f, 0xf6, 0x7a, 0x8c, 0x50, 0x78, 0x6e, 0x13, 0xc6, 0x9c, 0xf9, 0x15, 0x1f, 0x44, + 0x22, 0x20, 0x60, 0x7a, 0xdd, 0xa0, 0x61, 0xc5, 0xe2, 0x41, 0x59, 0x0f, 0xbd, 0xb3, 0xf1, 0xe6, + 0xfe, 0x90, 0x70, 0x1f, 0x38, 0xf8, 0xfc, 0x0e, 0x07, 0x87, 0x9e, 0x7c, 0x58, 0x27, 0x8f, 0x33, + 0xa2, 0x08, 0x6e, 0xe5, 0x72, 0x09, 0x45, 0x74, 0x00, 0x00, 0x38, 0x24, 0x7a, 0xaa, 0xf1, 0xb5, + 0x93, 0x2d, 0x8b, 0xb4, 0xcd, 0x51, 0xd9, 0xd4, 0xdc, 0xad, 0x05, 0x18, 0x07, 0x9a, 0xf3, 0xe7, + 0x1a, 0x15, 0x02, 0xa7, 0x1d, 0xbf, 0x22, 0xb7, 0xc3, 0xee, 0x54, 0x97, 0x93, 0x2c, 0x33, 0x01, + 0x4c, 0xcb, 0x7d, 0x8c, 0xc7, 0x38, 0xdd, 0xbe, 0x57, 0xe4, 0x12, 0x88, 0xe7, 0x6b, 0x2c, 0x3f, + 0xbf, 0x56, 0x90, 0x87, 0x0c, 0x6f, 0x2e, 0xd4, 0xf5, 0x59, 0xfc, 0xcd, 0xb0, 0x1f, 0xdc, 0x58, + 0xfa, 0xba, 0x30, 0x0f, 0xf7, 0x99, 0x1e, 0x42, 0xed, 0xd7, 0xde, 0x15, 0x5c, 0xc1, 0x82, 0xc5, + 0xd2, 0x2d, 0x18, 0x12, 0xda, 0x95, 0x58, 0xfd, 0xf6, 0xda, 0x0d, 0x24, 0x30, 0xf8, 0x1f, 0x07, + 0xf0, 0x71, 0xce, 0x2b, 0x10, 0x77, 0xe9, 0x61, 0xc4, 0x4f, 0xee, 0x21, 0x72, 0x09, 0x45, 0x7c, + 0x00, 0xc0, 0x4e, 0x5d, 0x55, 0x18, 0x8a, 0x1b, 0xf9, 0x01, 0xef, 0x8a, 0x03, 0xaf, 0x2f, 0xd8, + 0x1d, 0x02, 0xe6, 0xea, 0xa5, 0xf5, 0xca, 0x93, 0xcd, 0x94, 0xbe, 0x68, 0xd0, 0xc2, 0x1f, 0x14, + 0x83, 0x9c, 0x9d, 0xb4, 0x54, 0xa8, 0x9e, 0x0f, 0x85, 0x55, 0x2a, 0x75, 0x8f, 0x2b, 0x9f, 0x82, + 0xbd, 0xcc, 0x06, 0xf2, 0x15, 0x20, 0x9e, 0xe7, 0xc5, 0x36, 0xc4, 0x95, 0x17, 0x24, 0xdf, 0x79, + 0x82, 0x8f, 0x97, 0xcf, 0xff, 0xf0, 0xc2, 0x26, 0x8c, 0x44, 0xb7, 0xe0, 0x90, 0x9c, 0xd9, 0xd4, + 0xa3, 0x46, 0x12, 0x28, 0x35, 0x50, 0xaf, 0x87, 0x54, 0x78, 0x46, 0x68, 0x96, 0x47, 0x5d, 0x61, + 0xc9, 0x60, 0x3c, 0x31, 0x3c, 0x2f, 0x83, 0xe1, 0xf0, 0x65, 0xe1, 0xec, 0x6d, 0xfd, 0xcc, 0x16, + 0xa4, 0x4f, 0xee, 0x21, 0x72, 0x09, 0x35, 0x74, 0x00, 0x00, 0x52, 0x04, 0x91, 0x6d, 0x5c, 0xf3, + 0x05, 0x5a, 0x7a, 0xa2, 0xe9, 0x6b, 0xde, 0x98, 0xb1, 0x08, 0xe1, 0x5c, 0x6d, 0xa1, 0xd8, 0x20, + 0xeb, 0x51, 0xe3, 0x8d, 0x00, 0x0d, 0xcd, 0x57, 0x77, 0x2a, 0x3d, 0xe2, 0x05, 0x92, 0x5e, 0xce, + 0x33, 0x58, 0x77, 0x06, 0x6c, 0x72, 0x3e, 0xbb, 0xbd, 0x8f, 0x57, 0x06, 0x05, 0x05, 0xe4, 0x54, + 0xed, 0x6a, 0x8b, 0xc1, 0x08, 0x90, 0x16, 0x09, 0xfa, 0xd0, 0x4f, 0xa6, 0x17, 0xcf, 0x43, 0x1f, + 0xa4, 0xf4, 0x91, 0xff, 0x43, 0x30, 0x3f, 0x55, 0xce, 0x77, 0xe1, 0xed, 0x08, 0xeb, 0xa6, 0xfa, + 0xd0, 0xea, 0x8f, 0x4b, 0xe1, 0x85, 0x08, 0x35, 0x3c, 0x00, 0xfc, 0x73, 0xb8, 0x87, 0x87, 0x03, + 0x83, 0xc7, 0x3c, 0xe7, 0xe5, 0x39, 0x13, 0x9a, 0xa4, 0x4f, 0xee, 0x21, 0x72, 0x09, 0x25, 0x74, + 0x00, 0x01, 0x69, 0x46, 0xb4, 0x9f, 0x19, 0x25, 0xfe, 0x51, 0x09, 0xe7, 0x36, 0x89, 0x73, 0xd8, + 0x2c, 0x7a, 0xee, 0x1e, 0xe9, 0xb5, 0x26, 0x4f, 0x67, 0x8d, 0xdb, 0xc3, 0x40, 0xe2, 0x4c, 0x9e, + 0x4d, 0x52, 0x0e, 0xfb, 0xae, 0x34, 0x4a, 0xbf, 0x58, 0xe6, 0xf5, 0xb4, 0x4c, 0xc2, 0xca, 0xd1, + 0xd9, 0xb9, 0x98, 0x6b, 0x5f, 0x35, 0x68, 0x2d, 0xc7, 0x4a, 0x92, 0xf3, 0x4b, 0x3f, 0x36, 0x3f, + 0x49, 0xfa, 0x0d, 0xff, 0x91, 0xb6, 0x06, 0x18, 0xa6, 0xea, 0x41, 0xdf, 0x3d, 0xc2, 0x2f, 0xa8, + 0x36, 0x52, 0xb9, 0xc0, 0x73, 0x29, 0x0c, 0xc8, 0xef, 0x3c, 0x32, 0x65, 0xb0, 0x1d, 0x02, 0x03, + 0xb0, 0xca, 0x8f, 0xbe, 0x83, 0x07, 0x87, 0x8e, 0x0f, 0x87, 0xe7, 0x19, 0x8d, 0x9b, 0x52, 0xe3, + 0xc4, 0x4f, 0xee, 0x21, 0x72, 0x09, 0x35, 0x7c, 0x04, 0x81, 0xd0, 0x1a, 0x52, 0x2c, 0x52, 0x15, + 0x28, 0x18, 0x3e, 0xd7, 0x70, 0x05, 0x04, 0xa9, 0xc1, 0x9b, 0xb0, 0xac, 0xd4, 0xab, 0x23, 0xda, + 0xa1, 0xbf, 0x91, 0x8a, 0xc0, 0x58, 0x6f, 0x58, 0x08, 0x9c, 0x0f, 0x00, 0xb7, 0xba, 0xd9, 0x54, + 0x84, 0x13, 0x18, 0xa9, 0xfc, 0x95, 0x18, 0x31, 0x7e, 0x3e, 0xb6, 0xdd, 0x4d, 0xac, 0xac, 0x07, + 0x61, 0xb3, 0x5f, 0x30, 0x24, 0x40, 0x83, 0x77, 0xf7, 0x94, 0x7d, 0x0b, 0xbb, 0x57, 0x86, 0xf5, + 0x0a, 0x83, 0xd3, 0x34, 0xe2, 0xcf, 0xd3, 0x8d, 0xe0, 0x66, 0x8f, 0x79, 0xc9, 0xfa, 0x5e, 0x51, + 0x59, 0x50, 0xda, 0x57, 0xcb, 0x54, 0x04, 0xf3, 0x2b, 0x01, 0xd1, 0x9c, 0x63, 0xc1, 0xe0, 0x7c, + 0x3e, 0x10, 0x32, 0x14, 0x1f, 0x1e, 0x60, 0xe4, 0xc4, 0x50, 0x05, 0x21, 0x72, 0x09, 0x15, 0x74, + 0x00, 0x00, 0x02, 0x2c, 0x30, 0x2e, 0x0d, 0x66, 0x68, 0xc2, 0xbc, 0x54, 0x27, 0x50, 0xab, 0x11, + 0x04, 0x84, 0x49, 0x68, 0xc5, 0x34, 0xb3, 0x54, 0x0e, 0x16, 0x86, 0xe7, 0x6c, 0xfb, 0x63, 0x9d, + 0xc3, 0xdc, 0x24, 0x10, 0x63, 0xce, 0xe9, 0x24, 0x92, 0x48, 0xf3, 0x98, 0x79, 0x67, 0x8a, 0xe4, + 0x9f, 0x97, 0x0b, 0x0f, 0xce, 0x76, 0x31, 0x14, 0x68, 0xed, 0xe7, 0xd9, 0xe6, 0x48, 0xbb, 0x56, + 0x45, 0x9e, 0x5a, 0xd6, 0x6e, 0xea, 0xa5, 0xdf, 0x8e, 0x6a, 0x49, 0xcd, 0xe9, 0xf3, 0x27, 0x5d, + 0xdd, 0xe3, 0x56, 0x6d, 0xa0, 0xc1, 0xa8, 0xcb, 0xcb, 0xdb, 0xb1, 0xec, 0x15, 0x06, 0x00, 0x27, + 0x33, 0xe1, 0x87, 0x87, 0x87, 0xc0, 0xf8, 0x7c, 0x1c, 0x3e, 0x1e, 0x38, 0x7c, 0x78, 0xf5, 0x9c, + 0xc4, 0x50, 0x05, 0x21, 0x72, 0x09, 0x45, 0x7c, 0x00, 0xc0, 0x5f, 0xe9, 0x53, 0x55, 0x61, 0x1d, + 0x48, 0xa7, 0xe6, 0xdf, 0xa3, 0x82, 0xa9, 0x07, 0x81, 0x70, 0x8f, 0x20, 0x75, 0xa6, 0x79, 0x46, + 0xe0, 0x77, 0x1c, 0x5f, 0x7e, 0xee, 0x1d, 0x9f, 0x64, 0x15, 0x34, 0x3e, 0xc5, 0xb1, 0x96, 0x5e, + 0x00, 0x9d, 0x21, 0xb2, 0x6d, 0x52, 0x2d, 0x5a, 0xdc, 0xb9, 0x9d, 0x1d, 0x10, 0xe3, 0x49, 0x5f, + 0xe1, 0xec, 0x9b, 0x12, 0x17, 0x55, 0x03, 0x26, 0x94, 0x27, 0xfb, 0xfd, 0x20, 0x50, 0xba, 0x96, + 0x12, 0x45, 0x19, 0x36, 0xcf, 0xdf, 0xfe, 0xc1, 0xcb, 0xc7, 0x4d, 0x49, 0x20, 0x18, 0xc8, 0x89, + 0xa4, 0x28, 0xbe, 0x84, 0xf4, 0xa5, 0x1d, 0x85, 0x1d, 0x92, 0x05, 0xb2, 0x10, 0x66, 0x70, 0xf8, + 0xf8, 0x7e, 0x3e, 0x39, 0xb2, 0x3b, 0xc9, 0xee, 0xa4, 0x65, 0x4a, 0x41, 0x72, 0x09, 0x45, 0x8c, + 0x00, 0x00, 0x4e, 0x3f, 0xf7, 0x13, 0x0a, 0x6b, 0x85, 0xc9, 0x41, 0x44, 0x68, 0x48, 0xe7, 0xbc, + 0xe6, 0x89, 0xc2, 0x30, 0xef, 0x98, 0x65, 0x30, 0x2b, 0xbb, 0x35, 0x35, 0xe5, 0xa5, 0xa6, 0xe6, + 0x74, 0xc2, 0xa8, 0x66, 0xbe, 0x85, 0x22, 0x64, 0x7f, 0xcb, 0x2d, 0xf8, 0xbb, 0xa2, 0x14, 0x8a, + 0x19, 0x37, 0x4d, 0x10, 0x0e, 0x00, 0x01, 0x79, 0x71, 0x7f, 0x48, 0x69, 0x7c, 0x3e, 0x92, 0xe6, + 0xca, 0x0b, 0x90, 0x93, 0xab, 0x94, 0x3e, 0xec, 0x3f, 0xe1, 0x78, 0xec, 0x89, 0x28, 0x05, 0xb2, + 0x58, 0x45, 0x56, 0x43, 0xe9, 0x03, 0xfa, 0x01, 0x24, 0xc2, 0xf7, 0xc4, 0x85, 0x52, 0x15, 0xcc, + 0x86, 0x2f, 0x39, 0x8e, 0x60, 0x83, 0xc7, 0xc3, 0xc7, 0xc1, 0xdf, 0x4b, 0x5a, 0x28, 0xdf, 0xac, + 0xc4, 0x65, 0x4a, 0x41, 0x72, 0x09, 0x15, 0x94, 0x00, 0x00, 0x03, 0x61, 0x03, 0x38, 0x9c, 0x15, + 0xe6, 0xba, 0x02, 0x23, 0x84, 0x2e, 0x4f, 0xb2, 0x5d, 0xd6, 0xa6, 0x86, 0xfa, 0x03, 0xdf, 0xe8, + 0xcf, 0x2a, 0x3f, 0x94, 0x7e, 0xd1, 0x30, 0x53, 0x7f, 0x9d, 0x03, 0x54, 0x70, 0x77, 0xa7, 0x48, + 0xa3, 0x59, 0xb1, 0xd3, 0xea, 0x06, 0x82, 0x64, 0x53, 0x05, 0x0e, 0x81, 0xff, 0xd4, 0x57, 0x4c, + 0xd4, 0x0e, 0x2c, 0xfb, 0xd6, 0x8f, 0x35, 0x01, 0x01, 0x6b, 0x12, 0x21, 0xe7, 0x18, 0x15, 0x88, + 0xdd, 0xe2, 0x91, 0x24, 0x7e, 0x0f, 0xa2, 0x11, 0x45, 0x01, 0xfa, 0xa1, 0x45, 0xf9, 0xb4, 0x6f, + 0x70, 0xd1, 0x7b, 0x94, 0xc2, 0xf3, 0x9a, 0xc0, 0x04, 0x27, 0xc3, 0xe1, 0x8e, 0x0f, 0x0f, 0x80, + 0xe1, 0xc1, 0xc7, 0x0f, 0x18, 0xe5, 0xa2, 0x6d, 0xa6, 0xac, 0xc9, 0x85, 0x72, 0x09, 0x25, 0x94, + 0x00, 0x00, 0x5e, 0x8d, 0x23, 0xf9, 0xfa, 0x0d, 0xf3, 0xfe, 0xe5, 0xec, 0xbb, 0x2a, 0xe6, 0x25, + 0x70, 0x55, 0x07, 0x29, 0x79, 0xeb, 0x07, 0x66, 0x63, 0x76, 0xd7, 0xcc, 0x2d, 0x82, 0xaf, 0x89, + 0xaf, 0x90, 0xd2, 0x22, 0x2f, 0x35, 0x23, 0x84, 0x07, 0x33, 0x70, 0x32, 0x04, 0x75, 0xd5, 0x24, + 0xe6, 0x5d, 0xa8, 0xfa, 0x74, 0x9e, 0x23, 0x77, 0xf0, 0xff, 0xc4, 0xfc, 0xe0, 0x94, 0x37, 0x38, + 0x93, 0x3a, 0xeb, 0xdb, 0x66, 0x7d, 0xe5, 0x69, 0xda, 0x7f, 0x6e, 0x8e, 0xe9, 0xfe, 0xb6, 0x76, + 0xe0, 0x84, 0xe3, 0xc6, 0xe0, 0x0e, 0x10, 0x20, 0xcc, 0x53, 0x94, 0x20, 0xe4, 0x04, 0xf2, 0x9c, + 0xb6, 0xcd, 0x21, 0x86, 0x0f, 0x07, 0xc1, 0xe3, 0xc1, 0xc1, 0xc3, 0x85, 0xb6, 0x64, 0xfa, 0xd7, + 0xc4, 0x65, 0x4a, 0x41, 0x72, 0x09, 0x35, 0x8c, 0x00, 0xc3, 0x2e, 0x07, 0x4d, 0xcf, 0x40, 0xe3, + 0xc4, 0x6a, 0xbd, 0x87, 0xa0, 0x32, 0xc2, 0xf7, 0x32, 0xa2, 0x74, 0xf4, 0x62, 0xeb, 0x64, 0xac, + 0x75, 0x6d, 0x4c, 0xa0, 0x2f, 0xa5, 0xe7, 0x48, 0x75, 0x1b, 0x28, 0x84, 0x57, 0x6f, 0x72, 0x54, + 0x6b, 0xb6, 0x9e, 0xda, 0x48, 0xe3, 0xa9, 0xd6, 0x41, 0xe8, 0xc3, 0x12, 0x16, 0x20, 0x2c, 0x64, + 0xee, 0xad, 0x6c, 0xbb, 0x3e, 0x84, 0xff, 0x19, 0x5e, 0x42, 0xf1, 0x29, 0xc9, 0x67, 0x6d, 0x28, + 0x00, 0x73, 0x62, 0x00, 0x42, 0xdc, 0xc5, 0x6b, 0x46, 0x21, 0x2f, 0x22, 0x4f, 0xf0, 0x2d, 0x7e, + 0x52, 0x78, 0x76, 0x5a, 0x61, 0x99, 0x0f, 0xcf, 0x0f, 0xfa, 0x38, 0x38, 0x3e, 0x1f, 0x03, 0xc3, + 0xf0, 0xfc, 0x0c, 0x1e, 0x13, 0x46, 0x22, 0x8c, 0xc4, 0x65, 0x4a, 0x41, 0x72, 0x09, 0x25, 0x94, + 0x00, 0x00, 0x90, 0x17, 0x7a, 0x70, 0x6b, 0x33, 0xce, 0x57, 0x32, 0x9d, 0x05, 0x11, 0x10, 0xf2, + 0xef, 0x31, 0xe9, 0xcb, 0x2d, 0x86, 0x68, 0xdf, 0xcc, 0x6a, 0x7b, 0x59, 0x33, 0x52, 0x51, 0x0d, + 0xb0, 0xb8, 0x03, 0xe7, 0x91, 0x37, 0xc8, 0xe4, 0xa8, 0xf5, 0x3d, 0x36, 0x19, 0x72, 0xf3, 0xb9, + 0xa8, 0x79, 0xa5, 0x47, 0x52, 0x9a, 0xfd, 0x65, 0x0a, 0x75, 0x49, 0xc3, 0x3c, 0x15, 0xc4, 0x5f, + 0x88, 0x89, 0x96, 0x84, 0xf7, 0x6e, 0xa6, 0xb3, 0x40, 0x8c, 0xb2, 0x90, 0xc1, 0xfc, 0x19, 0x01, + 0xbb, 0xaf, 0xd4, 0xb5, 0x32, 0x48, 0xcf, 0x00, 0x43, 0x21, 0xb6, 0x04, 0xe9, 0x90, 0xc8, 0x60, + 0x4e, 0xdf, 0xd1, 0x8f, 0x07, 0x83, 0xc0, 0x7f, 0x07, 0xe7, 0xf0, 0x7c, 0xe2, 0x26, 0xc3, 0x4f, + 0xa4, 0x65, 0x4a, 0x41, 0x72, 0x09, 0x35, 0x94, 0x04, 0x84, 0x22, 0x81, 0x1a, 0xea, 0x9f, 0x75, + 0xa9, 0x1c, 0xcd, 0x73, 0xa5, 0xe9, 0x4c, 0xf7, 0x7f, 0x57, 0x3a, 0xb0, 0x97, 0xb6, 0x50, 0xf2, + 0x2b, 0x83, 0x69, 0x79, 0xc0, 0xe4, 0x32, 0x57, 0x55, 0xc8, 0x42, 0x07, 0xdf, 0xdd, 0xbc, 0x12, + 0xae, 0x05, 0xac, 0xe3, 0x3c, 0x81, 0x8f, 0x42, 0x43, 0x06, 0xf3, 0x21, 0xcf, 0x0e, 0x95, 0x01, + 0x67, 0x41, 0xb2, 0x9a, 0x64, 0x4a, 0x4b, 0xd7, 0xb1, 0x74, 0xbb, 0x65, 0xde, 0xcf, 0x7c, 0x02, + 0x16, 0x4a, 0x5d, 0xa7, 0xc8, 0xf0, 0x09, 0x9b, 0xac, 0x34, 0xc2, 0x4a, 0x04, 0x0a, 0x3a, 0x0e, + 0x0b, 0x86, 0x92, 0x8e, 0x2f, 0x21, 0xbb, 0xd6, 0x1d, 0x26, 0x61, 0x1f, 0xce, 0x38, 0x7c, 0x1e, + 0x1e, 0x03, 0xe0, 0xe4, 0xab, 0x52, 0x07, 0xcb, 0xa6, 0xac, 0xc9, 0x85, 0x72, 0x09, 0x35, 0x9c, + 0x00, 0x01, 0xf1, 0x6d, 0x83, 0xa1, 0xd4, 0xf4, 0xb9, 0xa8, 0xd9, 0xf0, 0xc3, 0x81, 0x40, 0xa0, + 0x6b, 0x6f, 0x26, 0x29, 0x64, 0x9f, 0x81, 0x6c, 0x01, 0x6c, 0xf4, 0x39, 0xf2, 0x67, 0xdd, 0x4c, + 0xba, 0x3a, 0x89, 0xc6, 0xc3, 0x4d, 0x4b, 0xa5, 0xeb, 0x7e, 0x67, 0xa9, 0x33, 0x30, 0xd9, 0x02, + 0xdc, 0x2a, 0x20, 0x82, 0x64, 0x54, 0x31, 0x43, 0x09, 0x71, 0x50, 0xdb, 0x3e, 0xf8, 0xb5, 0x68, + 0x2c, 0xcc, 0xb6, 0x95, 0xf6, 0x5e, 0x3c, 0x45, 0xea, 0x9c, 0x87, 0xf4, 0x3a, 0x3d, 0x82, 0xdf, + 0x62, 0xd5, 0x42, 0x60, 0x77, 0x0f, 0x85, 0x0d, 0x6d, 0x3a, 0x14, 0xdb, 0xaf, 0x35, 0x39, 0xdd, + 0xf2, 0x67, 0x42, 0x77, 0x38, 0x67, 0x0f, 0x0e, 0x0f, 0x1f, 0x0f, 0x51, 0xcc, 0xb1, 0xe7, 0x60, + 0xa6, 0xac, 0xc9, 0x85, 0x72, 0x09, 0x25, 0x9c, 0x00, 0xc0, 0xb8, 0x4b, 0x99, 0xf0, 0xf2, 0x0c, + 0x2d, 0xf0, 0x4c, 0xc3, 0xaf, 0x13, 0x4e, 0x1f, 0x8c, 0x8a, 0x9a, 0x24, 0xc5, 0x99, 0x9a, 0x91, + 0x95, 0xe2, 0x8f, 0x32, 0x01, 0x82, 0x23, 0x68, 0x4d, 0x79, 0xdf, 0x56, 0x6a, 0xf2, 0xfe, 0x02, + 0xb9, 0x73, 0xf2, 0xb3, 0x30, 0x7e, 0xab, 0xf5, 0x2f, 0x3a, 0x05, 0xdd, 0x4b, 0xae, 0x9b, 0xeb, + 0xd4, 0x5d, 0x97, 0x8f, 0xbd, 0x60, 0xcf, 0xa5, 0x6c, 0x17, 0x1a, 0x06, 0x98, 0x13, 0x12, 0x53, + 0xd3, 0x05, 0x5e, 0xb6, 0x98, 0x44, 0x83, 0x81, 0xef, 0x1c, 0xf6, 0x2a, 0x7c, 0x1d, 0xef, 0x4c, + 0x8e, 0x59, 0xd4, 0x7d, 0x74, 0x40, 0x57, 0x4c, 0x39, 0x04, 0xfc, 0x8f, 0x0f, 0x0c, 0x1e, 0x1f, + 0x08, 0x06, 0x18, 0x7d, 0x7d, 0xe3, 0x23, 0x7c, 0xb4, 0x39, 0x63, 0x0f, 0x72, 0x09, 0x25, 0xa4, + 0x00, 0x08, 0xa1, 0xf9, 0x79, 0xc3, 0x62, 0x17, 0x8c, 0xe5, 0xf8, 0xe3, 0x83, 0x33, 0x49, 0x18, + 0x31, 0x50, 0x6e, 0x27, 0x7f, 0x64, 0x22, 0x71, 0x6f, 0x98, 0x01, 0x0c, 0xb3, 0x86, 0x92, 0xa1, + 0x6b, 0xa3, 0x38, 0x9d, 0xce, 0x85, 0x71, 0x8e, 0x9a, 0x57, 0x44, 0x64, 0x5f, 0x29, 0x86, 0x05, + 0x0b, 0xe7, 0x26, 0x83, 0xb3, 0x90, 0x09, 0x08, 0x08, 0xe4, 0x61, 0xb2, 0x83, 0xd4, 0xda, 0xaf, + 0x82, 0x14, 0xdc, 0xf4, 0x26, 0x77, 0x61, 0xab, 0x7e, 0x3c, 0xed, 0xe6, 0x7c, 0x1c, 0x13, 0x78, + 0x9c, 0xc3, 0xcf, 0x08, 0x0d, 0x37, 0x7c, 0x63, 0x60, 0x33, 0xf1, 0xbd, 0x6b, 0x61, 0x53, 0xf5, + 0x68, 0x70, 0x07, 0xe8, 0x70, 0x78, 0x38, 0x70, 0x7c, 0x31, 0xdd, 0x9e, 0x4b, 0x33, 0xa4, 0x99, + 0xd4, 0x39, 0x63, 0x0f, 0x72, 0x09, 0x35, 0xa4, 0x04, 0x80, 0xd6, 0x01, 0x56, 0x1c, 0x09, 0x80, + 0xce, 0x23, 0x84, 0xbb, 0x48, 0x63, 0x43, 0xdc, 0x0a, 0x0c, 0xfe, 0xc3, 0xdc, 0xd9, 0x96, 0x4e, + 0x52, 0x80, 0x51, 0x35, 0x32, 0xd5, 0x63, 0x95, 0xbb, 0x1a, 0xf1, 0xce, 0xf9, 0x06, 0xa0, 0x19, + 0xb4, 0xf1, 0x24, 0x17, 0xe0, 0x13, 0x36, 0x9f, 0x71, 0x62, 0x96, 0x35, 0x84, 0x6d, 0x6d, 0x53, + 0x54, 0x69, 0xeb, 0x1a, 0x82, 0x11, 0x98, 0x10, 0xce, 0x8c, 0x8f, 0x66, 0xee, 0x30, 0xb6, 0x35, + 0x9b, 0x46, 0x72, 0xb9, 0x0d, 0x30, 0x34, 0xc2, 0x4a, 0xa2, 0x39, 0x5c, 0x0e, 0x3e, 0xe0, 0xe4, + 0x0c, 0x9a, 0xaa, 0xe0, 0xe8, 0x7a, 0x26, 0x2c, 0xc0, 0x41, 0x87, 0x0f, 0x03, 0xf0, 0x3f, 0x83, + 0xd0, 0x7e, 0x0e, 0x39, 0xd2, 0x1e, 0x2d, 0x14, 0xa2, 0x1d, 0xcb, 0x05, 0x72, 0x09, 0x35, 0xa4, + 0x3c, 0x03, 0xc7, 0xd2, 0x58, 0x84, 0xd2, 0x42, 0xee, 0x0e, 0xb8, 0x99, 0xe2, 0x91, 0xa5, 0x83, + 0x5e, 0x05, 0x58, 0x22, 0x32, 0xa1, 0x26, 0x54, 0xca, 0x12, 0x19, 0xaa, 0xab, 0xa7, 0xce, 0x8c, + 0x15, 0xdc, 0x68, 0xf3, 0x5b, 0x40, 0x81, 0xa1, 0x68, 0x60, 0x50, 0x52, 0x39, 0x70, 0x02, 0x11, + 0xe9, 0xef, 0x7c, 0x23, 0x6e, 0xdf, 0xf5, 0xea, 0x08, 0x19, 0x4e, 0x87, 0xd7, 0x68, 0x6f, 0x49, + 0xc6, 0xb6, 0x43, 0x9b, 0xa1, 0x66, 0xfd, 0x04, 0x96, 0x38, 0x6d, 0xba, 0xdf, 0xb4, 0xc4, 0x39, + 0xab, 0xbf, 0x6f, 0xa7, 0x12, 0x9d, 0xb9, 0xba, 0x39, 0x9e, 0xba, 0x45, 0x24, 0x22, 0x64, 0xe8, + 0xe2, 0x5e, 0x7f, 0xf0, 0xf1, 0xa1, 0xe1, 0xf4, 0x7a, 0x1e, 0x8e, 0x1c, 0xc7, 0x3c, 0x13, 0xc3, + 0xc2, 0x1d, 0xcb, 0x05, 0x72, 0x29, 0x15, 0xac, 0x00, 0x01, 0x2e, 0x19, 0xf0, 0x63, 0x1c, 0x64, + 0xa4, 0x1a, 0x45, 0xa2, 0x1c, 0xb8, 0x58, 0xab, 0x02, 0x4d, 0xd4, 0xb0, 0x01, 0xd3, 0xd3, 0x49, + 0x3d, 0xbc, 0xcc, 0x10, 0xad, 0xf4, 0xb7, 0xd9, 0x0e, 0xde, 0x14, 0x13, 0x3b, 0xa2, 0x5b, 0xdf, + 0xe7, 0x6a, 0x8a, 0x55, 0x20, 0xf9, 0x25, 0x46, 0x31, 0xd0, 0xbf, 0x71, 0x24, 0x72, 0xcf, 0xc3, + 0x50, 0xa1, 0x1f, 0xff, 0x40, 0x7b, 0x49, 0xc5, 0xea, 0x4f, 0xea, 0x59, 0x34, 0x44, 0x00, 0x5e, + 0x16, 0x0c, 0xa6, 0xa5, 0x7b, 0xc7, 0xd5, 0x39, 0x09, 0xb5, 0xfa, 0x9c, 0x9b, 0x81, 0x04, 0xcd, + 0xda, 0x35, 0xb6, 0x04, 0x44, 0x76, 0x66, 0x10, 0x3b, 0xec, 0xe1, 0xe0, 0x78, 0xf8, 0x1f, 0x81, + 0xe0, 0xfc, 0x33, 0xc4, 0x35, 0x18, 0xc3, 0x35, 0xa2, 0x1d, 0xcb, 0x05, 0x72, 0x09, 0x25, 0xac, + 0x69, 0xd4, 0x3b, 0xc2, 0x6e, 0x3b, 0x8f, 0xa9, 0x9b, 0x85, 0x62, 0x7b, 0xa2, 0x8b, 0xf5, 0xb3, + 0x17, 0x37, 0xfa, 0x96, 0x46, 0xb5, 0xfc, 0x72, 0xf6, 0x6c, 0x85, 0xe6, 0xfa, 0x79, 0xb8, 0x97, + 0xab, 0xc6, 0xc8, 0xe1, 0xcc, 0xb6, 0x29, 0x6d, 0x0f, 0xb9, 0x1c, 0xb1, 0xa1, 0xf4, 0x84, 0xe4, + 0x4f, 0x41, 0x17, 0x6b, 0xe7, 0x81, 0xbe, 0x7c, 0x03, 0xed, 0xee, 0xb9, 0xa9, 0xf9, 0xaa, 0x8b, + 0x8b, 0x15, 0x6d, 0x75, 0xe9, 0x03, 0x57, 0x45, 0x2b, 0x8f, 0x8a, 0xf5, 0xa8, 0xa0, 0x32, 0x11, + 0x77, 0x82, 0x15, 0x9f, 0x9a, 0x12, 0x75, 0x2c, 0x79, 0xd6, 0x8f, 0xd8, 0xe4, 0xfa, 0xd4, 0x13, + 0x54, 0xe9, 0x9c, 0x2d, 0x2c, 0x1b, 0x0f, 0xe0, 0xf8, 0x38, 0xd6, 0x66, 0x61, 0x8f, 0xc4, 0x6e, + 0xc2, 0x1d, 0xcb, 0x05, 0x72, 0x29, 0x15, 0xb4, 0x00, 0xc0, 0x66, 0x40, 0x7f, 0x3a, 0x68, 0x22, + 0x23, 0x2d, 0x81, 0xe6, 0x6f, 0x70, 0xf4, 0x3d, 0x5a, 0x5e, 0x8f, 0xd3, 0x0c, 0x36, 0x37, 0xd5, + 0xb5, 0x4f, 0xd7, 0x30, 0x19, 0x34, 0xaf, 0x2d, 0x85, 0xac, 0xf0, 0x7b, 0x7f, 0xd8, 0x91, 0x6b, + 0x11, 0xac, 0x64, 0x61, 0x16, 0x67, 0x73, 0x1b, 0x3e, 0xac, 0x10, 0xc7, 0xef, 0xb0, 0x43, 0xf6, + 0xe5, 0xc4, 0x98, 0x56, 0x21, 0xf7, 0xe8, 0x18, 0xd5, 0x36, 0xa1, 0xff, 0xcd, 0xac, 0xc6, 0xdc, + 0xee, 0xb2, 0xe9, 0xc4, 0xf7, 0xf1, 0xfc, 0x63, 0xce, 0x3e, 0xf6, 0x56, 0x33, 0x17, 0x13, 0x6e, + 0x45, 0x36, 0x95, 0x4e, 0x27, 0x32, 0x34, 0x13, 0x79, 0x8c, 0x38, 0x3c, 0x3e, 0x07, 0xe0, 0xfc, + 0x1c, 0x78, 0xe7, 0xfe, 0xc6, 0x07, 0x7c, 0x03, 0xa2, 0x1d, 0xcb, 0x05, 0x72, 0x09, 0x05, 0xb4, + 0x05, 0xc0, 0x97, 0x65, 0xaa, 0xb1, 0xdb, 0x33, 0x1d, 0x8f, 0x3e, 0xde, 0x42, 0x98, 0x77, 0xbf, + 0xd4, 0xf9, 0x31, 0x08, 0x0c, 0x22, 0x12, 0xef, 0x7b, 0xe4, 0x87, 0x47, 0xf9, 0xda, 0x34, 0x83, + 0x46, 0x0c, 0x01, 0x06, 0xd9, 0x6d, 0xdd, 0xe9, 0x38, 0xb9, 0xd1, 0xf4, 0xcf, 0xb6, 0xa7, 0xdb, + 0xd7, 0x4b, 0x67, 0x23, 0xad, 0xb8, 0x45, 0x03, 0x3c, 0xd2, 0xf6, 0x6b, 0xc8, 0x25, 0x8d, 0x1e, + 0xca, 0x4e, 0x48, 0x15, 0xa5, 0x4d, 0xa6, 0x00, 0xf5, 0xd3, 0x5d, 0xa0, 0xfe, 0x05, 0xde, 0x77, + 0x7c, 0xfc, 0x60, 0xd6, 0x42, 0x5c, 0xf0, 0xa0, 0x41, 0x14, 0x95, 0x5a, 0x5d, 0x0e, 0xa6, 0xb1, + 0xc4, 0xe0, 0x07, 0x07, 0x80, 0xf8, 0x78, 0x1f, 0x07, 0x03, 0x81, 0xe7, 0xa4, 0x6e, 0x3b, 0x16, + 0x82, 0x1d, 0xcb, 0x05, 0x72, 0x09, 0x15, 0xac, 0x04, 0x8e, 0x7b, 0x4b, 0x56, 0xca, 0x47, 0xa0, + 0x1d, 0xcf, 0x25, 0x47, 0x3c, 0xe5, 0x19, 0x82, 0x38, 0xb7, 0xdb, 0x0f, 0x0d, 0xb5, 0x0e, 0xd5, + 0x16, 0x2a, 0x45, 0xd5, 0xcc, 0xa2, 0xee, 0xa8, 0xf6, 0xad, 0xc8, 0xbc, 0x52, 0x85, 0x3c, 0x3e, + 0x63, 0x9a, 0x3d, 0xe8, 0xf3, 0x33, 0x53, 0xe7, 0x84, 0xa8, 0x16, 0x3b, 0x22, 0xf5, 0x94, 0xd1, + 0x4c, 0xf7, 0x03, 0x0d, 0xd4, 0xb4, 0x32, 0x59, 0xc9, 0xdb, 0x48, 0x6b, 0xdd, 0x03, 0xd4, 0xcc, + 0xff, 0xb7, 0xa7, 0x97, 0x1d, 0x83, 0x14, 0x3c, 0x0c, 0x4a, 0xc6, 0x1c, 0xa0, 0x3a, 0xd4, 0xbb, + 0x13, 0xa7, 0xd6, 0xd6, 0x44, 0x48, 0x4f, 0x79, 0xf8, 0xf0, 0x7c, 0x1f, 0xa0, 0x79, 0x01, 0xfc, + 0x83, 0xe3, 0x62, 0x37, 0x13, 0x8c, 0x90, 0x47, 0xa2, 0x1d, 0xcb, 0x05, 0x72, 0x09, 0x05, 0xac, + 0x00, 0x01, 0x26, 0xf7, 0x02, 0x45, 0xe6, 0xe1, 0xc8, 0xab, 0xbc, 0x2d, 0x72, 0xbb, 0x90, 0xb5, + 0xde, 0x32, 0xbe, 0x60, 0x37, 0x82, 0x31, 0x31, 0x2a, 0x9b, 0x18, 0xca, 0x48, 0xf0, 0xb5, 0xa7, + 0x46, 0x73, 0x53, 0x97, 0x83, 0xc4, 0x73, 0xaf, 0xf6, 0xd0, 0x9a, 0x01, 0xf1, 0x90, 0x4a, 0xb0, + 0x29, 0x00, 0x0f, 0x84, 0xc0, 0x91, 0x07, 0x0f, 0x66, 0x06, 0x55, 0x79, 0x81, 0x03, 0xd8, 0x2b, + 0xbf, 0xce, 0xaf, 0x58, 0x00, 0x5d, 0xa3, 0x51, 0x10, 0x01, 0x67, 0x83, 0x8c, 0xc8, 0x52, 0x71, + 0x2c, 0x72, 0x07, 0x0e, 0xc5, 0xb4, 0x70, 0xf2, 0x3a, 0x97, 0x84, 0x7e, 0xd7, 0xd6, 0xae, 0xf0, + 0x5b, 0xe3, 0xe3, 0xe0, 0x1f, 0xc0, 0xfd, 0x07, 0xc3, 0xf1, 0xcb, 0x31, 0x93, 0x9d, 0xc3, 0x7d, + 0xa2, 0x1d, 0xcb, 0x05, 0x72, 0x09, 0x15, 0xbc, 0x04, 0x80, 0x27, 0x96, 0xe5, 0x9f, 0x1d, 0x98, + 0x7f, 0xde, 0xa9, 0x06, 0x6d, 0xc7, 0xd7, 0xc3, 0xd7, 0x0d, 0xbe, 0xbc, 0xfe, 0xc4, 0xbb, 0x57, + 0x49, 0x0e, 0x1b, 0x73, 0x4e, 0x9e, 0xe9, 0xbd, 0x85, 0xb6, 0xb8, 0x53, 0x7b, 0x9d, 0x8f, 0x2c, + 0x36, 0x77, 0xcc, 0x79, 0x69, 0x4a, 0xd0, 0x70, 0x5a, 0x7a, 0x48, 0x88, 0xe5, 0x54, 0x6b, 0x83, + 0xad, 0x36, 0x6a, 0x20, 0xeb, 0x58, 0x8d, 0x8f, 0x2b, 0x0e, 0xd7, 0xfd, 0x28, 0x0d, 0xb4, 0x3e, + 0x8d, 0xa3, 0x0f, 0x85, 0xb9, 0xde, 0xbe, 0x06, 0x1a, 0x1a, 0x00, 0x55, 0x89, 0xa8, 0x1f, 0xec, + 0x45, 0x8a, 0x42, 0x58, 0x88, 0x64, 0xa0, 0x3e, 0xc4, 0x1f, 0x07, 0xc0, 0xf0, 0x70, 0x1f, 0x85, + 0xf0, 0x5c, 0x1f, 0xc6, 0x79, 0x30, 0x2b, 0x5c, 0xa2, 0x1d, 0xcb, 0x05, 0x72, 0x08, 0xf5, 0xa4, + 0x00, 0xc0, 0x1a, 0x82, 0xb9, 0xa8, 0x96, 0x29, 0xa5, 0x81, 0x9f, 0x39, 0x3b, 0x70, 0x23, 0x39, + 0x35, 0x0a, 0x95, 0x81, 0x24, 0xb3, 0xa0, 0x58, 0x6c, 0xf3, 0x5d, 0xd1, 0x39, 0xc1, 0x71, 0x21, + 0x10, 0xc2, 0x4b, 0x28, 0x89, 0x97, 0x94, 0x06, 0x7c, 0x8a, 0x5d, 0xaa, 0xba, 0x73, 0xaa, 0x37, + 0x76, 0x1c, 0x58, 0x7b, 0x78, 0x53, 0x13, 0xd9, 0x1d, 0xcc, 0x11, 0x3d, 0x87, 0xc9, 0x70, 0x9c, + 0x4a, 0xe5, 0x84, 0x26, 0x63, 0x1c, 0x21, 0xbb, 0x4e, 0x17, 0xb0, 0x80, 0x04, 0xbc, 0x61, 0x90, + 0x93, 0xc2, 0x90, 0x33, 0xf4, 0xbd, 0xe4, 0x6e, 0x57, 0xaa, 0xf0, 0xb6, 0x4b, 0x4e, 0x1f, 0xc3, + 0xe0, 0xf8, 0x3f, 0x04, 0xf5, 0x9a, 0x7e, 0xa7, 0xe0, 0x68, 0xe2, 0xe3, 0xc0, 0xf2, 0x01, 0xb3, + 0xa4, 0x65, 0x4a, 0x45, 0x72, 0x09, 0x05, 0xb4, 0x00, 0x01, 0xf0, 0xd7, 0x1b, 0x3d, 0x12, 0xfe, + 0x87, 0xbc, 0xf1, 0x46, 0x7f, 0xaf, 0xe8, 0x8e, 0xd8, 0xa8, 0x0f, 0x35, 0x81, 0xf6, 0xf3, 0x53, + 0xa1, 0xee, 0x9e, 0x47, 0x32, 0x60, 0x41, 0x56, 0x19, 0x5e, 0xcd, 0x91, 0x93, 0x3c, 0xd2, 0xb0, + 0xef, 0x03, 0x36, 0x91, 0xaa, 0x9a, 0x8f, 0x06, 0x90, 0xfe, 0x02, 0xce, 0x1f, 0xbc, 0x5f, 0x43, + 0x9e, 0x0d, 0xbf, 0x81, 0x52, 0xb4, 0xb0, 0xcf, 0x9f, 0xd6, 0xf4, 0x80, 0xe1, 0x9c, 0xa3, 0x54, + 0xa7, 0xcb, 0xae, 0x65, 0xa0, 0xbb, 0x60, 0x04, 0x5f, 0x2b, 0x58, 0x25, 0xd7, 0x1c, 0x18, 0x8c, + 0x6b, 0x87, 0x21, 0x29, 0x51, 0x92, 0xc2, 0x46, 0x2e, 0xbc, 0x38, 0x60, 0xfc, 0x0e, 0xc7, 0x87, + 0x0e, 0x0c, 0x3e, 0xde, 0x3d, 0x31, 0x45, 0x11, 0xa2, 0x1d, 0xcb, 0x05, 0x72, 0x08, 0xe5, 0xbc, + 0x00, 0x00, 0x40, 0x70, 0xf1, 0xc9, 0x87, 0xe9, 0x1b, 0x2a, 0x08, 0xfb, 0x57, 0x88, 0xb6, 0x0a, + 0x8e, 0x86, 0x71, 0x2b, 0x11, 0x1c, 0x02, 0x56, 0xbf, 0xbd, 0x5f, 0x02, 0xca, 0x76, 0x93, 0x36, + 0x6e, 0x68, 0xfd, 0xfe, 0x4d, 0xb0, 0x70, 0xfb, 0xfe, 0x93, 0xab, 0x7e, 0xe2, 0xdd, 0x26, 0x32, + 0x82, 0x73, 0x95, 0x17, 0x35, 0x0a, 0x59, 0x2c, 0xe7, 0x31, 0x16, 0xe6, 0xd2, 0xc5, 0x4a, 0x94, + 0x1c, 0xa5, 0xfb, 0x30, 0x7e, 0xec, 0x23, 0x7a, 0xf2, 0x1d, 0x92, 0x4f, 0xe2, 0xcf, 0xbf, 0x9a, + 0xec, 0xc2, 0x31, 0x03, 0x61, 0x81, 0x9a, 0x2b, 0xcc, 0xd6, 0xe7, 0x3f, 0x9c, 0x6e, 0x6f, 0x8f, + 0xf0, 0x5e, 0x7f, 0x21, 0xe6, 0x5f, 0xf0, 0x68, 0xfa, 0xa7, 0x28, 0x7a, 0xee, 0x4b, 0x56, 0xde, + 0xa4, 0x65, 0x4a, 0x45, 0x72, 0x08, 0xe5, 0xbc, 0x00, 0xc3, 0x1c, 0xbf, 0x03, 0xf7, 0xa9, 0x45, + 0xe6, 0xe9, 0x53, 0x2c, 0xa3, 0x3e, 0xd3, 0x05, 0x55, 0xc8, 0x9e, 0xf4, 0xf3, 0xa5, 0x9c, 0x17, + 0x7d, 0x48, 0x7e, 0x0b, 0x90, 0xe1, 0xd4, 0xae, 0x28, 0xb7, 0xfc, 0x5f, 0x7f, 0x3f, 0x84, 0x86, + 0xcc, 0x56, 0x0a, 0x75, 0x23, 0x72, 0x68, 0x0e, 0x1b, 0x59, 0xd5, 0x06, 0xfb, 0x2e, 0xaa, 0x30, + 0x5a, 0x37, 0x88, 0x6d, 0x75, 0xf8, 0x3a, 0x91, 0xbb, 0x72, 0x21, 0xfa, 0xad, 0x9a, 0x92, 0x6c, + 0x8e, 0xd5, 0xa2, 0xda, 0x89, 0x7d, 0x64, 0xf5, 0x9d, 0x55, 0xc8, 0x86, 0x06, 0x9e, 0xc1, 0x99, + 0xf2, 0x33, 0xd7, 0x89, 0xd4, 0xf2, 0x27, 0x87, 0x03, 0xf0, 0x0f, 0xe8, 0x0e, 0xe0, 0x0f, 0x03, + 0xfa, 0x38, 0x7f, 0x0f, 0x04, 0xa8, 0x31, 0x79, 0xa4, 0x65, 0x4a, 0x45, 0x72, 0x08, 0xe5, 0xbc, + 0x04, 0x82, 0x1b, 0xa4, 0x01, 0xe0, 0x13, 0x37, 0x59, 0xe0, 0xd9, 0x2b, 0x95, 0x47, 0x1c, 0x57, + 0xac, 0xdd, 0x50, 0x7d, 0xfb, 0xb2, 0x1b, 0xb9, 0xcb, 0xd5, 0xac, 0x55, 0x76, 0xde, 0x79, 0x88, + 0xff, 0xcd, 0x3f, 0xa9, 0x7c, 0x2c, 0x75, 0x4a, 0x1a, 0x26, 0xd2, 0xe1, 0x26, 0x94, 0x79, 0x08, + 0x5e, 0x25, 0x2d, 0x71, 0xa9, 0x95, 0xb9, 0x2a, 0xcf, 0x78, 0x15, 0x88, 0x84, 0x5b, 0xc3, 0xf2, + 0xca, 0x49, 0x1c, 0x54, 0xda, 0xf5, 0x9f, 0x94, 0xff, 0x8f, 0x98, 0x4a, 0x83, 0x1e, 0x01, 0x90, + 0x58, 0x53, 0x67, 0x24, 0x68, 0x8a, 0x6f, 0xc7, 0x15, 0xfc, 0x0d, 0xf5, 0x61, 0xe3, 0xfd, 0xfc, + 0x1d, 0xc3, 0xf0, 0x3f, 0x01, 0xe1, 0xd8, 0x1f, 0x07, 0xc0, 0xc6, 0xf1, 0xe7, 0x31, 0x8f, 0x73, + 0xa2, 0x1d, 0xcb, 0x05, 0x72, 0x09, 0x05, 0xcc, 0x05, 0xbf, 0xeb, 0x69, 0x94, 0x99, 0xa8, 0xf1, + 0x0e, 0x92, 0x78, 0xaf, 0x01, 0xdc, 0x41, 0x3e, 0xd9, 0x4d, 0xb5, 0xc3, 0xe6, 0x5e, 0x56, 0x0e, + 0xdb, 0x69, 0x6b, 0x2a, 0x17, 0xbe, 0xd8, 0x2a, 0x71, 0xec, 0x70, 0x96, 0x8e, 0xda, 0xf1, 0x2e, + 0xeb, 0x40, 0x3f, 0x94, 0x3d, 0x1c, 0x7b, 0x73, 0x92, 0x4f, 0x25, 0x3d, 0x4a, 0x1a, 0x00, 0x96, + 0xa1, 0xee, 0xad, 0xdc, 0xf5, 0x98, 0xea, 0x1c, 0x29, 0x20, 0x01, 0x5e, 0x7b, 0x38, 0x3b, 0x43, + 0x0e, 0x27, 0xcb, 0x30, 0x93, 0xe7, 0x9e, 0xbe, 0x6f, 0xb3, 0xdf, 0x0e, 0xec, 0xc8, 0x54, 0x02, + 0x9f, 0x24, 0xdb, 0x5c, 0x4f, 0x1a, 0xd2, 0x52, 0x1d, 0xe3, 0xcf, 0x8f, 0xe0, 0xf8, 0x07, 0xf1, + 0x3a, 0x8f, 0x08, 0x82, 0x63, 0x92, 0x07, 0x32, 0x82, 0x1d, 0xcb, 0x05, 0x72, 0x08, 0xe5, 0xd4, + 0x00, 0x06, 0x94, 0xa8, 0xb5, 0xb8, 0x7f, 0xec, 0x80, 0x29, 0x5d, 0xd8, 0xc1, 0x32, 0xdd, 0xd1, + 0x05, 0x53, 0x33, 0x6b, 0x58, 0x00, 0xcf, 0x48, 0xa4, 0xd6, 0xce, 0x18, 0x6a, 0xbe, 0xec, 0x08, + 0xa1, 0x16, 0x39, 0xd6, 0xcd, 0x75, 0x06, 0x8e, 0xdc, 0x22, 0x03, 0x83, 0x24, 0xd1, 0x5e, 0x0c, + 0x6c, 0xa1, 0xa4, 0x36, 0x06, 0xb8, 0xc8, 0x16, 0x32, 0xbe, 0x8c, 0x78, 0x04, 0xbe, 0x84, 0xf2, + 0x4a, 0xed, 0x94, 0x75, 0xde, 0xb4, 0xdc, 0x91, 0x8d, 0xb5, 0x96, 0x61, 0x43, 0xee, 0x3e, 0x69, + 0x03, 0x84, 0xb5, 0x43, 0xad, 0xa5, 0x35, 0x42, 0x75, 0x08, 0x3d, 0x0a, 0x27, 0x76, 0x6c, 0x7b, + 0xc3, 0x07, 0x81, 0xf9, 0x81, 0xf8, 0x7c, 0x07, 0xe8, 0xf1, 0xa2, 0x5e, 0x3c, 0xf4, 0x29, 0x51, + 0xa2, 0x1d, 0xcb, 0x05, 0x72, 0x08, 0xf5, 0xcc, 0x04, 0x8e, 0x04, 0x00, 0xff, 0x7a, 0x54, 0x6b, + 0x4a, 0x61, 0x23, 0x36, 0xd4, 0x6b, 0x8f, 0x20, 0x5c, 0xa3, 0xfb, 0x43, 0xde, 0x27, 0x6a, 0x30, + 0x65, 0xd6, 0x6f, 0x2c, 0x6b, 0xa1, 0x25, 0xbc, 0xa3, 0x4e, 0xbf, 0x32, 0x9b, 0xf0, 0x68, 0x3d, + 0xf9, 0xe8, 0x10, 0x34, 0xfa, 0xb4, 0x5d, 0x40, 0x02, 0x97, 0xa7, 0x90, 0x0c, 0xf9, 0xdf, 0x6c, + 0x21, 0xad, 0x56, 0xcc, 0xe4, 0xb6, 0xc0, 0x7b, 0x8f, 0x5b, 0x15, 0xe2, 0x34, 0xc8, 0x47, 0x2b, + 0x32, 0xc7, 0x48, 0x70, 0x23, 0xd9, 0x08, 0x31, 0x02, 0xa4, 0x99, 0x10, 0xf0, 0x20, 0x72, 0x89, + 0x11, 0xe2, 0x4b, 0x9a, 0x0b, 0x0a, 0x13, 0x04, 0xe1, 0xe0, 0x3c, 0x2e, 0x60, 0x7e, 0x1f, 0xc0, + 0x78, 0x7c, 0x78, 0xce, 0x37, 0x58, 0x68, 0xd8, 0xa2, 0x1d, 0xcb, 0x05, 0x72, 0x08, 0xe5, 0xcc, + 0x04, 0x90, 0x07, 0x33, 0x07, 0x60, 0xfd, 0xe3, 0xec, 0x7e, 0x9b, 0xe3, 0xd1, 0x30, 0x29, 0x22, + 0x2a, 0x23, 0x7b, 0x65, 0x26, 0x4d, 0xba, 0xfc, 0xd2, 0xfa, 0xe0, 0xf9, 0x20, 0x2f, 0x01, 0x72, + 0x86, 0xaf, 0x5b, 0x7f, 0x49, 0xaf, 0xbc, 0xbb, 0x31, 0x35, 0x9b, 0xda, 0xbf, 0x63, 0x88, 0xd5, + 0x5e, 0x2c, 0xbf, 0xb7, 0x44, 0xc1, 0xf9, 0x23, 0xde, 0x5a, 0x01, 0x4a, 0x44, 0x41, 0x2c, 0x32, + 0x34, 0x86, 0xac, 0x49, 0x62, 0xef, 0xb7, 0x8b, 0xfe, 0xfa, 0xf2, 0x66, 0x0e, 0x88, 0x72, 0x90, + 0x88, 0x7b, 0x83, 0x9b, 0x05, 0xd1, 0x51, 0x8f, 0xbf, 0x79, 0xc1, 0x79, 0xf2, 0x78, 0x40, 0x8c, + 0x3c, 0x3e, 0x03, 0xfc, 0x2d, 0xc1, 0xf8, 0x0f, 0x0f, 0xba, 0x8c, 0x86, 0x98, 0x47, 0x5c, 0xf2, + 0xa2, 0x1d, 0xcb, 0x05, 0x72, 0x08, 0xf5, 0xcc, 0x00, 0xcc, 0x0f, 0x92, 0x03, 0x75, 0x12, 0xdb, + 0x72, 0x37, 0x8b, 0x66, 0xc9, 0xe9, 0x64, 0xa3, 0x17, 0x5f, 0xa0, 0x2e, 0x6e, 0x60, 0xc1, 0xa6, + 0x8c, 0xfd, 0x02, 0x3b, 0xa7, 0x98, 0xa7, 0xda, 0x9e, 0x16, 0xcb, 0x8d, 0x65, 0x7a, 0x7e, 0xb7, + 0xc4, 0xf5, 0x37, 0x88, 0x71, 0x38, 0x2c, 0x32, 0x52, 0x17, 0x70, 0x3f, 0xd1, 0x6a, 0x6d, 0x8d, + 0xed, 0x5f, 0xa4, 0xed, 0x42, 0x06, 0x4b, 0xa8, 0x5e, 0x62, 0x4e, 0x4b, 0x02, 0xe7, 0xfe, 0x54, + 0xde, 0x88, 0xf7, 0xfd, 0xd3, 0x3d, 0x6f, 0x1b, 0xc9, 0x94, 0x74, 0x57, 0xc4, 0x3d, 0xdc, 0x54, + 0x91, 0xd5, 0xe7, 0x36, 0x17, 0x11, 0xac, 0x28, 0x2b, 0xe6, 0x1c, 0x1f, 0x03, 0xe4, 0xfc, 0x1f, + 0x85, 0x78, 0xe3, 0x32, 0x78, 0x57, 0x69, 0x2d, 0xa2, 0x1d, 0xcb, 0x05, 0x72, 0x08, 0xf5, 0xdc, + 0x00, 0x06, 0xa0, 0x3e, 0xa9, 0x76, 0x09, 0x2a, 0x4e, 0xa0, 0xcb, 0xdc, 0xf0, 0x30, 0x4d, 0xdf, + 0x8d, 0xd3, 0x19, 0x7b, 0x2c, 0x79, 0x1e, 0x6a, 0x23, 0xc5, 0xf9, 0x46, 0x91, 0xd0, 0x26, 0x1b, + 0xf8, 0x46, 0x50, 0x56, 0x83, 0x98, 0x27, 0x1a, 0xa7, 0x7c, 0xeb, 0x90, 0x9b, 0x94, 0x6f, 0x17, + 0x54, 0x89, 0x21, 0x94, 0xd2, 0x04, 0x00, 0x45, 0x98, 0x30, 0xb4, 0xcf, 0x4a, 0x90, 0xed, 0x77, + 0x51, 0x67, 0xe4, 0xf1, 0xd3, 0xaf, 0xec, 0x3c, 0x03, 0x0a, 0xf3, 0x83, 0xf5, 0x40, 0x49, 0x3f, + 0x15, 0x21, 0xf4, 0x41, 0x6f, 0xd7, 0x58, 0xc5, 0x6e, 0xcd, 0x4a, 0xbd, 0x91, 0x6f, 0x64, 0x08, + 0xf0, 0xf8, 0x7e, 0x1f, 0x80, 0xfe, 0x1f, 0xc7, 0x97, 0xb8, 0x63, 0x70, 0x0c, 0x18, 0x3f, 0xc8, + 0xa2, 0x1d, 0xcb, 0x05, 0x72, 0x09, 0x05, 0xd4, 0x00, 0x00, 0xf2, 0xb4, 0x00, 0x7b, 0xf6, 0x30, + 0x4b, 0xd2, 0x57, 0xae, 0x2e, 0xf3, 0x08, 0x05, 0x34, 0x38, 0x6e, 0xac, 0xfd, 0x94, 0xb9, 0xf9, + 0xd8, 0x5b, 0xef, 0x7c, 0x81, 0x95, 0xe9, 0xe0, 0x6b, 0x7d, 0x8a, 0xb8, 0x6f, 0x66, 0x82, 0x11, + 0xb7, 0x6a, 0x63, 0x28, 0xf7, 0x91, 0x58, 0x38, 0xce, 0xc8, 0x53, 0xb2, 0x9a, 0xb4, 0x07, 0x3c, + 0x81, 0x27, 0x4a, 0x88, 0x33, 0x6d, 0x37, 0xb1, 0xa7, 0xcb, 0x6e, 0xdd, 0xc7, 0x9a, 0x6e, 0xdc, + 0xb5, 0x21, 0x7f, 0xd3, 0x02, 0x0a, 0x79, 0x83, 0xb4, 0xaf, 0x74, 0x1b, 0xb4, 0x0f, 0xe2, 0xaf, + 0x15, 0x6d, 0x0d, 0x01, 0xc7, 0x02, 0x06, 0x33, 0xeb, 0xd8, 0x33, 0xe6, 0xe5, 0xe3, 0x2e, 0xf0, + 0x5f, 0x0f, 0x21, 0xcb, 0x6d, 0x86, 0x06, 0xb9, 0xb4, 0x39, 0x63, 0x0f, 0x72, 0x08, 0xd5, 0xdc, + 0x00, 0xc3, 0xf5, 0xf9, 0xd6, 0xe4, 0x55, 0xeb, 0x8c, 0xb5, 0x6c, 0xc9, 0xe2, 0x92, 0x54, 0xcb, + 0x36, 0x2d, 0x90, 0x55, 0x22, 0x29, 0x91, 0xbe, 0xfd, 0xd4, 0xba, 0x06, 0xcb, 0x7d, 0x5a, 0x1e, + 0x5a, 0xef, 0xb4, 0x5e, 0x44, 0xee, 0xd9, 0x9d, 0xae, 0x61, 0xfc, 0x66, 0x66, 0x1d, 0x2d, 0xd8, + 0x88, 0xd4, 0x4b, 0xf5, 0x0f, 0xcc, 0x70, 0xc7, 0x5e, 0xa4, 0x1b, 0xa0, 0xcc, 0x6f, 0x14, 0xa2, + 0x28, 0x84, 0x56, 0xdf, 0x9b, 0x9b, 0x1d, 0x31, 0x77, 0x7b, 0xbc, 0x6f, 0x3d, 0xae, 0x37, 0x24, + 0xe4, 0xef, 0xab, 0xb6, 0xc0, 0x00, 0xad, 0x44, 0xf1, 0x9e, 0x98, 0x19, 0x0b, 0xfd, 0x70, 0x67, + 0x9f, 0x9e, 0x1e, 0x87, 0xa1, 0xa0, 0xd0, 0x1c, 0x9d, 0x1a, 0x3d, 0x1b, 0xf6, 0x2c, 0xd9, 0xd3, + 0x94, 0x39, 0x63, 0x0f, 0x72, 0x08, 0xc5, 0xdc, 0x04, 0x8c, 0x0a, 0xd0, 0x8b, 0x08, 0x59, 0xea, + 0x37, 0x08, 0xa4, 0x24, 0x01, 0x0c, 0xa3, 0xaa, 0xb6, 0x2b, 0xca, 0x29, 0x89, 0x31, 0x5d, 0xa3, + 0xf5, 0xdc, 0xd1, 0x78, 0x34, 0xda, 0xce, 0xbe, 0x18, 0xff, 0x18, 0xd4, 0x8a, 0xf4, 0x80, 0x40, + 0x8e, 0xe5, 0x8f, 0x26, 0x02, 0xa1, 0x19, 0x3a, 0xa7, 0x4a, 0x85, 0x8b, 0xc8, 0xe2, 0xed, 0xfa, + 0xd3, 0x58, 0x19, 0xea, 0xe5, 0x7d, 0x86, 0xe8, 0x1b, 0x59, 0x73, 0x0f, 0x92, 0xfd, 0x6e, 0xb9, + 0x05, 0xb2, 0x21, 0x1d, 0xdd, 0xbc, 0xea, 0xfe, 0x15, 0xf9, 0x96, 0x7e, 0x39, 0x45, 0xa1, 0xfa, + 0xf9, 0x77, 0xca, 0x50, 0x47, 0x81, 0xa3, 0x4d, 0xf3, 0xc3, 0xc1, 0xce, 0x1d, 0x03, 0x9c, 0x9d, + 0x0b, 0x02, 0x9f, 0x43, 0x9d, 0x67, 0x93, 0xab, 0x94, 0x39, 0x63, 0x0f, 0x72, 0x08, 0xe5, 0xdc, + 0x00, 0x08, 0xa3, 0xf4, 0x59, 0x6e, 0x0b, 0x46, 0xee, 0xce, 0x77, 0xfe, 0x27, 0x55, 0xf6, 0xd6, + 0xf4, 0xf7, 0x2b, 0xab, 0xb3, 0x99, 0x0c, 0x42, 0xe4, 0x05, 0x9d, 0x21, 0x3b, 0x34, 0x6d, 0x0c, + 0x33, 0xf2, 0xee, 0x72, 0x2e, 0xd1, 0x1e, 0xeb, 0x70, 0x36, 0xd9, 0x45, 0x08, 0xd7, 0x3c, 0x79, + 0x05, 0x63, 0x41, 0x7c, 0x78, 0xc3, 0xaa, 0x76, 0x14, 0x22, 0xdf, 0xc4, 0x5b, 0x1b, 0x23, 0x88, + 0xac, 0xd9, 0x38, 0x7e, 0x84, 0x1c, 0x81, 0x80, 0x3c, 0x57, 0xa7, 0x2c, 0xe8, 0xf2, 0x59, 0xb4, + 0x9c, 0x8a, 0x56, 0xb3, 0xd0, 0x29, 0x1a, 0x0e, 0x3f, 0x19, 0x29, 0xbb, 0x8a, 0xf3, 0xfb, 0x03, + 0x31, 0xcf, 0xc1, 0xe0, 0x70, 0x70, 0xc6, 0x1f, 0x0d, 0x8e, 0x43, 0xf0, 0x73, 0xc1, 0x44, 0xfc, + 0xb4, 0x39, 0x63, 0x0f, 0x72, 0x08, 0xf5, 0xe4, 0x00, 0x04, 0x6e, 0x94, 0x9d, 0xaa, 0x6b, 0x43, + 0x9d, 0x6b, 0x8f, 0x14, 0x3b, 0xb0, 0x78, 0xb0, 0x33, 0x31, 0xc1, 0x8e, 0xf3, 0x75, 0x71, 0xbe, + 0xb9, 0x84, 0x5c, 0xfb, 0x3d, 0x2c, 0x0c, 0x32, 0x6a, 0xef, 0x90, 0x51, 0xdf, 0x6f, 0x43, 0x7b, + 0x96, 0x17, 0xd9, 0x81, 0x2c, 0xb6, 0x12, 0xd9, 0x8f, 0x4f, 0xbf, 0x44, 0xcc, 0x46, 0xab, 0xef, + 0xf3, 0xd1, 0xa1, 0x10, 0x28, 0xa4, 0x6d, 0xcc, 0x77, 0xd3, 0xf8, 0xd5, 0xd5, 0x95, 0xcf, 0xde, + 0xb4, 0x9e, 0xeb, 0xb2, 0x3f, 0x7d, 0xef, 0xbd, 0x2d, 0x86, 0x29, 0xfe, 0xd9, 0x70, 0x7a, 0x3d, + 0x48, 0xcd, 0xf0, 0x03, 0xe4, 0x04, 0x18, 0x8a, 0xce, 0x76, 0x66, 0x0c, 0x3c, 0x1c, 0x27, 0x33, + 0x81, 0x0e, 0x97, 0xd0, 0x77, 0xa3, 0x52, 0xe1, 0x94, 0x39, 0x63, 0x0f, 0x72, 0x08, 0xd5, 0xf4, + 0x04, 0x80, 0xb9, 0xd1, 0xea, 0x0b, 0x6d, 0x5b, 0x0a, 0xd6, 0xda, 0xe7, 0xa9, 0xe7, 0x58, 0x40, + 0x74, 0xdb, 0x35, 0xf6, 0x73, 0xc7, 0x81, 0x7c, 0xc1, 0x6e, 0xd3, 0xa8, 0xaa, 0xef, 0xe2, 0xf7, + 0x20, 0x16, 0xbc, 0x3e, 0x32, 0x32, 0x17, 0x5d, 0xfc, 0x7b, 0x2b, 0x95, 0x6c, 0x89, 0x9a, 0xd0, + 0xe4, 0xe9, 0x63, 0x5b, 0x56, 0x4f, 0x74, 0x16, 0x51, 0x96, 0x07, 0xe2, 0x2b, 0x78, 0xb7, 0x22, + 0x11, 0x0b, 0x86, 0x06, 0xa7, 0xa1, 0x93, 0xb8, 0xc4, 0x8a, 0x3f, 0x17, 0xb6, 0xef, 0x2c, 0x0f, + 0xa1, 0x7c, 0x56, 0x44, 0x22, 0x73, 0x7b, 0x4e, 0x3f, 0xbd, 0x5e, 0x9d, 0x79, 0xad, 0xbc, 0x57, + 0x4c, 0xe6, 0x07, 0x83, 0x18, 0x4f, 0x1f, 0x26, 0x8e, 0x1f, 0x1d, 0x8f, 0x84, 0x73, 0x97, 0x93, + 0x94, 0x39, 0x63, 0x0f, 0x72, 0x08, 0xf5, 0xe4, 0x05, 0xc0, 0xee, 0xc4, 0xb6, 0xf1, 0x78, 0x1c, + 0x92, 0xa3, 0x44, 0xa6, 0x8e, 0x34, 0x54, 0x3c, 0xf9, 0x70, 0x11, 0x72, 0xf7, 0xc3, 0xf8, 0xad, + 0x77, 0x05, 0x7e, 0x9c, 0x87, 0x4e, 0x37, 0xfe, 0x70, 0x58, 0x3e, 0x56, 0xb0, 0x6c, 0xca, 0xfc, + 0x7e, 0x7c, 0x9f, 0x2c, 0xf0, 0x7f, 0x0a, 0x88, 0xec, 0x6f, 0x83, 0xfd, 0xe8, 0xd4, 0x8a, 0x04, + 0x1f, 0xd5, 0x6c, 0x5e, 0x75, 0xdb, 0x2f, 0x2b, 0x44, 0x69, 0xbf, 0xdc, 0xeb, 0x71, 0xe6, 0xd0, + 0x53, 0xf1, 0xfa, 0x6d, 0x0f, 0xe1, 0x1e, 0x1f, 0x47, 0xe4, 0xbc, 0x23, 0x78, 0x89, 0xe5, 0x78, + 0x8c, 0x68, 0xc7, 0x3b, 0x54, 0x4e, 0xf7, 0x80, 0xbe, 0x3c, 0x78, 0x7c, 0x3e, 0x78, 0x78, 0xe3, + 0x17, 0x81, 0x1a, 0x4a, 0x1d, 0xec, 0x1a, 0xe3, 0x94, 0x39, 0x63, 0x0f, 0x72, 0x08, 0xd5, 0xf4, + 0x00, 0x07, 0xf9, 0xc9, 0xf0, 0xe6, 0x4c, 0x15, 0x5e, 0x3d, 0x52, 0x3a, 0xa8, 0x4a, 0x61, 0xe0, + 0x03, 0x4e, 0x61, 0x7a, 0xef, 0x54, 0x60, 0x34, 0x45, 0x5c, 0xd9, 0x41, 0xfc, 0x6e, 0x6c, 0x25, + 0xf6, 0xab, 0x6e, 0x7a, 0x2c, 0x3f, 0x2a, 0x6b, 0x3c, 0x46, 0x44, 0x43, 0x08, 0x95, 0xcd, 0xda, + 0xc3, 0x53, 0x0a, 0xac, 0x72, 0x02, 0x3e, 0xd6, 0x8c, 0xcc, 0x32, 0x1c, 0x4d, 0x64, 0x94, 0xc5, + 0xfb, 0xb0, 0x68, 0xe7, 0xaf, 0x6e, 0xbc, 0x9e, 0xbf, 0x27, 0xe0, 0x0a, 0x84, 0x6b, 0x28, 0x53, + 0xa7, 0xc1, 0xf3, 0xf1, 0xad, 0x27, 0xf2, 0xd6, 0xad, 0x45, 0x33, 0x0f, 0xde, 0x9d, 0x6b, 0x43, + 0x01, 0xe1, 0xf1, 0xe0, 0x78, 0x68, 0x2c, 0x12, 0x73, 0x05, 0x4b, 0x4c, 0xd9, 0x79, 0xa3, 0x4c, + 0xb4, 0x39, 0x63, 0x0f, 0x72, 0x08, 0xe5, 0xfc, 0x04, 0x83, 0xf2, 0x43, 0x5c, 0x3b, 0xb7, 0x22, + 0xf4, 0x83, 0x1a, 0x13, 0xf1, 0x44, 0x26, 0x9c, 0x93, 0xed, 0xf4, 0xfd, 0xc0, 0xb6, 0xef, 0xcb, + 0x43, 0x5d, 0xde, 0xf0, 0xeb, 0x01, 0x1b, 0x76, 0x82, 0xbb, 0x78, 0xa2, 0x26, 0x9b, 0x63, 0xb0, + 0x91, 0xa5, 0xd2, 0xd7, 0xc5, 0x54, 0xd9, 0x20, 0x51, 0x6e, 0xb0, 0x0b, 0x7d, 0x13, 0x46, 0x39, + 0xbd, 0xf9, 0x45, 0xeb, 0x7d, 0x41, 0xb4, 0x37, 0x3e, 0x09, 0xb5, 0xd2, 0xec, 0x67, 0x93, 0xcf, + 0x6d, 0xa9, 0xd0, 0x67, 0x10, 0x80, 0x08, 0x13, 0x66, 0x42, 0xe1, 0x77, 0x38, 0x4c, 0x54, 0xb4, + 0x87, 0xe5, 0xff, 0x95, 0x61, 0x25, 0x4d, 0x18, 0xff, 0x47, 0xbe, 0x3e, 0x1c, 0x16, 0xea, 0x1c, + 0x5e, 0x0f, 0x0f, 0x2b, 0x4f, 0x45, 0xce, 0x0b, 0xb4, 0x39, 0x63, 0x0f, 0x72, 0x08, 0xd5, 0xf4, + 0x04, 0x80, 0x89, 0x37, 0xc9, 0xab, 0x0b, 0x9d, 0xb6, 0x8a, 0xd4, 0x9b, 0x41, 0x45, 0x5a, 0xba, + 0xc7, 0xa5, 0x1b, 0x4e, 0xe8, 0xe3, 0x3f, 0xbf, 0x5d, 0x32, 0x99, 0xb8, 0x18, 0xb0, 0x4c, 0x0b, + 0x7a, 0xf4, 0x78, 0xe5, 0xb0, 0x90, 0x99, 0xaa, 0xf0, 0xb4, 0xc5, 0xec, 0xc4, 0x4f, 0xae, 0x75, + 0x57, 0x9f, 0x7b, 0x46, 0x7c, 0x0a, 0xee, 0xf1, 0x41, 0xc1, 0x74, 0x4d, 0x0b, 0xe1, 0xa3, 0x75, + 0xeb, 0x64, 0xc8, 0xbc, 0x29, 0x00, 0x21, 0x91, 0x9d, 0x0c, 0x29, 0x1f, 0xcd, 0xc2, 0x19, 0xc7, + 0x70, 0x7f, 0x12, 0x30, 0x3d, 0x9a, 0x37, 0xa6, 0x83, 0x08, 0x2c, 0x75, 0xf2, 0x65, 0x9f, 0x60, + 0x73, 0xe3, 0xf1, 0xc0, 0x7c, 0x3c, 0x7e, 0x1e, 0x78, 0xe1, 0xf5, 0xe8, 0xee, 0x3e, 0x7d, 0xb9, + 0x94, 0x39, 0x63, 0x0f, 0x72, 0x08, 0xe5, 0xfc, 0x04, 0x80, 0x29, 0xc1, 0xc4, 0x2f, 0x9d, 0x30, + 0x83, 0x82, 0x73, 0x6c, 0x33, 0xb6, 0x37, 0xcf, 0xec, 0xb3, 0xe8, 0x48, 0x24, 0xd6, 0x82, 0xab, + 0x23, 0xcb, 0x9d, 0xcb, 0x6b, 0x1a, 0xad, 0x96, 0x32, 0x3a, 0xed, 0x43, 0xf1, 0xdf, 0x02, 0xde, + 0x66, 0x4a, 0x8b, 0x5c, 0x1a, 0x8f, 0x70, 0x0a, 0xf2, 0xaa, 0x04, 0x2d, 0xa6, 0x23, 0x35, 0x8a, + 0x7f, 0x1e, 0xf9, 0x24, 0xec, 0x67, 0x7e, 0x7f, 0x1e, 0x7d, 0x4c, 0x99, 0x43, 0x3d, 0xb8, 0xed, + 0xef, 0xea, 0xb6, 0x25, 0x06, 0x20, 0x69, 0x25, 0xe4, 0x97, 0xd0, 0x9d, 0x0c, 0xb5, 0x3d, 0x3d, + 0x08, 0xe2, 0x54, 0x9d, 0xc2, 0xf8, 0x5f, 0x70, 0x78, 0xf1, 0xf8, 0x3e, 0x3c, 0x2e, 0x0f, 0xc4, + 0x20, 0x9f, 0x80, 0x42, 0x6e, 0xe7, 0xc6, 0x17, 0x94, 0x39, 0x63, 0x0f, 0x72, 0x09, 0x05, 0xf4, + 0x04, 0x80, 0x62, 0xdf, 0x2f, 0x51, 0xcc, 0x97, 0x7e, 0x59, 0xa8, 0x2a, 0xd7, 0x36, 0x6c, 0x58, + 0x4a, 0x4b, 0x7b, 0x51, 0x19, 0x51, 0x3d, 0xb2, 0x05, 0xfc, 0xe0, 0xcc, 0x89, 0xa9, 0xc6, 0xc7, + 0x24, 0xdd, 0x06, 0x2d, 0x74, 0xb4, 0x72, 0xc4, 0xbe, 0x2b, 0x17, 0xb5, 0x87, 0x6e, 0x3f, 0x6a, + 0x84, 0x9c, 0x59, 0x7a, 0x07, 0x64, 0xf0, 0x8a, 0x54, 0x2c, 0x1a, 0x5e, 0x8a, 0x5d, 0xd3, 0x8b, + 0xe0, 0x6f, 0x06, 0x0d, 0x7a, 0xc8, 0x6d, 0x9f, 0x0e, 0x15, 0x6b, 0x8f, 0xa7, 0xdf, 0x39, 0x2f, + 0x45, 0x1a, 0xdb, 0xc4, 0x36, 0xfc, 0xa2, 0xa5, 0xb1, 0x93, 0xd4, 0xea, 0x73, 0x91, 0x1f, 0x83, + 0x03, 0xc3, 0x81, 0xe0, 0x70, 0xf0, 0xf1, 0x87, 0x0b, 0x18, 0xfe, 0x55, 0xc4, 0xfc, 0x70, 0xde, + 0x94, 0x39, 0x63, 0x0f, 0x72, 0x08, 0xe6, 0x04, 0x00, 0x10, 0xbe, 0xbf, 0xc1, 0x4c, 0x3c, 0x03, + 0xe8, 0xeb, 0x0a, 0x6c, 0x91, 0xcb, 0xa3, 0xf1, 0xe3, 0xd5, 0x64, 0x95, 0x46, 0x53, 0xe1, 0x02, + 0x5f, 0x30, 0x79, 0x44, 0xd0, 0x69, 0x4d, 0xa1, 0xeb, 0x7f, 0x6f, 0x76, 0x59, 0x9b, 0xd4, 0x88, + 0x22, 0x14, 0x38, 0x7f, 0xaa, 0x4e, 0x5f, 0x90, 0xb9, 0x20, 0xf6, 0x8e, 0x58, 0x89, 0x05, 0x85, + 0xbf, 0x3f, 0xbc, 0x8b, 0xb2, 0x6c, 0xaa, 0x18, 0x66, 0xd8, 0xdf, 0x29, 0xea, 0x75, 0xf3, 0xb3, + 0x33, 0x17, 0x3a, 0x15, 0x63, 0xe0, 0x66, 0x04, 0x1d, 0xd6, 0x2b, 0x29, 0x01, 0x11, 0x48, 0x86, + 0xfa, 0x15, 0x8a, 0xd2, 0x06, 0x01, 0x4c, 0xcf, 0xe3, 0x8f, 0x1c, 0x61, 0xf3, 0xf4, 0x1e, 0xd8, + 0x1d, 0x3f, 0x7d, 0x1e, 0x5a, 0x85, 0xc3, 0x1e, 0x94, 0x39, 0x63, 0x0f, 0x72, 0x08, 0xd6, 0x04, + 0x00, 0xd0, 0x76, 0xf2, 0x7f, 0x99, 0x06, 0x42, 0xba, 0x96, 0xa4, 0x66, 0xa1, 0x65, 0x02, 0x8e, + 0x0b, 0x06, 0xb9, 0x14, 0x5b, 0xf5, 0x89, 0x5b, 0x66, 0xf4, 0x69, 0x54, 0x4e, 0x58, 0x4d, 0xd9, + 0xd3, 0xab, 0xd2, 0x53, 0x92, 0xc5, 0x77, 0x20, 0x12, 0x1c, 0xe8, 0xa6, 0x3e, 0xb7, 0x9f, 0x88, + 0xff, 0x50, 0x5b, 0xeb, 0x68, 0xb2, 0xe8, 0x7a, 0xbb, 0x9c, 0x05, 0x5f, 0x10, 0x4c, 0xc4, 0x8f, + 0x55, 0xd9, 0x6c, 0xf6, 0xb3, 0xbc, 0x53, 0x99, 0xa9, 0xfb, 0x82, 0x3f, 0xee, 0xcf, 0x37, 0x72, + 0xfa, 0x8b, 0xe5, 0x63, 0x9b, 0x43, 0xde, 0x64, 0x3d, 0x37, 0xbe, 0x00, 0xdd, 0x9a, 0x4d, 0x4e, + 0xa7, 0x8e, 0x0c, 0xf8, 0x7c, 0x2c, 0x3a, 0x69, 0x38, 0x94, 0x89, 0x6b, 0x31, 0xdc, 0xa7, 0x30, + 0x94, 0x39, 0x63, 0x0f, 0x72, 0x08, 0xc6, 0x0c, 0x04, 0x92, 0xbc, 0x03, 0x7e, 0xd0, 0xea, 0xb9, + 0x7b, 0xd3, 0x5f, 0xcb, 0xdf, 0x36, 0x51, 0x32, 0x20, 0x0f, 0x25, 0x93, 0xce, 0x92, 0xdc, 0x67, + 0x85, 0xf8, 0xa7, 0x11, 0x0b, 0x52, 0x1c, 0x67, 0x7f, 0x11, 0xf7, 0xbd, 0x73, 0x99, 0x32, 0xb3, + 0x85, 0x2b, 0x47, 0x6d, 0x06, 0x3c, 0xa6, 0x12, 0x4b, 0xa7, 0x65, 0x2f, 0x5a, 0xb9, 0xb9, 0xb8, + 0xf9, 0x0e, 0x07, 0x38, 0xf8, 0x16, 0x00, 0x16, 0x29, 0xee, 0xc0, 0xf6, 0x7a, 0x70, 0x17, 0x7a, + 0x0b, 0x6b, 0xb6, 0xba, 0x81, 0x15, 0x7d, 0xe9, 0x72, 0x05, 0x3d, 0xb0, 0x2c, 0xe9, 0xe0, 0x6d, + 0x72, 0x06, 0xfc, 0x3e, 0x1a, 0x23, 0x83, 0xe0, 0xc1, 0xf3, 0xe0, 0xf1, 0xe0, 0xff, 0xce, 0xfe, + 0x3c, 0x4c, 0x5f, 0x5c, 0x0c, 0xd4, 0x72, 0xf2, 0x94, 0x39, 0x63, 0x0f, 0x72, 0x08, 0xc6, 0x0c, + 0x00, 0x07, 0x36, 0x63, 0xdb, 0xdc, 0xae, 0x38, 0x21, 0x1b, 0xe5, 0xf8, 0x09, 0x1f, 0xd9, 0x49, + 0xb5, 0x70, 0xc3, 0x04, 0x20, 0xc7, 0x91, 0x5f, 0x41, 0x67, 0x58, 0x9e, 0xcc, 0x6f, 0x19, 0x17, + 0xba, 0xbb, 0x8f, 0x6b, 0x96, 0xea, 0xae, 0x01, 0x48, 0xac, 0xd3, 0x00, 0xa6, 0x22, 0xed, 0xbf, + 0x9c, 0x95, 0x21, 0x51, 0xe7, 0xf7, 0xda, 0x00, 0x14, 0xc1, 0x6e, 0xc5, 0x6d, 0xb5, 0x37, 0x0f, + 0xa0, 0xa2, 0xae, 0x80, 0x0b, 0x8d, 0x03, 0x1e, 0x8b, 0x0f, 0x81, 0x19, 0x1b, 0xaf, 0x80, 0x06, + 0xdc, 0xb0, 0x9d, 0x32, 0xaf, 0x09, 0x59, 0xbc, 0xfe, 0xc0, 0x0f, 0xe9, 0x14, 0x22, 0x16, 0xbc, + 0x78, 0xf1, 0xc7, 0x82, 0xa0, 0xd3, 0x3a, 0x79, 0x63, 0x61, 0xd0, 0xb8, 0x24, 0xc4, 0x7b, 0xc5, + 0x94, 0x39, 0x63, 0x0f, 0x72, 0x08, 0xd6, 0x0c, 0x02, 0x0e, 0x25, 0x72, 0x42, 0xbd, 0xb4, 0xc0, + 0xf2, 0x6f, 0x60, 0x06, 0x8a, 0x98, 0xa8, 0xef, 0xe8, 0x44, 0x26, 0x84, 0xe7, 0x86, 0xfb, 0x51, + 0x3c, 0x8c, 0x19, 0x84, 0x2a, 0x50, 0x74, 0x24, 0xf3, 0xd0, 0x37, 0xa4, 0x5c, 0x0d, 0x54, 0xf1, + 0xaf, 0x99, 0xb6, 0x5d, 0xf4, 0x72, 0x41, 0x06, 0x61, 0xec, 0xd2, 0x2d, 0xe5, 0xe6, 0xa1, 0x56, + 0xb3, 0x00, 0x09, 0xef, 0x3b, 0x48, 0xda, 0xee, 0xce, 0x68, 0x4c, 0x27, 0x5d, 0x7e, 0x0a, 0x03, + 0xfa, 0x7d, 0xf0, 0x29, 0x30, 0xa8, 0xbc, 0xff, 0x66, 0x26, 0xc7, 0x9a, 0xf1, 0xe3, 0x8e, 0xc2, + 0xae, 0xa9, 0x3f, 0x26, 0xd8, 0x9f, 0xdd, 0x8e, 0x61, 0xe1, 0xc7, 0x87, 0x07, 0x4e, 0x38, 0x03, + 0xc3, 0xc1, 0xfe, 0x0a, 0x30, 0x95, 0x41, 0x31, 0x94, 0x39, 0x63, 0x0f, 0x72, 0x08, 0xc6, 0x0c, + 0x00, 0x09, 0x4a, 0xba, 0x20, 0x0e, 0xdd, 0xb5, 0x71, 0x59, 0x9b, 0x48, 0xf7, 0xbd, 0x32, 0x2e, + 0x70, 0xf2, 0xb3, 0x61, 0x13, 0xd1, 0x27, 0xa7, 0xc3, 0xa3, 0xce, 0x3a, 0xbf, 0x7e, 0xc9, 0x87, + 0x8d, 0x2d, 0xa7, 0xa4, 0x10, 0x1d, 0x84, 0x94, 0xcd, 0x82, 0x0b, 0xa6, 0x3e, 0x87, 0x40, 0x2a, + 0x96, 0x04, 0x81, 0x4f, 0x3a, 0x8a, 0xe7, 0x15, 0x54, 0xaf, 0xb8, 0xb8, 0x55, 0x9b, 0x5c, 0x03, + 0x6d, 0xc1, 0x8e, 0x8c, 0xfd, 0x91, 0xb2, 0x44, 0xae, 0xc8, 0x8e, 0x54, 0xb2, 0x24, 0xf8, 0xe7, + 0x63, 0x79, 0x1d, 0x8a, 0x26, 0x04, 0xcc, 0x36, 0x28, 0xf5, 0x18, 0x11, 0x50, 0xa3, 0xf1, 0xfc, + 0xc6, 0x38, 0x63, 0xf0, 0x38, 0x68, 0x9e, 0xf7, 0x8e, 0x16, 0x77, 0xf0, 0x77, 0xf6, 0x59, 0x59, + 0x94, 0x39, 0x63, 0x0f, 0x72, 0x08, 0xd6, 0x0c, 0x02, 0x00, 0x42, 0x97, 0xbb, 0x39, 0xe8, 0x03, + 0xce, 0xd5, 0x36, 0x74, 0xc7, 0x31, 0x63, 0x1b, 0x4f, 0x59, 0xd8, 0x86, 0x4a, 0xe7, 0x5b, 0x0e, + 0xb9, 0x07, 0x66, 0xc9, 0xee, 0x38, 0x38, 0x0c, 0x07, 0xf7, 0x3b, 0xa5, 0x2b, 0x3c, 0x23, 0x3f, + 0x0c, 0x7b, 0x3a, 0x77, 0x87, 0xb3, 0x31, 0x7b, 0xcb, 0x2a, 0xf2, 0x27, 0x40, 0x3c, 0x49, 0x00, + 0x7b, 0x02, 0x97, 0xea, 0x0b, 0x68, 0x92, 0x64, 0x40, 0x87, 0x84, 0x16, 0x5d, 0xaa, 0xd6, 0x04, + 0xe2, 0xf8, 0x1b, 0x6c, 0xd0, 0x5b, 0xc0, 0x47, 0x96, 0xa3, 0x43, 0xa0, 0x76, 0x34, 0x63, 0xac, + 0x35, 0xff, 0x87, 0xf5, 0x7e, 0x5f, 0x6f, 0x81, 0x83, 0xcf, 0x83, 0x83, 0xc1, 0xae, 0xee, 0x31, + 0x3a, 0xd9, 0x39, 0xc1, 0xec, 0x58, 0xcd, 0xaa, 0x94, 0x39, 0x63, 0x0f, 0x72, 0x08, 0xb6, 0x1c, + 0x04, 0x84, 0x23, 0xaf, 0x99, 0xd5, 0x0c, 0x08, 0x4e, 0xf2, 0x00, 0xf3, 0x8d, 0x76, 0x65, 0xd4, + 0x95, 0x1a, 0x35, 0xb3, 0x28, 0xa2, 0x5d, 0xa3, 0xe6, 0x91, 0x75, 0xa9, 0x55, 0x61, 0xbd, 0x18, + 0xd9, 0xc3, 0xff, 0x69, 0xb2, 0x01, 0xba, 0xfa, 0x42, 0xa0, 0x53, 0xa2, 0xb1, 0x54, 0x2d, 0xd1, + 0x09, 0xf1, 0xbb, 0xc2, 0xe6, 0xa1, 0x5e, 0x01, 0xe9, 0x59, 0x8b, 0x23, 0x84, 0x74, 0x70, 0x47, + 0x6a, 0x6c, 0x2d, 0xee, 0x29, 0x86, 0x24, 0xdd, 0x90, 0x93, 0x8b, 0xfa, 0x89, 0x54, 0xbb, 0xbf, + 0x5e, 0xc9, 0xcf, 0xfd, 0x99, 0x85, 0xf1, 0xad, 0x54, 0xe8, 0x16, 0x48, 0x02, 0x10, 0x40, 0x07, + 0xfc, 0x3c, 0x30, 0x78, 0x7f, 0x03, 0xe6, 0xe2, 0x25, 0x38, 0xc1, 0x6d, 0xc7, 0x2e, 0x33, 0xa0, + 0x94, 0x39, 0x63, 0x0f, 0x72, 0x08, 0xe6, 0x1c, 0x00, 0xcd, 0xe3, 0x69, 0xf7, 0x40, 0x1e, 0x74, + 0x25, 0x44, 0x00, 0x92, 0x99, 0xed, 0x26, 0x50, 0x0b, 0x9f, 0x30, 0x0d, 0x8f, 0x1b, 0xe6, 0xa7, + 0x41, 0x36, 0xd5, 0x43, 0x3a, 0x1d, 0x24, 0x88, 0xc3, 0x28, 0x8f, 0x79, 0x70, 0x2f, 0xe3, 0x70, + 0x9b, 0x91, 0x93, 0xd8, 0xcc, 0x13, 0x9a, 0x15, 0xa1, 0xea, 0xb0, 0x07, 0xbc, 0x69, 0x82, 0x01, + 0xd4, 0xff, 0xc9, 0xbc, 0x58, 0x50, 0xc1, 0x69, 0xa8, 0x88, 0xd9, 0x8f, 0x05, 0x5d, 0xb5, 0xf8, + 0xbd, 0x17, 0x23, 0x9e, 0xae, 0x9f, 0x4c, 0xcd, 0x03, 0x29, 0xcc, 0x77, 0x3e, 0x15, 0x09, 0x15, + 0xc1, 0x5b, 0x8a, 0x59, 0xfe, 0x22, 0x66, 0x54, 0xff, 0x78, 0x3e, 0x3c, 0x3f, 0x07, 0x98, 0x7a, + 0x1f, 0x1f, 0x37, 0x20, 0xca, 0x39, 0xb9, 0x39, 0x95, 0x7a, 0xef, 0x6f, 0x72, 0x08, 0xd6, 0x14, + 0x04, 0x80, 0x10, 0x7b, 0xd8, 0x54, 0xad, 0xc6, 0x86, 0x84, 0x25, 0x8a, 0x23, 0x50, 0x2e, 0x21, + 0x07, 0x97, 0x1a, 0xab, 0xff, 0x1b, 0x4a, 0xab, 0x59, 0xea, 0x72, 0x68, 0x69, 0x76, 0xf3, 0x72, + 0x33, 0x74, 0x9c, 0xd9, 0xe1, 0x98, 0x96, 0x73, 0x92, 0xc6, 0x1f, 0xa1, 0xc7, 0x77, 0x6d, 0xf1, + 0x59, 0xdf, 0x86, 0xbd, 0x2e, 0xcf, 0x61, 0x42, 0x19, 0x0c, 0x08, 0xd5, 0x79, 0xdb, 0x9d, 0xe4, + 0xb5, 0x7a, 0x8e, 0xa7, 0xf2, 0xd8, 0xdd, 0x3b, 0xb0, 0xf3, 0x9f, 0x8c, 0xe8, 0xaa, 0x10, 0x01, + 0x41, 0xd8, 0xf9, 0x89, 0x06, 0xdb, 0xa6, 0x9c, 0x90, 0x2d, 0xa9, 0x50, 0x6b, 0x00, 0xce, 0x24, + 0x3c, 0x0f, 0xe3, 0xf8, 0x9e, 0x0f, 0xc0, 0xf8, 0x46, 0x66, 0xcb, 0xd7, 0x2a, 0xc0, 0x15, 0xd2, + 0x95, 0x7a, 0xef, 0x6f, 0x72, 0x08, 0xd6, 0x14, 0x00, 0xc0, 0x18, 0x52, 0x09, 0x56, 0x62, 0x26, + 0x69, 0x3e, 0x1e, 0xbf, 0x78, 0x75, 0xe9, 0x11, 0x95, 0x8d, 0x93, 0xa2, 0xc4, 0xf5, 0x83, 0x96, + 0xf7, 0x2c, 0x50, 0x79, 0x1c, 0x60, 0xb2, 0x28, 0x3a, 0x71, 0x84, 0x2c, 0xe8, 0xa6, 0x4c, 0xfd, + 0xdd, 0x61, 0x94, 0xaa, 0x41, 0xb8, 0xea, 0x9a, 0x9d, 0x51, 0xe4, 0x0a, 0x7d, 0x14, 0x4c, 0x06, + 0x05, 0x3a, 0xc6, 0x89, 0xad, 0x6e, 0xc1, 0x00, 0x88, 0x30, 0xa5, 0x60, 0x6a, 0x83, 0x5f, 0xc5, + 0xc6, 0x5a, 0xa8, 0xbd, 0x53, 0xcf, 0xe2, 0x15, 0x13, 0x28, 0x72, 0xc6, 0x94, 0x38, 0xe0, 0x02, + 0xb5, 0x98, 0x49, 0xbe, 0x65, 0xf8, 0xbc, 0x74, 0x4c, 0xe0, 0xf0, 0x78, 0x0f, 0xf0, 0xf0, 0x7f, + 0x94, 0xc0, 0x7c, 0xfa, 0xa5, 0x9f, 0x2b, 0x06, 0x95, 0x7a, 0xef, 0x6f, 0x72, 0x08, 0xd6, 0x24, + 0x07, 0x80, 0x4e, 0xc1, 0x89, 0x46, 0x26, 0xc4, 0x5e, 0xaa, 0x70, 0x30, 0xa7, 0xfb, 0x1f, 0x76, + 0xe7, 0xba, 0x40, 0xdf, 0xc2, 0x8b, 0x3a, 0x34, 0xbd, 0xae, 0xb2, 0x0c, 0x47, 0x4d, 0x75, 0xfa, + 0xca, 0x74, 0xf3, 0x9a, 0x93, 0x77, 0xe5, 0x6c, 0x8f, 0x18, 0x15, 0x8e, 0x78, 0xa5, 0xf6, 0xce, + 0x35, 0xd3, 0xc3, 0x92, 0x90, 0xe1, 0x57, 0xb8, 0x00, 0x4f, 0x2b, 0xf1, 0xcd, 0x8c, 0x6f, 0x32, + 0x9f, 0x1c, 0xc8, 0x4d, 0xd9, 0x6e, 0x64, 0xe5, 0xc1, 0xc6, 0x34, 0xad, 0x22, 0x74, 0x01, 0x2f, + 0x38, 0xc7, 0x1c, 0xac, 0x61, 0x21, 0x7a, 0xce, 0x4e, 0x8c, 0x8d, 0x8e, 0x1e, 0xe7, 0x9d, 0x92, + 0xf9, 0xe1, 0xf0, 0xf1, 0x1e, 0x0d, 0x6b, 0xd5, 0x3a, 0x37, 0x88, 0x71, 0xea, 0x38, 0x2e, 0x5e, + 0x95, 0x7a, 0xef, 0x6f, 0x72, 0x08, 0xb6, 0x1c, 0x0c, 0x08, 0x67, 0x4c, 0x0e, 0xad, 0xf1, 0x49, + 0x37, 0xa9, 0x04, 0xaa, 0xff, 0x81, 0xfb, 0xcd, 0xd6, 0xc4, 0x36, 0xcb, 0x0d, 0x4e, 0x54, 0x00, + 0x94, 0xa0, 0x08, 0x2d, 0x8a, 0x3b, 0xbc, 0x48, 0x14, 0x1c, 0x9a, 0x2a, 0x28, 0xa4, 0xb8, 0x44, + 0xfa, 0xa1, 0x5c, 0xc6, 0x38, 0x3b, 0x38, 0x56, 0xa6, 0xbd, 0xa4, 0x23, 0x0d, 0x51, 0x13, 0xd8, + 0x82, 0xb7, 0xd6, 0xb2, 0x0c, 0xb1, 0xbb, 0xee, 0x3c, 0xe9, 0xae, 0x8f, 0xa1, 0x58, 0xd3, 0xa4, + 0xf0, 0xb0, 0xd2, 0x1a, 0x47, 0xdc, 0x23, 0xa9, 0xeb, 0xd6, 0xed, 0x4b, 0xf8, 0x54, 0xd2, 0x6a, + 0x9a, 0xbd, 0xa9, 0xf3, 0x78, 0xd4, 0xec, 0x6c, 0x71, 0xe3, 0xf0, 0xfc, 0x0f, 0x07, 0x0f, 0x1a, + 0x41, 0xd3, 0x83, 0xed, 0x4d, 0x9b, 0x39, 0xb9, 0x86, 0xac, 0xc9, 0x85, 0x72, 0x08, 0xc6, 0x34, + 0x00, 0xc0, 0x50, 0x63, 0x0a, 0xf2, 0xb2, 0x04, 0xfb, 0xa2, 0xad, 0x2c, 0x66, 0x3c, 0x75, 0x78, + 0x71, 0x49, 0x83, 0x23, 0x56, 0x1d, 0x76, 0xf9, 0xfb, 0xdf, 0x6c, 0xf3, 0x8e, 0x7d, 0x79, 0x75, + 0x49, 0xa0, 0xea, 0xbc, 0xd4, 0x64, 0x06, 0x01, 0x4b, 0xae, 0x65, 0x0a, 0xe6, 0xa1, 0x4a, 0xea, + 0x4d, 0x7c, 0xa9, 0x87, 0xb2, 0x00, 0xed, 0xb8, 0xb8, 0x1d, 0x91, 0x66, 0x60, 0xbe, 0x75, 0x8c, + 0x8a, 0xec, 0x52, 0x3b, 0xcd, 0x11, 0x00, 0x86, 0x6b, 0x85, 0xc9, 0xbb, 0xbd, 0x7f, 0x8e, 0x6b, + 0x0d, 0x3c, 0x88, 0xc9, 0x5e, 0x5d, 0x7e, 0x50, 0x49, 0xdb, 0x5e, 0x21, 0x6f, 0x27, 0x47, 0xc7, + 0x88, 0x27, 0x1c, 0x3e, 0x18, 0x3d, 0x43, 0xe1, 0xf1, 0xc1, 0x64, 0xa7, 0x3b, 0x8c, 0x63, 0xd6, + 0x66, 0x62, 0x7e, 0x65, 0x72, 0x08, 0xd6, 0x2c, 0x00, 0x00, 0xd6, 0xba, 0x0a, 0xde, 0x0d, 0x61, + 0x67, 0xd8, 0xe3, 0x78, 0x6a, 0xff, 0x7d, 0x19, 0x94, 0xee, 0x63, 0x36, 0x3a, 0xe5, 0xad, 0xbe, + 0xd7, 0xa9, 0xa6, 0x9e, 0x01, 0x5a, 0x9e, 0x43, 0x1c, 0xa9, 0x0b, 0x96, 0xf7, 0xb7, 0x0d, 0x9e, + 0xfd, 0xfd, 0x1d, 0x8c, 0xe9, 0xdf, 0xe5, 0x75, 0x92, 0x38, 0x51, 0x8b, 0x11, 0x3a, 0x98, 0x91, + 0x48, 0x8d, 0xce, 0xdf, 0xf7, 0xf3, 0x36, 0x84, 0x06, 0x51, 0x0c, 0xa4, 0x04, 0xbb, 0x0e, 0xaa, + 0x3a, 0x32, 0xe6, 0x76, 0x90, 0x6e, 0xcc, 0x32, 0x22, 0xc0, 0x50, 0x53, 0x5a, 0xe4, 0xef, 0x68, + 0xe5, 0x5e, 0x42, 0x3a, 0x92, 0x48, 0xa2, 0x42, 0x92, 0x7f, 0x61, 0xf0, 0xf1, 0xf0, 0x1e, 0x0e, + 0x1e, 0x0c, 0x78, 0xe8, 0x7a, 0x19, 0x83, 0xa0, 0x86, 0x62, 0x7e, 0x65, 0x72, 0x08, 0xe6, 0x3c, + 0x00, 0x00, 0x0a, 0xff, 0x7b, 0xe7, 0x5b, 0x83, 0xba, 0x0c, 0x69, 0xdf, 0x15, 0x0f, 0x07, 0xbf, + 0xb0, 0x1d, 0xbc, 0xf4, 0x00, 0xec, 0x08, 0x89, 0x68, 0x80, 0x04, 0xdf, 0x2f, 0x2a, 0xb8, 0xbd, + 0x5b, 0x65, 0x6c, 0x7b, 0x32, 0xf3, 0x9d, 0x55, 0x70, 0xc5, 0xfb, 0xf8, 0xe3, 0x87, 0x28, 0xe7, + 0x71, 0xe7, 0x54, 0xd0, 0x2f, 0xec, 0xb5, 0x75, 0x2b, 0x46, 0xf4, 0x56, 0xac, 0xf6, 0xb6, 0xa0, + 0x28, 0xac, 0x21, 0x0f, 0x7e, 0x13, 0xe1, 0xe8, 0x80, 0x6c, 0x48, 0xd2, 0xb1, 0xcc, 0x2e, 0x65, + 0x01, 0xa8, 0x98, 0x0c, 0x68, 0x7f, 0xb2, 0x05, 0x2e, 0x9e, 0xb1, 0xff, 0x26, 0x55, 0xf0, 0x66, + 0xe7, 0xa1, 0x82, 0x16, 0x60, 0x1c, 0x7c, 0xf8, 0x70, 0x75, 0xa3, 0x84, 0xcd, 0x2b, 0x0a, 0x9d, + 0x86, 0x62, 0x7e, 0x65, 0x72, 0x08, 0xf6, 0x3c, 0x00, 0x02, 0x0e, 0x27, 0x82, 0x99, 0xe0, 0xe8, + 0x31, 0xb9, 0xde, 0x8e, 0x62, 0xa3, 0x93, 0x5b, 0x5a, 0x38, 0x66, 0x19, 0x54, 0xb2, 0x40, 0x91, + 0xbc, 0xbb, 0x17, 0x7f, 0x83, 0x0a, 0x3d, 0xe4, 0xc2, 0xbd, 0x75, 0xd3, 0x37, 0x22, 0x13, 0x41, + 0x28, 0xe4, 0x4c, 0x72, 0x8f, 0x26, 0x2e, 0xd9, 0x8f, 0x06, 0xc9, 0x7f, 0xbb, 0x7c, 0x31, 0xb2, + 0xb0, 0x7c, 0xd8, 0xa4, 0xa0, 0x33, 0x0d, 0x11, 0xfe, 0xb7, 0x75, 0xf2, 0x5a, 0x36, 0x1d, 0x1d, + 0x51, 0x78, 0xb5, 0x63, 0x7d, 0xd8, 0x11, 0xf5, 0x11, 0x15, 0x86, 0xde, 0xd6, 0xc7, 0x3d, 0xd2, + 0x3d, 0xd8, 0x50, 0x25, 0x2e, 0x10, 0x8b, 0xf0, 0xc7, 0xfa, 0x66, 0xa7, 0x1f, 0xce, 0x10, 0x53, + 0xb6, 0x41, 0xe6, 0xac, 0xd2, 0xe6, 0x7c, 0x52, 0xa6, 0x62, 0x7e, 0x65, 0x72, 0x08, 0xd6, 0x34, + 0x00, 0x02, 0x11, 0xd1, 0xf6, 0x74, 0xac, 0x18, 0x97, 0x32, 0x76, 0x76, 0x5a, 0x4b, 0x29, 0x5e, + 0xb0, 0xd3, 0x25, 0xb8, 0x55, 0x79, 0x84, 0x50, 0xce, 0x82, 0x68, 0xd1, 0x82, 0xd2, 0x01, 0x50, + 0x2d, 0xb7, 0x83, 0xfd, 0x1d, 0x6b, 0x00, 0x7f, 0x39, 0xc3, 0x51, 0x18, 0x64, 0x87, 0x42, 0xf2, + 0xa3, 0x6d, 0x4c, 0x76, 0x43, 0xe4, 0x04, 0x59, 0xc7, 0x6b, 0xad, 0x01, 0x9d, 0x8c, 0xdc, 0x4e, + 0x88, 0x3e, 0x0b, 0x06, 0xe2, 0xbd, 0xb6, 0x04, 0x77, 0x0b, 0x7a, 0x57, 0x9f, 0x00, 0x64, 0x18, + 0xbe, 0x03, 0x4d, 0x87, 0x13, 0x3f, 0x07, 0x0c, 0x48, 0xf5, 0x42, 0x31, 0x78, 0x67, 0xae, 0xf6, + 0xf8, 0x1e, 0x70, 0xe8, 0x78, 0x1e, 0x1e, 0x07, 0xc0, 0x47, 0xc5, 0x1a, 0xe8, 0xf4, 0x15, 0x45, + 0x86, 0x62, 0x7e, 0x65, 0x72, 0x08, 0xf6, 0x3c, 0x00, 0x00, 0x11, 0xb5, 0xe6, 0xc1, 0x00, 0x51, + 0x31, 0x12, 0xd9, 0x99, 0xfb, 0x0a, 0x15, 0x55, 0x1a, 0x94, 0xb5, 0x00, 0x76, 0xe2, 0x1a, 0xcf, + 0xe5, 0x93, 0xfc, 0xe1, 0x09, 0xcf, 0x27, 0xca, 0xd2, 0x88, 0xf5, 0x05, 0xa0, 0xb5, 0x9a, 0x72, + 0xf3, 0xcc, 0x46, 0xdd, 0x6e, 0xd2, 0xd6, 0x21, 0x3a, 0xb0, 0xa4, 0x22, 0x0c, 0xfc, 0xee, 0xc0, + 0x06, 0xba, 0x1c, 0xe5, 0x9f, 0x15, 0xac, 0x63, 0xa5, 0x14, 0xa5, 0x62, 0x4a, 0xbf, 0x0b, 0x74, + 0xde, 0x60, 0x22, 0x2b, 0xb7, 0x1b, 0x70, 0x45, 0xb8, 0xa8, 0x9d, 0xb0, 0x76, 0xf4, 0x51, 0x2c, + 0xc5, 0x2e, 0xeb, 0x1b, 0x76, 0x44, 0x3b, 0x63, 0x2f, 0x69, 0xa5, 0x20, 0x3b, 0x87, 0x8e, 0x78, + 0x7c, 0x3c, 0x1e, 0x86, 0xb8, 0xe6, 0x98, 0x5d, 0x66, 0x62, 0x7e, 0x65, 0x72, 0x08, 0xf6, 0x3c, + 0x0a, 0xff, 0xf1, 0x47, 0xd8, 0x22, 0x24, 0x56, 0xcc, 0x72, 0xf5, 0x72, 0x9c, 0xd8, 0x45, 0xb2, + 0x33, 0x94, 0xc7, 0xba, 0x3c, 0xb2, 0x1d, 0x7b, 0xf6, 0x6c, 0xc3, 0x5b, 0xe3, 0xeb, 0x71, 0xc8, + 0x62, 0xa5, 0xe9, 0x65, 0xd9, 0x67, 0x96, 0x6b, 0xd3, 0x77, 0xbf, 0xb0, 0x69, 0xce, 0xf3, 0xb2, + 0x95, 0xfc, 0x9d, 0xf5, 0xc1, 0x94, 0x33, 0xd7, 0x83, 0x10, 0x17, 0xbb, 0xb8, 0x58, 0x78, 0x0e, + 0x9f, 0xd0, 0xa8, 0xaf, 0x06, 0xfb, 0xb7, 0x4f, 0xad, 0x46, 0x84, 0x45, 0x11, 0xf0, 0x07, 0xe7, + 0xee, 0x1e, 0x3a, 0x7b, 0xe5, 0x53, 0xcf, 0x81, 0xd2, 0x55, 0x55, 0xfb, 0xf2, 0x72, 0x47, 0x04, + 0xc6, 0xfb, 0x38, 0xf1, 0xe0, 0x39, 0x3c, 0x0f, 0x8f, 0xc5, 0x18, 0x69, 0x17, 0x18, 0x51, 0x84, + 0x86, 0x62, 0x7e, 0x65, 0x72, 0x08, 0xe6, 0x3c, 0x00, 0x00, 0x4e, 0x9e, 0xb3, 0x62, 0xa1, 0x80, + 0x3c, 0xee, 0x6e, 0xcf, 0x55, 0xf6, 0xa5, 0xc3, 0x08, 0x2e, 0x79, 0xd4, 0xc2, 0x36, 0x30, 0x02, + 0xe4, 0xd9, 0x0e, 0x73, 0xd6, 0x03, 0x44, 0x6b, 0x47, 0x7c, 0x0c, 0xac, 0x1a, 0xa0, 0xe6, 0xf8, + 0xf7, 0x2e, 0xc9, 0x30, 0xa4, 0xe2, 0x16, 0x07, 0x6f, 0x02, 0x83, 0x3f, 0xba, 0x00, 0x96, 0xe4, + 0x5a, 0xca, 0x2e, 0xde, 0x08, 0xee, 0x91, 0xcd, 0x96, 0x84, 0x6f, 0xd0, 0xb9, 0xf7, 0x7b, 0x9d, + 0xa6, 0x07, 0x18, 0x93, 0x43, 0x80, 0x02, 0x30, 0xd9, 0x23, 0x47, 0xc8, 0x18, 0x3d, 0xb6, 0x1c, + 0x69, 0x9b, 0x04, 0x58, 0xe0, 0x7b, 0xd4, 0x33, 0xc6, 0x36, 0x3c, 0x11, 0xd0, 0x37, 0x0d, 0x82, + 0xe3, 0xcd, 0x62, 0xb6, 0x42, 0x8c, 0x5d, 0x3c, 0x86, 0x62, 0x7e, 0x65, 0x72, 0x08, 0xd6, 0x3c, + 0x00, 0x06, 0xa8, 0xec, 0x30, 0xf8, 0x02, 0xa1, 0x07, 0xfa, 0x5b, 0x5c, 0x8c, 0xc3, 0x42, 0x0c, + 0xe1, 0x29, 0xa5, 0x53, 0x1e, 0x51, 0x10, 0x26, 0x71, 0x87, 0x44, 0xaf, 0xee, 0x39, 0xaf, 0x5f, + 0x3f, 0xdd, 0x78, 0xec, 0xc0, 0x1c, 0xad, 0xf2, 0xb9, 0x85, 0x42, 0x67, 0x5d, 0x89, 0x9a, 0x09, + 0x80, 0x84, 0xb0, 0x18, 0xd6, 0x31, 0x00, 0x32, 0x0b, 0x3d, 0x09, 0x81, 0x4c, 0x0e, 0xcf, 0x17, + 0x6f, 0xaa, 0x1b, 0x05, 0x81, 0x33, 0xa8, 0x98, 0x2f, 0x59, 0xbc, 0xf7, 0x3b, 0x6f, 0x65, 0x0f, + 0x88, 0x3f, 0xeb, 0x50, 0x44, 0xc0, 0x9c, 0xe7, 0xa5, 0xf0, 0x80, 0xa0, 0x8e, 0x27, 0xe1, 0xb7, + 0xd1, 0x1e, 0xf0, 0x6e, 0x83, 0xf0, 0xdf, 0xbe, 0x1d, 0x1c, 0xf2, 0xdc, 0x10, 0x2e, 0xb1, 0x6e, + 0x86, 0x62, 0x7e, 0x65, 0x72, 0x08, 0xd6, 0x3c, 0x00, 0xc3, 0x46, 0xcc, 0xea, 0x31, 0xbc, 0xda, + 0x50, 0xd5, 0xd8, 0x31, 0xdb, 0xd6, 0xfa, 0x60, 0x5b, 0xf3, 0x68, 0x9c, 0xd3, 0x1c, 0x21, 0x39, + 0x8d, 0x20, 0x7e, 0x2b, 0x5e, 0xbb, 0x55, 0x62, 0x37, 0x9d, 0xbc, 0x96, 0xd7, 0x08, 0x18, 0x69, + 0x94, 0x6c, 0x3b, 0xed, 0x7a, 0xb9, 0xe4, 0xb4, 0x31, 0x38, 0x6b, 0x80, 0x00, 0x32, 0x83, 0x71, + 0x2e, 0x4c, 0xc4, 0xa8, 0x50, 0xf0, 0xce, 0xe8, 0xc6, 0xcc, 0x22, 0x79, 0x6b, 0x89, 0xed, 0x9a, + 0x3d, 0x81, 0x9e, 0x42, 0x0f, 0x88, 0x28, 0x35, 0xcb, 0x2c, 0x24, 0xf8, 0x09, 0x28, 0x1a, 0x43, + 0x8b, 0x4f, 0xb3, 0x90, 0x55, 0x1f, 0x16, 0x22, 0xf0, 0x09, 0xcc, 0x3d, 0xa7, 0x0e, 0xca, 0x71, + 0xe9, 0x0a, 0x27, 0x0e, 0x72, 0x79, 0x8b, 0x76, 0x86, 0x62, 0x7e, 0x65, 0x72, 0x08, 0xd6, 0x3c, + 0x00, 0x07, 0x5f, 0xc8, 0xe3, 0xa6, 0xd0, 0x3b, 0x8e, 0x82, 0x7a, 0xd8, 0x1a, 0x9f, 0x9f, 0x8a, + 0x9c, 0x91, 0x57, 0x5c, 0x78, 0x55, 0x30, 0x77, 0x38, 0xe1, 0x3a, 0x34, 0x48, 0x9b, 0x71, 0xdf, + 0x4f, 0xcf, 0x6b, 0x8a, 0xbe, 0xd6, 0x3e, 0x4c, 0x70, 0xc5, 0x75, 0x1c, 0x66, 0x3a, 0xa7, 0x49, + 0x24, 0x92, 0xb3, 0x00, 0x12, 0xda, 0xab, 0x09, 0x82, 0x4d, 0x33, 0x74, 0x8c, 0xe7, 0x7c, 0x3e, + 0x90, 0xf2, 0x88, 0x96, 0xa9, 0xeb, 0x40, 0x7a, 0x77, 0x28, 0xad, 0x6c, 0xf5, 0xb8, 0x80, 0x34, + 0x5f, 0x81, 0x47, 0xa2, 0x42, 0xc8, 0x70, 0xf4, 0x7f, 0x85, 0xd5, 0x93, 0x45, 0x1f, 0x47, 0x19, + 0xc4, 0xc8, 0x00, 0x71, 0x13, 0xec, 0xb2, 0xe2, 0x60, 0x70, 0xce, 0xb4, 0x41, 0xb5, 0x92, 0xe1, + 0x86, 0x62, 0x7e, 0x65, 0x72, 0x08, 0xe6, 0x3c, 0x00, 0x00, 0x84, 0xbd, 0x00, 0xfc, 0x0a, 0xf7, + 0xb4, 0x15, 0x10, 0xe4, 0xe0, 0xad, 0x2d, 0x1f, 0x1c, 0x7c, 0x1f, 0xeb, 0xa9, 0x43, 0x10, 0x58, + 0x41, 0x1e, 0x99, 0x52, 0x0d, 0x41, 0xf3, 0x1d, 0xec, 0x63, 0xc2, 0xcc, 0xe2, 0x8b, 0xc1, 0x09, + 0xc6, 0x3f, 0xd8, 0xbf, 0x3e, 0x08, 0x5e, 0x2e, 0x7a, 0x5a, 0x23, 0xe3, 0xb7, 0x53, 0x1c, 0x9e, + 0x27, 0xe5, 0x3d, 0x04, 0x5a, 0xdc, 0xa3, 0xc5, 0x94, 0x6b, 0xcb, 0x09, 0x1e, 0x71, 0x29, 0x47, + 0xd3, 0xbe, 0x4f, 0x08, 0xbe, 0x07, 0xf5, 0xbf, 0x98, 0xa7, 0xbc, 0xc5, 0x25, 0x51, 0xb7, 0x24, + 0x29, 0x21, 0x45, 0x41, 0x11, 0x0d, 0x40, 0x0f, 0x87, 0x78, 0xf4, 0xfc, 0x9f, 0x03, 0xc0, 0x25, + 0xd6, 0xb3, 0xe6, 0x8e, 0x2b, 0xcd, 0xc5, 0x59, 0x86, 0x62, 0x7e, 0x65, 0x72, 0x08, 0xd6, 0x3c, + 0x00, 0x01, 0x96, 0x93, 0x10, 0xac, 0x08, 0xb7, 0x3e, 0xc4, 0x99, 0x57, 0x08, 0x27, 0x1c, 0x8c, + 0x85, 0x3b, 0xb2, 0x7a, 0x65, 0x12, 0x36, 0x02, 0x13, 0x5a, 0x4b, 0x74, 0x08, 0xd4, 0x2f, 0xcb, + 0xe7, 0x6d, 0x1f, 0xe0, 0xa7, 0x35, 0x71, 0x09, 0x4b, 0x1e, 0xe5, 0x46, 0xc4, 0xd1, 0x23, 0x69, + 0xa8, 0x36, 0xa6, 0xaa, 0x17, 0x9d, 0x00, 0x03, 0xc5, 0x6e, 0xc2, 0x22, 0x2c, 0x97, 0xbe, 0x22, + 0xa2, 0x28, 0xb7, 0xfe, 0xd3, 0xdb, 0x97, 0x85, 0x75, 0x8f, 0x11, 0x55, 0xef, 0x2c, 0xa9, 0xd1, + 0xbe, 0x97, 0x3d, 0x3b, 0x27, 0x66, 0xcc, 0xb7, 0x2e, 0x2f, 0xe8, 0x13, 0x87, 0x02, 0x60, 0xfd, + 0x39, 0x3c, 0x9b, 0x9f, 0xd1, 0xd8, 0xde, 0x51, 0x7e, 0xb8, 0xc6, 0x15, 0xc2, 0xf3, 0x49, 0xce, + 0x86, 0x62, 0x7e, 0x65, 0x72, 0x08, 0xb6, 0x3c, 0x00, 0xc0, 0xea, 0xe4, 0x95, 0x80, 0x8d, 0x68, + 0xa0, 0x21, 0xd3, 0xb5, 0xc1, 0xda, 0x11, 0x65, 0x6e, 0xb6, 0xe1, 0xbf, 0x2d, 0xb8, 0x05, 0x78, + 0x44, 0x1f, 0xcf, 0x65, 0xce, 0x0f, 0x1e, 0x00, 0x61, 0x6d, 0xa4, 0x8f, 0x06, 0x03, 0xfb, 0x8d, + 0x7d, 0x9a, 0xbc, 0xf1, 0xf4, 0x24, 0x49, 0xfb, 0x12, 0x82, 0x12, 0xae, 0x1f, 0x5f, 0x00, 0xe8, + 0x79, 0x1a, 0xc1, 0x95, 0x79, 0x91, 0xec, 0x22, 0x15, 0xea, 0x8e, 0xb8, 0x41, 0x8e, 0xd2, 0xd4, + 0xac, 0x90, 0x3a, 0xfe, 0xad, 0xc8, 0x1e, 0x7f, 0x54, 0x7f, 0x5c, 0xe6, 0x78, 0xef, 0xdd, 0xe6, + 0x7d, 0x53, 0x46, 0x8b, 0x8b, 0xf4, 0x38, 0xce, 0x13, 0xd3, 0x78, 0xf0, 0x3c, 0x3f, 0x81, 0xb2, + 0x70, 0x98, 0x73, 0x85, 0xab, 0xf3, 0xc0, 0x41, 0x86, 0x62, 0x7e, 0x65, 0x72, 0x08, 0xe6, 0x3c, + 0x04, 0x80, 0xaa, 0x12, 0x97, 0xdc, 0xaa, 0x03, 0xa0, 0x77, 0xb1, 0x92, 0x08, 0x81, 0x46, 0x0c, + 0x6a, 0xd0, 0x59, 0x2f, 0x45, 0x77, 0xcc, 0xea, 0x25, 0x2a, 0xe3, 0xc4, 0xef, 0x93, 0x94, 0x07, + 0x04, 0xa9, 0x83, 0xbf, 0x71, 0x40, 0xa0, 0x0e, 0xbf, 0x89, 0x20, 0xe4, 0x0c, 0x33, 0xd5, 0x46, + 0xce, 0xb3, 0x82, 0xe6, 0xf5, 0x70, 0x4e, 0x30, 0x84, 0xb0, 0xd5, 0x7f, 0x41, 0x7c, 0x37, 0x6a, + 0x6e, 0xab, 0xf3, 0x46, 0x8d, 0xa8, 0x50, 0x4e, 0x42, 0xb8, 0xaa, 0xa7, 0x51, 0x60, 0x73, 0x64, + 0x89, 0xd0, 0xac, 0x08, 0x59, 0x36, 0xce, 0x12, 0x3f, 0xb5, 0x5c, 0x1a, 0x63, 0xf5, 0xb6, 0x41, + 0x19, 0x98, 0xf8, 0x71, 0xe1, 0x9c, 0xe8, 0xf0, 0x71, 0x56, 0x0e, 0x24, 0x34, 0xbd, 0xdd, 0x24, + 0x86, 0x62, 0x7e, 0x65, 0x72, 0x08, 0xc6, 0x3c, 0x04, 0x80, 0x8a, 0xc7, 0x95, 0x58, 0x0d, 0x38, + 0xb6, 0xc4, 0xc1, 0xd1, 0x23, 0x9a, 0x65, 0x8e, 0x7a, 0xd0, 0xcc, 0xdf, 0x30, 0xd4, 0x93, 0xd5, + 0x99, 0xf4, 0xa3, 0x34, 0xd7, 0xae, 0x5c, 0xb9, 0x4e, 0xf5, 0x3d, 0x85, 0x58, 0xff, 0x24, 0x04, + 0xba, 0xd7, 0x3e, 0xf8, 0xba, 0x43, 0x83, 0x08, 0x4d, 0xaa, 0x8d, 0x8a, 0x95, 0x0b, 0x1c, 0x00, + 0x00, 0x24, 0x0e, 0xfe, 0x14, 0xa3, 0xd9, 0x89, 0x57, 0x8c, 0xa6, 0x0a, 0x5a, 0x93, 0xaa, 0x9f, + 0xc0, 0xf7, 0x0f, 0x2e, 0xfa, 0xb1, 0xff, 0x22, 0x93, 0x32, 0xce, 0x42, 0x13, 0x17, 0x06, 0x0f, + 0xd1, 0xa0, 0xdb, 0xcb, 0x87, 0xe0, 0xe0, 0x84, 0x81, 0xc2, 0xc3, 0xe1, 0xe0, 0xf0, 0x3e, 0x7b, + 0x83, 0x9a, 0xb8, 0xf2, 0x76, 0x2f, 0x0c, 0x52, 0xa6, 0x62, 0x7e, 0x65, 0x72, 0x08, 0xc6, 0x3c, + 0x0d, 0xd9, 0x17, 0x1d, 0x9a, 0xd5, 0x20, 0xac, 0xd6, 0x8e, 0xd8, 0x3a, 0x75, 0x82, 0x41, 0x18, + 0x7d, 0xa2, 0x7d, 0x11, 0xd0, 0x21, 0x95, 0xe5, 0x11, 0x3a, 0x54, 0xb2, 0xda, 0x82, 0x94, 0xe1, + 0x2b, 0xb7, 0x6a, 0xca, 0xed, 0x38, 0x57, 0x99, 0x72, 0x64, 0x07, 0x03, 0x34, 0xb1, 0x34, 0x8b, + 0x0a, 0xe1, 0xce, 0xa2, 0x38, 0x53, 0xfe, 0x0c, 0x37, 0x99, 0x2e, 0x27, 0xa1, 0xc5, 0x3c, 0x04, + 0x28, 0xf1, 0xaa, 0x54, 0x63, 0x4b, 0x82, 0x25, 0x19, 0xab, 0xa0, 0x5d, 0x32, 0x65, 0x56, 0x64, + 0xc7, 0x3b, 0x65, 0x53, 0x33, 0x35, 0x55, 0x52, 0xaa, 0xaa, 0xa6, 0x66, 0xaa, 0xaa, 0xa6, 0x66, + 0x65, 0x55, 0x54, 0xcc, 0xcc, 0xcc, 0xca, 0xaa, 0x99, 0x99, 0x99, 0x99, 0x95, 0x56, 0x66, 0x66, + 0x45, 0xcf, 0xee, 0x5c, 0xf2, 0x0b, 0xa6, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x93, 0xe5, 0x28, 0x34, 0x00, 0x00, 0x04, +}; diff --git a/apps/auracast/src/main.c b/apps/auracast/src/main.c new file mode 100644 index 0000000000..bee05e8920 --- /dev/null +++ b/apps/auracast/src/main.c @@ -0,0 +1,385 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "console/console.h" +#include "config/config.h" + +#include "nimble/ble.h" +#include "host/ble_hs.h" +#include "host/util/util.h" + +#include "services/auracast/ble_svc_auracast.h" + +#include "hal/hal_gpio.h" +#include "bsp/bsp.h" +#include "app_priv.h" + +#define BROADCAST_SID 1 + +#if (MYNEWT_VAL(LC3_SAMPLING_FREQ) == 8000) +#define BROADCAST_SAMPLE_RATE BLE_AUDIO_SAMPLING_RATE_8000_HZ +#elif (MYNEWT_VAL(LC3_SAMPLING_FREQ) == 16000) +#define BROADCAST_SAMPLE_RATE BLE_AUDIO_SAMPLING_RATE_16000_HZ +#elif (MYNEWT_VAL(LC3_SAMPLING_FREQ) == 24000) +#define BROADCAST_SAMPLE_RATE BLE_AUDIO_SAMPLING_RATE_24000_HZ +#elif (MYNEWT_VAL(LC3_SAMPLING_FREQ) == 32000) +#define BROADCAST_SAMPLE_RATE BLE_AUDIO_SAMPLING_RATE_32000_HZ +#elif (MYNEWT_VAL(LC3_SAMPLING_FREQ) == 48000) +#define BROADCAST_SAMPLE_RATE BLE_AUDIO_SAMPLING_RATE_48000_HZ +#else +BUILD_ASSERT(0, "Sample frequency not supported"); +#endif + +/* Note: values need to be adjusted if sampling frequency is 44100 (currently + * not supported by app) or SDU interval is different from LC3 frame + * length + */ +#define OCTETS_PER_CODEC_FRAME (MYNEWT_VAL(LC3_BITRATE) / \ + 8 * MYNEWT_VAL(LC3_FRAME_DURATION) / \ + 1000000) +#define BIG_SDU_INTERVAL (MYNEWT_VAL(LC3_FRAME_DURATION)) +#define BIG_MAX_SDU (OCTETS_PER_CODEC_FRAME * \ + MYNEWT_VAL(AURACAST_CHAN_NUM) / \ + MYNEWT_VAL(BIG_NUM_BIS)) + +#define BROADCASTER_INTERRUPT_TASK_PRIO 4 +#define BROADCASTER_INTERRUPT_TASK_STACK_SZ 512 + +static uint8_t id_addr_type; + +static struct ble_audio_base auracast_base; +static struct ble_audio_big_subgroup big_subgroup; + +static os_membuf_t bis_mem[ + OS_MEMPOOL_SIZE(MYNEWT_VAL(BIG_NUM_BIS), + sizeof(struct ble_audio_bis)) +]; +static struct os_mempool bis_pool; + +static os_membuf_t codec_spec_mem[ + OS_MEMPOOL_SIZE(MYNEWT_VAL(BIG_NUM_BIS) * 2, 19) +]; +static struct os_mempool codec_spec_pool; + +static uint8_t auracast_adv_instance; + +static void +auracast_init(void) +{ + int rc; + + assert(MYNEWT_VAL(AURACAST_CHAN_NUM) > 0); + + rc = os_mempool_init(&bis_pool, MYNEWT_VAL(BIG_NUM_BIS), + sizeof(struct ble_audio_bis), bis_mem, + "bis_pool"); + assert(rc == 0); + + rc = os_mempool_init(&codec_spec_pool, + MYNEWT_VAL(BIG_NUM_BIS) * 2, 19, + codec_spec_mem, "codec_spec_pool"); + assert(rc == 0); +} + +static int +base_create(void) +{ +#if MYNEWT_VAL(BIG_NUM_BIS) > 1 + struct ble_audio_bis *bis_left; + struct ble_audio_bis *bis_right; + uint8_t codec_spec_config_left_chan[] = + BLE_AUDIO_BUILD_CODEC_CONFIG(BROADCAST_SAMPLE_RATE, + MYNEWT_VAL(LC3_FRAME_DURATION) == 10000 ? + BLE_AUDIO_SELECTED_FRAME_DURATION_10_MS : + BLE_AUDIO_SELECTED_FRAME_DURATION_7_5_MS, + BLE_AUDIO_LOCATION_FRONT_LEFT, + OCTETS_PER_CODEC_FRAME, ); + uint8_t codec_spec_config_right_chan[] = + BLE_AUDIO_BUILD_CODEC_CONFIG(BROADCAST_SAMPLE_RATE, + MYNEWT_VAL(LC3_FRAME_DURATION) == 10000 ? + BLE_AUDIO_SELECTED_FRAME_DURATION_10_MS : + BLE_AUDIO_SELECTED_FRAME_DURATION_7_5_MS, + BLE_AUDIO_LOCATION_FRONT_RIGHT, + OCTETS_PER_CODEC_FRAME, ); +#else + uint16_t chan_loc = BLE_AUDIO_LOCATION_FRONT_LEFT | + BLE_AUDIO_LOCATION_FRONT_RIGHT; + uint8_t codec_spec_config[] = + BLE_AUDIO_BUILD_CODEC_CONFIG(BROADCAST_SAMPLE_RATE, + MYNEWT_VAL(LC3_FRAME_DURATION) == 10000 ? + BLE_AUDIO_SELECTED_FRAME_DURATION_10_MS : + BLE_AUDIO_SELECTED_FRAME_DURATION_7_5_MS, + chan_loc, + OCTETS_PER_CODEC_FRAME, ); + + struct ble_audio_bis *bis; +#endif + if (MYNEWT_VAL(BROADCAST_ID) != 0) { + auracast_base.broadcast_id = MYNEWT_VAL(BROADCAST_ID); + } else { + ble_hs_hci_rand(&auracast_base.broadcast_id, 3); + } + auracast_base.presentation_delay = 20000; + + big_subgroup.bis_cnt = MYNEWT_VAL(BIG_NUM_BIS); + + /** LC3 */ + big_subgroup.codec_id.format = 0x06; + + big_subgroup.codec_spec_config_len = 0; +#if MYNEWT_VAL(BIG_NUM_BIS) > 1 + bis_left = os_memblock_get(&bis_pool); + if (!bis_left) { + return BLE_HS_ENOMEM; + } + + bis_left->codec_spec_config = os_memblock_get(&codec_spec_pool); + memcpy(bis_left->codec_spec_config, + codec_spec_config_left_chan, + sizeof(codec_spec_config_left_chan)); + bis_left->codec_spec_config_len = sizeof(codec_spec_config_left_chan); + bis_left->idx = 1; + + bis_right = os_memblock_get(&bis_pool); + if (!bis_right) { + return BLE_HS_ENOMEM; + } + + bis_right->codec_spec_config = os_memblock_get(&codec_spec_pool); + memcpy(bis_right->codec_spec_config, + codec_spec_config_right_chan, + sizeof(codec_spec_config_right_chan)); + bis_right->codec_spec_config_len = sizeof(codec_spec_config_right_chan); + bis_right->idx = 2; + + STAILQ_INSERT_HEAD(&big_subgroup.bises, bis_left, next); + STAILQ_INSERT_TAIL(&big_subgroup.bises, bis_right, next); +#else + bis = os_memblock_get(&bis_pool); + if (!bis) { + return BLE_HS_ENOMEM; + } + + bis->codec_spec_config = os_memblock_get(&codec_spec_pool); + memcpy(bis->codec_spec_config, + codec_spec_config, + sizeof(codec_spec_config)); + bis->codec_spec_config_len = sizeof(codec_spec_config); + STAILQ_INSERT_HEAD(&big_subgroup.bises, bis, next); +#endif + + STAILQ_INSERT_HEAD(&auracast_base.subs, &big_subgroup, next); + auracast_base.num_subgroups++; + return 0; +} + +static int +auracast_destroy_fn(struct ble_audio_base *base, void *args) +{ + struct ble_audio_bis *bis; + int i; + + STAILQ_FOREACH(bis, &big_subgroup.bises, next) { + os_memblock_put(&codec_spec_pool, bis->codec_spec_config); + os_memblock_put(&bis_pool, bis); + } + + memset(&big_subgroup, 0, sizeof(big_subgroup)); + + for (i = 0; i < MYNEWT_VAL(AURACAST_CHAN_NUM); i++) { + audio_chan_set_conn_handle(i, BLE_HS_CONN_HANDLE_NONE); + } + + return 0; +} + +static int +iso_event(struct ble_iso_event *event, void *arg) +{ + int i; + + switch (event->type) { + case BLE_ISO_EVENT_BIG_CREATE_COMPLETE: + console_printf("BIG created\n"); + if (event->big_created.desc.num_bis > + MYNEWT_VAL(AURACAST_CHAN_NUM)) { + return BLE_HS_EINVAL; + } + if (MYNEWT_VAL(AURACAST_CHAN_NUM) == event->big_created.desc.num_bis) { + for (i = 0; i < MYNEWT_VAL(AURACAST_CHAN_NUM); i++) { + audio_chan_set_conn_handle(i, event->big_created.desc.conn_handle[i]); + } + } else { + for (i = 0; i < MYNEWT_VAL(AURACAST_CHAN_NUM); i++) { + audio_chan_set_conn_handle(i, event->big_created.desc.conn_handle[0]); + } + } + return 0; + case BLE_ISO_EVENT_BIG_TERMINATE_COMPLETE: + console_printf("BIG terminated\n"); + return 0; + default: + return BLE_HS_ENOTSUP; + } +} + +static int +auracast_create(void) +{ + const char *program_info = "NimBLE Auracast Test"; + static struct ble_iso_big_params big_params = { + .sdu_interval = BIG_SDU_INTERVAL, + .max_sdu = BIG_MAX_SDU, + .max_transport_latency = MYNEWT_VAL(LC3_FRAME_DURATION) / 1000, + .rtn = MYNEWT_VAL(BIG_RTN), + .phy = MYNEWT_VAL(BIG_PHY), + .packing = MYNEWT_VAL(BIG_PACKING), + .framing = MYNEWT_VAL(BIG_FRAMING), + .encryption = MYNEWT_VAL(BIG_ENCRYPTION), + .broadcast_code = MYNEWT_VAL(BROADCAST_CODE), + }; + + struct ble_svc_auracast_create_params create_params = { + .base = &auracast_base, + .big_params = &big_params, + .name = MYNEWT_VAL(BROADCAST_NAME), + .program_info = program_info, + .own_addr_type = id_addr_type, + .secondary_phy = BLE_HCI_LE_PHY_2M, + .sid = BROADCAST_SID, + .frame_duration = MYNEWT_VAL(LC3_FRAME_DURATION), + .sampling_frequency = MYNEWT_VAL(LC3_SAMPLING_FREQ), + .bitrate = MYNEWT_VAL(LC3_BITRATE), + }; + + return ble_svc_auracast_create(&create_params, + &auracast_adv_instance, + auracast_destroy_fn, + NULL, + NULL); +} + +static int +auracast_start(void) +{ + return ble_svc_auracast_start(auracast_adv_instance, iso_event, NULL); +} + +static void +on_sync(void) +{ + int rc; + + console_printf("Bluetooth initialized\n"); + + /* Make sure we have proper identity address set (public preferred) */ + rc = ble_hs_util_ensure_addr(0); + assert(rc == 0); + + /* configure global address */ + rc = ble_hs_id_infer_auto(0, &id_addr_type); + assert(rc == 0); + + auracast_init(); + + rc = base_create(); + assert(rc == 0); + + rc = auracast_create(); + assert(rc == 0); + + rc = auracast_start(); + assert(rc == 0); +} + +#if MYNEWT_VAL(AURACAST_STOP_BUTTON) >= 0 +#include "hal/hal_gpio.h" +#include "bsp/bsp.h" + +#define AURACAST_INTERRUPT_TASK_PRIO 4 +#define AURACAST_INTERRUPT_TASK_STACK_SZ 512 + +static struct os_task auracast_interrupt_task_str; +static struct os_eventq auracast_interrupt_eventq; +static os_stack_t auracast_interrupt_task_stack[AURACAST_INTERRUPT_TASK_STACK_SZ]; +static void +auracast_interrupt_task(void *arg) +{ + while (1) { + os_eventq_run(&auracast_interrupt_eventq); + } +} + +static void +broadcast_stop_ev_cb(struct os_event *ev) +{ + ble_svc_auracast_stop(auracast_adv_instance); + ble_svc_auracast_terminate(auracast_adv_instance); +} + +static struct os_event broadcast_stop_ev = { + .ev_cb = broadcast_stop_ev_cb, +}; + +static void +auracast_gpio_irq(void *arg) +{ + os_eventq_put(&auracast_interrupt_eventq, &broadcast_stop_ev); +} +#endif /* MYNEWT_VAL(AURACAST_STOP_BUTTON) >= 0 */ + +/* + * main + * + * The main task for the project. This function initializes the packages, + * then starts serving events from default event queue. + * + * @return int NOTE: this function should never return! + */ +int +mynewt_main(int argc, char **argv) +{ + /* Initialize OS */ + sysinit(); + + console_printf("LE Audio Broadcast sample application\n"); + + /* Set sync callback */ + ble_hs_cfg.sync_cb = on_sync; + +#if MYNEWT_VAL(AURACAST_STOP_BUTTON) >= 0 + os_eventq_init(&auracast_interrupt_eventq); + os_task_init(&auracast_interrupt_task_str, "auracast_interrupt_task", + auracast_interrupt_task, NULL, + AURACAST_INTERRUPT_TASK_PRIO, OS_WAIT_FOREVER, + auracast_interrupt_task_stack, + AURACAST_INTERRUPT_TASK_STACK_SZ); + + hal_gpio_irq_init(MYNEWT_VAL(AURACAST_STOP_BUTTON), auracast_gpio_irq, + NULL, HAL_GPIO_TRIG_RISING, HAL_GPIO_PULL_UP); + hal_gpio_irq_enable(MYNEWT_VAL(AURACAST_STOP_BUTTON)); +#endif /* MYNEWT_VAL(AURACAST_STOP_BUTTON) >= 0 */ + + /* As the last thing, process events from default event queue */ + while (1) { + os_eventq_run(os_eventq_dflt_get()); + } + + return 0; +} diff --git a/apps/auracast/src/usb_desc.c b/apps/auracast/src/usb_desc.c new file mode 100644 index 0000000000..4738b47e9a --- /dev/null +++ b/apps/auracast/src/usb_desc.c @@ -0,0 +1,398 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include + +#if MYNEWT_VAL(AUDIO_USB) +#include +#include +#include +#include +#include +#include +#include +#include + +#define USBD_PRODUCT_RELEASE_NUMBER MYNEWT_VAL(USBD_PRODUCT_RELEASE_NUMBER) + +#ifndef CONFIG_NUM +#define CONFIG_NUM 1 +#endif + +typedef enum { + USB_STRING_DESCRIPTOR_LANG = 0, + USB_STRING_DESCRIPTOR_MANUFACTURER = 1, + USB_STRING_DESCRIPTOR_PRODUCT = 2, + USB_STRING_DESCRIPTOR_INTERFACE = 3, + USB_STRING_DESCRIPTOR_CDC = 4, + USB_STRING_DESCRIPTOR_SERIAL = 16, + USB_STRING_DESCRIPTOR_MICROSOFT_OS = 0xEE, +} usb_string_descriptor_ix_t; + +#define CDC_IF_STR_IX (MYNEWT_VAL(USBD_CDC_DESCRIPTOR_STRING) == NULL ? 0 : 4) + +const tusb_desc_device_t desc_device = { + .bLength = sizeof(tusb_desc_device_t), + .bDescriptorType = TUSB_DESC_DEVICE, + .bcdUSB = 0x0200, + + .bDeviceClass = 0x00, + .bDeviceSubClass = 0x00, + .bDeviceProtocol = 0x00, + + .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, + + .idVendor = MYNEWT_VAL(USBD_VID), + .idProduct = MYNEWT_VAL(USBD_PID), + .bcdDevice = USBD_PRODUCT_RELEASE_NUMBER, + + .iManufacturer = USB_STRING_DESCRIPTOR_MANUFACTURER, + .iProduct = USB_STRING_DESCRIPTOR_PRODUCT, + .iSerialNumber = USB_STRING_DESCRIPTOR_SERIAL, + + .bNumConfigurations = 0x01 +}; + +/* + * Invoked when received GET DEVICE DESCRIPTOR + * Application return pointer to descriptor + */ +const uint8_t * +tud_descriptor_device_cb(void) +{ + return (const uint8_t *)&desc_device; +} + +#if MYNEWT_VAL_CHOICE(MCU_TARGET, nRF5340_APP) || MYNEWT_VAL_CHOICE(MCU_TARGET, nRF52840) +#define ISO_EP 8 +#else +#error MCU not supported +#endif + +/* + * Configuration Descriptor + */ + +enum { +#if CFG_TUD_BTH + ITF_NUM_BTH, +#if CFG_TUD_BTH_ISO_ALT_COUNT > 0 + ITF_NUM_BTH_VOICE, +#endif +#endif + +#if CFG_TUD_CDC + ITF_NUM_CDC, + ITF_NUM_CDC_DATA, +#endif + +#if CFG_TUD_MSC + ITF_NUM_MSC, +#endif + +#if CFG_TUD_HID + ITF_NUM_HID, +#endif + +#if CFG_TUD_AUDIO_IN + ITF_NUM_AUDIO_AC, + ITF_NUM_AUDIO_AS_IN, +#elif CFG_TUD_AUDIO_OUT + ITF_NUM_AUDIO_AC, + ITF_NUM_AUDIO_AS_OUT, +#elif CFG_TUD_AUDIO_IN_OUT + ITF_NUM_AUDIO_AC, + ITF_NUM_AUDIO_AS_IN, + ITF_NUM_AUDIO_AS_OUT, +#endif + + ITF_NUM_TOTAL +}; + +#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + \ + CFG_TUD_CDC * TUD_CDC_DESC_LEN + \ + CFG_TUD_MSC * TUD_MSC_DESC_LEN + \ + CFG_TUD_HID * TUD_HID_DESC_LEN + \ + CFG_TUD_BTH * TUD_BTH_DESC_LEN + \ + CFG_TUD_AUDIO_IN * TUD_AUDIO_MIC_ONE_CH_DESC_LEN + \ + (1 + CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP) * CFG_TUD_AUDIO_OUT * \ + (TUD_AUDIO_SPEAKER_MONO_DESC_LEN * (CFG_TUD_AUDIO_N_CHANNELS_RX == 1 ? 1 : 0)) + \ + (1 - CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP) * CFG_TUD_AUDIO_OUT * \ + (TUD_AUDIO_SPEAKER_STEREO_DESC_LEN * (CFG_TUD_AUDIO_N_CHANNELS_RX == 2 ? 1 : 0)) + \ + 0) + +const uint8_t desc_configuration[] = { + TUD_CONFIG_DESCRIPTOR(CONFIG_NUM, ITF_NUM_TOTAL, 0, CONFIG_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, + MYNEWT_VAL(USBD_CONFIGURATION_MAX_POWER)), + +#if CFG_TUD_BTH + TUD_BTH_DESCRIPTOR(ITF_NUM_BTH, BTH_IF_STR_IX, USBD_BTH_EVENT_EP, USBD_BTH_EVENT_EP_SIZE, + USBD_BTH_EVENT_EP_INTERVAL, USBD_BTH_DATA_IN_EP, USBD_BTH_DATA_OUT_EP, USBD_BTH_DATA_EP_SIZE, + 0, 9, 17, 25, 33, 49), +#endif + + +#if CFG_TUD_CDC + TUD_CDC_DESCRIPTOR(ITF_NUM_CDC, CDC_IF_STR_IX, USBD_CDC_NOTIFY_EP, USBD_CDC_NOTIFY_EP_SIZE, + USBD_CDC_DATA_OUT_EP, USBD_CDC_DATA_IN_EP, USBD_CDC_DATA_EP_SIZE), +#endif + +#if CFG_TUD_MSC + /* TODO: MSC not handled yet */ + TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, MSC_IF_STR_IX, EPNUM_MSC_OUT, EPNUM_MSC_IN, + (CFG_TUSB_RHPORT0_MODE & OPT_MODE_HIGH_SPEED) ? 512 : 64), +#endif + +#if CFG_TUD_HID + TUD_HID_DESCRIPTOR(ITF_NUM_HID, HID_IF_STR_IX, HID_PROTOCOL_NONE, sizeof(desc_hid_report), + USBD_HID_REPORT_EP, USBD_HID_REPORT_EP_SIZE, USBD_HID_REPORT_EP_INTERVAL), +#endif + +#if CFG_TUD_AUDIO_IN_OUT +#elif CFG_TUD_AUDIO_IN + TUD_AUDIO_MIC2_DESCRIPTOR(ITF_NUM_AUDIO_AC_IN, 0, 2, 16, 0x80 | ISO_EP, 192), +#elif CFG_TUD_AUDIO_OUT && CFG_TUD_AUDIO_N_CHANNELS_RX == 2 +#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP == 1 + TUD_AUDIO_SPEAKER_STEREO_FB_DESCRIPTOR(ITF_NUM_AUDIO_AC, 0, CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX, + 8 * CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX, ISO_EP, CFG_TUD_AUDIO_EPSIZE_OUT, 0x80 | ISO_EP, 1), +#else + TUD_AUDIO_SPEAKER_STEREO_DESCRIPTOR(ITF_NUM_AUDIO_AC, 0, CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX, + 8 * CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX, ISO_EP, CFG_TUD_AUDIO_EPSIZE_OUT), +#endif +#elif CFG_TUD_AUDIO_OUT && CFG_TUD_AUDIO_N_CHANNELS_RX == 1 + #if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP + TUD_AUDIO_SPEAKER_MONO_FB_DESCRIPTOR(ITF_NUM_AUDIO_AC, 0, 2, 16, ISO_EP, 100, 0x80 | ISO_EP), +#else + TUD_AUDIO_SPEAKER_MONO_DESCRIPTOR(ITF_NUM_AUDIO_AC, 0, CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX, + 8 * CFG_TUD_AUDIO_N_BYTES_PER_SAMPLE_RX, ISO_EP, CFG_TUD_AUDIO_EPSIZE_OUT), +#endif +#endif +}; + +/** + * Invoked when received GET CONFIGURATION DESCRIPTOR + * Application return pointer to descriptor + * Descriptor contents must exist long enough for transfer to complete + */ +const uint8_t * +tud_descriptor_configuration_cb(uint8_t index) +{ + (void)index; + + return desc_configuration; +} + +static uint16_t desc_string[MYNEWT_VAL(USBD_STRING_DESCRIPTOR_MAX_LENGTH) + 1]; + +#if CFG_TUD_AUDIO + +#if CFG_TUD_AUDIO_IN +const uint16_t tud_audio_desc_lengths[] = {TUD_AUDIO_MIC2_DESC_LEN}; +#elif CFG_TUD_AUDIO_OUT && CFG_TUD_AUDIO_N_CHANNELS_RX == 1 +#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP +const uint16_t tud_audio_desc_lengths[] = {TUD_AUDIO_SPEAKER_MONO_FB_DESC_LEN}; +#else +const uint16_t tud_audio_desc_lengths[] = {TUD_AUDIO_SPEAKER_MONO_DESC_LEN}; +#endif +#elif CFG_TUD_AUDIO_OUT && CFG_TUD_AUDIO_N_CHANNELS_RX == 2 +#if CFG_TUD_AUDIO_ENABLE_FEEDBACK_EP +const uint16_t tud_audio_desc_lengths[] = {TUD_AUDIO_SPEAKER_STEREO_FB_DESC_LEN}; +#else +const uint16_t tud_audio_desc_lengths[] = {TUD_AUDIO_SPEAKER_STEREO_DESC_LEN}; +#endif +#endif + +static uint32_t g_sample_rate = CFG_TUD_AUDIO_SAMPLE_RATE; +static usb_audio_sample_rate_cb_t sample_rate_cb; + +/* Invoked when audio class specific set request received for an entity */ +bool +tud_audio_set_req_entity_cb(uint8_t rhport, tusb_control_request_t const * p_request, uint8_t *pBuff) +{ + uint32_t new_sample_rate; + + (void) rhport; + audio_control_request_t *request = (audio_control_request_t *) p_request; + + if (request->bEntityID == 2 && request->bControlSelector == AUDIO_FU_CTRL_VOLUME && + request->bRequest == AUDIO_CS_REQ_CUR) { + /* Ignore value but accept request */ + return true; + } else if (request->bEntityID == 4 && request->bControlSelector == AUDIO_CS_CTRL_SAM_FREQ && + request->bRequest == AUDIO_CS_REQ_CUR) { + /* Ignore value but accept request */ + new_sample_rate = ((audio_control_cur_4_t *)(pBuff))->bCur; + if (new_sample_rate != g_sample_rate) { + g_sample_rate = new_sample_rate; + if (sample_rate_cb) { + sample_rate_cb(g_sample_rate); + } + } + return true; + } else { + __BKPT(1); + } + return false; +} + +bool +tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const * p_request) +{ + (void) rhport; + audio_control_request_t *request = (audio_control_request_t *) p_request; + if (request->bEntityID == 4 && request->bControlSelector == AUDIO_CS_CTRL_SAM_FREQ) { + if (request->bRequest == AUDIO_CS_REQ_CUR) { + audio_control_cur_4_t curf = {g_sample_rate}; + return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &curf, sizeof(curf)); + } else if (request->bRequest == AUDIO_CS_REQ_RANGE) { +#if 1 + audio_control_range_4_n_t(1) rangef = { + .wNumSubRanges = 1, + .subrange[0] = {g_sample_rate, g_sample_rate, 0}, + }; +#else + audio_control_range_4_n_t(2) rangef = { + .wNumSubRanges = 2, + .subrange[0] = {16000, 16000, 0}, + .subrange[1] = {48000, 48000, 0}, + }; +#endif + return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &rangef, sizeof(rangef)); + } + } else if (request->bEntityID == 5 && request->bControlSelector == AUDIO_CX_CTRL_CONTROL) { + if (request->bRequest == AUDIO_CS_REQ_CUR) { + audio_control_cur_1_t cur_clk = {1}; + return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &cur_clk, sizeof(cur_clk)); + } + } else if (request->bEntityID == 4 && request->bControlSelector == AUDIO_CS_CTRL_CLK_VALID && + request->bRequest == AUDIO_CS_REQ_CUR) { + audio_control_cur_1_t cur_valid = {.bCur = 1}; + return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &cur_valid, sizeof(cur_valid)); + } else if (request->bEntityID == 2 && request->bControlSelector == AUDIO_FU_CTRL_MUTE && + request->bRequest == AUDIO_CS_REQ_CUR) { + audio_control_cur_1_t mute = {.bCur = 0}; + return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &mute, sizeof(mute)); + } else if (request->bEntityID == 2 && request->bControlSelector == AUDIO_FU_CTRL_VOLUME) { + if (request->bRequest == AUDIO_CS_REQ_RANGE) { + audio_control_range_2_n_t(1) range_vol = { + .wNumSubRanges = 1, + .subrange[0] = {0, 1000, 10} + }; + return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &range_vol, sizeof(range_vol)); + } else if (request->bRequest == AUDIO_CS_REQ_CUR) { + audio_control_cur_2_t cur_vol = {.bCur = 1280}; + return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &cur_vol, sizeof(cur_vol)); + } + } else { + __BKPT(1); + } + return false; +} + +#endif + +/* Function converts ASCII string to USB descriptor format */ +static uint16_t * +string_to_usb_desc_string(const char *str, uint16_t *desc, uint8_t desc_size) +{ + int i; + int char_num = strlen(str); + + assert(char_num < desc_size); + if (char_num >= desc_size) { + char_num = desc_size - 1; + } + + /* Encode length in first byte, type in second byte */ + desc[0] = tu_htole16(tu_u16(TUSB_DESC_STRING, 2 * (char_num + 1))); + + /* Copy characters 8bit to 16 bits */ + for (i = 0; i < char_num; ++i) { + desc[1 + i] = tu_htole16(str[i]); + } + + return desc; +} + +/* LANGID string descriptors */ +static const uint16_t usbd_lang_id[2] = { + (TUSB_DESC_STRING << 8) + 4, /* Size of this descriptor */ + tu_htole16(MYNEWT_VAL(USBD_LANGID)) +}; + +static struct { + uint16_t major; + uint16_t minor; + uint16_t revision; + uint32_t build; +} img_version = { + 1, 0, 0, 1 +}; + +static char serial_number[11]; + +static uint16_t * +serial_to_usb_desc_string(uint16_t *desc, size_t size) +{ + if (serial_number[0] == 0) { + uint64_t serial = MYNEWT_VAL(USBD_SERIAL_ID); + + snprintf(serial_number, 11, "%010" PRIu64, serial); + } + + return string_to_usb_desc_string(serial_number, desc, size); +} + +/* + * Invoked when received GET STRING DESCRIPTOR request + * Application return pointer to descriptor, whose contents must exist long enough for transfer to complete + */ +const uint16_t * +tud_descriptor_string_cb(uint8_t index, uint16_t langid) +{ + const uint16_t *ret = NULL; + char interface[100]; + +#if MYNEWT_VAL(USBD_WINDOWS_COMP_ID) + if (index == USB_STRING_DESCRIPTOR_MICROSOFT_OS) { + ret = (const uint16_t *)microsoft_os_string_descriptor; + } +#endif + if (index == USB_STRING_DESCRIPTOR_LANG) { + ret = usbd_lang_id; + } else if (index == USB_STRING_DESCRIPTOR_SERIAL) { + ret = serial_to_usb_desc_string(desc_string, ARRAY_SIZE(desc_string)); + } else if (index == USB_STRING_DESCRIPTOR_MANUFACTURER) { + ret = string_to_usb_desc_string(MYNEWT_VAL(USBD_VENDOR_STRING), desc_string, ARRAY_SIZE(desc_string)); + } else if (index == USB_STRING_DESCRIPTOR_PRODUCT) { + ret = string_to_usb_desc_string(MYNEWT_VAL(USBD_PRODUCT_STRING), desc_string, ARRAY_SIZE(desc_string)); + } else if (index == USB_STRING_DESCRIPTOR_INTERFACE) { + snprintf(interface, sizeof(interface), "%s, (%u.%u.%u.%lu)", MYNEWT_VAL(USBD_PRODUCT_STRING), + img_version.major, img_version.minor, img_version.revision, img_version.build); + ret = string_to_usb_desc_string(interface, desc_string, ARRAY_SIZE(desc_string)); + } + return ret; +} + +void +usb_desc_sample_rate_set(uint32_t sample_rate) +{ + g_sample_rate = sample_rate; +} +#endif /* AUDIO_USB */ diff --git a/apps/auracast/syscfg.usb.yml b/apps/auracast/syscfg.usb.yml new file mode 100644 index 0000000000..d9967b5128 --- /dev/null +++ b/apps/auracast/syscfg.usb.yml @@ -0,0 +1,174 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +syscfg.defs.TINYUSB: + USBD_STRING_DESCRIPTOR_MAX_LENGTH: + description: Maximum length of string descriptor in characters + value: 31 + USBD_EP0_SIZE: + description: > + Endpoint 0 size + value: 64 + USBD_SERIAL_ID: + description: Serial ID + value: 1 + restrictions: + - $notnull + USBD_VID: + description: Vendor ID + value: + restrictions: + - $notnull + USBD_PID: + description: Product ID + value: + restrictions: + - $notnull + USBD_PRODUCT_RELEASE_NUMBER: + description: Product release number needed for USB descriptor + value: 0x100 + USBD_CONFIGURATION_MAX_POWER: + description: > + Maximum power consumption of the USB device from the bus in this specific + configuration when the device is fully operational. Expressed in 2 mA units + (i.e., 50 = 100 mA). + value: 100 + USBD_LANGID: + description: Language ID as specified by usb.org + value: 0x0409 + USBD_VENDOR_STRING: + description: Manufacturer identification string + value: '"Apache Software Foundation"' + USBD_PRODUCT_STRING: + description: Device friendly name + value: '"NimBLE Auracast"' + USBD_CDC: + description: Enable CDC device + value: 0 + USBD_CDC_CONSOLE: + description: Enable CDC device function for console in TinyUSB stack. + value: + USBD_HID: + description: Enable HID device + value: 0 + USBD_MSC: + description: Enable MSC device + value: 0 + USBD_BTH: + description: Enable BT HCI device + value: 0 + USBD_AUDIO: + description: Enable Audio device + value: 0 + USBD_AUDIO_IN: + description: Enable Audio device + value: 0 + USBD_AUDIO_OUT: + description: Enable Audio device + value: 1 + USBD_AUDIO_IN_OUT: + description: Enable Audio device + value: 0 + USB_AUDIO_OUT_CHANNELS: + description: Number of audio channels on USB stream + value: MYNEWT_VAL(AURACAST_CHAN_NUM) + USB_AUDIO_OUT_SAMPLE_RATE: + description: USB sample rate + value: 48000 + + USBD_CDC_DATA_OUT_EP: + description: CDC data out endpoint number + value: + USBD_CDC_DATA_IN_EP: + description: CDC data out endpoint number + value: + USBD_CDC_DATA_EP_SIZE: + description: CDC data endpoint size + value: + USBD_CDC_NOTIFY_EP: + description: CDC notify endpoint number + value: + USBD_CDC_NOTIFY_EP_SIZE: + description: CDC notify endpoint size + value: + + USBD_CDC_DESCRIPTOR_STRING: + description: String for CDC interface + value: NULL + + USBD_MSC_DESCRIPTOR_STRING: + description: String for MSC interface + value: NULL + + USBD_HID_DESCRIPTOR_STRING: + description: String for HID interface + value: NULL + + USBD_BTH_DESCRIPTOR_STRING: + description: String for BT descriptor + value: NULL + + USBD_HID_REPORT_EP: + description: HID report endpoint number + value: + USBD_HID_REPORT_EP_SIZE: + description: HID report endpoint size + value: + USBD_HID_REPORT_EP_INTERVAL: + description: HID report endpoint interval + value: + + USBD_HID_REPORT_ID_KEYBOARD: + description: HID keyboard report ID + value: + USBD_HID_CAPS_LOCK_LED_PIN: + description: Caps Lock LED + value: -1 + USBD_HID_CAPS_LOCK_LED_ON_VALUE: + description: Value to set to pin to turn led on + value: 0 + USBD_HID_NUM_LOCK_LED_PIN: + description: Num Lock LED + value: -1 + USBD_HID_NUM_LOCK_LED_ON_VALUE: + description: Value to set to pin to turn led on + value: 0 + USBD_HID_REPORT_ID_MOUSE: + description: HID keyboard report ID + value: + + USBD_BTH_EVENT_EP: + description: BTH event endpoint number + value: + USBD_BTH_EVENT_EP_SIZE: + description: BTH event endpoint size + value: + USBD_BTH_EVENT_EP_INTERVAL: + description: BTH event endpoint interval + value: + USBD_BTH_DATA_IN_EP: + description: BTH data in endpoint number + value: + USBD_BTH_DATA_OUT_EP: + description: BTH data out endpoint number + value: + USBD_BTH_DATA_EP_SIZE: + description: BTH data endpoints size + value: + +syscfg.restrictions: + - '!USBD_STD_DESCRIPTORS' diff --git a/apps/auracast/syscfg.yml b/apps/auracast/syscfg.yml new file mode 100644 index 0000000000..e243f690e7 --- /dev/null +++ b/apps/auracast/syscfg.yml @@ -0,0 +1,149 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +syscfg.defs: + AUDIO_USB: + description: Enable USB audio output device driver. + value: 1 + restrictions: + # For now, LC3 encoded audio data, with 48kHz sample rate is supported only. + - '(LC3_SAMPLING_FREQ == 48000) if 0' + - '(LC3_FRAME_DURATION == 10000) is 0' + + ISO_HCI_FEEDBACK: + description: Enable HCI feedback for resampler. This reduces jitter between USB and ISO. + value: 0 + + AURACAST_CHAN_NUM: 2 + + AURACAST_STOP_BUTTON: + description: > + Button number for Auracast Stop action. + Negative value if disabled. + value: BUTTON_3 + + BROADCAST_ID: + description: Broadcast ID value, will use random number if 0 + value: 0x000000 + BROADCAST_NAME: + description: Broadcast name + value: '"NimBLE Auracast"' + BROADCAST_CODE: + description: Broadcast code used for encrpytion + value: '"listen2nimble"' + + LC3_FRAME_DURATION: + description: LC3 frame duration + value: 10000 + LC3_SAMPLING_FREQ: + description: LC3 sampling frequency + value: 48000 + LC3_BITRATE: + description: LC3 bitrate + value: 96000 + + BIG_PHY: + description: + value: 2 + BIG_NUM_BIS: + description: Max number of BISes used + value: 2 + BIG_RTN: + description: BIG RTN (number of retransmissions) + value: 0 + BIG_PACKING: + description: Arrangement of BIS subevents (0 = sequential, 1 = interleaved) + value: 0 + BIG_FRAMING: + description: + value: 0 + BIG_ENCRYPTION: + description: BIS encryption + value: 0 + +syscfg.vals: + CONSOLE_IMPLEMENTATION: full + LOG_IMPLEMENTATION: full + STATS_IMPLEMENTATION: full + + # Disable not used GAP roles (we only do non-connectable + # advertising here) + BLE_ROLE_BROADCASTER: 1 + BLE_ROLE_CENTRAL: 0 + BLE_ROLE_OBSERVER: 0 + BLE_ROLE_PERIPHERAL: 0 + + # Enable Extended Advertising + BLE_EXT_ADV: 1 + + # Enable Periodic Advertising + BLE_PERIODIC_ADV: 1 + + # Max advertising data size + BLE_EXT_ADV_MAX_SIZE: 261 + + # Number of multi-advertising instances. Note that due + # to historical reasonds total number of advertising + # instances is BLE_MULTI_ADV_INSTANCES + 1 as instance + # 0 is always available + BLE_MULTI_ADV_INSTANCES: 1 + + # Controller uses msys pool for storing advertising data and scan responses. + # Since we advertise a lot of data (~6k in total) at the same time we need + # to increase block count. + MSYS_1_BLOCK_COUNT: 32 + + BLE_PHY_2M: 1 + + BLE_VERSION: 54 + BLE_ISO: 1 + BLE_ISO_BROADCAST_SOURCE: 1 + BLE_ISO_MAX_BIGS: 1 + BLE_ISO_MAX_BISES: 2 + + BLE_AUDIO: 1 + + MCU_HFCLK_DIV: 1 + HARDFLOAT: 1 + +syscfg.vals.AUDIO_USB: + # TinyUSB + USBD_VID: 0xFFFF + USBD_PID: 0x0001 + USBD_VENDOR_STRING: '"Apache Software Foundation"' + USBD_PRODUCT_STRING: '"NimBLE Auracast"' + USBD_AUDIO_OUT: 1 + USBD_STACK_SIZE: 500 + USBD_STD_DESCRIPTORS: 0 + + USB_AUDIO_OUT_CHANNELS: MYNEWT_VAL(AURACAST_CHAN_NUM) + + # Resampler + LIBSAMPLERATE_ENABLE_SINC_BEST_CONVERTER: 0 + LIBSAMPLERATE_ENABLE_SINC_MEDIUM_CONVERTER: 0 + LIBSAMPLERATE_ENABLE_SINC_FAST_CONVERTER: 1 + LIBSAMPLERATE_LIBSAMPLER_NDEBUG: 1 + +syscfg.vals.ISO_HCI_FEEDBACK: + BLE_LL_ISO_HCI_FEEDBACK_INTERVAL_MS: 1000 + BLE_HS_GAP_UNHANDLED_HCI_EVENT: 1 + +syscfg.vals.BSP_NRF52: + BLE_PHY_NRF52_HEADERMASK_WORKAROUND: 1 + +$import: + - "@apache-mynewt-nimble/apps/auracast/syscfg.usb.yml" \ No newline at end of file diff --git a/apps/blecent/pkg.yml b/apps/blecent/pkg.yml index 12d539e6dd..7b06e62792 100644 --- a/apps/blecent/pkg.yml +++ b/apps/blecent/pkg.yml @@ -24,13 +24,12 @@ pkg.keywords: pkg.deps: - "@apache-mynewt-core/kernel/os" - - "@apache-mynewt-core/sys/console/full" - - "@apache-mynewt-core/sys/log/full" + - "@apache-mynewt-core/sys/console" + - "@apache-mynewt-core/sys/log" - "@apache-mynewt-core/sys/log/modlog" - - "@apache-mynewt-core/sys/stats/full" + - "@apache-mynewt-core/sys/stats" - nimble/host - nimble/host/util - nimble/host/services/gap - nimble/host/services/gatt - nimble/host/store/config - - nimble/transport diff --git a/apps/blecent/src/main.c b/apps/blecent/src/main.c index 788f21158e..57d5d10910 100644 --- a/apps/blecent/src/main.c +++ b/apps/blecent/src/main.c @@ -272,7 +272,7 @@ blecent_should_connect(const struct ble_gap_disc_desc *disc) rc = ble_hs_adv_parse_fields(&fields, disc->data, disc->length_data); if (rc != 0) { - return rc; + return 0; } /* The device has to advertise support for the Alert Notification @@ -496,7 +496,7 @@ blecent_on_sync(void) * @return int NOTE: this function should never return! */ int -main(void) +mynewt_main(int argc, char **argv) { int rc; diff --git a/apps/blecent/syscfg.yml b/apps/blecent/syscfg.yml index e186383968..30c0febb66 100644 --- a/apps/blecent/syscfg.yml +++ b/apps/blecent/syscfg.yml @@ -17,6 +17,10 @@ # syscfg.vals: + CONSOLE_IMPLEMENTATION: full + LOG_IMPLEMENTATION: full + STATS_IMPLEMENTATION: full + # DEBUG logging is a bit noisy; use INFO. LOG_LEVEL: 1 diff --git a/apps/blecsc/pkg.yml b/apps/blecsc/pkg.yml index 828ff301ee..3f862f3805 100644 --- a/apps/blecsc/pkg.yml +++ b/apps/blecsc/pkg.yml @@ -26,15 +26,13 @@ pkg.keywords: pkg.deps: - "@apache-mynewt-core/kernel/os" - - "@apache-mynewt-core/sys/console/full" - - "@apache-mynewt-core/sys/log/full" + - "@apache-mynewt-core/sys/console" + - "@apache-mynewt-core/sys/log" - "@apache-mynewt-core/sys/log/modlog" - - "@apache-mynewt-core/sys/stats/full" + - "@apache-mynewt-core/sys/stats" - "@apache-mynewt-core/sys/sysinit" - "@apache-mynewt-core/sys/id" - - nimble/controller - nimble/host - nimble/host/services/gap - nimble/host/services/gatt - nimble/host/store/config - - nimble/transport diff --git a/apps/blecsc/src/gatt_svr.c b/apps/blecsc/src/gatt_svr.c index e66aa9a8b0..0c178c0ca7 100644 --- a/apps/blecsc/src/gatt_svr.c +++ b/apps/blecsc/src/gatt_svr.c @@ -264,7 +264,7 @@ gatt_svr_chr_access_sc_control_point(uint16_t conn_handle, } #endif - rc = ble_gattc_indicate_custom(conn_handle, csc_control_point_handle, + rc = ble_gatts_indicate_custom(conn_handle, csc_control_point_handle, om_indication); return rc; @@ -321,7 +321,7 @@ gatt_svr_chr_notify_csc_measurement(uint16_t conn_handle) om = ble_hs_mbuf_from_flat(data_buf, data_offset); - rc = ble_gattc_notify_custom(conn_handle, csc_measurement_handle, om); + rc = ble_gatts_notify_custom(conn_handle, csc_measurement_handle, om); return rc; } diff --git a/apps/blecsc/src/main.c b/apps/blecsc/src/main.c index 60f0b3d8f7..993824084a 100644 --- a/apps/blecsc/src/main.c +++ b/apps/blecsc/src/main.c @@ -58,7 +58,7 @@ static struct os_callout blecsc_measure_timer; /* Variable holds current CSC measurement state */ static struct ble_csc_measurement_state csc_measurement_state; -/* Variable holds simulted speed (kilometers per hour) */ +/* Variable holds simulated speed (kilometers per hour) */ static uint16_t csc_sim_speed_kph = CSC_SIM_SPEED_KPH_MIN; /* Variable holds simulated cadence (RPM) */ @@ -278,7 +278,7 @@ blecsc_on_sync(void) * @return int NOTE: this function should never return! */ int -main(void) +mynewt_main(int argc, char **argv) { int rc; diff --git a/apps/blecsc/syscfg.yml b/apps/blecsc/syscfg.yml index ecf4b25f15..8234ae8ad8 100644 --- a/apps/blecsc/syscfg.yml +++ b/apps/blecsc/syscfg.yml @@ -17,6 +17,10 @@ syscfg.vals: + CONSOLE_IMPLEMENTATION: full + LOG_IMPLEMENTATION: full + STATS_IMPLEMENTATION: full + # Disable central and observer roles. BLE_ROLE_BROADCASTER: 1 BLE_ROLE_CENTRAL: 0 @@ -32,7 +36,7 @@ syscfg.vals: CONFIG_FCB: 1 # Set public device address. - BLE_PUBLIC_DEV_ADDR: ((uint8_t[6]){0xcc, 0xbb, 0xaa, 0x33, 0x22, 0x11}) + BLE_LL_PUBLIC_DEV_ADDR: 0x1122aabb33cc # Set device appearance to Cycling Speed and Cadence Sensor BLE_SVC_GAP_APPEARANCE: BLE_SVC_GAP_APPEARANCE_CYC_SPEED_AND_CADENCE_SENSOR diff --git a/apps/blehci/pkg.yml b/apps/blehci/pkg.yml index 06e6189468..915ae5b604 100644 --- a/apps/blehci/pkg.yml +++ b/apps/blehci/pkg.yml @@ -23,11 +23,10 @@ pkg.homepage: "http://mynewt.apache.org/" pkg.keywords: pkg.deps: - - "@apache-mynewt-core/sys/console/stub" - - "@apache-mynewt-core/sys/log/stub" - - "@apache-mynewt-core/sys/stats/full" + - "@apache-mynewt-core/sys/console" + - "@apache-mynewt-core/sys/log" + - "@apache-mynewt-core/sys/stats" - "@apache-mynewt-core/kernel/os" - - nimble/controller - nimble/transport pkg.req_apis: diff --git a/apps/blehci/src/main.c b/apps/blehci/src/main.c index 040c1572cb..848d705031 100644 --- a/apps/blehci/src/main.c +++ b/apps/blehci/src/main.c @@ -17,11 +17,10 @@ * under the License. */ -#include #include "os/mynewt.h" int -main(void) +mynewt_main(int argc, char **argv) { /* Initialize OS */ sysinit(); diff --git a/apps/blehci/syscfg.yml b/apps/blehci/syscfg.yml index 48a02005ac..3a8f53f75a 100644 --- a/apps/blehci/syscfg.yml +++ b/apps/blehci/syscfg.yml @@ -19,5 +19,11 @@ syscfg.vals: # Default task settings OS_MAIN_STACK_SIZE: 64 - # Use UART transport by default - BLE_HCI_TRANSPORT: uart + # Stub console + CONSOLE_IMPLEMENTATION: stub + LOG_IMPLEMENTATION: stub + STATS_IMPLEMENTATION: full + +syscfg.vals.'!BLE_TRANSPORT_NETCORE': + # Use UART by default if not built on netcore + BLE_TRANSPORT_HS: uart diff --git a/apps/blehr/pkg.yml b/apps/blehr/pkg.yml index b91ba3775b..43c84ce3e8 100644 --- a/apps/blehr/pkg.yml +++ b/apps/blehr/pkg.yml @@ -26,15 +26,13 @@ pkg.keywords: pkg.deps: - "@apache-mynewt-core/kernel/os" - - "@apache-mynewt-core/sys/console/full" - - "@apache-mynewt-core/sys/log/full" + - "@apache-mynewt-core/sys/console" + - "@apache-mynewt-core/sys/log" - "@apache-mynewt-core/sys/log/modlog" - - "@apache-mynewt-core/sys/stats/full" + - "@apache-mynewt-core/sys/stats" - "@apache-mynewt-core/sys/sysinit" - "@apache-mynewt-core/sys/id" - - nimble/controller - nimble/host - nimble/host/services/gap - nimble/host/services/gatt - nimble/host/store/config - - nimble/transport/ram diff --git a/apps/blehr/src/main.c b/apps/blehr/src/main.c index bf0f3f302c..dad16c7b2b 100644 --- a/apps/blehr/src/main.c +++ b/apps/blehr/src/main.c @@ -111,7 +111,7 @@ blehr_tx_hrate_stop(void) os_callout_stop(&blehr_tx_timer); } -/* Reset heartrate measurment */ +/* Reset heartrate measurement */ static void blehr_tx_hrate_reset(void) { @@ -146,7 +146,7 @@ blehr_tx_hrate(struct os_event *ev) om = ble_hs_mbuf_from_flat(hrm, sizeof(hrm)); - rc = ble_gattc_notify_custom(conn_handle, hrs_hrm_handle, om); + rc = ble_gatts_notify_custom(conn_handle, hrs_hrm_handle, om); assert(rc == 0); blehr_tx_hrate_reset(); @@ -193,9 +193,6 @@ blehr_gap_event(struct ble_gap_event *event, void *arg) if (event->subscribe.attr_handle == hrs_hrm_handle) { notify_state = event->subscribe.cur_notify; blehr_tx_hrate_reset(); - } else if (event->subscribe.attr_handle != hrs_hrm_handle) { - notify_state = event->subscribe.cur_notify; - blehr_tx_hrate_stop(); } break; @@ -232,7 +229,7 @@ blehr_on_sync(void) * @return int NOTE: this function should never return! */ int -main(void) +mynewt_main(int argc, char **argv) { int rc; diff --git a/apps/blehr/syscfg.yml b/apps/blehr/syscfg.yml index 5f047041e1..a34080ed90 100644 --- a/apps/blehr/syscfg.yml +++ b/apps/blehr/syscfg.yml @@ -17,6 +17,10 @@ syscfg.vals: + CONSOLE_IMPLEMENTATION: full + LOG_IMPLEMENTATION: full + STATS_IMPLEMENTATION: full + # Disable central and observer roles. BLE_ROLE_BROADCASTER: 1 BLE_ROLE_CENTRAL: 0 @@ -32,7 +36,7 @@ syscfg.vals: CONFIG_FCB: 1 # Set public device address. - BLE_PUBLIC_DEV_ADDR: ((uint8_t[6]){0xcc, 0xbb, 0xaa, 0x33, 0x22, 0x11}) + BLE_LL_PUBLIC_DEV_ADDR: 0x1122aabb33cc # Whether to save data to sys/config, or just keep it in RAM. BLE_STORE_CONFIG_PERSIST: 0 diff --git a/apps/blemesh/pkg.yml b/apps/blemesh/pkg.yml index c70565423c..fb4c494146 100644 --- a/apps/blemesh/pkg.yml +++ b/apps/blemesh/pkg.yml @@ -24,14 +24,12 @@ pkg.keywords: pkg.deps: - "@apache-mynewt-core/kernel/os" - - "@apache-mynewt-core/sys/console/full" - - "@apache-mynewt-core/sys/log/full" + - "@apache-mynewt-core/sys/console" + - "@apache-mynewt-core/sys/log" - "@apache-mynewt-core/sys/log/modlog" - - "@apache-mynewt-core/sys/stats/full" + - "@apache-mynewt-core/sys/stats" - "@apache-mynewt-core/sys/shell" - - nimble/controller - nimble/host - nimble/host/services/gap - nimble/host/services/gatt - nimble/host/store/config - - nimble/transport/ram diff --git a/apps/blemesh/src/main.c b/apps/blemesh/src/main.c index 65270554b3..1636bdcf19 100644 --- a/apps/blemesh/src/main.c +++ b/apps/blemesh/src/main.c @@ -32,6 +32,10 @@ #include "services/gap/ble_svc_gap.h" #include "mesh/glue.h" +#ifndef min +#define min(a, b) ((a) < (b) ? (a) : (b)) +#endif + /* Company ID */ #define CID_VENDOR 0x05C3 #define STANDARD_TEST_ID 0x00 @@ -144,11 +148,12 @@ static struct bt_mesh_model_pub gen_onoff_pub; static uint8_t gen_on_off_state; static int16_t gen_level_state; -static void gen_onoff_status(struct bt_mesh_model *model, +static int gen_onoff_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx) { struct os_mbuf *msg = NET_BUF_SIMPLE(3); uint8_t *status; + int rc; console_printf("#mesh-onoff STATUS\n"); @@ -156,23 +161,25 @@ static void gen_onoff_status(struct bt_mesh_model *model, status = net_buf_simple_add(msg, 1); *status = gen_on_off_state; - if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { + rc = bt_mesh_model_send(model, ctx, msg, NULL, NULL); + if (rc) { console_printf("#mesh-onoff STATUS: send status failed\n"); } os_mbuf_free_chain(msg); + return rc; } -static void gen_onoff_get(struct bt_mesh_model *model, +static int gen_onoff_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { console_printf("#mesh-onoff GET\n"); - gen_onoff_status(model, ctx); + return gen_onoff_status(model, ctx); } -static void gen_onoff_set(struct bt_mesh_model *model, +static int gen_onoff_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -181,10 +188,10 @@ static void gen_onoff_set(struct bt_mesh_model *model, gen_on_off_state = buf->om_data[0]; hal_gpio_write(LED_2, !gen_on_off_state); - gen_onoff_status(model, ctx); + return gen_onoff_status(model, ctx); } -static void gen_onoff_set_unack(struct bt_mesh_model *model, +static int gen_onoff_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -192,6 +199,7 @@ static void gen_onoff_set_unack(struct bt_mesh_model *model, gen_on_off_state = buf->om_data[0]; hal_gpio_write(LED_2, !gen_on_off_state); + return 0; } static const struct bt_mesh_model_op gen_onoff_op[] = { @@ -201,48 +209,56 @@ static const struct bt_mesh_model_op gen_onoff_op[] = { BT_MESH_MODEL_OP_END, }; -static void gen_level_status(struct bt_mesh_model *model, +static int gen_level_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx) { struct os_mbuf *msg = NET_BUF_SIMPLE(4); + int rc; console_printf("#mesh-level STATUS\n"); bt_mesh_model_msg_init(msg, BT_MESH_MODEL_OP_2(0x82, 0x08)); net_buf_simple_add_le16(msg, gen_level_state); - if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { + rc = bt_mesh_model_send(model, ctx, msg, NULL, NULL); + if (rc) { console_printf("#mesh-level STATUS: send status failed\n"); } os_mbuf_free_chain(msg); + return rc; } -static void gen_level_get(struct bt_mesh_model *model, +static int gen_level_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { console_printf("#mesh-level GET\n"); - gen_level_status(model, ctx); + return gen_level_status(model, ctx); } -static void gen_level_set(struct bt_mesh_model *model, +static int gen_level_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { int16_t level; + int rc; level = (int16_t) net_buf_simple_pull_le16(buf); console_printf("#mesh-level SET: level=%d\n", level); - gen_level_status(model, ctx); + rc = gen_level_status(model, ctx); + if (rc) { + return rc; + } gen_level_state = level; console_printf("#mesh-level: level=%d\n", gen_level_state); + return 0; } -static void gen_level_set_unack(struct bt_mesh_model *model, +static int gen_level_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -253,9 +269,10 @@ static void gen_level_set_unack(struct bt_mesh_model *model, gen_level_state = level; console_printf("#mesh-level: level=%d\n", gen_level_state); + return 0; } -static void gen_delta_set(struct bt_mesh_model *model, +static int gen_delta_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -268,9 +285,10 @@ static void gen_delta_set(struct bt_mesh_model *model, gen_level_state += delta_level; console_printf("#mesh-level: level=%d\n", gen_level_state); + return 0; } -static void gen_delta_set_unack(struct bt_mesh_model *model, +static int gen_delta_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -281,18 +299,21 @@ static void gen_delta_set_unack(struct bt_mesh_model *model, gen_level_state += delta_level; console_printf("#mesh-level: level=%d\n", gen_level_state); + return 0; } -static void gen_move_set(struct bt_mesh_model *model, +static int gen_move_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { + return 0; } -static void gen_move_set_unack(struct bt_mesh_model *model, +static int gen_move_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { + return 0; } static const struct bt_mesh_model_op gen_level_op[] = { @@ -317,11 +338,12 @@ static struct bt_mesh_model root_models[] = { static struct bt_mesh_model_pub vnd_model_pub; -static void vnd_model_recv(struct bt_mesh_model *model, +static int vnd_model_recv(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { struct os_mbuf *msg = NET_BUF_SIMPLE(3); + int rc; console_printf("#vendor-model-recv\n"); @@ -331,11 +353,13 @@ static void vnd_model_recv(struct bt_mesh_model *model, bt_mesh_model_msg_init(msg, BT_MESH_MODEL_OP_3(0x01, CID_VENDOR)); os_mbuf_append(msg, buf->om_data, buf->om_len); + rc = bt_mesh_model_send(model, ctx, msg, NULL, NULL); if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { console_printf("#vendor-model-recv: send rsp failed\n"); } os_mbuf_free_chain(msg); + return rc; } static const struct bt_mesh_model_op vnd_model_op[] = { @@ -422,13 +446,8 @@ blemesh_on_sync(void) } int -main(int argc, char **argv) +mynewt_main(int argc, char **argv) { - -#ifdef ARCH_sim - mcu_sim_parse_args(argc, argv); -#endif - /* Initialize OS */ sysinit(); diff --git a/apps/blemesh/syscfg.yml b/apps/blemesh/syscfg.yml index 4424b14de0..e6e961bf49 100644 --- a/apps/blemesh/syscfg.yml +++ b/apps/blemesh/syscfg.yml @@ -17,6 +17,10 @@ # syscfg.vals: + CONSOLE_IMPLEMENTATION: full + LOG_IMPLEMENTATION: full + STATS_IMPLEMENTATION: full + # Enable the shell task. SHELL_TASK: 1 diff --git a/apps/blemesh_light/pkg.yml b/apps/blemesh_light/pkg.yml index 75a60df7bb..f261a6f4ef 100644 --- a/apps/blemesh_light/pkg.yml +++ b/apps/blemesh_light/pkg.yml @@ -24,14 +24,12 @@ pkg.keywords: pkg.deps: - "@apache-mynewt-core/kernel/os" - - "@apache-mynewt-core/sys/console/full" - - "@apache-mynewt-core/sys/log/full" + - "@apache-mynewt-core/sys/console" + - "@apache-mynewt-core/sys/log" - "@apache-mynewt-core/sys/log/modlog" - - "@apache-mynewt-core/sys/stats/full" + - "@apache-mynewt-core/sys/stats" - "@apache-mynewt-core/sys/shell" - - nimble/controller - nimble/host - nimble/host/services/gap - nimble/host/services/gatt - nimble/host/store/config - - nimble/transport/ram diff --git a/apps/blemesh_light/src/main.c b/apps/blemesh_light/src/main.c index 70deede10a..b90888c2c5 100644 --- a/apps/blemesh_light/src/main.c +++ b/apps/blemesh_light/src/main.c @@ -96,7 +96,7 @@ blemesh_on_sync(void) } int -main(void) +mynewt_main(int argc, char **argv) { /* Initialize OS */ sysinit(); diff --git a/apps/blemesh_light/syscfg.yml b/apps/blemesh_light/syscfg.yml index 826d9d5f34..0443549f8c 100644 --- a/apps/blemesh_light/syscfg.yml +++ b/apps/blemesh_light/syscfg.yml @@ -21,6 +21,10 @@ syscfg.defs: value: 0 syscfg.vals: + CONSOLE_IMPLEMENTATION: full + LOG_IMPLEMENTATION: full + STATS_IMPLEMENTATION: full + # Enable the shell task. SHELL_TASK: 1 diff --git a/apps/blemesh_models_example_1/pkg.yml b/apps/blemesh_models_example_1/pkg.yml index 451f37a11c..3cf9cd81d0 100644 --- a/apps/blemesh_models_example_1/pkg.yml +++ b/apps/blemesh_models_example_1/pkg.yml @@ -24,11 +24,9 @@ pkg.keywords: pkg.deps: - "@apache-mynewt-core/kernel/os" - - "@apache-mynewt-core/sys/console/full" - - "@apache-mynewt-core/sys/log/full" - - "@apache-mynewt-core/sys/stats/full" - - nimble/controller + - "@apache-mynewt-core/sys/console" + - "@apache-mynewt-core/sys/log" + - "@apache-mynewt-core/sys/stats" - nimble/host - nimble/host/services/gap - nimble/host/services/gatt - - nimble/transport/ram diff --git a/apps/blemesh_models_example_1/src/main.c b/apps/blemesh_models_example_1/src/main.c index 736d4d32bf..e3ab7559e3 100644 --- a/apps/blemesh_models_example_1/src/main.c +++ b/apps/blemesh_models_example_1/src/main.c @@ -68,19 +68,19 @@ #define BT_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK BT_MESH_MODEL_OP_2(0x82, 0x03) #define BT_MESH_MODEL_OP_GEN_ONOFF_STATUS BT_MESH_MODEL_OP_2(0x82, 0x04) -static void gen_onoff_set(struct bt_mesh_model *model, +static int gen_onoff_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf); -static void gen_onoff_set_unack(struct bt_mesh_model *model, +static int gen_onoff_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf); -static void gen_onoff_get(struct bt_mesh_model *model, +static int gen_onoff_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf); -static void gen_onoff_status(struct bt_mesh_model *model, +static int gen_onoff_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf); @@ -318,26 +318,29 @@ static uint16_t primary_net_idx; * */ -static void gen_onoff_get(struct bt_mesh_model *model, +static int gen_onoff_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 1 + 4); struct onoff_state *state = model->user_data; + int rc; BT_INFO("addr 0x%04x onoff 0x%02x", bt_mesh_model_elem(model)->addr, state->current); bt_mesh_model_msg_init(msg, BT_MESH_MODEL_OP_GEN_ONOFF_STATUS); net_buf_simple_add_u8(msg, state->current); - if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { + rc = bt_mesh_model_send(model, ctx, msg, NULL, NULL); + if (rc) { BT_ERR("Unable to send On Off Status response"); } os_mbuf_free_chain(msg); + return rc; } -static void gen_onoff_set_unack(struct bt_mesh_model *model, +static int gen_onoff_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -372,23 +375,34 @@ static void gen_onoff_set_unack(struct bt_mesh_model *model, BT_MESH_MODEL_OP_GEN_ONOFF_STATUS); net_buf_simple_add_u8(msg, state->current); err = bt_mesh_model_publish(model); - if (err) { + if (err != 0) { BT_ERR("bt_mesh_model_publish err %d", err); + return err; } } + return 0; } -static void gen_onoff_set(struct bt_mesh_model *model, +static int gen_onoff_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { BT_INFO(""); + int rc; + + rc = gen_onoff_set_unack(model, ctx, buf); + if (rc != 0) { + return rc; + } - gen_onoff_set_unack(model, ctx, buf); - gen_onoff_get(model, ctx, buf); + rc = gen_onoff_get(model, ctx, buf); + if (rc != 0) { + return rc; + } + return 0; } -static void gen_onoff_status(struct bt_mesh_model *model, +static int gen_onoff_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -398,6 +412,7 @@ static void gen_onoff_status(struct bt_mesh_model *model, BT_INFO("Node 0x%04x OnOff status from 0x%04x with state 0x%02x", bt_mesh_model_elem(model)->addr, ctx->addr, state); + return 0; } static int output_number(bt_mesh_output_action_t action, uint32_t number) @@ -637,12 +652,9 @@ blemesh_on_sync(void) console_printf("Mesh initialized\n"); } -int main(void) +int +mynewt_main(int argc, char **argv) { -#ifdef ARCH_sim - mcu_sim_parse_args(argc, argv); -#endif - /* Initialize OS */ sysinit(); diff --git a/apps/blemesh_models_example_1/syscfg.yml b/apps/blemesh_models_example_1/syscfg.yml index 969753fe05..26e178b0dc 100644 --- a/apps/blemesh_models_example_1/syscfg.yml +++ b/apps/blemesh_models_example_1/syscfg.yml @@ -17,6 +17,10 @@ # syscfg.vals: + CONSOLE_IMPLEMENTATION: full + LOG_IMPLEMENTATION: full + STATS_IMPLEMENTATION: full + # Set log level to info (disable debug logging). LOG_LEVEL: 1 diff --git a/apps/blemesh_models_example_2/pkg.yml b/apps/blemesh_models_example_2/pkg.yml index ee2be6da2a..f4ceacbc7a 100644 --- a/apps/blemesh_models_example_2/pkg.yml +++ b/apps/blemesh_models_example_2/pkg.yml @@ -24,16 +24,14 @@ pkg.keywords: pkg.deps: - "@apache-mynewt-core/kernel/os" - - "@apache-mynewt-core/sys/console/full" - - "@apache-mynewt-core/sys/log/full" - - "@apache-mynewt-core/sys/stats/full" + - "@apache-mynewt-core/sys/console" + - "@apache-mynewt-core/sys/log" + - "@apache-mynewt-core/sys/stats" - "@apache-mynewt-core/encoding/base64" - "@apache-mynewt-core/sys/config" - - nimble/controller - nimble/host - nimble/host/services/gap - nimble/host/services/gatt - - nimble/transport/ram pkg.lflags: - -DFLOAT_SUPPORT diff --git a/apps/blemesh_models_example_2/src/device_composition.c b/apps/blemesh_models_example_2/src/device_composition.c index 5dfeaf8ed5..40ede50126 100644 --- a/apps/blemesh_models_example_2/src/device_composition.c +++ b/apps/blemesh_models_example_2/src/device_composition.c @@ -147,7 +147,7 @@ static struct bt_mesh_elem elements[]; /* message handlers (Start) */ /* Generic OnOff Server message handlers */ -static void gen_onoff_get(struct bt_mesh_model *model, +static int gen_onoff_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -168,16 +168,17 @@ static void gen_onoff_get(struct bt_mesh_model *model, } os_mbuf_free_chain(msg); + return 0; } -void gen_onoff_publish(struct bt_mesh_model *model) +int gen_onoff_publish(struct bt_mesh_model *model) { int err; struct os_mbuf *msg = model->pub->msg; struct generic_onoff_state *state = model->user_data; if (model->pub->addr == BT_MESH_ADDR_UNASSIGNED) { - return; + return 0; } bt_mesh_model_msg_init(msg, BT_MESH_MODEL_OP_GEN_ONOFF_STATUS); @@ -193,21 +194,23 @@ void gen_onoff_publish(struct bt_mesh_model *model) if (err) { printk("bt_mesh_model_publish err %d\n", err); } + return err; } -static void gen_onoff_set_unack(struct bt_mesh_model *model, +static int gen_onoff_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { uint8_t tid, onoff, tt, delay; int64_t now; + int err; struct generic_onoff_state *state = model->user_data; onoff = net_buf_simple_pull_u8(buf); tid = net_buf_simple_pull_u8(buf); if (onoff > STATE_ON) { - return; + return 0; } now = k_uptime_get(); @@ -215,7 +218,7 @@ static void gen_onoff_set_unack(struct bt_mesh_model *model, state->last_src_addr == ctx->addr && state->last_dst_addr == ctx->recv_dst && (now - state->last_msg_timestamp <= K_SECONDS(6))) { - return; + return 0; } switch (buf->om_len) { @@ -226,13 +229,13 @@ static void gen_onoff_set_unack(struct bt_mesh_model *model, case 0x02: /* Optional fields are available */ tt = net_buf_simple_pull_u8(buf); if ((tt & 0x3F) == 0x3F) { - return; + return 0; } delay = net_buf_simple_pull_u8(buf); break; default: - return; + return 0; } *ptr_counter = 0; @@ -247,8 +250,7 @@ static void gen_onoff_set_unack(struct bt_mesh_model *model, if (state->target_onoff != state->onoff) { onoff_tt_values(state, tt, delay); } else { - gen_onoff_publish(model); - return; + return gen_onoff_publish(model); } /* For Instantaneous Transition */ @@ -257,23 +259,28 @@ static void gen_onoff_set_unack(struct bt_mesh_model *model, } state->transition->just_started = true; - gen_onoff_publish(model); + err = gen_onoff_publish(model); onoff_handler(state); + if (err) { + return err; + } + return 0; } -static void gen_onoff_set(struct bt_mesh_model *model, +static int gen_onoff_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { uint8_t tid, onoff, tt, delay; int64_t now; + int rc; struct generic_onoff_state *state = model->user_data; onoff = net_buf_simple_pull_u8(buf); tid = net_buf_simple_pull_u8(buf); if (onoff > STATE_ON) { - return; + return 0; } now = k_uptime_get(); @@ -281,8 +288,8 @@ static void gen_onoff_set(struct bt_mesh_model *model, state->last_src_addr == ctx->addr && state->last_dst_addr == ctx->recv_dst && (now - state->last_msg_timestamp <= K_SECONDS(6))) { - gen_onoff_get(model, ctx, buf); - return; + rc = gen_onoff_get(model, ctx, buf); + return rc; } switch (buf->om_len) { @@ -293,13 +300,13 @@ static void gen_onoff_set(struct bt_mesh_model *model, case 0x02: /* Optional fields are available */ tt = net_buf_simple_pull_u8(buf); if ((tt & 0x3F) == 0x3F) { - return; + return 0; } delay = net_buf_simple_pull_u8(buf); break; default: - return; + return 0; } *ptr_counter = 0; @@ -315,8 +322,8 @@ static void gen_onoff_set(struct bt_mesh_model *model, onoff_tt_values(state, tt, delay); } else { gen_onoff_get(model, ctx, buf); - gen_onoff_publish(model); - return; + rc = gen_onoff_publish(model); + return rc; } /* For Instantaneous Transition */ @@ -326,12 +333,13 @@ static void gen_onoff_set(struct bt_mesh_model *model, state->transition->just_started = true; gen_onoff_get(model, ctx, buf); - gen_onoff_publish(model); + rc = gen_onoff_publish(model); onoff_handler(state); + return rc; } /* Generic OnOff Client message handlers */ -static void gen_onoff_status(struct bt_mesh_model *model, +static int gen_onoff_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -342,10 +350,11 @@ static void gen_onoff_status(struct bt_mesh_model *model, printk("Target OnOff = %02x\n", net_buf_simple_pull_u8(buf)); printk("Remaining Time = %02x\n", net_buf_simple_pull_u8(buf)); } + return 0; } /* Generic Level Server message handlers */ -static void gen_level_get(struct bt_mesh_model *model, +static int gen_level_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -366,16 +375,17 @@ static void gen_level_get(struct bt_mesh_model *model, } os_mbuf_free_chain(msg); + return 0; } -void gen_level_publish(struct bt_mesh_model *model) +int gen_level_publish(struct bt_mesh_model *model) { int err; struct os_mbuf *msg = model->pub->msg; struct generic_level_state *state = model->user_data; if (model->pub->addr == BT_MESH_ADDR_UNASSIGNED) { - return; + return 0; } bt_mesh_model_msg_init(msg, BT_MESH_MODEL_OP_GEN_LEVEL_STATUS); @@ -391,9 +401,10 @@ void gen_level_publish(struct bt_mesh_model *model) if (err) { printk("bt_mesh_model_publish err %d\n", err); } + return err; } -static void gen_level_set_unack(struct bt_mesh_model *model, +static int gen_level_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -410,7 +421,7 @@ static void gen_level_set_unack(struct bt_mesh_model *model, state->last_src_addr == ctx->addr && state->last_dst_addr == ctx->recv_dst && (now - state->last_msg_timestamp <= K_SECONDS(6))) { - return; + return 0; } switch (buf->om_len) { @@ -421,13 +432,13 @@ static void gen_level_set_unack(struct bt_mesh_model *model, case 0x02: /* Optional fields are available */ tt = net_buf_simple_pull_u8(buf); if ((tt & 0x3F) == 0x3F) { - return; + return 0; } delay = net_buf_simple_pull_u8(buf); break; default: - return; + return 0; } *ptr_counter = 0; @@ -443,7 +454,7 @@ static void gen_level_set_unack(struct bt_mesh_model *model, level_tt_values(state, tt, delay); } else { gen_level_publish(model); - return; + return 0; } /* For Instantaneous Transition */ @@ -463,9 +474,10 @@ static void gen_level_set_unack(struct bt_mesh_model *model, transition_type = LEVEL_TEMP_TT; level_temp_handler(state); } + return 0; } -static void gen_level_set(struct bt_mesh_model *model, +static int gen_level_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -483,7 +495,7 @@ static void gen_level_set(struct bt_mesh_model *model, state->last_dst_addr == ctx->recv_dst && (now - state->last_msg_timestamp <= K_SECONDS(6))) { gen_level_get(model, ctx, buf); - return; + return 0; } switch (buf->om_len) { @@ -494,13 +506,13 @@ static void gen_level_set(struct bt_mesh_model *model, case 0x02: /* Optional fields are available */ tt = net_buf_simple_pull_u8(buf); if ((tt & 0x3F) == 0x3F) { - return; + return 0; } delay = net_buf_simple_pull_u8(buf); break; default: - return; + return 0; } *ptr_counter = 0; @@ -517,7 +529,7 @@ static void gen_level_set(struct bt_mesh_model *model, } else { gen_level_get(model, ctx, buf); gen_level_publish(model); - return; + return 0; } /* For Instantaneous Transition */ @@ -538,9 +550,10 @@ static void gen_level_set(struct bt_mesh_model *model, transition_type = LEVEL_TEMP_TT; level_temp_handler(state); } + return 0; } -static void gen_delta_set_unack(struct bt_mesh_model *model, +static int gen_delta_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -559,7 +572,7 @@ static void gen_delta_set_unack(struct bt_mesh_model *model, (now - state->last_msg_timestamp <= K_SECONDS(6))) { if (state->last_delta == delta) { - return; + return 0; } tmp32 = state->last_level + delta; @@ -576,13 +589,13 @@ static void gen_delta_set_unack(struct bt_mesh_model *model, case 0x02: /* Optional fields are available */ tt = net_buf_simple_pull_u8(buf); if ((tt & 0x3F) == 0x3F) { - return; + return 0; } delay = net_buf_simple_pull_u8(buf); break; default: - return; + return 0; } *ptr_counter = 0; @@ -605,8 +618,7 @@ static void gen_delta_set_unack(struct bt_mesh_model *model, if (state->target_level != state->level) { level_tt_values(state, tt, delay); } else { - gen_level_publish(model); - return; + return gen_level_publish(model); } /* For Instantaneous Transition */ @@ -627,9 +639,10 @@ static void gen_delta_set_unack(struct bt_mesh_model *model, transition_type = LEVEL_TEMP_TT_DELTA; level_temp_handler(state); } + return 0; } -static void gen_delta_set(struct bt_mesh_model *model, +static int gen_delta_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -649,7 +662,7 @@ static void gen_delta_set(struct bt_mesh_model *model, if (state->last_delta == delta) { gen_level_get(model, ctx, buf); - return; + return 0; } tmp32 = state->last_level + delta; @@ -666,13 +679,13 @@ static void gen_delta_set(struct bt_mesh_model *model, case 0x02: /* Optional fields are available */ tt = net_buf_simple_pull_u8(buf); if ((tt & 0x3F) == 0x3F) { - return; + return 0; } delay = net_buf_simple_pull_u8(buf); break; default: - return; + return 0; } *ptr_counter = 0; @@ -697,7 +710,7 @@ static void gen_delta_set(struct bt_mesh_model *model, } else { gen_level_get(model, ctx, buf); gen_level_publish(model); - return; + return 0; } /* For Instantaneous Transition */ @@ -718,14 +731,16 @@ static void gen_delta_set(struct bt_mesh_model *model, transition_type = LEVEL_TEMP_TT_DELTA; level_temp_handler(state); } + return 0; } -static void gen_level_move_get(struct bt_mesh_model *model, +static int gen_level_move_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 5 + 4); struct generic_level_state *state = model->user_data; + int rc; bt_mesh_model_msg_init(msg, BT_MESH_MODEL_OP_GEN_LEVEL_STATUS); net_buf_simple_add_le16(msg, state->level); @@ -740,21 +755,23 @@ static void gen_level_move_get(struct bt_mesh_model *model, net_buf_simple_add_u8(msg, UNKNOWN_VALUE); } - if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { + rc = bt_mesh_model_send(model, ctx, msg, NULL, NULL); + if (rc) { printk("Unable to send GEN_LEVEL_SRV Status response\n"); } os_mbuf_free_chain(msg); + return rc; } -static void gen_level_move_publish(struct bt_mesh_model *model) +static int gen_level_move_publish(struct bt_mesh_model *model) { int err; struct os_mbuf *msg = model->pub->msg; struct generic_level_state *state = model->user_data; if (model->pub->addr == BT_MESH_ADDR_UNASSIGNED) { - return; + return 0; } bt_mesh_model_msg_init(msg, BT_MESH_MODEL_OP_GEN_LEVEL_STATUS); @@ -774,9 +791,10 @@ static void gen_level_move_publish(struct bt_mesh_model *model) if (err) { printk("bt_mesh_model_publish err %d\n", err); } + return err; } -static void gen_move_set_unack(struct bt_mesh_model *model, +static int gen_move_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -785,6 +803,7 @@ static void gen_move_set_unack(struct bt_mesh_model *model, int32_t tmp32; int64_t now; struct generic_level_state *state = model->user_data; + int rc; delta = (int16_t) net_buf_simple_pull_le16(buf); tid = net_buf_simple_pull_u8(buf); @@ -794,7 +813,7 @@ static void gen_move_set_unack(struct bt_mesh_model *model, state->last_src_addr == ctx->addr && state->last_dst_addr == ctx->recv_dst && (now - state->last_msg_timestamp <= K_SECONDS(6))) { - return; + return 0; } switch (buf->om_len) { @@ -805,13 +824,13 @@ static void gen_move_set_unack(struct bt_mesh_model *model, case 0x02: /* Optional fields are available */ tt = net_buf_simple_pull_u8(buf); if ((tt & 0x3F) == 0x3F) { - return; + return 0; } delay = net_buf_simple_pull_u8(buf); break; default: - return; + return 0; } *ptr_counter = 0; @@ -835,16 +854,16 @@ static void gen_move_set_unack(struct bt_mesh_model *model, if (state->target_level != state->level) { level_tt_values(state, tt, delay); } else { - gen_level_move_publish(model); - return; + rc = gen_level_move_publish(model); + return rc; } if (state->transition->counter == 0) { - return; + return 0; } state->transition->just_started = true; - gen_level_move_publish(model); + rc = gen_level_move_publish(model); if (bt_mesh_model_elem(model)->addr == elements[0].addr) { /* Root element */ @@ -855,9 +874,10 @@ static void gen_move_set_unack(struct bt_mesh_model *model, transition_type = LEVEL_TEMP_TT_MOVE; level_temp_handler(state); } + return rc; } -static void gen_move_set(struct bt_mesh_model *model, +static int gen_move_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -866,6 +886,7 @@ static void gen_move_set(struct bt_mesh_model *model, int32_t tmp32; int64_t now; struct generic_level_state *state = model->user_data; + int rc; delta = (int16_t) net_buf_simple_pull_le16(buf); tid = net_buf_simple_pull_u8(buf); @@ -875,8 +896,8 @@ static void gen_move_set(struct bt_mesh_model *model, state->last_src_addr == ctx->addr && state->last_dst_addr == ctx->recv_dst && (now - state->last_msg_timestamp <= K_SECONDS(6))) { - gen_level_move_get(model, ctx, buf); - return; + rc = gen_level_move_get(model, ctx, buf); + return rc; } switch (buf->om_len) { @@ -887,13 +908,13 @@ static void gen_move_set(struct bt_mesh_model *model, case 0x02: /* Optional fields are available */ tt = net_buf_simple_pull_u8(buf); if ((tt & 0x3F) == 0x3F) { - return; + return 0; } delay = net_buf_simple_pull_u8(buf); break; default: - return; + return 0; } *ptr_counter = 0; @@ -918,17 +939,17 @@ static void gen_move_set(struct bt_mesh_model *model, level_tt_values(state, tt, delay); } else { gen_level_move_get(model, ctx, buf); - gen_level_move_publish(model); - return; + rc = gen_level_move_publish(model); + return rc; } if (state->transition->counter == 0) { - return; + return 0; } state->transition->just_started = true; gen_level_move_get(model, ctx, buf); - gen_level_move_publish(model); + rc = gen_level_move_publish(model); if (bt_mesh_model_elem(model)->addr == elements[0].addr) { /* Root element */ @@ -939,10 +960,11 @@ static void gen_move_set(struct bt_mesh_model *model, transition_type = LEVEL_TEMP_TT_MOVE; level_temp_handler(state); } + return rc; } /* Generic Level Client message handlers */ -static void gen_level_status(struct bt_mesh_model *model, +static int gen_level_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -953,10 +975,11 @@ static void gen_level_status(struct bt_mesh_model *model, printk("Target Level = %04x\n", net_buf_simple_pull_le16(buf)); printk("Remaining Time = %02x\n", net_buf_simple_pull_u8(buf)); } + return 0; } /* Generic Default Transition Time Server message handlers */ -static void gen_def_trans_time_get(struct bt_mesh_model *model, +static int gen_def_trans_time_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -971,16 +994,17 @@ static void gen_def_trans_time_get(struct bt_mesh_model *model, } os_mbuf_free_chain(msg); + return 0; } -static void gen_def_trans_time_publish(struct bt_mesh_model *model) +static int gen_def_trans_time_publish(struct bt_mesh_model *model) { int err; struct os_mbuf *msg = model->pub->msg; struct gen_def_trans_time_state *state = model->user_data; if (model->pub->addr == BT_MESH_ADDR_UNASSIGNED) { - return; + return 0; } bt_mesh_model_msg_init(msg, BT_MESH_MODEL_GEN_DEF_TRANS_TIME_STATUS); @@ -990,6 +1014,7 @@ static void gen_def_trans_time_publish(struct bt_mesh_model *model) if (err) { printk("bt_mesh_model_publish err %d\n", err); } + return err; } static bool gen_def_trans_time_setunack(struct bt_mesh_model *model, @@ -1017,71 +1042,78 @@ static bool gen_def_trans_time_setunack(struct bt_mesh_model *model, return true; } -static void gen_def_trans_time_set_unack(struct bt_mesh_model *model, +static int gen_def_trans_time_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { if (gen_def_trans_time_setunack(model, ctx, buf) == true) { - gen_def_trans_time_publish(model); + return gen_def_trans_time_publish(model); } + return 0; } -static void gen_def_trans_time_set(struct bt_mesh_model *model, +static int gen_def_trans_time_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { if (gen_def_trans_time_setunack(model, ctx, buf) == true) { gen_def_trans_time_get(model, ctx, buf); - gen_def_trans_time_publish(model); + return gen_def_trans_time_publish(model); } + return 0; } /* Generic Default Transition Time Client message handlers */ -static void gen_def_trans_time_status(struct bt_mesh_model *model, +static int gen_def_trans_time_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { printk("Acknownledgement from GEN_DEF_TT_SRV\n"); printk("Transition Time = %02x\n", net_buf_simple_pull_u8(buf)); + return 0; } /* Generic Power OnOff Server message handlers */ -static void gen_onpowerup_get(struct bt_mesh_model *model, +static int gen_onpowerup_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 1 + 4); struct generic_onpowerup_state *state = model->user_data; + int rc; bt_mesh_model_msg_init(msg, BT_MESH_MODEL_GEN_ONPOWERUP_STATUS); net_buf_simple_add_u8(msg, state->onpowerup); - if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { + rc = bt_mesh_model_send(model, ctx, msg, NULL, NULL); + if (rc) { printk("Unable to send GEN_POWER_ONOFF_SRV Status response\n"); } os_mbuf_free_chain(msg); + return rc; } /* Generic Power OnOff Client message handlers */ -static void gen_onpowerup_status(struct bt_mesh_model *model, +static int gen_onpowerup_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { printk("Acknownledgement from GEN_POWER_ONOFF_SRV\n"); printk("OnPowerUp = %02x\n", net_buf_simple_pull_u8(buf)); + return 0; } /* Generic Power OnOff Setup Server message handlers */ -static void gen_onpowerup_publish(struct bt_mesh_model *model) +static int gen_onpowerup_publish(struct bt_mesh_model *model) { int err; struct os_mbuf *msg = model->pub->msg; struct generic_onpowerup_state *state = model->user_data; if (model->pub->addr == BT_MESH_ADDR_UNASSIGNED) { - return; + return 0; } bt_mesh_model_msg_init(msg, BT_MESH_MODEL_GEN_ONPOWERUP_STATUS); @@ -1091,6 +1123,7 @@ static void gen_onpowerup_publish(struct bt_mesh_model *model) if (err) { printk("bt_mesh_model_publish err %d\n", err); } + return err; } static bool gen_onpowerup_setunack(struct bt_mesh_model *model, @@ -1117,32 +1150,35 @@ static bool gen_onpowerup_setunack(struct bt_mesh_model *model, return true; } -static void gen_onpowerup_set_unack(struct bt_mesh_model *model, +static int gen_onpowerup_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { if (gen_onpowerup_setunack(model, ctx, buf) == true) { - gen_onpowerup_publish(model); + return gen_onpowerup_publish(model); } + return 0; } -static void gen_onpowerup_set(struct bt_mesh_model *model, +static int gen_onpowerup_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { if (gen_onpowerup_setunack(model, ctx, buf) == true) { gen_onpowerup_get(model, ctx, buf); - gen_onpowerup_publish(model); + return gen_onpowerup_publish(model); } + return 0; } /* Vendor Model message handlers*/ -static void vnd_get(struct bt_mesh_model *model, +static int vnd_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { struct os_mbuf *msg = NET_BUF_SIMPLE(3 + 6 + 4); struct vendor_state *state = model->user_data; + int err; /* This is dummy response for demo purpose */ state->response = 0xA578FEB3; @@ -1151,14 +1187,16 @@ static void vnd_get(struct bt_mesh_model *model, net_buf_simple_add_le16(msg, state->current); net_buf_simple_add_le32(msg, state->response); - if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { + err = bt_mesh_model_send(model, ctx, msg, NULL, NULL); + if (err) { printk("Unable to send VENDOR Status response\n"); } os_mbuf_free_chain(msg); + return err; } -static void vnd_set_unack(struct bt_mesh_model *model, +static int vnd_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -1175,7 +1213,7 @@ static void vnd_set_unack(struct bt_mesh_model *model, state->last_src_addr == ctx->addr && state->last_dst_addr == ctx->recv_dst && (now - state->last_msg_timestamp <= K_SECONDS(6))) { - return; + return 0; } state->last_tid = tid; @@ -1193,27 +1231,37 @@ static void vnd_set_unack(struct bt_mesh_model *model, /* LED2 Off */ hal_gpio_write(led_device[1], 1); } + return 0; } -static void vnd_set(struct bt_mesh_model *model, +static int vnd_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { - vnd_set_unack(model, ctx, buf); - vnd_get(model, ctx, buf); + int rc; + rc = vnd_set_unack(model, ctx, buf); + if (rc) { + return rc; + } + rc = vnd_get(model, ctx, buf); + if (rc) { + return rc; + } + return 0; } -static void vnd_status(struct bt_mesh_model *model, +static int vnd_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { printk("Acknownledgement from Vendor\n"); printk("cmd = %04x\n", net_buf_simple_pull_le16(buf)); printk("response = %08lx\n", net_buf_simple_pull_le32(buf)); + return 0; } /* Light Lightness Server message handlers */ -static void light_lightness_get(struct bt_mesh_model *model, +static int light_lightness_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -1234,16 +1282,17 @@ static void light_lightness_get(struct bt_mesh_model *model, } os_mbuf_free_chain(msg); + return 0; } -void light_lightness_publish(struct bt_mesh_model *model) +int light_lightness_publish(struct bt_mesh_model *model) { int err; struct os_mbuf *msg = model->pub->msg; struct light_lightness_state *state = model->user_data; if (model->pub->addr == BT_MESH_ADDR_UNASSIGNED) { - return; + return 0; } bt_mesh_model_msg_init(msg, BT_MESH_MODEL_LIGHT_LIGHTNESS_STATUS); @@ -1259,9 +1308,10 @@ void light_lightness_publish(struct bt_mesh_model *model) if (err) { printk("bt_mesh_model_publish err %d\n", err); } + return err; } -static void light_lightness_set_unack(struct bt_mesh_model *model, +static int light_lightness_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -1278,7 +1328,7 @@ static void light_lightness_set_unack(struct bt_mesh_model *model, state->last_src_addr == ctx->addr && state->last_dst_addr == ctx->recv_dst && (now - state->last_msg_timestamp <= K_SECONDS(6))) { - return; + return 0; } switch (buf->om_len) { @@ -1289,13 +1339,13 @@ static void light_lightness_set_unack(struct bt_mesh_model *model, case 0x02: /* Optional fields are available */ tt = net_buf_simple_pull_u8(buf); if ((tt & 0x3F) == 0x3F) { - return; + return 0; } delay = net_buf_simple_pull_u8(buf); break; default: - return; + return 0; } *ptr_counter = 0; @@ -1318,7 +1368,7 @@ static void light_lightness_set_unack(struct bt_mesh_model *model, light_lightness_actual_tt_values(state, tt, delay); } else { light_lightness_publish(model); - return; + return 0; } /* For Instantaneous Transition */ @@ -1329,9 +1379,10 @@ static void light_lightness_set_unack(struct bt_mesh_model *model, state->transition->just_started = true; light_lightness_publish(model); light_lightness_actual_handler(state); + return 0; } -static void light_lightness_set(struct bt_mesh_model *model, +static int light_lightness_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -1339,6 +1390,7 @@ static void light_lightness_set(struct bt_mesh_model *model, uint16_t actual; int64_t now; struct light_lightness_state *state = model->user_data; + int rc; actual = net_buf_simple_pull_le16(buf); tid = net_buf_simple_pull_u8(buf); @@ -1348,8 +1400,7 @@ static void light_lightness_set(struct bt_mesh_model *model, state->last_src_addr == ctx->addr && state->last_dst_addr == ctx->recv_dst && (now - state->last_msg_timestamp <= K_SECONDS(6))) { - light_lightness_get(model, ctx, buf); - return; + return light_lightness_get(model, ctx, buf); } switch (buf->om_len) { @@ -1360,13 +1411,13 @@ static void light_lightness_set(struct bt_mesh_model *model, case 0x02: /* Optional fields are available */ tt = net_buf_simple_pull_u8(buf); if ((tt & 0x3F) == 0x3F) { - return; + return 0; } delay = net_buf_simple_pull_u8(buf); break; default: - return; + return 0; } *ptr_counter = 0; @@ -1388,9 +1439,9 @@ static void light_lightness_set(struct bt_mesh_model *model, if (state->target_actual != state->actual) { light_lightness_actual_tt_values(state, tt, delay); } else { - light_lightness_get(model, ctx, buf); + rc = light_lightness_get(model, ctx, buf); light_lightness_publish(model); - return; + return rc; } /* For Instantaneous Transition */ @@ -1402,9 +1453,10 @@ static void light_lightness_set(struct bt_mesh_model *model, light_lightness_get(model, ctx, buf); light_lightness_publish(model); light_lightness_actual_handler(state); + return 0; } -static void light_lightness_linear_get(struct bt_mesh_model *model, +static int light_lightness_linear_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -1426,16 +1478,17 @@ static void light_lightness_linear_get(struct bt_mesh_model *model, } os_mbuf_free_chain(msg); + return 0; } -void light_lightness_linear_publish(struct bt_mesh_model *model) +int light_lightness_linear_publish(struct bt_mesh_model *model) { int err; struct os_mbuf *msg = model->pub->msg; struct light_lightness_state *state = model->user_data; if (model->pub->addr == BT_MESH_ADDR_UNASSIGNED) { - return; + return 0; } bt_mesh_model_msg_init(msg, @@ -1452,9 +1505,10 @@ void light_lightness_linear_publish(struct bt_mesh_model *model) if (err) { printk("bt_mesh_model_publish err %d\n", err); } + return err; } -static void light_lightness_linear_set_unack(struct bt_mesh_model *model, +static int light_lightness_linear_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -1471,7 +1525,7 @@ static void light_lightness_linear_set_unack(struct bt_mesh_model *model, state->last_src_addr == ctx->addr && state->last_dst_addr == ctx->recv_dst && (now - state->last_msg_timestamp <= K_SECONDS(6))) { - return; + return 0; } switch (buf->om_len) { @@ -1482,13 +1536,13 @@ static void light_lightness_linear_set_unack(struct bt_mesh_model *model, case 0x02: /* Optional fields are available */ tt = net_buf_simple_pull_u8(buf); if ((tt & 0x3F) == 0x3F) { - return; + return 0; } delay = net_buf_simple_pull_u8(buf); break; default: - return; + return 0; } *ptr_counter = 0; @@ -1504,7 +1558,7 @@ static void light_lightness_linear_set_unack(struct bt_mesh_model *model, light_lightness_linear_tt_values(state, tt, delay); } else { light_lightness_linear_publish(model); - return; + return 0; } /* For Instantaneous Transition */ @@ -1515,9 +1569,10 @@ static void light_lightness_linear_set_unack(struct bt_mesh_model *model, state->transition->just_started = true; light_lightness_linear_publish(model); light_lightness_linear_handler(state); + return 0; } -static void light_lightness_linear_set(struct bt_mesh_model *model, +static int light_lightness_linear_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -1525,6 +1580,7 @@ static void light_lightness_linear_set(struct bt_mesh_model *model, uint16_t linear; int64_t now; struct light_lightness_state *state = model->user_data; + int rc; linear = net_buf_simple_pull_le16(buf); tid = net_buf_simple_pull_u8(buf); @@ -1534,8 +1590,7 @@ static void light_lightness_linear_set(struct bt_mesh_model *model, state->last_src_addr == ctx->addr && state->last_dst_addr == ctx->recv_dst && (now - state->last_msg_timestamp <= K_SECONDS(6))) { - light_lightness_linear_get(model, ctx, buf); - return; + return light_lightness_linear_get(model, ctx, buf); } switch (buf->om_len) { @@ -1546,13 +1601,13 @@ static void light_lightness_linear_set(struct bt_mesh_model *model, case 0x02: /* Optional fields are available */ tt = net_buf_simple_pull_u8(buf); if ((tt & 0x3F) == 0x3F) { - return; + return 0; } delay = net_buf_simple_pull_u8(buf); break; default: - return; + return 0; } *ptr_counter = 0; @@ -1567,9 +1622,9 @@ static void light_lightness_linear_set(struct bt_mesh_model *model, if (state->target_linear != state->linear) { light_lightness_linear_tt_values(state, tt, delay); } else { - light_lightness_linear_get(model, ctx, buf); + rc = light_lightness_linear_get(model, ctx, buf); light_lightness_linear_publish(model); - return; + return rc; } /* For Instantaneous Transition */ @@ -1581,9 +1636,10 @@ static void light_lightness_linear_set(struct bt_mesh_model *model, light_lightness_linear_get(model, ctx, buf); light_lightness_linear_publish(model); light_lightness_linear_handler(state); + return 0; } -static void light_lightness_last_get(struct bt_mesh_model *model, +static int light_lightness_last_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -1598,9 +1654,10 @@ static void light_lightness_last_get(struct bt_mesh_model *model, } os_mbuf_free_chain(msg); + return 0; } -static void light_lightness_default_get(struct bt_mesh_model *model, +static int light_lightness_default_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -1616,9 +1673,10 @@ static void light_lightness_default_get(struct bt_mesh_model *model, } os_mbuf_free_chain(msg); + return 0; } -static void light_lightness_range_get(struct bt_mesh_model *model, +static int light_lightness_range_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -1637,18 +1695,19 @@ static void light_lightness_range_get(struct bt_mesh_model *model, } os_mbuf_free_chain(msg); + return 0; } /* Light Lightness Setup Server message handlers */ -static void light_lightness_default_publish(struct bt_mesh_model *model) +static int light_lightness_default_publish(struct bt_mesh_model *model) { int err; struct os_mbuf *msg = model->pub->msg; struct light_lightness_state *state = model->user_data; if (model->pub->addr == BT_MESH_ADDR_UNASSIGNED) { - return; + return 0; } bt_mesh_model_msg_init(msg, @@ -1659,9 +1718,10 @@ static void light_lightness_default_publish(struct bt_mesh_model *model) if (err) { printk("bt_mesh_model_publish err %d\n", err); } + return err; } -static void light_lightness_default_set_unack(struct bt_mesh_model *model, +static int light_lightness_default_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -1679,26 +1739,37 @@ static void light_lightness_default_set_unack(struct bt_mesh_model *model, save_on_flash(LIGHTNESS_TEMP_DEF_STATE); } - light_lightness_default_publish(model); + return light_lightness_default_publish(model); } -static void light_lightness_default_set(struct bt_mesh_model *model, +static int light_lightness_default_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { - light_lightness_default_set_unack(model, ctx, buf); - light_lightness_default_get(model, ctx, buf); - light_lightness_default_publish(model); + int rc; + rc = light_lightness_default_set_unack(model, ctx, buf); + if (rc) { + return rc; + } + rc = light_lightness_default_get(model, ctx, buf); + if (rc) { + return rc; + } + rc = light_lightness_default_publish(model); + if (rc) { + return rc; + } + return 0; } -static void light_lightness_range_publish(struct bt_mesh_model *model) +static int light_lightness_range_publish(struct bt_mesh_model *model) { int err; struct os_mbuf *msg = model->pub->msg; struct light_lightness_state *state = model->user_data; if (model->pub->addr == BT_MESH_ADDR_UNASSIGNED) { - return; + return 0; } bt_mesh_model_msg_init(msg, BT_MESH_MODEL_LIGHT_LIGHTNESS_RANGE_STATUS); @@ -1710,6 +1781,7 @@ static void light_lightness_range_publish(struct bt_mesh_model *model) if (err) { printk("bt_mesh_model_publish err %d\n", err); } + return err; } static bool light_lightness_range_setunack(struct bt_mesh_model *model, @@ -1748,27 +1820,36 @@ static bool light_lightness_range_setunack(struct bt_mesh_model *model, return true; } -static void light_lightness_range_set_unack(struct bt_mesh_model *model, +static int light_lightness_range_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { if (light_lightness_range_setunack(model, ctx, buf) == true) { - light_lightness_range_publish(model); + return light_lightness_range_publish(model); } + return 0; } -static void light_lightness_range_set(struct bt_mesh_model *model, +static int light_lightness_range_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { + int rc; if (light_lightness_range_setunack(model, ctx, buf) == true) { - light_lightness_range_get(model, ctx, buf); - light_lightness_range_publish(model); + rc = light_lightness_range_get(model, ctx, buf); + if (rc) { + return rc; + } + rc = light_lightness_range_publish(model); + if (rc) { + return rc; + } } + return 0; } /* Light Lightness Client message handlers */ -static void light_lightness_status(struct bt_mesh_model *model, +static int light_lightness_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -1780,9 +1861,10 @@ static void light_lightness_status(struct bt_mesh_model *model, net_buf_simple_pull_le16(buf)); printk("Remaining Time = %02x\n", net_buf_simple_pull_u8(buf)); } + return 0; } -static void light_lightness_linear_status(struct bt_mesh_model *model, +static int light_lightness_linear_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -1794,25 +1876,28 @@ static void light_lightness_linear_status(struct bt_mesh_model *model, net_buf_simple_pull_le16(buf)); printk("Remaining Time = %02x\n", net_buf_simple_pull_u8(buf)); } + return 0; } -static void light_lightness_last_status(struct bt_mesh_model *model, +static int light_lightness_last_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { printk("Acknownledgement from LIGHT_LIGHTNESS_SRV (Last)\n"); printk("Lightness = %04x\n", net_buf_simple_pull_le16(buf)); + return 0; } -static void light_lightness_default_status(struct bt_mesh_model *model, +static int light_lightness_default_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { printk("Acknownledgement from LIGHT_LIGHTNESS_SRV (Default)\n"); printk("Lightness = %04x\n", net_buf_simple_pull_le16(buf)); + return 0; } -static void light_lightness_range_status(struct bt_mesh_model *model, +static int light_lightness_range_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -1820,10 +1905,11 @@ static void light_lightness_range_status(struct bt_mesh_model *model, printk("Status Code = %02x\n", net_buf_simple_pull_u8(buf)); printk("Range Min = %04x\n", net_buf_simple_pull_le16(buf)); printk("Range Max = %04x\n", net_buf_simple_pull_le16(buf)); + return 0; } /* Light CTL Server message handlers */ -static void light_ctl_get(struct bt_mesh_model *model, +static int light_ctl_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -1846,16 +1932,17 @@ static void light_ctl_get(struct bt_mesh_model *model, } os_mbuf_free_chain(msg); + return 0; } -void light_ctl_publish(struct bt_mesh_model *model) +int light_ctl_publish(struct bt_mesh_model *model) { int err; struct os_mbuf *msg = model->pub->msg; struct light_ctl_state *state = model->user_data; if (model->pub->addr == BT_MESH_ADDR_UNASSIGNED) { - return; + return 0; } bt_mesh_model_msg_init(msg, BT_MESH_MODEL_LIGHT_CTL_STATUS); @@ -1877,9 +1964,10 @@ void light_ctl_publish(struct bt_mesh_model *model) if (err) { printk("bt_mesh_model_publish err %d\n", err); } + return err; } -static void light_ctl_set_unack(struct bt_mesh_model *model, +static int light_ctl_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -1895,7 +1983,7 @@ static void light_ctl_set_unack(struct bt_mesh_model *model, tid = net_buf_simple_pull_u8(buf); if (temp < TEMP_MIN || temp > TEMP_MAX) { - return; + return 0; } now = k_uptime_get(); @@ -1903,7 +1991,7 @@ static void light_ctl_set_unack(struct bt_mesh_model *model, state->last_src_addr == ctx->addr && state->last_dst_addr == ctx->recv_dst && (now - state->last_msg_timestamp <= K_SECONDS(6))) { - return; + return 0; } switch (buf->om_len) { @@ -1914,13 +2002,13 @@ static void light_ctl_set_unack(struct bt_mesh_model *model, case 0x02: /* Optional fields are available */ tt = net_buf_simple_pull_u8(buf); if ((tt & 0x3F) == 0x3F) { - return; + return 0; } delay = net_buf_simple_pull_u8(buf); break; default: - return; + return 0; } *ptr_counter = 0; @@ -1947,7 +2035,7 @@ static void light_ctl_set_unack(struct bt_mesh_model *model, light_ctl_tt_values(state, tt, delay); } else { light_ctl_publish(model); - return; + return 0; } /* For Instantaneous Transition */ @@ -1960,9 +2048,10 @@ static void light_ctl_set_unack(struct bt_mesh_model *model, state->transition->just_started = true; light_ctl_publish(model); light_ctl_handler(state); + return 0; } -static void light_ctl_set(struct bt_mesh_model *model, +static int light_ctl_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -1978,7 +2067,7 @@ static void light_ctl_set(struct bt_mesh_model *model, tid = net_buf_simple_pull_u8(buf); if (temp < TEMP_MIN || temp > TEMP_MAX) { - return; + return 0; } now = k_uptime_get(); @@ -1987,7 +2076,7 @@ static void light_ctl_set(struct bt_mesh_model *model, state->last_dst_addr == ctx->recv_dst && (now - state->last_msg_timestamp <= K_SECONDS(6))) { light_ctl_get(model, ctx, buf); - return; + return 0; } switch (buf->om_len) { @@ -1998,13 +2087,13 @@ static void light_ctl_set(struct bt_mesh_model *model, case 0x02: /* Optional fields are available */ tt = net_buf_simple_pull_u8(buf); if ((tt & 0x3F) == 0x3F) { - return; + return 0; } delay = net_buf_simple_pull_u8(buf); break; default: - return; + return 0; } *ptr_counter = 0; @@ -2032,7 +2121,7 @@ static void light_ctl_set(struct bt_mesh_model *model, } else { light_ctl_get(model, ctx, buf); light_ctl_publish(model); - return; + return 0; } /* For Instantaneous Transition */ @@ -2046,14 +2135,16 @@ static void light_ctl_set(struct bt_mesh_model *model, light_ctl_get(model, ctx, buf); light_ctl_publish(model); light_ctl_handler(state); + return 0; } -static void light_ctl_temp_range_get(struct bt_mesh_model *model, +static int light_ctl_temp_range_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 5 + 4); struct light_ctl_state *state = model->user_data; + int rc; state->status_code = RANGE_SUCCESSFULLY_UPDATED; @@ -2062,42 +2153,47 @@ static void light_ctl_temp_range_get(struct bt_mesh_model *model, net_buf_simple_add_le16(msg, state->temp_range_min); net_buf_simple_add_le16(msg, state->temp_range_max); - if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { + rc = bt_mesh_model_send(model, ctx, msg, NULL, NULL); + if (rc) { printk("Unable to send LightCTL Temp Range Status response\n"); } os_mbuf_free_chain(msg); + return rc; } -static void light_ctl_default_get(struct bt_mesh_model *model, +static int light_ctl_default_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 6 + 4); struct light_ctl_state *state = model->user_data; + int rc; bt_mesh_model_msg_init(msg, BT_MESH_MODEL_LIGHT_CTL_DEFAULT_STATUS); net_buf_simple_add_le16(msg, state->lightness_def); net_buf_simple_add_le16(msg, state->temp_def); net_buf_simple_add_le16(msg, state->delta_uv_def); - if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { + rc = bt_mesh_model_send(model, ctx, msg, NULL, NULL); + if (rc) { printk("Unable to send LightCTL Default Status response\n"); } os_mbuf_free_chain(msg); + return rc; } /* Light CTL Setup Server message handlers */ -static void light_ctl_default_publish(struct bt_mesh_model *model) +static int light_ctl_default_publish(struct bt_mesh_model *model) { int err; struct os_mbuf *msg = model->pub->msg; struct light_ctl_state *state = model->user_data; if (model->pub->addr == BT_MESH_ADDR_UNASSIGNED) { - return; + return 0; } bt_mesh_model_msg_init(msg, BT_MESH_MODEL_LIGHT_CTL_DEFAULT_STATUS); @@ -2109,6 +2205,7 @@ static void light_ctl_default_publish(struct bt_mesh_model *model) if (err) { printk("bt_mesh_model_publish err %d\n", err); } + return err; } static bool light_ctl_default_setunack(struct bt_mesh_model *model, @@ -2147,33 +2244,35 @@ static bool light_ctl_default_setunack(struct bt_mesh_model *model, return true; } -static void light_ctl_default_set_unack(struct bt_mesh_model *model, +static int light_ctl_default_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { if (light_ctl_default_setunack(model, ctx, buf) == true) { - light_ctl_default_publish(model); + return light_ctl_default_publish(model); } + return 0; } -static void light_ctl_default_set(struct bt_mesh_model *model, +static int light_ctl_default_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { if (light_ctl_default_setunack(model, ctx, buf) == true) { light_ctl_default_get(model, ctx, buf); - light_ctl_default_publish(model); + return light_ctl_default_publish(model); } + return 0; } -static void light_ctl_temp_range_publish(struct bt_mesh_model *model) +static int light_ctl_temp_range_publish(struct bt_mesh_model *model) { int err; struct os_mbuf *msg = model->pub->msg; struct light_ctl_state *state = model->user_data; if (model->pub->addr == BT_MESH_ADDR_UNASSIGNED) { - return; + return 0; } bt_mesh_model_msg_init(msg, BT_MESH_MODEL_LIGHT_CTL_TEMP_RANGE_STATUS); @@ -2185,6 +2284,7 @@ static void light_ctl_temp_range_publish(struct bt_mesh_model *model) if (err) { printk("bt_mesh_model_publish err %d\n", err); } + return err; } static bool light_ctl_temp_range_setunack(struct bt_mesh_model *model, @@ -2225,27 +2325,29 @@ static bool light_ctl_temp_range_setunack(struct bt_mesh_model *model, return true; } -static void light_ctl_temp_range_set_unack(struct bt_mesh_model *model, +static int light_ctl_temp_range_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { if (light_ctl_temp_range_setunack(model, ctx, buf) == true) { - light_ctl_temp_range_publish(model); + return light_ctl_temp_range_publish(model); } + return 0; } -static void light_ctl_temp_range_set(struct bt_mesh_model *model, +static int light_ctl_temp_range_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { if (light_ctl_temp_range_setunack(model, ctx, buf) == true) { light_ctl_temp_range_get(model, ctx, buf); - light_ctl_temp_range_publish(model); + return light_ctl_temp_range_publish(model); } + return 0; } /* Light CTL Client message handlers */ -static void light_ctl_status(struct bt_mesh_model *model, +static int light_ctl_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -2261,9 +2363,10 @@ static void light_ctl_status(struct bt_mesh_model *model, net_buf_simple_pull_le16(buf)); printk("Remaining Time = %02x\n", net_buf_simple_pull_u8(buf)); } + return 0; } -static void light_ctl_temp_range_status(struct bt_mesh_model *model, +static int light_ctl_temp_range_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -2271,9 +2374,10 @@ static void light_ctl_temp_range_status(struct bt_mesh_model *model, printk("Status Code = %02x\n", net_buf_simple_pull_u8(buf)); printk("Range Min = %04x\n", net_buf_simple_pull_le16(buf)); printk("Range Max = %04x\n", net_buf_simple_pull_le16(buf)); + return 0; } -static void light_ctl_temp_status(struct bt_mesh_model *model, +static int light_ctl_temp_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -2290,9 +2394,10 @@ static void light_ctl_temp_status(struct bt_mesh_model *model, net_buf_simple_pull_le16(buf)); printk("Remaining Time = %02x\n", net_buf_simple_pull_u8(buf)); } + return 0; } -static void light_ctl_default_status(struct bt_mesh_model *model, +static int light_ctl_default_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -2300,10 +2405,11 @@ static void light_ctl_default_status(struct bt_mesh_model *model, printk("Lightness = %04x\n", net_buf_simple_pull_le16(buf)); printk("Temperature = %04x\n", net_buf_simple_pull_le16(buf)); printk("Delta UV = %04x\n", net_buf_simple_pull_le16(buf)); + return 0; } /* Light CTL Temp. Server message handlers */ -static void light_ctl_temp_get(struct bt_mesh_model *model, +static int light_ctl_temp_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -2326,16 +2432,17 @@ static void light_ctl_temp_get(struct bt_mesh_model *model, } os_mbuf_free_chain(msg); + return 0; } -void light_ctl_temp_publish(struct bt_mesh_model *model) +int light_ctl_temp_publish(struct bt_mesh_model *model) { int err; struct os_mbuf *msg = model->pub->msg; struct light_ctl_state *state = model->user_data; if (model->pub->addr == BT_MESH_ADDR_UNASSIGNED) { - return; + return 0; } bt_mesh_model_msg_init(msg, BT_MESH_MODEL_LIGHT_CTL_TEMP_STATUS); @@ -2353,9 +2460,10 @@ void light_ctl_temp_publish(struct bt_mesh_model *model) if (err) { printk("bt_mesh_model_publish err %d\n", err); } + return err; } -static void light_ctl_temp_set_unack(struct bt_mesh_model *model, +static int light_ctl_temp_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -2370,7 +2478,7 @@ static void light_ctl_temp_set_unack(struct bt_mesh_model *model, tid = net_buf_simple_pull_u8(buf); if (temp < TEMP_MIN || temp > TEMP_MAX) { - return; + return 0; } now = k_uptime_get(); @@ -2378,7 +2486,7 @@ static void light_ctl_temp_set_unack(struct bt_mesh_model *model, state->last_src_addr == ctx->addr && state->last_dst_addr == ctx->recv_dst && (now - state->last_msg_timestamp <= K_SECONDS(6))) { - return; + return 0; } switch (buf->om_len) { @@ -2389,13 +2497,13 @@ static void light_ctl_temp_set_unack(struct bt_mesh_model *model, case 0x02: /* Optional fields are available */ tt = net_buf_simple_pull_u8(buf); if ((tt & 0x3F) == 0x3F) { - return; + return 0; } delay = net_buf_simple_pull_u8(buf); break; default: - return; + return 0; } *ptr_counter = 0; @@ -2420,7 +2528,7 @@ static void light_ctl_temp_set_unack(struct bt_mesh_model *model, light_ctl_temp_tt_values(state, tt, delay); } else { light_ctl_temp_publish(model); - return; + return 0; } /* For Instantaneous Transition */ @@ -2432,9 +2540,10 @@ static void light_ctl_temp_set_unack(struct bt_mesh_model *model, state->transition->just_started = true; light_ctl_temp_publish(model); light_ctl_temp_handler(state); + return 0; } -static void light_ctl_temp_set(struct bt_mesh_model *model, +static int light_ctl_temp_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -2449,7 +2558,7 @@ static void light_ctl_temp_set(struct bt_mesh_model *model, tid = net_buf_simple_pull_u8(buf); if (temp < TEMP_MIN || temp > TEMP_MAX) { - return; + return 0; } now = k_uptime_get(); @@ -2457,8 +2566,7 @@ static void light_ctl_temp_set(struct bt_mesh_model *model, state->last_src_addr == ctx->addr && state->last_dst_addr == ctx->recv_dst && (now - state->last_msg_timestamp <= K_SECONDS(6))) { - light_ctl_temp_get(model, ctx, buf); - return; + return light_ctl_temp_get(model, ctx, buf); } switch (buf->om_len) { @@ -2469,13 +2577,13 @@ static void light_ctl_temp_set(struct bt_mesh_model *model, case 0x02: /* Optional fields are available */ tt = net_buf_simple_pull_u8(buf); if ((tt & 0x3F) == 0x3F) { - return; + return 0; } delay = net_buf_simple_pull_u8(buf); break; default: - return; + return 0; } *ptr_counter = 0; @@ -2501,7 +2609,7 @@ static void light_ctl_temp_set(struct bt_mesh_model *model, } else { light_ctl_temp_get(model, ctx, buf); light_ctl_temp_publish(model); - return; + return 0; } /* For Instantaneous Transition */ @@ -2514,6 +2622,7 @@ static void light_ctl_temp_set(struct bt_mesh_model *model, light_ctl_temp_get(model, ctx, buf); light_ctl_temp_publish(model); light_ctl_temp_handler(state); + return 0; } /* message handlers (End) */ diff --git a/apps/blemesh_models_example_2/src/device_composition.h b/apps/blemesh_models_example_2/src/device_composition.h index d0f054ee2b..1b5bf5f72a 100644 --- a/apps/blemesh_models_example_2/src/device_composition.h +++ b/apps/blemesh_models_example_2/src/device_composition.h @@ -167,11 +167,11 @@ extern struct bt_mesh_model s0_models[]; extern const struct bt_mesh_comp comp; -void gen_onoff_publish(struct bt_mesh_model *model); -void gen_level_publish(struct bt_mesh_model *model); -void light_lightness_publish(struct bt_mesh_model *model); -void light_lightness_linear_publish(struct bt_mesh_model *model); -void light_ctl_publish(struct bt_mesh_model *model); -void light_ctl_temp_publish(struct bt_mesh_model *model); +int gen_onoff_publish(struct bt_mesh_model *model); +int gen_level_publish(struct bt_mesh_model *model); +int light_lightness_publish(struct bt_mesh_model *model); +int light_lightness_linear_publish(struct bt_mesh_model *model); +int light_ctl_publish(struct bt_mesh_model *model); +int light_ctl_temp_publish(struct bt_mesh_model *model); #endif diff --git a/apps/blemesh_models_example_2/src/main.c b/apps/blemesh_models_example_2/src/main.c index 741367b401..979395d219 100644 --- a/apps/blemesh_models_example_2/src/main.c +++ b/apps/blemesh_models_example_2/src/main.c @@ -214,12 +214,9 @@ void bt_initialized(void) short_time_multireset_bt_mesh_unprovisioning(); } -int main(void) +int +mynewt_main(int argc, char **argv) { -#ifdef ARCH_sim - mcu_sim_parse_args(argc, argv); -#endif - /* Initialize OS */ sysinit(); diff --git a/apps/blemesh_models_example_2/syscfg.yml b/apps/blemesh_models_example_2/syscfg.yml index b56e9d2d00..4ba0e1b7e2 100644 --- a/apps/blemesh_models_example_2/syscfg.yml +++ b/apps/blemesh_models_example_2/syscfg.yml @@ -17,6 +17,10 @@ # syscfg.vals: + CONSOLE_IMPLEMENTATION: full + LOG_IMPLEMENTATION: full + STATS_IMPLEMENTATION: full + # Set log level to info (disable debug logging). LOG_LEVEL: 1 diff --git a/apps/blemesh_shell/pkg.yml b/apps/blemesh_shell/pkg.yml index e4852f6fa5..df3a45d444 100644 --- a/apps/blemesh_shell/pkg.yml +++ b/apps/blemesh_shell/pkg.yml @@ -24,14 +24,12 @@ pkg.keywords: pkg.deps: - "@apache-mynewt-core/kernel/os" - - "@apache-mynewt-core/sys/console/full" - - "@apache-mynewt-core/sys/log/full" + - "@apache-mynewt-core/sys/console" + - "@apache-mynewt-core/sys/log" - "@apache-mynewt-core/sys/log/modlog" - - "@apache-mynewt-core/sys/stats/full" + - "@apache-mynewt-core/sys/stats" - "@apache-mynewt-core/sys/shell" - - nimble/controller - nimble/host - nimble/host/services/gap - nimble/host/services/gatt - nimble/host/store/config - - nimble/transport/ram diff --git a/apps/blemesh_shell/src/main.c b/apps/blemesh_shell/src/main.c index fcf80127f0..ee6f763e73 100644 --- a/apps/blemesh_shell/src/main.c +++ b/apps/blemesh_shell/src/main.c @@ -17,8 +17,6 @@ * under the License. */ -#define MESH_LOG_MODULE BLE_MESH_LOG - #include #include "os/mynewt.h" #include "mesh/mesh.h" @@ -95,7 +93,7 @@ blemesh_on_sync(void) } int -main(void) +mynewt_main(int argc, char **argv) { /* Initialize OS */ sysinit(); diff --git a/apps/blemesh_shell/syscfg.yml b/apps/blemesh_shell/syscfg.yml index 0756e46fe5..a450ae4bea 100644 --- a/apps/blemesh_shell/syscfg.yml +++ b/apps/blemesh_shell/syscfg.yml @@ -17,6 +17,10 @@ # syscfg.vals: + CONSOLE_IMPLEMENTATION: full + LOG_IMPLEMENTATION: full + STATS_IMPLEMENTATION: full + # Enable the shell task. SHELL_TASK: 1 diff --git a/apps/bleprph/pkg.yml b/apps/bleprph/pkg.yml index 38b6e4451d..6a7a354cfd 100644 --- a/apps/bleprph/pkg.yml +++ b/apps/bleprph/pkg.yml @@ -29,10 +29,10 @@ pkg.deps: - "@apache-mynewt-core/mgmt/imgmgr" - "@apache-mynewt-core/mgmt/smp" - "@apache-mynewt-core/mgmt/smp/transport/ble" - - "@apache-mynewt-core/sys/console/full" - - "@apache-mynewt-core/sys/log/full" + - "@apache-mynewt-core/sys/console" + - "@apache-mynewt-core/sys/log" - "@apache-mynewt-core/sys/log/modlog" - - "@apache-mynewt-core/sys/stats/full" + - "@apache-mynewt-core/sys/stats" - "@apache-mynewt-core/sys/sysinit" - "@apache-mynewt-core/sys/id" - nimble/host @@ -42,4 +42,3 @@ pkg.deps: - nimble/host/services/gatt - nimble/host/store/config - nimble/host/util - - nimble/transport diff --git a/apps/bleprph/src/main.c b/apps/bleprph/src/main.c index 66f9baccb4..b9f2d26416 100644 --- a/apps/bleprph/src/main.c +++ b/apps/bleprph/src/main.c @@ -303,7 +303,7 @@ bleprph_on_sync(void) * @return int NOTE: this function should never return! */ int -main(void) +mynewt_main(int argc, char **argv) { #if MYNEWT_VAL(BLE_SVC_DIS_FIRMWARE_REVISION_READ_PERM) >= 0 struct image_version ver; diff --git a/apps/bleprph/syscfg.yml b/apps/bleprph/syscfg.yml index e00eb3b8e9..5f417d7cd7 100644 --- a/apps/bleprph/syscfg.yml +++ b/apps/bleprph/syscfg.yml @@ -38,6 +38,10 @@ syscfg.defs: value: "(int[]){ LED_1, LED_2, LED_3 }" syscfg.vals: + CONSOLE_IMPLEMENTATION: full + LOG_IMPLEMENTATION: full + STATS_IMPLEMENTATION: full + # Disable central and observer roles. BLE_ROLE_BROADCASTER: 1 BLE_ROLE_CENTRAL: 0 @@ -58,7 +62,7 @@ syscfg.vals: CONFIG_MGMT: 1 # OS main/default task - OS_MAIN_STACK_SIZE: 512 + OS_MAIN_STACK_SIZE: 768 # Lots of smaller mbufs are required for smp using typical BLE ATT MTU # values. diff --git a/apps/blestress/pkg.yml b/apps/blestress/pkg.yml index b23358c564..e56cdd64a2 100644 --- a/apps/blestress/pkg.yml +++ b/apps/blestress/pkg.yml @@ -26,14 +26,12 @@ pkg.deps: - "@mcuboot/boot/bootutil" - "@apache-mynewt-core/sys/log/modlog" - "@apache-mynewt-core/kernel/os" - - "@apache-mynewt-core/sys/console/full" - - "@apache-mynewt-core/sys/log/full" - - "@apache-mynewt-core/sys/stats/full" + - "@apache-mynewt-core/sys/console" + - "@apache-mynewt-core/sys/log" + - "@apache-mynewt-core/sys/stats" - "@apache-mynewt-core/sys/id" - - "@apache-mynewt-nimble/nimble/controller" - "@apache-mynewt-nimble/nimble/host" - "@apache-mynewt-nimble/nimble/host/util" - "@apache-mynewt-nimble/nimble/host/services/gap" - "@apache-mynewt-nimble/nimble/host/services/gatt" - "@apache-mynewt-nimble/nimble/host/store/config" - - "@apache-mynewt-nimble/nimble/transport/ram" diff --git a/apps/blestress/src/main.c b/apps/blestress/src/main.c index ec28ed8a65..c19e0cdd32 100644 --- a/apps/blestress/src/main.c +++ b/apps/blestress/src/main.c @@ -66,7 +66,7 @@ stress_test_on_sync(void) * @return int NOTE: this function should never return! */ int -main(void) +mynewt_main(int argc, char **argv) { int rc; diff --git a/apps/blestress/src/rx_stress.c b/apps/blestress/src/rx_stress.c index 440966adcc..5e086733cb 100644 --- a/apps/blestress/src/rx_stress.c +++ b/apps/blestress/src/rx_stress.c @@ -20,6 +20,10 @@ #include #include "rx_stress.h" +#ifndef min +#define min(a, b) ((a) < (b) ? (a) : (b)) +#endif + /* UUID128 of stress test use cases*/ static uint8_t rx_stress_uuid128[STRESS_UUIDS_NUM][16]; @@ -60,7 +64,7 @@ static struct os_sem rx_stress_main_sem; static void rx_stress_on_test_finish(int test_num) { - console_printf("\033[0;32m\nStress test %d completed\033[0m\n", test_num); + MODLOG_DFLT(INFO, "\nStress test %d completed\n", test_num); os_sem_release(&rx_stress_main_sem); } @@ -72,7 +76,8 @@ rx_stress_adv_start(uint8_t instance) /* Resume advertising earlier configured instance */ rc = ble_gap_ext_adv_start(instance, 0, 0); assert (rc == 0 || rc == 2); - MODLOG_DFLT(INFO, "Instance %d started; rc: %d\n", instance, rc); + MODLOG_DFLT(DEBUG, "Ext Adv - Test Instance %d started; rc: %d\n", + instance, rc); return rc; } @@ -109,8 +114,7 @@ rx_stress_simple_adv(struct rx_stress_adv_set *adv_set) /* Determine own address type */ rc = ble_hs_id_infer_auto(0, &own_addr_type); if (rc != 0) { - MODLOG_DFLT(ERROR, "\033[0;31mError determining own address type; " - "rc=%d\033[0m\n", rc); + MODLOG_DFLT(ERROR, "Error determining own address type; rc=%d\n", rc); return; } @@ -155,7 +159,8 @@ rx_stress_simple_adv(struct rx_stress_adv_set *adv_set) assert (rc == 0); if (own_addr_type == 0) { - memcpy(addr.val, MYNEWT_VAL(BLE_PUBLIC_DEV_ADDR), 6); + rc = ble_hs_id_copy_addr(BLE_ADDR_PUBLIC, addr.val, NULL); + assert (rc == 0); } else { rc = ble_hs_id_gen_rnd(1, &addr); assert (rc == 0); @@ -208,7 +213,7 @@ rx_stress_0_gap_event(struct ble_gap_event *event, void *arg) if (event->connect.status == 0) { MODLOG_DFLT(INFO, "\nConnection established; status=%d; num=%d\n", event->connect.status, - ++rx_stress_ctx->con_stat[0].num); + ++rx_stress_ctx->con_stat[1].num); /* Stop test advert */ ble_gap_ext_adv_stop(TEST_INSTANCE); @@ -221,9 +226,9 @@ rx_stress_0_gap_event(struct ble_gap_event *event, void *arg) } return 0; case BLE_GAP_EVENT_DISCONNECT: - MODLOG_DFLT(INFO, "Disconnect; reason=%d \n", + MODLOG_DFLT(DEBUG, "Disconnect; reason=%d \n", event->disconnect.reason); - console_printf("\033[0;32mReceived signal to switch test\033[0m\n"); + MODLOG_DFLT(INFO, "Received signal to switch test\n"); /* Add token to semaphore. Main task will start next test. */ os_sem_release(&rx_stress_main_sem); @@ -242,22 +247,24 @@ rx_stress_2_gap_event(struct ble_gap_event *event, void *arg) ++rx_stress_ctx->con_stat[2].attempts_num; /* A new connection was established or a connection attempt failed. */ if (event->connect.status == 0) { - MODLOG_DFLT(INFO, "\nConnection established; status=%d; num=%d\n", + MODLOG_DFLT(INFO, "\nConnection established; " + "status=%d; num=%d; conn handle=%d;\n", event->connect.status, - ++rx_stress_ctx->con_stat[2].num); + ++rx_stress_ctx->con_stat[2].num, + event->connect.conn_handle); } else { /* Connection failed; resume advertising. */ - MODLOG_DFLT(INFO, "Connection failed; status=%d ", - event->connect.status); + MODLOG_DFLT(WARN, "Connection failed; status=%d; conn handle=%d;" + "\n ", + event->connect.status, event->connect.conn_handle); rx_stress_adv_start(TEST_INSTANCE); } return 0; case BLE_GAP_EVENT_DISCONNECT: - MODLOG_DFLT(INFO, "Disconnect; reason=%d \n", + MODLOG_DFLT(DEBUG, "Disconnect; reason=%d \n", event->disconnect.reason); - console_printf("\033[0;32m>\033[0m"); if (rx_stress_ctx->con_stat[2].num >= MYNEWT_VAL(BLE_STRESS_REPEAT)) { rx_stress_on_test_finish(2); } else { @@ -267,7 +274,7 @@ rx_stress_2_gap_event(struct ble_gap_event *event, void *arg) return 0; default: - MODLOG_DFLT(INFO, "Other event occurs=%d\n", event->type); + MODLOG_DFLT(DEBUG, "Other event occurs=%d\n", event->type); return 0; } } @@ -280,19 +287,24 @@ rx_stress_3_gap_event(struct ble_gap_event *event, void *arg) ++rx_stress_ctx->con_stat[3].attempts_num; /* A new connection was established or a connection attempt failed. */ if (event->connect.status == 0) { - MODLOG_DFLT(INFO, "\nConnection established; status=%d; num=%d\n", + MODLOG_DFLT(INFO, "\nConnection established; status=%d; num=%d;" + " handle=%d;\n", event->connect.status, - ++rx_stress_ctx->con_stat[3].num); + ++rx_stress_ctx->con_stat[3].num, + event->connect.conn_handle); } else { /* Connection failed; resume advertising. */ + MODLOG_DFLT(WARN, "Connection failed; status=%d; conn handle=%d;" + "\n ", + event->connect.status, event->connect.conn_handle); + rx_stress_adv_start(TEST_INSTANCE); } return 0; case BLE_GAP_EVENT_DISCONNECT: - MODLOG_DFLT(INFO, "Disconnect; reason=%d \n", + MODLOG_DFLT(DEBUG, "Disconnect; reason=%d \n", event->disconnect.reason); - console_printf("\033[0;32m>\033[0m"); if (rx_stress_ctx->con_stat[3].num >= MYNEWT_VAL(BLE_STRESS_REPEAT)) { rx_stress_on_test_finish(3); } else { @@ -302,7 +314,7 @@ rx_stress_3_gap_event(struct ble_gap_event *event, void *arg) return 0; default: - MODLOG_DFLT(INFO, "Other event occurs=%d\n", event->type); + MODLOG_DFLT(DEBUG, "Other event occurs=%d\n", event->type); return 0; } } @@ -318,7 +330,7 @@ rx_stress_4_gap_event(struct ble_gap_event *event, void *arg) ++rx_stress_ctx->con_stat[4].attempts_num; /* A new connection was established or a connection attempt failed. */ if (event->connect.status == 0) { - MODLOG_DFLT(INFO, "Connection established; status=%d; num=%d", + MODLOG_DFLT(DEBUG, "Connection established; status=%d; num=%d", event->connect.status, ++rx_stress_ctx->con_stat[4].num); @@ -328,14 +340,14 @@ rx_stress_4_gap_event(struct ble_gap_event *event, void *arg) rx_stress_ctx->conn_handle = event->connect.conn_handle; } else { /* Connection failed; resume advertising. */ - MODLOG_DFLT(INFO, "Connection failed; status=%d ", - event->connect.status); + MODLOG_DFLT(WARN, "Connection failed; status=%d; conn handle=%d", + event->connect.status, event->connect.conn_handle); rx_stress_adv_start(TEST_INSTANCE); } return 0; case BLE_GAP_EVENT_DISCONNECT: - MODLOG_DFLT(INFO, "Disconnect; reason=%d ", event->disconnect.reason); + MODLOG_DFLT(DEBUG, "Disconnect; reason=%d ", event->disconnect.reason); if (rx_stress_ctx->con_stat[4].prms_upd_num >= MYNEWT_VAL(BLE_STRESS_REPEAT)) { rx_stress_on_test_finish(4); @@ -347,11 +359,11 @@ rx_stress_4_gap_event(struct ble_gap_event *event, void *arg) case BLE_GAP_EVENT_CONN_UPDATE: if (event->conn_update.status != 0) { - MODLOG_DFLT(INFO, "Connection update failed\n"); + MODLOG_DFLT(WARN, "Connection update failed\n; conn handle=%d", + event->connect.conn_handle); } else { MODLOG_DFLT(INFO, "Connection updated; num=%d\n", ++rx_stress_ctx->con_stat[4].prms_upd_num); - console_printf("\033[0;32m>\033[0m"); } if (rx_stress_ctx->con_stat[4].prms_upd_num >= @@ -363,7 +375,7 @@ rx_stress_4_gap_event(struct ble_gap_event *event, void *arg) return 0; default: - MODLOG_DFLT(INFO, "Other event occurs=%d\n", event->type); + MODLOG_DFLT(DEBUG, "Other event occurs=%d\n", event->type); return 0; } } @@ -392,13 +404,12 @@ rx_stress_5_con_update(void) rc = ble_gap_update_params(rx_stress_ctx->conn_handle, ¶ms); if (rc == BLE_HS_ENOTCONN) { - MODLOG_DFLT(INFO, "Device disconnected. Connection update failed\n"); + MODLOG_DFLT(ERROR, "Device disconnected. Connection update failed\n"); assert(0); } if (rc != 0) { - MODLOG_DFLT(ERROR, "\033[0;31mError during connection update; " - "rc=%d\033[0m\n", rc); + MODLOG_DFLT(ERROR, "Error during connection update; rc=%d\n", rc); assert(0); } @@ -417,7 +428,7 @@ rx_stress_5_gap_event(struct ble_gap_event *event, void *arg) /* A new connection was established or a connection attempt failed. */ if (event->connect.status == 0) { - MODLOG_DFLT(INFO, "Connection established; status=%d; num=%d", + MODLOG_DFLT(DEBUG, "Connection established; status=%d; num=%d", event->connect.status, ++rx_stress_ctx->con_stat[5].num); @@ -431,14 +442,14 @@ rx_stress_5_gap_event(struct ble_gap_event *event, void *arg) assert(rc == 0); } else { /* Connection failed; resume advertising. */ - MODLOG_DFLT(INFO, "Connection failed; status=%d ", - event->connect.status); + MODLOG_DFLT(WARN, "Connection failed; status=%d; conn handle=%d", + event->connect.status, event->connect.conn_handle); rx_stress_adv_start(TEST_INSTANCE); } return 0; case BLE_GAP_EVENT_DISCONNECT: - MODLOG_DFLT(INFO, "Disconnect; reason=%d ", event->disconnect.reason); + MODLOG_DFLT(DEBUG, "Disconnect; reason=%d ", event->disconnect.reason); if (rx_stress_ctx->con_stat[5].prms_upd_num >= MYNEWT_VAL(BLE_STRESS_REPEAT)) { rx_stress_on_test_finish(5); @@ -450,11 +461,10 @@ rx_stress_5_gap_event(struct ble_gap_event *event, void *arg) case BLE_GAP_EVENT_CONN_UPDATE: if (event->conn_update.status != 0) { - MODLOG_DFLT(INFO, "Connection update failed\n"); + MODLOG_DFLT(DEBUG, "Connection update failed\n"); } else { MODLOG_DFLT(INFO, "Connection updated; num=%d\n", ++rx_stress_ctx->con_stat[5].prms_upd_num); - console_printf("\033[0;32m>\033[0m"); } if (rx_stress_ctx->con_stat[5].prms_upd_num >= @@ -494,7 +504,7 @@ rx_stress_7_gap_event(struct ble_gap_event *event, void *arg) /* A new connection was established or a connection attempt failed. */ if (event->connect.status == 0) { - MODLOG_DFLT(INFO, "Connection established; status=%d; num=%d", + MODLOG_DFLT(DEBUG, "Connection established; status=%d; num=%d", event->connect.status, ++rx_stress_ctx->con_stat[7].num); @@ -504,14 +514,14 @@ rx_stress_7_gap_event(struct ble_gap_event *event, void *arg) rx_stress_ctx->conn_handle = event->connect.conn_handle; } else { /* Connection failed; resume advertising. */ - MODLOG_DFLT(INFO, "Connection failed; status=%d ", + MODLOG_DFLT(DEBUG, "Connection failed; status=%d ", event->connect.status); rx_stress_adv_start(TEST_INSTANCE); } return 0; case BLE_GAP_EVENT_DISCONNECT: - MODLOG_DFLT(INFO, "Disconnect; reason=%d ", event->disconnect.reason); + MODLOG_DFLT(DEBUG, "Disconnect; reason=%d ", event->disconnect.reason); if (rx_stress_ctx->con_stat[7].phy_upd_num >= MYNEWT_VAL(BLE_STRESS_REPEAT)) { rx_stress_on_test_finish(7); @@ -523,11 +533,11 @@ rx_stress_7_gap_event(struct ble_gap_event *event, void *arg) case BLE_GAP_EVENT_PHY_UPDATE_COMPLETE: if (event->phy_updated.status != 0) { - MODLOG_DFLT(INFO, "PHY update failed\n"); + MODLOG_DFLT(WARN, "PHY update failed\n"); } else { - MODLOG_DFLT(INFO, "PHY updated; num=%d\n", - ++rx_stress_ctx->con_stat[7].phy_upd_num); - console_printf("\033[0;32m>\033[0m"); + MODLOG_DFLT(INFO, "PHY updated; num=%d; rx:%d, tx:%d\n", + ++rx_stress_ctx->con_stat[7].phy_upd_num, + event->phy_updated.rx_phy, event->phy_updated.tx_phy); } if (rx_stress_ctx->con_stat[7].phy_upd_num >= @@ -592,14 +602,16 @@ rx_stress_8_con_update(void) rc = ble_gap_set_prefered_le_phy(rx_stress_ctx->conn_handle, tx_phys_mask, rx_phys_mask, 0); + MODLOG_DFLT(INFO, "Set PHY params: tx_phys_mask=%d; rx_phys_mask=%d\n", + tx_phys_mask, rx_phys_mask); + if (rc == BLE_HS_ENOTCONN) { MODLOG_DFLT(INFO, "Device disconnected. Connection update failed\n"); return rc; } if (rc != 0) { - MODLOG_DFLT(ERROR, "\033[0;31mError during PHY update; " - "rc=%d\033[0m\n", rc); + MODLOG_DFLT(ERROR, "Error during PHY update; rc=%d\n", rc); } return rc; @@ -617,7 +629,7 @@ rx_stress_8_gap_event(struct ble_gap_event *event, void *arg) /* A new connection was established or a connection attempt failed. */ if (event->connect.status == 0) { - MODLOG_DFLT(INFO, "Connection established; status=%d; num=%d", + MODLOG_DFLT(DEBUG, "Connection established; status=%d; num=%d", event->connect.status, ++rx_stress_ctx->con_stat[8].num); @@ -631,14 +643,14 @@ rx_stress_8_gap_event(struct ble_gap_event *event, void *arg) assert(rc == 0); } else { /* Connection failed; resume advertising. */ - MODLOG_DFLT(INFO, "Connection failed; status=%d ", + MODLOG_DFLT(DEBUG, "Connection failed; status=%d ", event->connect.status); rx_stress_adv_start(TEST_INSTANCE); } return 0; case BLE_GAP_EVENT_DISCONNECT: - MODLOG_DFLT(INFO, "Disconnect; reason=%d ", event->disconnect.reason); + MODLOG_DFLT(DEBUG, "Disconnect; reason=%d ", event->disconnect.reason); if (rx_stress_ctx->con_stat[8].phy_upd_num >= MYNEWT_VAL(BLE_STRESS_REPEAT)) { rx_stress_on_test_finish(8); @@ -650,12 +662,11 @@ rx_stress_8_gap_event(struct ble_gap_event *event, void *arg) case BLE_GAP_EVENT_PHY_UPDATE_COMPLETE: if (event->phy_updated.status != 0) { - MODLOG_DFLT(INFO, "PHY update failed\n"); + MODLOG_DFLT(WARN, "PHY update failed\n"); } else { MODLOG_DFLT(INFO, "PHY updated; num=%d; rx:%d, tx:%d\n", ++rx_stress_ctx->con_stat[8].phy_upd_num, event->phy_updated.rx_phy, event->phy_updated.tx_phy); - console_printf("\033[0;32m>\033[0m"); } if (rx_stress_ctx->con_stat[8].phy_upd_num >= @@ -685,10 +696,9 @@ rx_stress_9_gap_event(struct ble_gap_event *event, void *arg) /* A new connection was established or a connection attempt failed. */ if (event->connect.status == 0) { - MODLOG_DFLT(INFO, "Connection established; status=%d; num=%d", + MODLOG_DFLT(INFO, "Connection established; status=%d; num=%d\n", event->connect.status, ++rx_stress_ctx->con_stat[9].num); - console_printf("\033[0;32m>\033[0m"); /* Remember max number of established connections */ if (rx_stress_ctx->con_stat[9].num > @@ -697,14 +707,14 @@ rx_stress_9_gap_event(struct ble_gap_event *event, void *arg) } } else { /* Connection failed; resume advertising. */ - MODLOG_DFLT(INFO, "Connection failed; status=%d ", + MODLOG_DFLT(INFO, "Connection failed; status=%d\n", event->connect.status); } return 0; case BLE_GAP_EVENT_DISCONNECT: - MODLOG_DFLT(INFO, "Disconnect; reason=%d ", event->disconnect.reason); - console_printf("\033[0;31mX\033[0m"); + MODLOG_DFLT(INFO, "Disconnect; reason=%d; conn handle=%d\n", + event->disconnect.reason, event->connect.conn_handle); MODLOG_DFLT(INFO, "Connections num: %d\n", --rx_stress_ctx->con_stat[9].num); @@ -730,7 +740,7 @@ rx_stress_9_gap_event(struct ble_gap_event *event, void *arg) return 0; default: - MODLOG_DFLT(INFO, "Other event occurs=%d\n", event->type); + MODLOG_DFLT(DEBUG, "Other event occurs=%d\n", event->type); } return 0; } @@ -739,9 +749,11 @@ static void tx_stress_10_l2cap_update_event(uint16_t conn_handle, int status, void *arg) { if (status == 0) { - MODLOG_DFLT(INFO, "L2CAP params updated\n"); + MODLOG_DFLT(INFO, "L2CAP params updated; conn handle=%d\n", + conn_handle); } else { - MODLOG_DFLT(INFO, "L2CAP params update failed; rc=%d\n", status); + MODLOG_DFLT(ERROR, "L2CAP params update failed; rc=%d; conn " + "handle=%d\n", status, conn_handle); assert(0); } } @@ -759,7 +771,7 @@ rx_stress_10_l2cap_event(struct ble_l2cap_event *event, void *arg) switch (event->type) { case BLE_L2CAP_EVENT_COC_CONNECTED: if (event->connect.status) { - MODLOG_DFLT(INFO, "LE COC error: %d\n", event->connect.status); + MODLOG_DFLT(ERROR, "LE COC error: %d\n", event->connect.status); return 0; } @@ -800,7 +812,7 @@ rx_stress_10_l2cap_event(struct ble_l2cap_event *event, void *arg) case BLE_L2CAP_EVENT_COC_DATA_RECEIVED: stress_l2cap_coc_recv(event->receive.chan, event->receive.sdu_rx); - MODLOG_DFLT(INFO, "L2CAP server received data; num=%d\n", + MODLOG_DFLT(DEBUG, "L2CAP server received data; num=%d\n", ++rx_stress_ctx->rcv_num); rx_stress_ctx->chan = event->receive.chan; @@ -834,7 +846,7 @@ rx_stress_10_l2cap_event(struct ble_l2cap_event *event, void *arg) /* Get mbuf for adv data */ data_buf = os_msys_get_pkthdr(data_len, 0); - MODLOG_DFLT(INFO, "Data buf %s\n", data_buf ? "OK" : "NOK"); + MODLOG_DFLT(DEBUG, "Data buf %s\n", data_buf ? "OK" : "NOK"); assert(data_buf != NULL); /* Fill mbuf with the pattern */ @@ -842,13 +854,13 @@ rx_stress_10_l2cap_event(struct ble_l2cap_event *event, void *arg) /* Send data */ rc = ble_l2cap_send(rx_stress_ctx->chan, data_buf); - MODLOG_DFLT(INFO, "Return code=%d\n", rc); + MODLOG_DFLT(DEBUG, "Return code=%d\n", rc); if (rc) { if (rc == BLE_HS_ESTALLED) { - MODLOG_DFLT(INFO, "L2CAP stalled - waiting\n"); + MODLOG_DFLT(ERROR, "L2CAP stalled - waiting\n"); stalled = true; } else { - MODLOG_DFLT(INFO, "Sending data via L2CAP failed with error " + MODLOG_DFLT(ERROR, "Sending data via L2CAP failed with error " "code %d\n", rc); } } @@ -904,12 +916,13 @@ rx_stress_11_gap_event(struct ble_gap_event *event, void *arg) ++rx_stress_ctx->con_stat[11].attempts_num; /* A new connection was established or a connection attempt failed. */ if (event->connect.status == 0) { - MODLOG_DFLT(INFO, "\nConnection established; status=%d; num=%d\n", - event->connect.status, - ++rx_stress_ctx->con_stat[11].num); + MODLOG_DFLT(INFO, "\nConnection established; status=%d; num=%d; " + "conn handle=%d\n", event->connect.status, + ++rx_stress_ctx->con_stat[11].num, + event->connect.conn_handle); } else { - MODLOG_DFLT(INFO, "\033[0;31mError: connection attempt failed; " - "status=%d\033[0m\n", event->connect.status); + MODLOG_DFLT(ERROR, "Error: connection attempt failed; status=%d\n", + event->connect.status); } ble_gap_terminate(event->connect.conn_handle, @@ -917,9 +930,8 @@ rx_stress_11_gap_event(struct ble_gap_event *event, void *arg) return 0; case BLE_GAP_EVENT_DISCONNECT: - MODLOG_DFLT(INFO, "Disconnect; reason=%d \n", + MODLOG_DFLT(DEBUG, "Disconnect; reason=%d \n", event->disconnect.reason); - console_printf("\033[0;32m>\033[0m"); if (rx_stress_ctx->con_stat[11].num >= MYNEWT_VAL(BLE_STRESS_REPEAT)) { rx_stress_on_test_finish(11); } else { @@ -929,7 +941,7 @@ rx_stress_11_gap_event(struct ble_gap_event *event, void *arg) return 0; default: - MODLOG_DFLT(INFO, "Other event occurs=%d\n", event->type); + MODLOG_DFLT(DEBUG, "Other event occurs=%d\n", event->type); return 0; } } @@ -954,19 +966,19 @@ rx_stress_12_gap_event(struct ble_gap_event *event, void *arg) break; } else { /* Connection failed; resume advertising */ - MODLOG_DFLT(INFO, "Connection failed; status=%d ", + MODLOG_DFLT(DEBUG, "Connection failed; status=%d ", event->connect.status); } return 0; case BLE_GAP_EVENT_DISCONNECT: - MODLOG_DFLT(INFO, "Disconnect; reason=%d \n", + MODLOG_DFLT(DEBUG, "Disconnect; reason=%d \n", event->disconnect.reason); rx_stress_ctx->s12_notif_time = rx_stress_ctx->time_sum / rx_stress_ctx->send_num; - MODLOG_DFLT(INFO, "Average time: %d us\n", + MODLOG_DFLT(DEBUG, "Average time: %d us\n", rx_stress_ctx->s12_notif_time); rx_stress_on_test_finish(12); @@ -974,7 +986,7 @@ rx_stress_12_gap_event(struct ble_gap_event *event, void *arg) case BLE_GAP_EVENT_NOTIFY_TX: rx_stress_ctx->end_us = os_get_uptime_usec(); - MODLOG_DFLT(INFO, "Notify TX event\n"); + MODLOG_DFLT(DEBUG, "Notify TX event\n"); if (!event->notify_tx.status) { /* Send next only after previous indication is done */ @@ -990,13 +1002,12 @@ rx_stress_12_gap_event(struct ble_gap_event *event, void *arg) /* Time of data sending */ us = rx_stress_ctx->end_us - rx_stress_ctx->begin_us; - console_printf("Indication time: %lld\n", us); + MODLOG_DFLT(DEBUG, "Indication time: %lld\n", us); rx_stress_ctx->time_sum += us; - console_printf("\033[0;32m>\033[0m"); break; default: - MODLOG_DFLT(INFO, "Other event occurs=%d\n", event->type); + MODLOG_DFLT(DEBUG, "Other event occurs=%d\n", event->type); return 0; } @@ -1004,18 +1015,30 @@ rx_stress_12_gap_event(struct ble_gap_event *event, void *arg) rx_stress_ctx->begin_us = os_get_uptime_usec(); om = os_msys_get_pkthdr(om_len, 0); stress_fill_mbuf_with_pattern(om, om_len); - rc = ble_gattc_indicate_custom(rx_stress_ctx->conn_handle, hrs_hrm_handle, + rc = ble_gatts_indicate_custom(rx_stress_ctx->conn_handle, hrs_hrm_handle, om); assert(rc == 0); return 0; } -static int -rx_stress_13_gap_event(struct ble_gap_event *event, void *arg) +static struct ble_npl_event rx_stress_13_notify_ev; + +static void +rx_stress_13_notify_ev_func(struct ble_npl_event *ev) { + struct os_mbuf *om; int rc; - struct os_mbuf *om = NULL; + om = ble_hs_mbuf_from_flat(test_6_pattern, 10); + rc = ble_gatts_notify_custom(rx_stress_ctx->conn_handle, + hrs_hrm_handle, om); + assert(rc == 0); + +} + +static int +rx_stress_13_gap_event(struct ble_gap_event *event, void *arg) +{ switch (event->type) { case BLE_GAP_EVENT_CONNECT: /* A new connection was established or a connection attempt failed */ @@ -1026,6 +1049,9 @@ rx_stress_13_gap_event(struct ble_gap_event *event, void *arg) rx_stress_ctx->conn_handle = event->connect.conn_handle; rx_stress_ctx->begin_us = os_get_uptime_usec(); + + ble_npl_eventq_put((struct ble_npl_eventq *)os_eventq_dflt_get(), + &rx_stress_13_notify_ev); break; } else { /* Connection failed; resume advertising */ @@ -1045,7 +1071,7 @@ rx_stress_13_gap_event(struct ble_gap_event *event, void *arg) rx_stress_ctx->s13_notif_time = rx_stress_ctx->time_sum / rx_stress_ctx->send_num; - MODLOG_DFLT(INFO, "Average time: %lld us\n", + MODLOG_DFLT(INFO, "Average time: %d us\n", rx_stress_ctx->s13_notif_time); rx_stress_on_test_finish(13); return 0; @@ -1061,6 +1087,9 @@ rx_stress_13_gap_event(struct ble_gap_event *event, void *arg) BLE_ERR_REM_USER_CONN_TERM); return 0; } + + ble_npl_eventq_put((struct ble_npl_eventq *)os_eventq_dflt_get(), + &rx_stress_13_notify_ev); break; default: @@ -1068,10 +1097,6 @@ rx_stress_13_gap_event(struct ble_gap_event *event, void *arg) return 0; } - om = ble_hs_mbuf_from_flat(test_6_pattern, 10); - rc = ble_gattc_notify_custom(rx_stress_ctx->conn_handle, - hrs_hrm_handle, om); - assert(rc == 0); return 0; } @@ -1092,55 +1117,53 @@ rx_stress_14_gap_event(struct ble_gap_event *event, void *arg) rx_stress_ctx->conn_handle = event->connect.conn_handle; } else { /* Connection failed; resume advertising */ - MODLOG_DFLT(INFO, "Connection failed; status=%d ", + MODLOG_DFLT(DEBUG, "Connection failed; status=%d ", event->connect.status); assert(0); } return 0; case BLE_GAP_EVENT_DISCONNECT: - MODLOG_DFLT(INFO, "Disconnect; reason=%d \n", + MODLOG_DFLT(DEBUG, "Disconnect; reason=%d \n", event->disconnect.reason); rx_stress_ctx->s14_notif_time = rx_stress_ctx->time_sum / rx_stress_ctx->send_num; - MODLOG_DFLT(INFO, "Average time: %d us\n", + MODLOG_DFLT(DEBUG, "Average time: %d us\n", rx_stress_ctx->s14_notif_time); rx_stress_on_test_finish(14); return 0; case BLE_GAP_EVENT_NOTIFY_TX: - MODLOG_DFLT(INFO, "Notify TX event\n"); + MODLOG_DFLT(DEBUG, "Notify TX event\n"); assert(event->notify_tx.status == 0); return 0; case BLE_GAP_EVENT_SUBSCRIBE: - MODLOG_DFLT(INFO, "Subscribe event\n"); + MODLOG_DFLT(DEBUG, "Subscribe event\n"); if (event->subscribe.cur_notify) { - MODLOG_DFLT(INFO, "Notification subscribed\n"); + MODLOG_DFLT(DEBUG, "Notification subscribed\n"); ++rx_stress_ctx->send_num; /* Notify data pattern */ om = ble_hs_mbuf_from_flat(test_6_pattern, bytes_num); - rc = ble_gattc_notify_custom(rx_stress_ctx->conn_handle, + rc = ble_gatts_notify_custom(rx_stress_ctx->conn_handle, hrs_hrm_handle, om); assert(rc == 0); - - console_printf("\033[0;32m>\033[0m"); } else if (event->subscribe.prev_notify) { - MODLOG_DFLT(INFO, "Notification unsubscribed\n"); + MODLOG_DFLT(DEBUG, "Notification unsubscribed\n"); } else { - MODLOG_DFLT(INFO, "Other subscription\n"); + MODLOG_DFLT(DEBUG, "Other subscription\n"); } return 0; default: - MODLOG_DFLT(INFO, "Other event occurs=%d\n", event->type); + MODLOG_DFLT(DEBUG, "Other event occurs=%d\n", event->type); return 0; } } @@ -1157,16 +1180,15 @@ rx_stress_15_gap_event(struct ble_gap_event *event, void *arg) event->connect.status, ++rx_stress_ctx->con_stat[15].num); } else { - MODLOG_DFLT(INFO, "\033[0;31mError: connection attempt failed; " - "status=%d\033[0m\n", event->connect.status); + MODLOG_DFLT(DEBUG, "Error: connection attempt failed; " + "status=%d\n", event->connect.status); assert(0); } return 0; case BLE_GAP_EVENT_DISCONNECT: - MODLOG_DFLT(INFO, "Disconnect; reason=%d \n", + MODLOG_DFLT(DEBUG, "Disconnect; reason=%d \n", event->disconnect.reason); - console_printf("\033[0;32m>\033[0m"); if (rx_stress_ctx->con_stat[15].num >= MYNEWT_VAL(BLE_STRESS_REPEAT)) { rx_stress_on_test_finish(15); } else { @@ -1176,7 +1198,7 @@ rx_stress_15_gap_event(struct ble_gap_event *event, void *arg) return 0; default: - MODLOG_DFLT(INFO, "Other event occurs=%d\n", event->type); + MODLOG_DFLT(DEBUG, "Other event occurs=%d\n", event->type); return 0; } } @@ -1193,7 +1215,7 @@ static struct rx_stress_adv_set rx_stress_adv_sets[] = { }, { .instance = SWITCHER_INSTANCE, - .instance_uuid128 = rx_stress_uuid128[0], + .instance_uuid128 = rx_stress_uuid128[1], .legacy_pdu = LEGACY_ADVERT, .cb = rx_stress_0_gap_event, .pattern_data = NULL, @@ -1321,75 +1343,82 @@ rx_stress_start(int test_num) /* Init semaphore with 0 tokens. */ os_sem_init(&rx_stress_main_sem, 0); - console_printf("\033[1;36mStart test num %d - ", test_num); + MODLOG_DFLT(INFO, "Start test num %d - ", test_num); /* Start test. */ switch (test_num) { + case 0: + return; + case 1: + MODLOG_DFLT(INFO, "Nothing to do\n"); + rx_stress_simple_adv(&rx_stress_adv_sets[1]); + return; case 2: - console_printf("Stress Connect/Disconnect legacy\033[0m\n"); + MODLOG_DFLT(INFO, "Stress Connect/Disconnect legacy\n"); rx_stress_simple_adv(&rx_stress_adv_sets[2]); break; case 3: - console_printf("Stress Connect/Disconnect ext adv\033[0m\n"); + MODLOG_DFLT(INFO, "Stress Connect/Disconnect ext adv\n"); rx_stress_simple_adv(&rx_stress_adv_sets[3]); break; case 4: - console_printf("Stress connection params update (TX)\033[0m\n"); + MODLOG_DFLT(INFO, "Stress connection params update (TX)\n"); rx_stress_simple_adv(&rx_stress_adv_sets[4]); break; case 5: - console_printf("Stress connection params update (RX)\033[0m\n"); + MODLOG_DFLT(INFO, "Stress connection params update (RX)\n"); rx_stress_simple_adv(&rx_stress_adv_sets[5]); break; case 6: /* Start SWITCHER advert that gives possibility to remotely start * next test advert */ - console_printf("Stress Scan\033[0m\n"); + MODLOG_DFLT(INFO, "Stress Scan\n"); rx_stress_simple_adv(&rx_stress_adv_sets[0]); rx_stress_simple_adv(&rx_stress_adv_sets[6]); break; case 7: - console_printf("Stress PHY Update (TX)\033[0m\n"); + MODLOG_DFLT(INFO, "Stress PHY Update (TX)\n"); rx_stress_simple_adv(&rx_stress_adv_sets[7]); break; case 8: - console_printf("Stress PHY Update (RX)\033[0m\n"); + MODLOG_DFLT(INFO, "Stress PHY Update (RX)\n"); rx_stress_simple_adv(&rx_stress_adv_sets[8]); break; case 9: - console_printf("Stress multi connection\033[0m\n"); + MODLOG_DFLT(INFO, "Stress multi connection\n"); rx_stress_simple_adv(&rx_stress_adv_sets[9]); break; case 10: - console_printf("Stress L2CAP send\033[0m\n"); + MODLOG_DFLT(INFO, "Stress L2CAP send\n"); rc = ble_l2cap_create_server(TEST_PSM, STRESS_COC_MTU, rx_stress_10_l2cap_event, NULL); assert(rc == 0); rx_stress_simple_adv(&rx_stress_adv_sets[10]); break; case 11: - console_printf("Stress Advertise/Connect/Disconnect\033[0m\n"); + MODLOG_DFLT(INFO, "Stress Advertise/Connect/Disconnect\n"); rx_stress_simple_adv(&rx_stress_adv_sets[11]); break; case 12: - console_printf("Stress GATT indication\033[0m\n"); + MODLOG_DFLT(INFO, "Stress GATT indication\n"); rx_stress_simple_adv(&rx_stress_adv_sets[12]); break; case 13: - console_printf("Stress GATT notification\033[0m\n"); + MODLOG_DFLT(INFO, "Stress GATT notification\n"); + ble_npl_event_init(&rx_stress_13_notify_ev, + rx_stress_13_notify_ev_func, NULL); rx_stress_simple_adv(&rx_stress_adv_sets[13]); break; case 14: - console_printf("Stress GATT Subscribe/Notify/Unsubscribe\033[0m\n"); + MODLOG_DFLT(INFO, "Stress GATT Subscribe/Notify/Unsubscribe\n"); rx_stress_simple_adv(&rx_stress_adv_sets[14]); break; case 15: - console_printf("Stress Connect/Send/Disconnect\033[0m\n"); + MODLOG_DFLT(INFO, "Stress Connect/Send/Disconnect\n"); rx_stress_simple_adv(&rx_stress_adv_sets[15]); break; default: - console_printf("\033[0;31mFound test, but do not know how to perform." - "\033[0m\n"); + MODLOG_DFLT(ERROR, "Found test, but do not know how to perform.\n"); assert(0); } @@ -1419,7 +1448,7 @@ stress_uuid_init() static void rx_stress_read_command_cb(void) { - console_printf("Start testing\n"); + MODLOG_DFLT(INFO, "Start testing\n"); os_sem_release(&rx_stress_main_sem); } @@ -1430,21 +1459,15 @@ rx_stress_main_task_fn(void *arg) stress_uuid_init(); - console_printf("\033[1;36mRX device\033[0m\n"); - console_printf("Press ENTER to start: \n"); + MODLOG_DFLT(INFO, "RX device\n"); + MODLOG_DFLT(INFO, "Press ENTER to start: \n"); console_init(&rx_stress_read_command_cb); /* Waite for pressing ENTER in console */ os_sem_pend(&rx_stress_main_sem, OS_TIMEOUT_NEVER); /* Standard tests perform */ - for (i = 11; i < STRESS_UUIDS_NUM; ++i) { - if (i == 7 || i == 8 || i == 13) { - /* 7,8: PHY update tests cause that the device during the next test - * will stuck somewhere and will reset. Skip them for now. - * 13: Should work after fixing ble_gattc_notify_custom (nimble issue on GitHub)*/ - continue; - } + for (i = 1; i < STRESS_UUIDS_NUM; ++i) { /* Start test. */ rx_stress_start(i); } diff --git a/apps/blestress/src/rx_stress.h b/apps/blestress/src/rx_stress.h index 62f84117a4..b2f897197a 100644 --- a/apps/blestress/src/rx_stress.h +++ b/apps/blestress/src/rx_stress.h @@ -24,7 +24,7 @@ #include #include #include -#include +#include /* BLE */ #include "nimble/ble.h" diff --git a/apps/blestress/src/stress.c b/apps/blestress/src/stress.c index 1bdbafa9ec..85f103cb2a 100644 --- a/apps/blestress/src/stress.c +++ b/apps/blestress/src/stress.c @@ -24,73 +24,80 @@ static struct os_callout stress_timer_callout; void com_stress_print_report(const struct com_stress_test_ctx *test_ctxs) { - console_printf("\033[0;32mAll tests completed\033[0m\n"); - console_printf("Tests results:\n"); - - console_printf( - "\033[0;33mUse case 1 - Stress Connect -> Connect Cancel: \n\033[0m"); - console_printf("Con attempts = %d\n", test_ctxs->con_stat[1].attempts_num); - console_printf("Con success = %d\n", test_ctxs->con_stat[1].num); - - console_printf( - "\033[0;33mUse case 2 - Stress Connect/Disconnect legacy: \n\033[0m"); - console_printf("Con attempts = %d\n", test_ctxs->con_stat[2].attempts_num); - console_printf("Con success = %d\n", test_ctxs->con_stat[2].num); - - console_printf( - "\033[0;33mUse case 3 - Stress Connect/Disconnect ext adv: \n\033[0m"); - console_printf("Con attempts = %d\n", test_ctxs->con_stat[3].attempts_num); - console_printf("Con success = %d\n", test_ctxs->con_stat[3].num); - - console_printf( - "\033[0;33mUse case 4 - Stress connection params update (TX): \n\033[0m"); - console_printf("Params updates = %d\n", - test_ctxs->con_stat[4].prms_upd_num); - - console_printf( - "\033[0;33mUse case 5 - Stress connection params update (RX): \n\033[0m"); - console_printf("Params updates = %d\n", - test_ctxs->con_stat[5].prms_upd_num); - - console_printf("\033[0;33mUse case 6 - Stress Scan: \n\033[0m"); - console_printf("Received first packets = %d\n", - test_ctxs->s6_rcv_adv_first); - console_printf("Received all packets = %d\n", test_ctxs->s6_rcv_adv_suc); - - console_printf("\033[0;33mUse case 7 - Stress PHY Update (TX): \n\033[0m"); - console_printf("PHY updates = %d\n", test_ctxs->con_stat[7].phy_upd_num); - - console_printf("\033[0;33mUse case 8 - Stress PHY Update (RX): \n\033[0m"); - console_printf("PHY updates = %d\n", test_ctxs->con_stat[8].phy_upd_num); - - console_printf( - "\033[0;33mUse case 9 - Stress multi connection: \n\033[0m"); - console_printf("Max reached num of connections = %d\n", - test_ctxs->con_stat[9].max_num); - - console_printf("\033[0;33mUse case 10 - Stress L2CAP send: \n\033[0m"); - console_printf("Average bit rate = %d\n", test_ctxs->s10_bit_rate); - console_printf("Max received MTU = %lld\n", test_ctxs->s10_max_mtu); - - console_printf("\033[0;33mUse case 11 - " - "Stress Advertise/Connect/Continue adv \n\033[0m"); -// console_printf(" = %d\n",); - - console_printf("\033[0;33mUse case 12 - " - "Stress GATT indication: \n\033[0m"); - console_printf("Average bit rate = %d\n", test_ctxs->s12_notif_time); - - console_printf("\033[0;33mUse case 13 - " - "Stress GATT notification: \n\033[0m"); - console_printf("Average time = %d\n", test_ctxs->s13_notif_time); - - console_printf("\033[0;33mUse case 14 - " - "Stress GATT Subscribe/Notify/Unsubscribe: \n\033[0m"); - console_printf("Average time = %d\n", test_ctxs->s14_notif_time); - - console_printf("\033[0;33mUse case 15 - " - "Stress Connect/Send/Disconnect: \n\033[0m"); - console_printf("Con num = %d\n", test_ctxs->con_stat[15].num); + MODLOG_DFLT(INFO, "All tests completed\n"); + MODLOG_DFLT(INFO, "Tests results:\n"); + + MODLOG_DFLT(INFO, "Use case 1 - " + "Stress Connect -> Connect Cancel: \n"); + MODLOG_DFLT(INFO, "Con attempts = %d\n", + test_ctxs->con_stat[1].attempts_num); + MODLOG_DFLT(INFO, "Con success = %d\n", test_ctxs->con_stat[1].num); + + MODLOG_DFLT(INFO, "Use case 2 - " + "Stress Connect/Disconnect legacy: \n"); + MODLOG_DFLT(INFO, "Con attempts = %d\n", + test_ctxs->con_stat[2].attempts_num); + MODLOG_DFLT(INFO, "Con success = %d\n", test_ctxs->con_stat[2].num); + + MODLOG_DFLT(INFO, "Use case 3 - " + "Stress Connect/Disconnect ext adv: \n"); + MODLOG_DFLT(INFO, "Con attempts = %d\n", + test_ctxs->con_stat[3].attempts_num); + MODLOG_DFLT(INFO, "Con success = %d\n", test_ctxs->con_stat[3].num); + + MODLOG_DFLT(INFO, "Use case 4 - " + "Stress connection params update (TX): \n"); + MODLOG_DFLT(INFO, "Params updates = %d\n", + test_ctxs->con_stat[4].prms_upd_num); + + MODLOG_DFLT(INFO, "Use case 5 - " + "Stress connection params update (RX): \n"); + MODLOG_DFLT(INFO, "Params updates = %d\n", + test_ctxs->con_stat[5].prms_upd_num); + + MODLOG_DFLT(INFO, "Use case 6 - Stress Scan: \n"); + MODLOG_DFLT(INFO, "Received first packets = %d\n", + test_ctxs->s6_rcv_adv_first); + MODLOG_DFLT(INFO, "Received all packets = %d\n", + test_ctxs->s6_rcv_adv_suc); + + MODLOG_DFLT(INFO, "Use case 7 - " + "Stress PHY Update (TX): \n"); + MODLOG_DFLT(INFO, "PHY updates = %d\n", + test_ctxs->con_stat[7].phy_upd_num); + + MODLOG_DFLT(INFO, "Use case 8 - " + "Stress PHY Update (RX): \n"); + MODLOG_DFLT(INFO, "PHY updates = %d\n", + test_ctxs->con_stat[8].phy_upd_num); + + MODLOG_DFLT(INFO, "Use case 9 - " + "Stress multi connection: \n"); + MODLOG_DFLT(INFO, "Max reached num of connections = %d\n", + test_ctxs->con_stat[9].max_num); + + MODLOG_DFLT(INFO, "Use case 10 - Stress L2CAP send: \n"); + MODLOG_DFLT(INFO, "Average bit rate = %d\n", test_ctxs->s10_bit_rate); + MODLOG_DFLT(INFO, "Max received MTU = %lld\n", test_ctxs->s10_max_mtu); + + MODLOG_DFLT(INFO, "Use case 11 - " + "Stress Advertise/Connect/Continue adv \n"); + + MODLOG_DFLT(INFO, "Use case 12 - " + "Stress GATT indication: \n"); + MODLOG_DFLT(INFO, "Average bit rate = %d\n", test_ctxs->s12_notif_time); + + MODLOG_DFLT(INFO, "Use case 13 - " + "Stress GATT notification: \n"); + MODLOG_DFLT(INFO, "Average time = %d\n", test_ctxs->s13_notif_time); + + MODLOG_DFLT(INFO, "Use case 14 - " + "Stress GATT Subscribe/Notify/Unsubscribe: \n"); + MODLOG_DFLT(INFO, "Average time = %d\n", test_ctxs->s14_notif_time); + + MODLOG_DFLT(INFO, "Use case 15 - " + "Stress Connect/Send/Disconnect: \n"); + MODLOG_DFLT(INFO, "Con num = %d\n", test_ctxs->con_stat[15].num); } void @@ -143,8 +150,8 @@ void stress_l2cap_coc_recv(struct ble_l2cap_chan *chan, struct os_mbuf *sdu) { int rc; - console_printf("LE CoC SDU received, chan: 0x%08lx, data len %d\n", - (uint32_t) chan, OS_MBUF_PKTLEN(sdu)); + MODLOG_DFLT(DEBUG, "LE CoC SDU received, chan: 0x%08lx, data len %d\n", + (uint32_t) chan, OS_MBUF_PKTLEN(sdu)); rc = os_mbuf_free_chain(sdu); assert(rc == 0); @@ -164,14 +171,16 @@ stress_l2cap_coc_accept(uint16_t peer_mtu, struct ble_l2cap_chan *chan) struct os_mbuf *sdu_rx; int rc; - console_printf("LE CoC accepting, chan: 0x%08lx, peer_mtu %d\n", - (uint32_t) chan, peer_mtu); + MODLOG_DFLT(DEBUG, "LE CoC accepting, chan: 0x%08lx, peer_mtu %d\n", + (uint32_t) chan, peer_mtu); - sdu_rx = os_msys_get_pkthdr(STRESS_COC_MTU, 0); - assert(sdu_rx != NULL); + for (int i = 0; i < MYNEWT_VAL(BLE_L2CAP_COC_SDU_BUFF_COUNT); i++) { + sdu_rx = os_msys_get_pkthdr(STRESS_COC_MTU, 0); + assert(sdu_rx != NULL); - rc = ble_l2cap_recv_ready(chan, sdu_rx); - assert(rc == 0); + rc = ble_l2cap_recv_ready(chan, sdu_rx); + assert(rc == 0); + } } void @@ -214,9 +223,9 @@ stress_disc_dsc_fn(uint16_t conn_handle, if (error->status == 0) { if (!ble_uuid_cmp(&dsc->uuid.u, &search_ctx->dsc_uuid.u) && !found) { - MODLOG_DFLT(INFO, "Found chr descriptor\n"); + MODLOG_DFLT(DEBUG, "Found chr descriptor\n"); search_ctx->dsc_handle = dsc->handle; - MODLOG_DFLT(INFO, "uuid=%#06x; handle=%#06x", dsc->uuid.u16.value, + MODLOG_DFLT(DEBUG, "uuid=%#06x; handle=%#06x", dsc->uuid.u16.value, dsc->handle); found = true; } @@ -224,7 +233,7 @@ stress_disc_dsc_fn(uint16_t conn_handle, } if (error->status == BLE_HS_EDONE) { - MODLOG_DFLT(INFO, "Done descriptor discovery\n"); + MODLOG_DFLT(DEBUG, "Done descriptor discovery\n"); if (found) { found = false; @@ -232,13 +241,11 @@ stress_disc_dsc_fn(uint16_t conn_handle, return 0; } - MODLOG_DFLT(ERROR, "\033[0;31mDid not find particular descriptor" - "\033[0m\n"); + MODLOG_DFLT(ERROR, "Did not find particular descriptor\n"); return 0; } - MODLOG_DFLT(ERROR, "\033[0;31mError during descriptor discovery" - "\033[0m\n"); + MODLOG_DFLT(ERROR, "Error during descriptor discovery\n"); assert(0); return 0; } @@ -255,14 +262,14 @@ stress_disc_chr_fn(uint16_t conn_handle, search_ctx = (struct stress_gatt_search_ctx *) arg; if (error->status == 0) { - MODLOG_DFLT(INFO, "Found characteristic\n"); + MODLOG_DFLT(DEBUG, "Found characteristic\n"); search_ctx->chr_start_handle = chr->val_handle; found = true; return 0; } if (error->status == BLE_HS_EDONE) { - MODLOG_DFLT(INFO, "Done characteristic discovery\n"); + MODLOG_DFLT(DEBUG, "Done characteristic discovery\n"); if (found) { found = false; @@ -280,13 +287,11 @@ stress_disc_chr_fn(uint16_t conn_handle, return 0; } - MODLOG_DFLT(ERROR, "\033[0;31mDid not find particular " - "characteristic\033[0m\n"); + MODLOG_DFLT(ERROR, "Did not find particular characteristic\n"); return 0; } - MODLOG_DFLT(ERROR, - "\033[0;31mError during characteristic discovery\033[0m\n"); + MODLOG_DFLT(ERROR, "Error during characteristic discovery\n"); assert(0); return 0; } @@ -302,7 +307,7 @@ stress_disc_svc_fn(uint16_t conn_handle, const struct ble_gatt_error *error, search_ctx = (struct stress_gatt_search_ctx *) arg; if (error->status == 0) { - MODLOG_DFLT(INFO, "Found service\n"); + MODLOG_DFLT(DEBUG, "Found service\n"); search_ctx->srv_start_handle = service->start_handle; search_ctx->srv_end_handle = service->end_handle; found = true; @@ -310,7 +315,7 @@ stress_disc_svc_fn(uint16_t conn_handle, const struct ble_gatt_error *error, } if (error->status == BLE_HS_EDONE) { - MODLOG_DFLT(INFO, "Done service discovery\n"); + MODLOG_DFLT(DEBUG, "Done service discovery\n"); if (found) { found = false; @@ -325,17 +330,17 @@ stress_disc_svc_fn(uint16_t conn_handle, const struct ble_gatt_error *error, &search_ctx->chr_uuid.u, &stress_disc_chr_fn, search_ctx); - MODLOG_DFLT(INFO, "rc=%d\n", rc); + MODLOG_DFLT(DEBUG, "rc=%d\n", rc); assert(rc == 0); return 0; } MODLOG_DFLT(ERROR, - "\033[0;31mDid not find particular service\033[0m\n"); + "Did not find particular service\n"); return 0; } - MODLOG_DFLT(ERROR, "\033[0;31mError during service discovery\033[0m\n"); + MODLOG_DFLT(ERROR, "Error during service discovery\n"); assert(0); return 0; } diff --git a/apps/blestress/src/stress_gatt.c b/apps/blestress/src/stress_gatt.c index a6d845c5d0..a076132752 100644 --- a/apps/blestress/src/stress_gatt.c +++ b/apps/blestress/src/stress_gatt.c @@ -82,23 +82,23 @@ stress_gatt_access_cb(uint16_t conn_handle, uint16_t attr_handle, switch(uuid){ case STRESS_GATT_READ_UUID: - MODLOG_DFLT(INFO, "GATT Read event\n"); + MODLOG_DFLT(DEBUG, "GATT Read event\n"); rc = os_mbuf_append(ctxt->om, &chr_value, sizeof(chr_value)); assert(rc == 0); //return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; return 0; case STRESS_GATT_WRITE_UUID: - MODLOG_DFLT(INFO, "GATT Write event\n"); + MODLOG_DFLT(DEBUG, "GATT Write event\n"); print_mbuf(ctxt->om); return 0; case STRESS_GATT_NOTIFY_UUID: - MODLOG_DFLT(INFO, "GATT Notify event\n"); + MODLOG_DFLT(DEBUG, "GATT Notify event\n"); return 0; case STRESS_GATT_INDICATE_UUID: - MODLOG_DFLT(INFO, "GATT Indicate event\n"); + MODLOG_DFLT(DEBUG, "GATT Indicate event\n"); return 0; default: - MODLOG_DFLT(ERROR, "GATT UUID does not exist\n"); + MODLOG_DFLT(DEBUG, "GATT UUID does not exist\n"); assert(0); return BLE_ATT_ERR_UNLIKELY; } diff --git a/apps/blestress/src/tx_stress.c b/apps/blestress/src/tx_stress.c index 4416c568cb..20333f1faa 100644 --- a/apps/blestress/src/tx_stress.c +++ b/apps/blestress/src/tx_stress.c @@ -19,6 +19,7 @@ #include #include +#include "inttypes.h" #include #include #include "tx_stress.h" @@ -48,7 +49,8 @@ static int completed_tests = 0; static void tx_stress_on_test_finish(int test_num) { - console_printf("\033[0;32m\nStress test %d completed\033[0m\n", test_num); + MODLOG_DFLT(INFO, "\nStress test %d completed\n", + test_num); ++completed_tests; tx_stress_ctx->completed[test_num] = true; os_sem_release(&tx_stress_main_sem); @@ -64,8 +66,7 @@ tx_stress_simple_scan(ble_gap_event_fn *cb, uint16_t duration) /* Figure out address to use while scanning. */ rc = ble_hs_id_infer_auto(0, &own_addr_type); if (rc != 0) { - console_printf("\033[0;31mError determining own address type; " - "rc=%d\033[0m\n", rc); + MODLOG_DFLT(ERROR, "Error determining own address type; rc=%d\n", rc); assert(0); } @@ -73,17 +74,17 @@ tx_stress_simple_scan(ble_gap_event_fn *cb, uint16_t duration) params.passive = 1; params.window = BLE_GAP_SCAN_FAST_WINDOW; - rc = ble_gap_ext_disc(own_addr_type, duration, 0, 1, 0, 0, ¶ms, NULL, + rc = ble_gap_ext_disc(own_addr_type, duration, 0, 0, 0, 0, ¶ms, NULL, cb, NULL); if (rc != 0) { - console_printf("\033[0;31mError initiating GAP discovery procedure" - "; rc=%d\033[0m\n", rc); + MODLOG_DFLT(WARN, "Error initiating GAP discovery procedure" + "; rc=%d\n", rc); } } static int -tx_stress_simple_connect(ble_gap_event_fn *cb, int test_num) +tx_stress_simple_connect(ble_gap_event_fn *cb, int test_num, struct ble_gap_conn_params *params) { uint8_t own_addr_type; int rc; @@ -94,21 +95,21 @@ tx_stress_simple_connect(ble_gap_event_fn *cb, int test_num) /* Figure out address to use while connecting. */ rc = ble_hs_id_infer_auto(0, &own_addr_type); if (rc != 0) { - MODLOG_DFLT(INFO, "\033[0;31mError determining own address type; " - "rc=%d\033[0m\n", rc); + MODLOG_DFLT(ERROR, "Error determining own address type; " + "rc=%d\n", rc); return rc; } - MODLOG_DFLT(INFO, "Connection attempt: %d\n", + MODLOG_DFLT(DEBUG, "Connection attempt: %d\n", ++tx_stress_ctx->con_stat[test_num].attempts_num); rc = ble_gap_ext_connect(own_addr_type, &tx_stress_ctx->dev_addr, 10000, BLE_GAP_LE_PHY_1M_MASK | BLE_GAP_LE_PHY_2M_MASK, - NULL, NULL, NULL, cb, NULL); + params, params, NULL, cb, NULL); if (rc != 0) { - MODLOG_DFLT(INFO, "\033[0;31mError during connection; rc=%d\033[0m\n", + MODLOG_DFLT(ERROR, "Error during connection; rc=%d\n", rc); } @@ -165,17 +166,17 @@ tx_stress_switcher_gap_event(struct ble_gap_event *event, void *arg) case BLE_GAP_EVENT_CONNECT: /* A new connection was established or a connection attempt failed. */ if (event->connect.status == 0) { - MODLOG_DFLT(INFO, "Success to connect to device\n"); + MODLOG_DFLT(DEBUG, "Success to connect to device\n"); return 0; } else if (event->connect.status == BLE_HS_ETIMEOUT_HCI) { - MODLOG_DFLT(INFO, "Connection timeout\n"); + MODLOG_DFLT(WARN, "Connection timeout\n"); } else { - MODLOG_DFLT(INFO, "Error: connection attempt failed; status=%d\n", + MODLOG_DFLT(WARN, "Error: connection attempt failed; status=%d\n", event->connect.status); } /* Connect to rx device just to give it a signal to switch test. */ tx_stress_simple_connect(tx_stress_switcher_gap_event, - tx_stress_ctx->cur_test_id); + tx_stress_ctx->cur_test_id, NULL); return 0; case BLE_GAP_EVENT_DISCONNECT: @@ -196,7 +197,7 @@ tx_stress_switcher_gap_event(struct ble_gap_event *event, void *arg) return 0; case BLE_GAP_EVENT_DISC_COMPLETE: - MODLOG_DFLT(INFO, "Discovery complete; reason=%d\n", + MODLOG_DFLT(DEBUG, "Discovery complete; reason=%d\n", event->disc_complete.reason); return 0; @@ -212,7 +213,7 @@ tx_stress_switch_test() tx_stress_simple_scan(tx_stress_switcher_gap_event, 0); os_sem_pend(&tx_stress_main_sem, OS_TIMEOUT_NEVER); - tx_stress_simple_connect(tx_stress_switcher_gap_event, 0); + tx_stress_simple_connect(tx_stress_switcher_gap_event, 0, NULL); } static int @@ -228,7 +229,7 @@ tx_stress_1_gap_event(struct ble_gap_event *event, void *arg) if (event->connect.status == 0) { /* Connection successfully established. In this use case * it is error of 'Connect cancel'. Stress test failed. */ - MODLOG_DFLT(INFO, "Success to connect to device\n"); + MODLOG_DFLT(DEBUG, "Success to connect to device\n"); ++tx_stress_ctx->con_stat[1].num; ble_gap_terminate(event->connect.conn_handle, BLE_ERR_NO_PAIRING); @@ -236,7 +237,7 @@ tx_stress_1_gap_event(struct ble_gap_event *event, void *arg) return 0; case BLE_GAP_EVENT_DISCONNECT: - MODLOG_DFLT(INFO, "Disconnect; reason=%d ", event->disconnect.reason); + MODLOG_DFLT(DEBUG, "Disconnect; reason=%d ", event->disconnect.reason); return 0; default: @@ -259,8 +260,7 @@ tx_stress_1_test() /* Figure out address to use while advertising. */ rc = ble_hs_id_infer_auto(0, &own_addr_type); if (rc != 0) { - MODLOG_DFLT(INFO, "\033[0;31mError determining own address type; " - "rc=%d\033[0m\n", rc); + MODLOG_DFLT(ERROR, "Error determining own address type; rc=%d\n", rc); os_sem_release(&tx_stress_main_sem); return; } @@ -271,27 +271,25 @@ tx_stress_1_test() rc = ble_hs_id_gen_rnd(1, &rnd_rx_addr); assert (rc == 0); - MODLOG_DFLT(INFO, "Connection attempt; num=%d\n", + MODLOG_DFLT(DEBUG, "Connection attempt; num=%d\n", ++tx_stress_ctx->con_stat[1].attempts_num); rc = ble_gap_connect(own_addr_type, &rnd_rx_addr, 10000, NULL, tx_stress_1_gap_event, NULL); if (rc != 0) { - MODLOG_DFLT(INFO, "\033[0;31mConnection error; rc=%d\033[0m\n", + MODLOG_DFLT(ERROR, "Connection error; rc=%d\n", rc); os_sem_release(&tx_stress_main_sem); return; } - MODLOG_DFLT(INFO, "Connect cancel\n"); + MODLOG_DFLT(DEBUG, "Connect cancel\n"); ble_gap_conn_cancel(); - console_printf("\033[0;32m>\033[0m"); } - console_printf( - "\033[0;32m\nFirst part of test completed\nStart second part: " - "Connect->random delay->cancel\n\033[0m"); + MODLOG_DFLT(INFO, "\nFirst part of test completed\nStart second part: " + "Connect->random delay->cancel\n"); while (tx_stress_ctx->con_stat[1].attempts_num < 2 * MYNEWT_VAL(BLE_STRESS_REPEAT)) { @@ -299,7 +297,7 @@ tx_stress_1_test() rc = ble_hs_id_gen_rnd(1, &rnd_rx_addr); assert (rc == 0); - MODLOG_DFLT(INFO, "Connection attempt; num=%d\n", + MODLOG_DFLT(DEBUG, "Connection attempt; num=%d\n", ++tx_stress_ctx->con_stat[1].attempts_num); delay_time = rand() % 1000; @@ -310,7 +308,7 @@ tx_stress_1_test() tx_stress_1_gap_event, NULL); if (rc != 0) { - MODLOG_DFLT(INFO, "\033[0;31mConnection error; rc=%d\033[0m\n", + MODLOG_DFLT(ERROR, "Connection error; rc=%d\n", rc); os_sem_release(&tx_stress_main_sem); return; @@ -318,9 +316,8 @@ tx_stress_1_test() os_time_delay(os_time_ms_to_ticks32(delay_time)); - MODLOG_DFLT(INFO, "Connect cancel\n"); + MODLOG_DFLT(DEBUG, "Connect cancel\n"); ble_gap_conn_cancel(); - console_printf("\033[0;32m>\033[0m"); } tx_stress_on_test_finish(1); @@ -336,7 +333,9 @@ tx_stress_2_gap_event(struct ble_gap_event *event, void *arg) case BLE_GAP_EVENT_CONNECT: /* A new connection was established or a connection attempt failed. */ if (event->connect.status == 0) { - MODLOG_DFLT(INFO, "Success to connect to device\n"); + MODLOG_DFLT(INFO, "Success to connect to device, conn " + "handle=%d\n", + event->connect.conn_handle); ++tx_stress_ctx->con_stat[2].num; rc = ble_gap_conn_find(event->connect.conn_handle, &desc); @@ -344,26 +343,30 @@ tx_stress_2_gap_event(struct ble_gap_event *event, void *arg) tx_stress_ctx->conn_handle = desc.conn_handle; - ble_gap_terminate(event->connect.conn_handle, + rc = ble_gap_terminate(event->connect.conn_handle, BLE_ERR_REM_USER_CONN_TERM); + + MODLOG_DFLT(INFO, "Connection terminated; conn handle=%d, rc=%d\n", + event->connect.conn_handle, rc); } else { - MODLOG_DFLT(INFO, "\033[0;31mError: connection attempt failed; " - "status=%d\033[0m\n", event->connect.status); + MODLOG_DFLT(ERROR, "Error: connection attempt failed; " + "status=%d; conn handle=%d;\n", + event->connect.status, + event->connect.conn_handle); os_sem_release(&tx_stress_main_sem); } return 0; case BLE_GAP_EVENT_DISCONNECT: - MODLOG_DFLT(INFO, "Disconnect; reason=%d \n", + MODLOG_DFLT(DEBUG, "Disconnect; reason=%d \n", event->disconnect.reason); - console_printf("\033[0;32m>\033[0m"); if (tx_stress_ctx->con_stat[2].num >= MYNEWT_VAL(BLE_STRESS_REPEAT)) { tx_stress_on_test_finish(2); return 0; } tx_stress_simple_connect(tx_stress_2_gap_event, - tx_stress_ctx->cur_test_id); + tx_stress_ctx->cur_test_id, NULL); return 0; default: @@ -382,34 +385,34 @@ tx_stress_3_gap_event(struct ble_gap_event *event, void *arg) /* A new connection was established or a connection attempt failed. */ if (event->connect.status == 0) { ++tx_stress_ctx->con_stat[3].num; - MODLOG_DFLT(INFO, "Success to connect to device\n"); + MODLOG_DFLT(INFO, "Success to connect to device; conn " + "handle=%d\n", event->connect.conn_handle); rc = ble_gap_terminate(event->connect.conn_handle, BLE_ERR_REM_USER_CONN_TERM); - MODLOG_DFLT(INFO, "rc=%d\n", rc); + MODLOG_DFLT(DEBUG, "rc=%d\n", rc); } else { - MODLOG_DFLT(INFO, "\033[0;31mError: connection attempt failed; " - "status=%d\033[0m\n", event->connect.status); + MODLOG_DFLT(ERROR, "Error: connection attempt failed; " + "status=%d\n", event->connect.status); os_sem_release(&tx_stress_main_sem); } return 0; case BLE_GAP_EVENT_DISCONNECT: - MODLOG_DFLT(INFO, "Disconnect; reason=%d \n", + MODLOG_DFLT(DEBUG, "Disconnect; reason=%d \n", event->disconnect.reason); - console_printf("\033[0;32m>\033[0m"); if (tx_stress_ctx->con_stat[3].num >= MYNEWT_VAL(BLE_STRESS_REPEAT)) { tx_stress_on_test_finish(3); return 0; } tx_stress_simple_connect(tx_stress_3_gap_event, - tx_stress_ctx->cur_test_id); + tx_stress_ctx->cur_test_id, NULL); return 0; default: - MODLOG_DFLT(INFO, "Other event occurs=%d\n", event->type); + MODLOG_DFLT(DEBUG, "Other event occurs=%d\n", event->type); return 0; } } @@ -438,13 +441,12 @@ tx_stress_4_con_update(void) rc = ble_gap_update_params(tx_stress_ctx->conn_handle, ¶ms); if (rc == BLE_HS_ENOTCONN) { - MODLOG_DFLT(INFO, "Device disconnected. Connection update failed\n"); + MODLOG_DFLT(ERROR, "Device disconnected. Connection update failed\n"); assert(0); } if (rc != 0) { - MODLOG_DFLT(ERROR, "\033[0;31mError during connection update; " - "rc=%d\033[0m\n", rc); + MODLOG_DFLT(ERROR, "Error during connection update; rc=%d\n", rc); assert(0); } @@ -468,25 +470,24 @@ tx_stress_4_gap_event(struct ble_gap_event *event, void *arg) tx_stress_4_con_update(); } else { - MODLOG_DFLT(INFO, "\033[0;31mError: connection attempt failed; " - "status=%d\033[0m\n", event->connect.status); + MODLOG_DFLT(ERROR, "Error: connection attempt failed; " + "status=%d\n", event->connect.status); os_sem_release(&tx_stress_main_sem); } return 0; case BLE_GAP_EVENT_DISCONNECT: - MODLOG_DFLT(INFO, "Disconnect; reason=%d \n", + MODLOG_DFLT(DEBUG, "Disconnect; reason=%d \n", event->disconnect.reason); tx_stress_on_test_finish(4); return 0; case BLE_GAP_EVENT_CONN_UPDATE: if (event->conn_update.status != 0) { - MODLOG_DFLT(INFO, "Connection update failed\n"); + MODLOG_DFLT(WARN, "Connection update failed\n"); } else { MODLOG_DFLT(INFO, "Connection updated; num=%d\n", ++tx_stress_ctx->con_stat[4].prms_upd_num); - console_printf("\033[0;32m>\033[0m"); } if (tx_stress_ctx->con_stat[4].prms_upd_num >= @@ -498,19 +499,18 @@ tx_stress_4_gap_event(struct ble_gap_event *event, void *arg) rc = tx_stress_4_con_update(); if (rc != 0) { - MODLOG_DFLT(INFO, "\033[0;31mError: update fail; " - "rc=%d\033[0m\n", rc); + MODLOG_DFLT(ERROR, "Error: update fail; rc=%d\n", rc); os_sem_release(&tx_stress_main_sem); } } return 0; case BLE_GAP_EVENT_CONN_UPDATE_REQ: - MODLOG_DFLT(INFO, "Connection update request\n"); + MODLOG_DFLT(DEBUG, "Connection update request\n"); return 0; default: - MODLOG_DFLT(INFO, "Other event occurs=%d\n", event->type); + MODLOG_DFLT(DEBUG, "Other event occurs=%d\n", event->type); return 0; } } @@ -527,25 +527,24 @@ tx_stress_5_gap_event(struct ble_gap_event *event, void *arg) ++tx_stress_ctx->con_stat[5].num; tx_stress_ctx->conn_handle = event->connect.conn_handle; } else { - console_printf("\033[0;31mError: Update fail; " - "status=%d\033[0m\n", event->connect.status); + MODLOG_DFLT(ERROR, "Error: Update fail; status=%d\n", + event->connect.status); os_sem_release(&tx_stress_main_sem); } return 0; case BLE_GAP_EVENT_DISCONNECT: - MODLOG_DFLT(INFO, "Disconnect; reason=%d \n", + MODLOG_DFLT(DEBUG, "Disconnect; reason=%d \n", event->disconnect.reason); tx_stress_on_test_finish(5); return 0; case BLE_GAP_EVENT_CONN_UPDATE: if (event->conn_update.status != 0) { - MODLOG_DFLT(INFO, "Connection update failed\n"); + MODLOG_DFLT(DEBUG, "Connection update failed\n"); } else { MODLOG_DFLT(INFO, "Connection updated; num=%d\n", ++tx_stress_ctx->con_stat[5].prms_upd_num); - console_printf("\033[0;32m>\033[0m"); } if (tx_stress_ctx->con_stat[5].prms_upd_num >= @@ -556,11 +555,11 @@ tx_stress_5_gap_event(struct ble_gap_event *event, void *arg) return 0; case BLE_GAP_EVENT_CONN_UPDATE_REQ: - MODLOG_DFLT(INFO, "Connection update request\n"); + MODLOG_DFLT(DEBUG, "Connection update request\n"); return 0; default: - MODLOG_DFLT(INFO, "Other event occurs=%d\n", event->type); + MODLOG_DFLT(DEBUG, "Other event occurs=%d\n", event->type); return 0; } } @@ -622,9 +621,9 @@ tx_stress_6_gap_event(struct ble_gap_event *event, void *arg) BLE_GAP_EXT_ADV_DATA_STATUS_COMPLETE) { /* Got all packets of advert. */ ++tx_stress_ctx->s6_rcv_adv_suc; + MODLOG_DFLT(INFO, "Adv data=%" PRIu8 "\n", *(event->ext_disc.data)); MODLOG_DFLT(INFO, "Got all packets of advert. num=%d\n", tx_stress_ctx->s6_rcv_adv_suc); - console_printf("\033[0;32m>\033[0m"); start_id = 0; if (tx_stress_ctx->s6_rcv_adv_suc >= @@ -637,12 +636,12 @@ tx_stress_6_gap_event(struct ble_gap_event *event, void *arg) return 0; case BLE_GAP_EVENT_DISC_COMPLETE: - MODLOG_DFLT(INFO, "Discovery complete; reason=%d\n", + MODLOG_DFLT(DEBUG, "Discovery complete; reason=%d\n", event->disc_complete.reason); return 0; default: - MODLOG_DFLT(INFO, "Other event occurs=%d\n", event->type); + MODLOG_DFLT(DEBUG, "Other event occurs=%d\n", event->type); return 0; } } @@ -704,14 +703,17 @@ tx_stress_7_phy_update(void) rc = ble_gap_set_prefered_le_phy(tx_stress_ctx->conn_handle, tx_phys_mask, rx_phys_mask, 0); + MODLOG_DFLT(INFO, "Set PHY params: tx_phys_mask=%d; rx_phys_mask=%d\n", + tx_phys_mask, rx_phys_mask); + if (rc == BLE_HS_ENOTCONN) { - MODLOG_DFLT(INFO, "Device disconnected. Connection update failed\n"); + MODLOG_DFLT(WARN, "Device disconnected. Connection update failed\n"); return rc; } if (rc != 0) { - MODLOG_DFLT(ERROR, "\033[0;31mError during PHY update; " - "rc=%d\033[0m\n", rc); + MODLOG_DFLT(ERROR, "Error during PHY update; " + "rc=%d\n", rc); } return rc; @@ -726,41 +728,40 @@ tx_stress_7_gap_event(struct ble_gap_event *event, void *arg) case BLE_GAP_EVENT_CONNECT: /* A new connection was established or a connection attempt failed. */ if (event->connect.status == 0) { - MODLOG_DFLT(INFO, "Success to connect to device\n"); + MODLOG_DFLT(DEBUG, "Success to connect to device\n"); ++tx_stress_ctx->con_stat[7].num; tx_stress_ctx->conn_handle = event->connect.conn_handle; tx_stress_7_phy_update(); } else { - console_printf("\033[0;31mError: Update fail; " - "status=%d\033[0m\n", event->connect.status); + MODLOG_DFLT(ERROR, "Error: Update fail; " + "status=%d\n", event->connect.status); os_sem_release(&tx_stress_main_sem); } return 0; case BLE_GAP_EVENT_DISCONNECT: - MODLOG_DFLT(INFO, "Disconnect; reason=%d \n", + MODLOG_DFLT(DEBUG, "Disconnect; reason=%d \n", event->disconnect.reason); tx_stress_on_test_finish(7); return 0; case BLE_GAP_EVENT_CONN_UPDATE: - MODLOG_DFLT(INFO, "Connection updated\n"); + MODLOG_DFLT(DEBUG, "Connection updated\n"); return 0; case BLE_GAP_EVENT_CONN_UPDATE_REQ: - MODLOG_DFLT(INFO, "Connection update request\n"); + MODLOG_DFLT(DEBUG, "Connection update request\n"); return 0; case BLE_GAP_EVENT_PHY_UPDATE_COMPLETE: if (event->phy_updated.status != 0) { - MODLOG_DFLT(INFO, "PHY update failed\n"); + MODLOG_DFLT(WARN, "PHY update failed\n"); } else { MODLOG_DFLT(INFO, "PHY updated; num=%d; rx:%d, tx:%d\n", ++tx_stress_ctx->con_stat[7].phy_upd_num, event->phy_updated.rx_phy, event->phy_updated.tx_phy); - console_printf("\033[0;32m>\033[0m"); } if (tx_stress_ctx->con_stat[7].phy_upd_num >= @@ -771,8 +772,9 @@ tx_stress_7_gap_event(struct ble_gap_event *event, void *arg) /* Update connection. */ rc = tx_stress_7_phy_update(); if (rc != 0) { - console_printf("\033[0;31mError: PHPY update fail; " - "rc=%d\033[0m\n", event->phy_updated.status); + MODLOG_DFLT(ERROR, "Error: PHPY update fail; " + "rc=%d\n", + event->phy_updated.status); assert(0); } } @@ -791,43 +793,43 @@ tx_stress_8_gap_event(struct ble_gap_event *event, void *arg) case BLE_GAP_EVENT_CONNECT: /* A new connection was established or a connection attempt failed. */ if (event->connect.status == 0) { - MODLOG_DFLT(INFO, "Success to connect to device\n"); + MODLOG_DFLT(DEBUG, "Success to connect to device\n"); ++tx_stress_ctx->con_stat[8].num; tx_stress_ctx->conn_handle = event->connect.conn_handle; } else { - MODLOG_DFLT(INFO, "\033[0;31mError: connection attempt failed; " - "status=%d\033[0m\n", event->connect.status); + MODLOG_DFLT(ERROR, "Error: connection attempt failed; " + "status=%d\n", event->connect.status); os_sem_release(&tx_stress_main_sem); } return 0; case BLE_GAP_EVENT_DISCONNECT: - MODLOG_DFLT(INFO, "Disconnect; reason=%d \n", + MODLOG_DFLT(DEBUG, "Disconnect; reason=%d \n", event->disconnect.reason); tx_stress_on_test_finish(8); return 0; case BLE_GAP_EVENT_CONN_UPDATE: if (event->conn_update.status != 0) { - MODLOG_DFLT(INFO, "Connection update failed\n"); + MODLOG_DFLT(DEBUG, "Connection update failed\n"); } else { - MODLOG_DFLT(INFO, "Connection updated; num=%d\n", + MODLOG_DFLT(DEBUG, "Connection updated; num=%d\n", ++tx_stress_ctx->con_stat[8].prms_upd_num); } return 0; case BLE_GAP_EVENT_CONN_UPDATE_REQ: - MODLOG_DFLT(INFO, "Connection update request\n"); + MODLOG_DFLT(DEBUG, "Connection update request\n"); return 0; case BLE_GAP_EVENT_PHY_UPDATE_COMPLETE: if (event->phy_updated.status != 0) { - MODLOG_DFLT(INFO, "PHY update failed\n"); + MODLOG_DFLT(WARN, "PHY update failed\n"); } else { - MODLOG_DFLT(INFO, "PHY updated; num=%d\n", - ++tx_stress_ctx->con_stat[8].phy_upd_num); - console_printf("\033[0;32m>\033[0m"); + MODLOG_DFLT(INFO, "PHY updated; num=%d; rx:%d, tx:%d\n", + ++tx_stress_ctx->con_stat[8].phy_upd_num, + event->phy_updated.rx_phy, event->phy_updated.tx_phy); } if (tx_stress_ctx->con_stat[8].phy_upd_num >= @@ -848,6 +850,16 @@ tx_stress_9_gap_event(struct ble_gap_event *event, void *arg) { ble_addr_t addr; int test; + struct ble_gap_conn_params conn_params = { + .scan_itvl = 0x0010, + .scan_window = 0x0010, + .itvl_min = BLE_GAP_INITIAL_CONN_ITVL_MIN, + .itvl_max = BLE_GAP_INITIAL_CONN_ITVL_MAX, + .latency = 0, + .supervision_timeout = 0x0C80, + .min_ce_len = 0x0010, + .max_ce_len = 0x0300, + }; switch (event->type) { case BLE_GAP_EVENT_EXT_DISC: @@ -860,13 +872,13 @@ tx_stress_9_gap_event(struct ble_gap_event *event, void *arg) ble_gap_disc_cancel(); tx_stress_ctx->dev_addr = event->ext_disc.addr; tx_stress_simple_connect(tx_stress_9_gap_event, - tx_stress_ctx->cur_test_id); + tx_stress_ctx->cur_test_id, &conn_params); } return 0; case BLE_GAP_EVENT_DISC_COMPLETE: if (event->disc_complete.reason == 0 && !tx_stress_ctx->completed[9]) { - console_printf("\033[0;31mScanning timeout\033[0m"); + MODLOG_DFLT(ERROR, "Scanning timeout"); tx_stress_ctx->completed[9] = true; os_sem_release(&tx_stress_main_sem); return 0; @@ -876,24 +888,24 @@ tx_stress_9_gap_event(struct ble_gap_event *event, void *arg) case BLE_GAP_EVENT_CONNECT: /* A new connection was established or a connection attempt failed. */ if (event->connect.status == 0) { - MODLOG_DFLT(INFO, "Success to connect to device\n"); + MODLOG_DFLT(INFO, "Success to connect to device, conn " + "handle=%d\n", event->connect.conn_handle); MODLOG_DFLT(INFO, "Connections num: %d\n", ++tx_stress_ctx->con_stat[9].num); - console_printf("\033[0;32m>\033[0m"); /* Remember max number of handled connections */ if (tx_stress_ctx->con_stat[9].num > tx_stress_ctx->con_stat[9].max_num) { tx_stress_ctx->con_stat[9].max_num = tx_stress_ctx->con_stat[9].num; } } else { - MODLOG_DFLT(INFO, "\033[0;31mError: connection attempt failed; " - "status=%d\033[0m\n", event->connect.status); + MODLOG_DFLT(ERROR, "Error: connection attempt failed; " + "status=%d\n", event->connect.status); } break; case BLE_GAP_EVENT_DISCONNECT: - MODLOG_DFLT(INFO, "Disconnect; reason=%d ", event->disconnect.reason); - console_printf("\033[0;31mX\033[0m"); + MODLOG_DFLT(DEBUG, "Disconnect; reason=%d; conn handle=%d", + event->disconnect.reason); MODLOG_DFLT(INFO, "Connections num: %d\n", --tx_stress_ctx->con_stat[9].num); @@ -904,7 +916,7 @@ tx_stress_9_gap_event(struct ble_gap_event *event, void *arg) break; default: - MODLOG_DFLT(INFO, "Other event occurs=%d\n", event->type); + MODLOG_DFLT(DEBUG, "Other event occurs=%d\n", event->type); return 0; } @@ -946,7 +958,7 @@ tx_stress_9_perform() for (i = 0; i <= MYNEWT_VAL(BLE_MAX_CONNECTIONS); ++i) { rc = ble_gap_conn_find(i, NULL); if (rc == 0) { - MODLOG_DFLT(INFO, "Terminating...\n"); + MODLOG_DFLT(DEBUG, "Terminating...\n"); ble_gap_terminate(i, BLE_ERR_REM_USER_CONN_TERM); } } @@ -1071,19 +1083,19 @@ tx_stress_10_l2cap_event(struct ble_l2cap_event *event, void *arg) /* Time of data sending */ us = tx_stress_ctx->end_us - tx_stress_ctx->begin_us; - MODLOG_DFLT(INFO, "Time of receiving L2CAP data: %ld \n", + MODLOG_DFLT(DEBUG, "Time of receiving L2CAP data: %ld \n", tx_stress_ctx->end_us); /* Remember size of entire mbuf chain */ tx_stress_ctx->rcv_data_bytes = OS_MBUF_PKTLEN( event->receive.sdu_rx); - MODLOG_DFLT(INFO, "Num of received bytes: %lld\n", + MODLOG_DFLT(DEBUG, "Num of received bytes: %lld\n", tx_stress_ctx->rcv_data_bytes); /* Calculate the bit rate of this send */ tx_stress_ctx->s10_bit_rate = stress_calc_bit_rate(us, tx_stress_ctx->rcv_data_bytes); - MODLOG_DFLT(INFO, "Bit rate: %d B/s\n", tx_stress_ctx->s10_bit_rate); + MODLOG_DFLT(DEBUG, "Bit rate: %d B/s\n", tx_stress_ctx->s10_bit_rate); /* Remember the sum of bytes and the time to calculate the average * bit rate. */ @@ -1094,7 +1106,6 @@ tx_stress_10_l2cap_event(struct ble_l2cap_event *event, void *arg) if (tx_stress_ctx->s10_max_mtu < tx_stress_ctx->rcv_data_bytes) { tx_stress_ctx->s10_max_mtu = tx_stress_ctx->rcv_data_bytes; } - console_printf("\033[0;32m>\033[0m"); MODLOG_DFLT(INFO, "Loop nr: %d\n", ++i); tx_stress_10_l2cap_send_req(); @@ -1132,8 +1143,8 @@ tx_stress_10_gap_event(struct ble_gap_event *event, void *arg) tx_stress_10_l2cap_event, NULL); assert(rc == 0); } else { - MODLOG_DFLT(INFO, "\033[0;31mError: connection attempt failed; " - "status=%d\033[0m\n", event->connect.status); + MODLOG_DFLT(ERROR, "Error: connection attempt failed; " + "status=%d\n", event->connect.status); } return 0; @@ -1141,13 +1152,13 @@ tx_stress_10_gap_event(struct ble_gap_event *event, void *arg) tx_stress_ctx->s10_bit_rate = 1000000 * tx_stress_ctx->bytes_sum / tx_stress_ctx->time_sum; - MODLOG_DFLT(INFO, "Average bit rate: %d B/s\n", + MODLOG_DFLT(DEBUG, "Average bit rate: %d B/s\n", tx_stress_ctx->s10_bit_rate); tx_stress_on_test_finish(10); return 0; default: - MODLOG_DFLT(INFO, "Other event occurs=%d\n", event->type); + MODLOG_DFLT(DEBUG, "Other event occurs=%d\n", event->type); return 0; } } @@ -1169,7 +1180,7 @@ tx_stress_11_gap_event(struct ble_gap_event *event, void *arg) ble_gap_disc_cancel(); tx_stress_ctx->dev_addr = event->ext_disc.addr; tx_stress_simple_connect(tx_stress_11_gap_event, - tx_stress_ctx->cur_test_id); + tx_stress_ctx->cur_test_id, NULL); } return 0; @@ -1177,18 +1188,18 @@ tx_stress_11_gap_event(struct ble_gap_event *event, void *arg) /* A new connection was established or a connection attempt failed. */ if (event->connect.status == 0) { ++tx_stress_ctx->con_stat[11].num; - MODLOG_DFLT(INFO, "Success to connect to device\n"); + MODLOG_DFLT(INFO, "Success to connect to device; conn " + "handle=%d\n", event->connect.conn_handle); } else { - MODLOG_DFLT(INFO, "\033[0;31mError: connection attempt failed; " - "status=%d\033[0m\n", event->connect.status); + MODLOG_DFLT(ERROR, "Error: connection attempt failed; " + "status=%d\n", event->connect.status); break; } return 0; case BLE_GAP_EVENT_DISCONNECT: - MODLOG_DFLT(INFO, "Disconnect; reason=%d \n", + MODLOG_DFLT(DEBUG, "Disconnect; reason=%d \n", event->disconnect.reason); - console_printf("\033[0;32m>\033[0m"); if (tx_stress_ctx->con_stat[11].num >= MYNEWT_VAL(BLE_STRESS_REPEAT)) { tx_stress_on_test_finish(11); @@ -1197,7 +1208,7 @@ tx_stress_11_gap_event(struct ble_gap_event *event, void *arg) break; default: - MODLOG_DFLT(INFO, "Other event occurs=%d\n", event->type); + MODLOG_DFLT(DEBUG, "Other event occurs=%d\n", event->type); return 0; } @@ -1217,16 +1228,16 @@ tx_stress_12_gap_event(struct ble_gap_event *event, void *arg) /* A new connection was established or a connection attempt failed. */ if (event->connect.status == 0) { ++tx_stress_ctx->con_stat[12].num; - MODLOG_DFLT(INFO, "Success to connect to device\n"); + MODLOG_DFLT(DEBUG, "Success to connect to device\n"); tx_stress_ctx->conn_handle = event->connect.conn_handle; } else { - MODLOG_DFLT(INFO, "\033[0;31mError: connection attempt failed; " - "status=%d\033[0m\n", event->connect.status); + MODLOG_DFLT(ERROR, "Error: connection attempt failed; " + "status=%d\n", event->connect.status); } return 0; case BLE_GAP_EVENT_DISCONNECT: - MODLOG_DFLT(INFO, "Disconnect; reason=%d \n", + MODLOG_DFLT(DEBUG, "Disconnect; reason=%d \n", event->disconnect.reason); /* Finish test after first disconnection */ tx_stress_on_test_finish(12); @@ -1234,12 +1245,11 @@ tx_stress_12_gap_event(struct ble_gap_event *event, void *arg) case BLE_GAP_EVENT_NOTIFY_RX: /* Received indication */ - MODLOG_DFLT(INFO, "Notify RX event\n"); - console_printf("\033[0;32m>\033[0m"); + MODLOG_DFLT(INFO, "Received indication\n"); return 0; default: - MODLOG_DFLT(INFO, "Other event occurs=%d\n", event->type); + MODLOG_DFLT(DEBUG, "Other event occurs=%d\n", event->type); return 0; } } @@ -1252,31 +1262,30 @@ tx_stress_13_gap_event(struct ble_gap_event *event, void *arg) /* A new connection was established or a connection attempt failed. */ if (event->connect.status == 0) { ++tx_stress_ctx->con_stat[13].num; - MODLOG_DFLT(INFO, "Success to connect to device\n"); + MODLOG_DFLT(DEBUG, "Success to connect to device\n"); tx_stress_ctx->conn_handle = event->connect.conn_handle; } else { - MODLOG_DFLT(INFO, "\033[0;31mError: connection attempt failed; " - "status=%d\033[0m\n", event->connect.status); + MODLOG_DFLT(ERROR, "Error: connection attempt failed; " + "status=%d\n", event->connect.status); assert(0); } return 0; case BLE_GAP_EVENT_DISCONNECT: - MODLOG_DFLT(INFO, "Disconnect; reason=%d \n", + MODLOG_DFLT(DEBUG, "Disconnect; reason=%d \n", event->disconnect.reason); /* Finish test after disconnection */ tx_stress_on_test_finish(13); return 0; case BLE_GAP_EVENT_NOTIFY_RX: - MODLOG_DFLT(INFO, "Notify RX event\n"); - console_printf("\033[0;32m>\033[0m"); - os_mbuf_free_chain(event->notify_rx.om); ++tx_stress_ctx->rcv_num; + MODLOG_DFLT(INFO, "Received notification; count=%d\n", + tx_stress_ctx->rcv_num); return 0; default: - MODLOG_DFLT(INFO, "Other event occurs=%d\n", event->type); + MODLOG_DFLT(DEBUG, "Other event occurs=%d\n", event->type); return 0; } } @@ -1345,7 +1354,7 @@ tx_stress_14_gap_event(struct ble_gap_event *event, void *arg) /* A new connection was established or a connection attempt failed. */ if (event->connect.status == 0) { ++tx_stress_ctx->con_stat[14].num; - MODLOG_DFLT(INFO, "Success to connect to device\n"); + MODLOG_DFLT(DEBUG, "Success to connect to device\n"); tx_stress_ctx->conn_handle = event->connect.conn_handle; /* Find CCCD handle (with default UUID16 = 0x2902) */ @@ -1355,21 +1364,21 @@ tx_stress_14_gap_event(struct ble_gap_event *event, void *arg) BLE_UUID16_DECLARE(0x2902), &tx_stress_14_disc_cccd_fn); } else { - MODLOG_DFLT(INFO, "\033[0;31mError: connection attempt failed; " - "status=%d\033[0m\n", event->connect.status); + MODLOG_DFLT(ERROR, "Error: connection attempt failed; " + "status=%d\n", event->connect.status); assert(0); } return 0; case BLE_GAP_EVENT_DISCONNECT: - MODLOG_DFLT(INFO, "Disconnect; reason=%d \n", + MODLOG_DFLT(DEBUG, "Disconnect; reason=%d \n", event->disconnect.reason); /* Calc average notifying time */ if (tx_stress_ctx->rcv_num > 0) { tx_stress_ctx->s14_notif_time = tx_stress_ctx->time_sum / tx_stress_ctx->rcv_num; } - MODLOG_DFLT(INFO, "Average notification time: %d\n", + MODLOG_DFLT(DEBUG, "Average notification time: %d\n", tx_stress_ctx->s14_notif_time); /* Finish test after first disconnection */ tx_stress_on_test_finish(14); @@ -1377,20 +1386,19 @@ tx_stress_14_gap_event(struct ble_gap_event *event, void *arg) case BLE_GAP_EVENT_NOTIFY_RX: tx_stress_ctx->end_us = os_get_uptime_usec(); - MODLOG_DFLT(INFO, "Notify RX event\n"); + MODLOG_DFLT(DEBUG, "Notify RX event\n"); /* Time of data sending */ us = tx_stress_ctx->end_us - tx_stress_ctx->begin_us; - MODLOG_DFLT(INFO, "Notification time: %lld\n us", us); + MODLOG_DFLT(DEBUG, "Notification time: %lld\n us", us); tx_stress_ctx->time_sum += us; - console_printf("\033[0;32m>\033[0m"); /* Perform use case specified number of times */ if (++tx_stress_ctx->rcv_num >= MYNEWT_VAL(BLE_STRESS_REPEAT)) { rc = ble_gap_terminate(event->notify_rx.conn_handle, BLE_ERR_REM_USER_CONN_TERM); - MODLOG_DFLT(INFO, "rc=%d\n"); + MODLOG_DFLT(DEBUG, "rc=%d\n", rc); assert(rc == 0); return 0; } @@ -1407,7 +1415,7 @@ tx_stress_14_gap_event(struct ble_gap_event *event, void *arg) return 0; default: - MODLOG_DFLT(INFO, "Other event occurs=%d\n", event->type); + MODLOG_DFLT(DEBUG, "Other event occurs=%d\n", event->type); return 0; } } @@ -1418,7 +1426,6 @@ tx_stress_15_write_cb(uint16_t conn_handle, const struct ble_gatt_error *error, { /* Disconnect */ ble_gap_terminate(conn_handle, BLE_ERR_REM_USER_CONN_TERM); - console_printf("\033[0;32m>\033[0m"); return 0; } @@ -1429,7 +1436,7 @@ tx_stress_15_disc_chr_fn(struct stress_gatt_search_ctx *search_ctx) struct os_mbuf *om; /* Send some data */ - MODLOG_DFLT(INFO, "Write to chr\n"); + MODLOG_DFLT(DEBUG, "Write to chr\n"); om = ble_hs_mbuf_from_flat(test_6_pattern, 20); rc = ble_gattc_write(tx_stress_ctx->conn_handle, @@ -1445,7 +1452,7 @@ tx_stress_15_gap_event(struct ble_gap_event *event, void *arg) case BLE_GAP_EVENT_CONNECT: /* A new connection was established or a connection attempt failed. */ if (event->connect.status == 0) { - MODLOG_DFLT(INFO, "Success to connect to device; num: %d\n", + MODLOG_DFLT(DEBUG, "Success to connect to device; num: %d\n", ++tx_stress_ctx->con_stat[15].num); tx_stress_ctx->conn_handle = event->connect.conn_handle; @@ -1455,8 +1462,8 @@ tx_stress_15_gap_event(struct ble_gap_event *event, void *arg) BLE_UUID16_DECLARE(STRESS_GATT_WRITE_UUID), &tx_stress_15_disc_chr_fn); } else { - MODLOG_DFLT(INFO, "\033[0;31mError: connection attempt failed; " - "status=%d\033[0m\n", event->connect.status); + MODLOG_DFLT(ERROR, "Error: connection attempt failed; " + "status=%d\n", event->connect.status); assert(0); } return 0; @@ -1468,11 +1475,11 @@ tx_stress_15_gap_event(struct ble_gap_event *event, void *arg) return 0; } /* Reconnect */ - tx_stress_simple_connect(tx_stress_15_gap_event, 15); + tx_stress_simple_connect(tx_stress_15_gap_event, 15, NULL); return 0; default: - MODLOG_DFLT(INFO, "Other event occurs=%d\n", event->type); + MODLOG_DFLT(DEBUG, "Other event occurs=%d\n", event->type); return 0; } } @@ -1504,12 +1511,12 @@ scan_for_test_gap_event(struct ble_gap_event *event, void *arg) case BLE_GAP_EVENT_DISC_COMPLETE: /* On timeout */ tx_stress_ctx->scan_timeout = true; - console_printf("\033[1;36mDiscover complete\033[0m\n"); + MODLOG_DFLT(DEBUG, "Discover complete\n"); os_sem_release(&tx_stress_main_sem); return 0; default: - MODLOG_DFLT(INFO, "Other event occurs=%d\n", event->type); + MODLOG_DFLT(DEBUG, "Other event occurs=%d\n", event->type); return 0; } } @@ -1526,75 +1533,74 @@ tx_stress_test_perform(int test_num) tx_stress_ctx->completed[test_num] = false; tx_stress_ctx->conn_handle = 0xffff; - console_printf("\033[1;36mStart test num %d - ", test_num); + MODLOG_DFLT(INFO, "Start test num %d - ", test_num); /* Start test */ switch (test_num) { case 0: return; case 1: - console_printf("Stress Connect -> Connect Cancel\033[0m\n"); + MODLOG_DFLT(INFO, "Stress Connect -> Connect Cancel\n"); tx_stress_1_test(); break; case 2: - console_printf("Stress Connect/Disconnect legacy\033[0m\n"); - tx_stress_simple_connect(&tx_stress_2_gap_event, 2); + MODLOG_DFLT(INFO, "Stress Connect/Disconnect legacy\n"); + tx_stress_simple_connect(&tx_stress_2_gap_event, 2, NULL); break; case 3: - console_printf("Stress Connect/Disconnect ext adv\033[0m\n"); - tx_stress_simple_connect(&tx_stress_3_gap_event, 3); + MODLOG_DFLT(INFO, "Stress Connect/Disconnect ext adv\n"); + tx_stress_simple_connect(&tx_stress_3_gap_event, 3, NULL); break; case 4: - console_printf("Stress connection params update (TX)\033[0m\n"); - tx_stress_simple_connect(&tx_stress_4_gap_event, 4); + MODLOG_DFLT(INFO, "Stress connection params update (TX)\n"); + tx_stress_simple_connect(&tx_stress_4_gap_event, 4, NULL); break; case 5: - console_printf("Stress connection params update (RX)\033[0m\n"); - tx_stress_simple_connect(&tx_stress_5_gap_event, 5); + MODLOG_DFLT(INFO, "Stress connection params update (RX)\n"); + tx_stress_simple_connect(&tx_stress_5_gap_event, 5, NULL); break; case 6: - console_printf("Stress Scan\033[0m\n"); + MODLOG_DFLT(INFO, "Stress Scan\n"); tx_stress_6_perform(); break; case 7: - console_printf("Stress PHY Update (TX)\033[0m\n"); - tx_stress_simple_connect(&tx_stress_7_gap_event, 7); + MODLOG_DFLT(INFO, "Stress PHY Update (TX)\n"); + tx_stress_simple_connect(&tx_stress_7_gap_event, 7, NULL); break; case 8: - console_printf("Stress PHY Update (RX)\033[0m\n"); - tx_stress_simple_connect(&tx_stress_8_gap_event, 8); + MODLOG_DFLT(INFO, "Stress PHY Update (RX)\n"); + tx_stress_simple_connect(&tx_stress_8_gap_event, 8, NULL); break; case 9: - console_printf("Stress multi connection\033[0m\n"); + MODLOG_DFLT(INFO, "Stress multi connection\n"); tx_stress_9_perform(); break; case 10: - console_printf("Stress L2CAP send\033[0m\n"); - tx_stress_simple_connect(&tx_stress_10_gap_event, 10); + MODLOG_DFLT(INFO, "Stress L2CAP send\n"); + tx_stress_simple_connect(&tx_stress_10_gap_event, 10, NULL); break; case 11: - console_printf("Stress Advertise/Connect/Disconnect\033[0m\n"); - tx_stress_simple_connect(&tx_stress_11_gap_event, 11); + MODLOG_DFLT(INFO, "Stress Advertise/Connect/Disconnect\n"); + tx_stress_simple_connect(&tx_stress_11_gap_event, 11, NULL); break; case 12: - console_printf("Stress GATT indication\033[0m\n"); - tx_stress_simple_connect(&tx_stress_12_gap_event, 12); + MODLOG_DFLT(INFO, "Stress GATT indication\n"); + tx_stress_simple_connect(&tx_stress_12_gap_event, 12, NULL); break; case 13: - console_printf("Stress GATT notification\033[0m\n"); - tx_stress_simple_connect(&tx_stress_13_gap_event, 13); + MODLOG_DFLT(INFO, "Stress GATT notification\n"); + tx_stress_simple_connect(&tx_stress_13_gap_event, 13, NULL); break; case 14: - console_printf("Stress GATT Subscribe/Notify/Unsubscribe\033[0m\n"); - tx_stress_simple_connect(&tx_stress_14_gap_event, 14); + MODLOG_DFLT(INFO, "Stress GATT Subscribe/Notify/Unsubscribe\n"); + tx_stress_simple_connect(&tx_stress_14_gap_event, 14, NULL); break; case 15: - console_printf("Stress Connect/Send/Disconnect\033[0m\n"); - tx_stress_simple_connect(&tx_stress_15_gap_event, 15); + MODLOG_DFLT(INFO, "Stress Connect/Send/Disconnect\n"); + tx_stress_simple_connect(&tx_stress_15_gap_event, 15, NULL); break; default: - console_printf("\033[0;31mFound test, but do not know how to perform." - "\033[0m\n"); + MODLOG_DFLT(ERROR, "Found test, but do not know how to perform.\n"); assert(0); } @@ -1608,7 +1614,7 @@ tx_stress_test_perform(int test_num) static void tx_stress_read_command_cb(void) { - console_printf("Start testing\n"); + MODLOG_DFLT(INFO, "Start testing\n"); os_sem_release(&tx_stress_main_sem); } @@ -1619,8 +1625,8 @@ tx_stress_main_task_fn(void *arg) tx_stress_ctx = &tx_stress_ctxD; - console_printf("\033[1;36mTX device\033[0m\n"); - console_printf("Press ENTER to start: \n"); + MODLOG_DFLT(INFO, "TX device\n"); + MODLOG_DFLT(INFO, "Press ENTER to start: \n"); console_init(&tx_stress_read_command_cb); /* Waite for pressing ENTER in console */ @@ -1634,7 +1640,7 @@ tx_stress_main_task_fn(void *arg) //tx_stress_test_perform(1); while (1) { - console_printf("\033[0;36mStart scan for test\033[0m\n"); + MODLOG_DFLT(INFO, "Start scan for test\n"); /* Scan for known UUID128 of one of the stress tests. */ tx_stress_simple_scan(scan_for_test_gap_event, 2000); diff --git a/apps/blestress/syscfg.yml b/apps/blestress/syscfg.yml index 3acf280bb1..b24280436b 100644 --- a/apps/blestress/syscfg.yml +++ b/apps/blestress/syscfg.yml @@ -35,6 +35,10 @@ syscfg.defs: # Settings this app overrides. syscfg.vals: + CONSOLE_IMPLEMENTATION: full + LOG_IMPLEMENTATION: full + STATS_IMPLEMENTATION: full + # Change these settings: # Set 0 to print all debug logs, but keep in mind that plenty of @@ -67,11 +71,17 @@ syscfg.vals: # BLE_L2CAP_COC_MAX_NUM: 2 + # L2CAP COC SDU buffers in RX endpoint + BLE_L2CAP_COC_SDU_BUFF_COUNT: 1 + # Enable 2M PHY - BLE_LL_CFG_FEAT_LE_2M_PHY: 1 + BLE_PHY_2M: 1 # Enable CODED PHY - BLE_LL_CFG_FEAT_LE_CODED_PHY: 1 + BLE_PHY_CODED: 1 # Whether to save data to sys/config, or just keep it in RAM. BLE_STORE_CONFIG_PERSIST: 0 + + # ACL buf size must be able to contain CoC MPS plus ACL header + BLE_TRANSPORT_ACL_SIZE: MYNEWT_VAL_BLE_L2CAP_COC_MPS + 4 diff --git a/apps/btshell/pkg.yml b/apps/btshell/pkg.yml index be6d68548f..79b0dcfa3e 100644 --- a/apps/btshell/pkg.yml +++ b/apps/btshell/pkg.yml @@ -24,17 +24,20 @@ pkg.keywords: pkg.deps: - "@apache-mynewt-core/kernel/os" - - "@apache-mynewt-core/sys/log/full" + - "@apache-mynewt-core/sys/log" - "@apache-mynewt-core/sys/log/modlog" - - "@apache-mynewt-core/sys/stats/full" - - "@apache-mynewt-core/sys/console/full" + - "@apache-mynewt-core/sys/stats" + - "@apache-mynewt-core/sys/console" - "@apache-mynewt-core/sys/shell" + - "@apache-mynewt-core/util/parse_arg" - nimble/host - nimble/host/services/gap - nimble/host/services/gatt - nimble/host/store/config - nimble/host/util - - nimble/transport pkg.deps.BTSHELL_ANS: - nimble/host/services/ans + +pkg.deps.BLE_AUDIO: + - nimble/host/audio diff --git a/apps/btshell/src/btshell.h b/apps/btshell/src/btshell.h index 7c978221c6..d8bf83d2ff 100644 --- a/apps/btshell/src/btshell.h +++ b/apps/btshell/src/btshell.h @@ -83,10 +83,15 @@ struct btshell_conn { struct btshell_l2cap_coc_list coc_list; }; +#define NAME_FILTER_LEN_MAX 20 + struct btshell_scan_opts { uint16_t limit; - uint8_t ignore_legacy:1; - uint8_t periodic_only:1; + uint8_t ignore_legacy : 1; + uint8_t periodic_only : 1; + uint8_t silent : 1; + uint8_t name_filter_len; + char name_filter[NAME_FILTER_LEN_MAX]; }; extern struct btshell_conn btshell_conns[MYNEWT_VAL(BLE_MAX_CONNECTIONS)]; @@ -96,22 +101,22 @@ int btshell_exchange_mtu(uint16_t conn_handle); int btshell_disc_svcs(uint16_t conn_handle); int btshell_disc_svc_by_uuid(uint16_t conn_handle, const ble_uuid_t *uuid); int btshell_disc_all_chrs(uint16_t conn_handle, uint16_t start_handle, - uint16_t end_handle); + uint16_t end_handle); int btshell_disc_all_chrs_in_svc(uint16_t conn_handle, struct btshell_svc *svc); int btshell_disc_chrs_by_uuid(uint16_t conn_handle, uint16_t start_handle, - uint16_t end_handle, const ble_uuid_t *uuid); + uint16_t end_handle, const ble_uuid_t *uuid); int btshell_disc_all_dscs(uint16_t conn_handle, uint16_t start_handle, uint16_t end_handle); int btshell_disc_full(uint16_t conn_handle); int btshell_find_inc_svcs(uint16_t conn_handle, uint16_t start_handle, - uint16_t end_handle); + uint16_t end_handle); int btshell_read(uint16_t conn_handle, uint16_t attr_handle); int btshell_read_long(uint16_t conn_handle, uint16_t attr_handle, uint16_t offset); int btshell_read_by_uuid(uint16_t conn_handle, uint16_t start_handle, - uint16_t end_handle, const ble_uuid_t *uuid); + uint16_t end_handle, const ble_uuid_t *uuid); int btshell_read_mult(uint16_t conn_handle, uint16_t *attr_handles, - int num_attr_handles); + int num_attr_handles, bool variable); int btshell_write(uint16_t conn_handle, uint16_t attr_handle, struct os_mbuf *om); int btshell_write_no_rsp(uint16_t conn_handle, uint16_t attr_handle, @@ -120,6 +125,12 @@ int btshell_write_long(uint16_t conn_handle, uint16_t attr_handle, uint16_t offset, struct os_mbuf *om); int btshell_write_reliable(uint16_t conn_handle, struct ble_gatt_attr *attrs, int num_attrs); +#if MYNEWT_VAL(BLE_GATT_NOTIFY_MULTIPLE) +int btshell_enqueue_notif(uint16_t handle, uint16_t len, uint8_t *value); +int btshell_send_pending_notif(uint16_t conn_handle); +int btshell_clear_pending_notif(void); +#endif + #if MYNEWT_VAL(BLE_EXT_ADV) int btshell_ext_adv_configure(uint8_t instance, const struct ble_gap_ext_adv_params *params, @@ -178,9 +189,45 @@ int btshell_l2cap_send(uint16_t conn, uint16_t idx, uint16_t bytes); int btshell_l2cap_reconfig(uint16_t conn_handle, uint16_t mtu, uint8_t num, uint8_t idxs[]); +#if (MYNEWT_VAL(BLE_ISO_BROADCAST_SOURCE)) +int btshell_broadcast_base_add(uint8_t adv_instance, uint32_t presentation_delay); +int btshell_broadcast_big_sub_add(uint8_t adv_instance, + uint8_t codec_fmt, + uint16_t company_id, + uint16_t vendor_spec, + uint8_t *metadata, + unsigned int metadata_len, + uint8_t *codec_spec_cfg, + unsigned int codec_spec_cfg_len); +int btshell_broadcast_bis_add(uint8_t adv_instance, + uint8_t *codec_spec_cfg, + unsigned int codec_spec_cfg_len); +int btshell_broadcast_create(uint8_t adv_instance, + struct ble_gap_ext_adv_params *ext_params, + struct ble_gap_periodic_adv_params + *per_params, + const char *name, + struct ble_iso_big_params big_params, + uint8_t *extra_data, + unsigned int extra_data_len); +int btshell_broadcast_destroy(uint8_t adv_instance); +int btshell_broadcast_update(uint8_t adv_instance, + const char *name, + uint8_t *extra_data, + unsigned int extra_data_len); +int btshell_broadcast_start(uint8_t adv_instance); +int btshell_broadcast_stop(uint8_t adv_instance); +#endif + +#if MYNEWT_VAL(BLE_AUDIO) +void btshell_leaudio_init(void); +#else +#define btshell_leaudio_init() +#endif /* BLE_AUDIO */ + int btshell_gap_event(struct ble_gap_event *event, void *arg); void btshell_sync_stats(uint16_t handle); - +uint8_t btshell_get_default_own_addr_type(void); /** GATT server. */ #define GATT_SVR_SVC_ALERT_UUID 0x1811 #define GATT_SVR_CHR_SUP_NEW_ALERT_CAT_UUID 0x2A47 diff --git a/apps/btshell/src/cmd.c b/apps/btshell/src/cmd.c index a0452d22eb..3380de7547 100644 --- a/apps/btshell/src/cmd.c +++ b/apps/btshell/src/cmd.c @@ -41,7 +41,13 @@ #include "cmd.h" #include "btshell.h" #include "cmd_gatt.h" +#include "cmd_iso.h" #include "cmd_l2cap.h" +#include "cmd_leaudio.h" + +#ifndef min +#define min(a, b) ((a) < (b) ? (a) : (b)) +#endif #define BTSHELL_MODULE "btshell" @@ -69,7 +75,7 @@ cmd_parse_conn_start_end(uint16_t *out_conn, uint16_t *out_start, return 0; } -static const struct kv_pair cmd_own_addr_types[] = { +static const struct parse_arg_kv_pair cmd_own_addr_types[] = { { "public", BLE_OWN_ADDR_PUBLIC }, { "random", BLE_OWN_ADDR_RANDOM }, { "rpa_pub", BLE_OWN_ADDR_RPA_PUBLIC_DEFAULT }, @@ -77,7 +83,7 @@ static const struct kv_pair cmd_own_addr_types[] = { { NULL } }; -static const struct kv_pair cmd_peer_addr_types[] = { +static const struct parse_arg_kv_pair cmd_peer_addr_types[] = { { "public", BLE_ADDR_PUBLIC }, { "random", BLE_ADDR_RANDOM }, { "public_id", BLE_ADDR_PUBLIC_ID }, @@ -85,38 +91,59 @@ static const struct kv_pair cmd_peer_addr_types[] = { { NULL } }; -static const struct kv_pair cmd_addr_type[] = { +const struct parse_arg_kv_pair cmd_addr_type[] = { { "public", BLE_ADDR_PUBLIC }, { "random", BLE_ADDR_RANDOM }, { NULL } }; +const char * +cmd_addr_type_str(uint8_t type) +{ + const struct parse_arg_kv_pair *kvs = cmd_addr_type; + int i; -static int -parse_dev_addr(const char *prefix, const struct kv_pair *addr_types, + for (i = 0; kvs[i].key != NULL; i++) { + if (type == kvs[i].val) { + return kvs[i].key; + } + } + + return "unknown"; +} + +int +parse_dev_addr(const char *prefix, const struct parse_arg_kv_pair *addr_types, ble_addr_t *addr) { char name[32]; int rc; + int written = 0; if (!prefix) { name[0] = '\0'; } else { - if (strlcpy(name, prefix, sizeof(name)) >= sizeof(name)) { + written = snprintf(name, sizeof(name), "%s", prefix); + if (written >= sizeof(name) || written < 0) { return EINVAL; } } - if (strlcat(name, "addr", sizeof(name)) >= sizeof(name)) { + rc = snprintf(name + written, sizeof(name) - written, "%s", "addr"); + if (rc >= sizeof(name) - written || rc < 0) { return EINVAL; } - rc = parse_arg_addr(name, addr); + written += rc; + + rc = parse_arg_ble_addr(name, addr); if (rc == ENOENT) { /* not found */ return rc; } else if (rc == EAGAIN) { /* address found, but no type provided */ - if (strlcat(name, "_type", sizeof(name)) >= sizeof(name)) { + rc = written; + written = snprintf(name + written, sizeof(name) - written, "%s", "_type"); + if (written >= sizeof(name) - rc || written < 0) { return EINVAL; } addr->type = parse_arg_kv(name, addr_types, &rc); @@ -130,7 +157,9 @@ parse_dev_addr(const char *prefix, const struct kv_pair *addr_types, return rc; } else { /* full address found, but let's just make sure there is no type arg */ - if (strlcat(name, "_type", sizeof(name)) >= sizeof(name)) { + rc = written; + written = snprintf(name + written, sizeof(name) - written, "%s", "_type"); + if (written >= sizeof(name) - rc || written < 0) { return EINVAL; } if (parse_arg_extract(name)) { @@ -141,10 +170,16 @@ parse_dev_addr(const char *prefix, const struct kv_pair *addr_types, return 0; } +int +cmd_parse_addr(const char *prefix, ble_addr_t *addr) +{ + return parse_dev_addr(prefix, cmd_addr_type, addr); +} + /***************************************************************************** * $advertise * *****************************************************************************/ -static const struct kv_pair cmd_adv_filt_types[] = { +static const struct parse_arg_kv_pair cmd_adv_filt_types[] = { { "none", BLE_HCI_ADV_FILT_NONE }, { "scan", BLE_HCI_ADV_FILT_SCAN }, { "conn", BLE_HCI_ADV_FILT_CONN }, @@ -153,7 +188,7 @@ static const struct kv_pair cmd_adv_filt_types[] = { }; #if MYNEWT_VAL(BLE_EXT_ADV) -static struct kv_pair cmd_ext_adv_phy_opts[] = { +static struct parse_arg_kv_pair cmd_ext_adv_phy_opts[] = { { "1M", 0x01 }, { "2M", 0x02 }, { "coded", 0x03 }, @@ -168,7 +203,7 @@ cmd_advertise_configure(int argc, char **argv) uint8_t instance; int rc; - rc = parse_arg_all(argc - 1, argv + 1); + rc = parse_arg_init(argc - 1, argv + 1); if (rc != 0) { return rc; } @@ -251,7 +286,7 @@ cmd_advertise_configure(int argc, char **argv) params.own_addr_type = parse_arg_kv_dflt("own_addr_type", cmd_own_addr_types, - BLE_OWN_ADDR_PUBLIC, &rc); + btshell_get_default_own_addr_type(), &rc); if (rc != 0) { console_printf("invalid 'own_addr_type' parameter\n"); return rc; @@ -329,7 +364,7 @@ cmd_advertise_set_addr(int argc, char **argv) uint8_t instance; int rc; - rc = parse_arg_all(argc - 1, argv + 1); + rc = parse_arg_init(argc - 1, argv + 1); if (rc != 0) { return rc; } @@ -340,7 +375,7 @@ cmd_advertise_set_addr(int argc, char **argv) return rc; } - rc = parse_arg_mac("addr", addr.val); + rc = parse_arg_mac_addr("addr", addr.val); if (rc != 0) { console_printf("invalid 'addr' parameter\n"); return rc; @@ -366,7 +401,7 @@ cmd_advertise_start(int argc, char **argv) bool restart; int rc; - rc = parse_arg_all(argc - 1, argv + 1); + rc = parse_arg_init(argc - 1, argv + 1); if (rc != 0) { return rc; } @@ -410,7 +445,7 @@ cmd_advertise_stop(int argc, char **argv) uint8_t instance; int rc; - rc = parse_arg_all(argc - 1, argv + 1); + rc = parse_arg_init(argc - 1, argv + 1); if (rc != 0) { return rc; } @@ -436,7 +471,7 @@ cmd_advertise_remove(int argc, char **argv) uint8_t instance; int rc; - rc = parse_arg_all(argc - 1, argv + 1); + rc = parse_arg_init(argc - 1, argv + 1); if (rc != 0) { return rc; } @@ -464,7 +499,7 @@ static const struct shell_param advertise_configure_params[] = { {"directed", "directed advertising, usage: =[0-1], default: 0"}, {"peer_addr_type", "usage: =[public|random|public_id|random_id], default: public"}, {"peer_addr", "usage: =[XX:XX:XX:XX:XX:XX]"}, - {"own_addr_type", "usage: =[public|random|rpa_pub|rpa_rnd], default: public"}, + {"own_addr_type", "usage: =[public|random|rpa_pub|rpa_rnd], default: public if available, otherwise random"}, {"channel_map", "usage: =[0x00-0xff], default: 0"}, {"filter", "usage: =[none|scan|conn|both], default: none"}, {"interval_min", "usage: =[0-UINT32_MAX], default: 0"}, @@ -537,14 +572,14 @@ static const struct shell_cmd_help advertise_remove_help = { #endif #else -static const struct kv_pair cmd_adv_conn_modes[] = { +static const struct parse_arg_kv_pair cmd_adv_conn_modes[] = { { "non", BLE_GAP_CONN_MODE_NON }, { "und", BLE_GAP_CONN_MODE_UND }, { "dir", BLE_GAP_CONN_MODE_DIR }, { NULL } }; -static const struct kv_pair cmd_adv_disc_modes[] = { +static const struct parse_arg_kv_pair cmd_adv_disc_modes[] = { { "non", BLE_GAP_DISC_MODE_NON }, { "ltd", BLE_GAP_DISC_MODE_LTD }, { "gen", BLE_GAP_DISC_MODE_GEN }, @@ -562,7 +597,7 @@ cmd_advertise(int argc, char **argv) bool restart; int rc; - rc = parse_arg_all(argc - 1, argv + 1); + rc = parse_arg_init(argc - 1, argv + 1); if (rc != 0) { return rc; } @@ -606,7 +641,7 @@ cmd_advertise(int argc, char **argv) } own_addr_type = parse_arg_kv_dflt("own_addr_type", cmd_own_addr_types, - BLE_OWN_ADDR_PUBLIC, &rc); + btshell_get_default_own_addr_type(), &rc); if (rc != 0) { console_printf("invalid 'own_addr_type' parameter\n"); return rc; @@ -667,7 +702,7 @@ static const struct shell_param advertise_params[] = { {"discov", "discoverable mode, usage: =[non|ltd|gen], default: gen"}, {"peer_addr_type", "usage: =[public|random|public_id|random_id], default: public"}, {"peer_addr", "usage: =[XX:XX:XX:XX:XX:XX]"}, - {"own_addr_type", "usage: =[public|random|rpa_pub|rpa_rnd], default: public"}, + {"own_addr_type", "usage: =[public|random|rpa_pub|rpa_rnd], default: public if available, otherwise random"}, {"channel_map", "usage: =[0x00-0xff], default: 0"}, {"filter", "usage: =[none|scan|conn|both], default: none"}, {"interval_min", "usage: =[0-UINT16_MAX], default: 0"}, @@ -690,7 +725,7 @@ static const struct shell_cmd_help advertise_help = { * $connect * *****************************************************************************/ -static struct kv_pair cmd_ext_conn_phy_opts[] = { +static struct parse_arg_kv_pair cmd_ext_conn_phy_opts[] = { { "none", 0x00 }, { "1M", 0x01 }, { "coded", 0x02 }, @@ -712,7 +747,7 @@ cmd_connect(int argc, char **argv) int own_addr_type; int rc; - rc = parse_arg_all(argc - 1, argv + 1); + rc = parse_arg_init(argc - 1, argv + 1); if (rc != 0) { return rc; } @@ -743,7 +778,7 @@ cmd_connect(int argc, char **argv) } own_addr_type = parse_arg_kv_dflt("own_addr_type", cmd_own_addr_types, - BLE_OWN_ADDR_PUBLIC, &rc); + btshell_get_default_own_addr_type(), &rc); if (rc != 0) { console_printf("invalid 'own_addr_type' parameter\n"); return rc; @@ -960,7 +995,7 @@ static const struct shell_param connect_params[] = { {"extended", "usage: =[none|1M|coded|both|all], default: none"}, {"peer_addr_type", "usage: =[public|random|public_id|random_id], default: public"}, {"peer_addr", "usage: =[XX:XX:XX:XX:XX:XX]"}, - {"own_addr_type", "usage: =[public|random|rpa_pub|rpa_rnd], default: public"}, + {"own_addr_type", "usage: =[public|random|rpa_pub|rpa_rnd], default: public if available, otherwise random"}, {"duration", "usage: =[1-INT32_MAX], default: 0"}, {"scan_interval", "usage: =[0-UINT16_MAX], default: 0x0010"}, {"scan_window", "usage: =[0-UINT16_MAX], default: 0x0010"}, @@ -1005,7 +1040,7 @@ cmd_disconnect(int argc, char **argv) uint8_t reason; int rc; - rc = parse_arg_all(argc - 1, argv + 1); + rc = parse_arg_init(argc - 1, argv + 1); if (rc != 0) { return rc; } @@ -1096,16 +1131,20 @@ static const struct shell_cmd_help disconnect_help = { *****************************************************************************/ static struct btshell_scan_opts g_scan_opts = { - .limit = UINT16_MAX, - .ignore_legacy = 0, + .limit = UINT16_MAX, + .ignore_legacy = 0, + .periodic_only = 0, + .silent = 0, + .name_filter_len = 0, }; static int cmd_set_scan_opts(int argc, char **argv) { + char *name_filter; int rc; - rc = parse_arg_all(argc - 1, argv + 1); + rc = parse_arg_init(argc - 1, argv + 1); if (rc != 0) { return rc; } @@ -1122,12 +1161,28 @@ cmd_set_scan_opts(int argc, char **argv) return rc; } + g_scan_opts.silent = parse_arg_bool_dflt("silent", 0, &rc); + if (rc != 0) { + console_printf("invalid 'silent' parameter\n"); + return rc; + } + g_scan_opts.periodic_only = parse_arg_bool_dflt("periodic_only", 0, &rc); if (rc != 0) { console_printf("invalid 'periodic_only' parameter\n"); return rc; } + name_filter = parse_arg_extract("name_filter"); + if (name_filter) { + strncpy(g_scan_opts.name_filter, name_filter, NAME_FILTER_LEN_MAX); + g_scan_opts.name_filter[NAME_FILTER_LEN_MAX - 1] = '\0'; + } else { + g_scan_opts.name_filter[0] = '\0'; + } + + g_scan_opts.name_filter_len = strlen(g_scan_opts.name_filter); + return rc; } @@ -1136,6 +1191,8 @@ static const struct shell_param set_scan_opts_params[] = { {"decode_limit", "usage: =[0-UINT16_MAX], default: UINT16_MAX"}, {"ignore_legacy", "usage: =[0-1], default: 0"}, {"periodic_only", "usage: =[0-1], default: 0"}, + {"silent", "usage: =[0-1], default: 0"}, + {"name_filter", "usage: =name, default: {none}"}, {NULL, NULL} }; @@ -1150,7 +1207,7 @@ static const struct shell_cmd_help set_scan_opts_help = { * $scan * *****************************************************************************/ -static const struct kv_pair cmd_scan_filt_policies[] = { +static const struct parse_arg_kv_pair cmd_scan_filt_policies[] = { { "no_wl", BLE_HCI_SCAN_FILT_NO_WL }, { "use_wl", BLE_HCI_SCAN_FILT_USE_WL }, { "no_wl_inita", BLE_HCI_SCAN_FILT_NO_WL_INITA }, @@ -1158,7 +1215,7 @@ static const struct kv_pair cmd_scan_filt_policies[] = { { NULL } }; -static struct kv_pair cmd_scan_ext_types[] = { +static struct parse_arg_kv_pair cmd_scan_ext_types[] = { { "none", 0x00 }, { "1M", 0x01 }, { "coded", 0x02 }, @@ -1181,12 +1238,12 @@ cmd_scan(int argc, char **argv) uint16_t period; int rc; - rc = parse_arg_all(argc - 1, argv + 1); + rc = parse_arg_init(argc - 1, argv + 1); if (rc != 0) { return rc; } - if (argc > 1 && strcmp(argv[1], "cancel") == 0) { + if (argc > 1 && (strcmp(argv[1], "cancel") == 0 || strcmp(argv[1], "off") == 0)) { rc = btshell_scan_cancel(); if (rc != 0) { console_printf("scan cancel fail: %d\n", rc); @@ -1245,7 +1302,7 @@ cmd_scan(int argc, char **argv) } own_addr_type = parse_arg_kv_dflt("own_addr_type", cmd_own_addr_types, - BLE_OWN_ADDR_PUBLIC, &rc); + btshell_get_default_own_addr_type(), &rc); if (rc != 0) { console_printf("invalid 'own_addr_type' parameter\n"); return rc; @@ -1330,6 +1387,7 @@ cmd_scan(int argc, char **argv) #if MYNEWT_VAL(SHELL_CMD_HELP) static const struct shell_param scan_params[] = { {"cancel", "cancel scan procedure"}, + {"off", "\"cancel\" param substitute"}, {"extended", "usage: =[none|1M|coded|both], default: none"}, {"duration", "usage: =[1-INT32_MAX], default: INT32_MAX"}, {"limited", "usage: =[0-1], default: 0"}, @@ -1338,7 +1396,7 @@ static const struct shell_param scan_params[] = { {"window", "usage: =[0-UINT16_MAX], default: 0"}, {"filter", "usage: =[no_wl|use_wl|no_wl_inita|use_wl_inita], default: no_wl"}, {"nodups", "usage: =[0-1], default: 0"}, - {"own_addr_type", "usage: =[public|random|rpa_pub|rpa_rnd], default: public"}, + {"own_addr_type", "usage: =[public|random|rpa_pub|rpa_rnd], default: public if available, otherwise random"}, {"extended_duration", "usage: =[0-UINT16_MAX], default: 0"}, {"extended_period", "usage: =[0-UINT16_MAX], default: 0"}, {"longrange_interval", "usage: =[0-UINT16_MAX], default: 0"}, @@ -1404,7 +1462,7 @@ cmd_set(int argc, char **argv) int good = 0; int rc; - rc = parse_arg_all(argc - 1, argv + 1); + rc = parse_arg_init(argc - 1, argv + 1); if (rc != 0) { return rc; } @@ -1520,11 +1578,11 @@ cmd_set_adv_data_or_scan_rsp(int argc, char **argv, bool scan_rsp, int8_t eddystone_measured_power = 0; char eddystone_url_body[BLE_EDDYSTONE_URL_MAX_LEN]; char *eddystone_url_full; - int svc_data_uuid16_len; - int svc_data_uuid32_len; - int svc_data_uuid128_len; - int uri_len; - int mfg_data_len; + unsigned int svc_data_uuid16_len; + unsigned int svc_data_uuid32_len; + unsigned int svc_data_uuid128_len; + unsigned int uri_len; + unsigned int mfg_data_len; int tmp; int rc; #if MYNEWT_VAL(BLE_EXT_ADV) @@ -1542,7 +1600,7 @@ cmd_set_adv_data_or_scan_rsp(int argc, char **argv, bool scan_rsp, memset(&adv_fields, 0, sizeof adv_fields); - rc = parse_arg_all(argc - 1, argv + 1); + rc = parse_arg_init(argc - 1, argv + 1); if (rc != 0) { return rc; } @@ -1729,9 +1787,9 @@ cmd_set_adv_data_or_scan_rsp(int argc, char **argv, bool scan_rsp, return rc; } - rc = parse_arg_byte_stream("service_data_uuid128", + rc = parse_arg_byte_stream_custom("service_data_uuid128", ":-", CMD_ADV_DATA_SVC_DATA_UUID128_MAX_LEN, - svc_data_uuid128, &svc_data_uuid128_len); + svc_data_uuid128, 0, &svc_data_uuid128_len); if (rc == 0) { adv_fields.svc_data_uuid128 = svc_data_uuid128; adv_fields.svc_data_uuid128_len = svc_data_uuid128_len; @@ -1821,7 +1879,7 @@ cmd_set_adv_data_or_scan_rsp(int argc, char **argv, bool scan_rsp, rc = ble_gap_ext_adv_rsp_set_data(instance, adv_data); #if MYNEWT_VAL(BLE_PERIODIC_ADV) } else if (periodic) { - rc = ble_gap_periodic_adv_set_data(instance, adv_data); + rc = ble_gap_periodic_adv_set_data(instance, adv_data, NULL); #endif } else { rc = ble_gap_ext_adv_set_data(instance, adv_data); @@ -1908,7 +1966,7 @@ cmd_set_priv_mode(int argc, char **argv) uint8_t priv_mode; int rc; - rc = parse_arg_all(argc - 1, argv + 1); + rc = parse_arg_init(argc - 1, argv + 1); if (rc != 0) { return rc; } @@ -1956,7 +2014,7 @@ cmd_white_list(int argc, char **argv) int addrs_cnt; int rc; - rc = parse_arg_all(argc - 1, argv + 1); + rc = parse_arg_init(argc - 1, argv + 1); if (rc != 0) { return rc; } @@ -2012,7 +2070,7 @@ cmd_conn_rssi(int argc, char **argv) int8_t rssi; int rc; - rc = parse_arg_all(argc - 1, argv + 1); + rc = parse_arg_init(argc - 1, argv + 1); if (rc != 0) { return rc; } @@ -2058,7 +2116,7 @@ cmd_conn_update_params(int argc, char **argv) uint16_t conn_handle; int rc; - rc = parse_arg_all(argc - 1, argv + 1); + rc = parse_arg_init(argc - 1, argv + 1); if (rc != 0) { return rc; } @@ -2152,7 +2210,7 @@ cmd_conn_datalen(int argc, char **argv) uint16_t tx_time; int rc; - rc = parse_arg_all(argc - 1, argv + 1); + rc = parse_arg_init(argc - 1, argv + 1); if (rc != 0) { return rc; } @@ -2205,7 +2263,7 @@ static const struct shell_cmd_help conn_datalen_help = { * keystore * *****************************************************************************/ -static const struct kv_pair cmd_keystore_entry_type[] = { +static const struct parse_arg_kv_pair cmd_keystore_entry_type[] = { { "msec", BLE_STORE_OBJ_TYPE_PEER_SEC }, { "ssec", BLE_STORE_OBJ_TYPE_OUR_SEC }, { "cccd", BLE_STORE_OBJ_TYPE_CCCD }, @@ -2234,17 +2292,6 @@ cmd_keystore_parse_keydata(int argc, char **argv, union ble_store_key *out, return rc; } - out->sec.ediv = parse_arg_uint16("ediv", &rc); - if (rc != 0) { - console_printf("invalid 'ediv' parameter\n"); - return rc; - } - - out->sec.rand_num = parse_arg_uint64("rand", &rc); - if (rc != 0) { - console_printf("invalid 'rand' parameter\n"); - return rc; - } return 0; default: @@ -2293,8 +2340,6 @@ cmd_keystore_parse_valuedata(int argc, char **argv, return rc; } out->sec.peer_addr = key->sec.peer_addr; - out->sec.ediv = key->sec.ediv; - out->sec.rand_num = key->sec.rand_num; break; } @@ -2316,7 +2361,7 @@ cmd_keystore_add(int argc, char **argv) int obj_type; int rc; - rc = parse_arg_all(argc - 1, argv + 1); + rc = parse_arg_init(argc - 1, argv + 1); if (rc != 0) { return rc; } @@ -2380,7 +2425,7 @@ cmd_keystore_del(int argc, char **argv) int obj_type; int rc; - rc = parse_arg_all(argc - 1, argv + 1); + rc = parse_arg_init(argc - 1, argv + 1); if (rc != 0) { return rc; } @@ -2426,7 +2471,7 @@ cmd_keystore_iterator(int obj_type, console_printf("Key: "); if (ble_addr_cmp(&val->sec.peer_addr, BLE_ADDR_ANY) == 0) { console_printf("ediv=%u ", val->sec.ediv); - console_printf("ediv=%llu ", val->sec.rand_num); + console_printf("rand=%" PRIu64, val->sec.rand_num); } else { console_printf("addr_type=%u ", val->sec.peer_addr.type); print_addr(val->sec.peer_addr.val); @@ -2469,7 +2514,7 @@ cmd_keystore_show(int argc, char **argv) int type; int rc; - rc = parse_arg_all(argc - 1, argv + 1); + rc = parse_arg_init(argc - 1, argv + 1); if (rc != 0) { return rc; } @@ -2535,7 +2580,7 @@ cmd_auth_passkey(int argc, char **argv) char *yesno; int rc; - rc = parse_arg_all(argc - 1, argv + 1); + rc = parse_arg_init(argc - 1, argv + 1); if (rc != 0) { return rc; } @@ -2655,7 +2700,7 @@ cmd_security_pair(int argc, char **argv) uint16_t conn_handle; int rc; - rc = parse_arg_all(argc - 1, argv + 1); + rc = parse_arg_init(argc - 1, argv + 1); if (rc != 0) { return rc; } @@ -2699,7 +2744,7 @@ cmd_security_unpair(int argc, char **argv) int rc; int oldest; - rc = parse_arg_all(argc - 1, argv + 1); + rc = parse_arg_init(argc - 1, argv + 1); if (rc != 0) { return rc; } @@ -2756,7 +2801,7 @@ cmd_security_start(int argc, char **argv) uint16_t conn_handle; int rc; - rc = parse_arg_all(argc - 1, argv + 1); + rc = parse_arg_init(argc - 1, argv + 1); if (rc != 0) { return rc; } @@ -2804,7 +2849,7 @@ cmd_security_encryption(int argc, char **argv) int rc; int auth; - rc = parse_arg_all(argc - 1, argv + 1); + rc = parse_arg_init(argc - 1, argv + 1); if (rc != 0) { return rc; } @@ -2885,7 +2930,7 @@ cmd_security_set_data(int argc, char **argv) good = 0; - rc = parse_arg_all(argc - 1, argv + 1); + rc = parse_arg_init(argc - 1, argv + 1); if (rc != 0) { return rc; } @@ -2999,7 +3044,7 @@ cmd_test_tx(int argc, char **argv) uint16_t num; uint8_t stop; - rc = parse_arg_all(argc - 1, argv + 1); + rc = parse_arg_init(argc - 1, argv + 1); if (rc != 0) { return rc; } @@ -3076,7 +3121,7 @@ cmd_phy_set(int argc, char **argv) uint16_t phy_opts; int rc; - rc = parse_arg_all(argc - 1, argv + 1); + rc = parse_arg_init(argc - 1, argv + 1); if (rc != 0) { return rc; } @@ -3136,7 +3181,7 @@ cmd_phy_set_default(int argc, char **argv) uint8_t rx_phys_mask; int rc; - rc = parse_arg_all(argc - 1, argv + 1); + rc = parse_arg_init(argc - 1, argv + 1); if (rc != 0) { return rc; } @@ -3182,7 +3227,7 @@ cmd_phy_read(int argc, char **argv) uint8_t rx_phy; int rc; - rc = parse_arg_all(argc - 1, argv + 1); + rc = parse_arg_init(argc - 1, argv + 1); if (rc != 0) { return rc; } @@ -3393,6 +3438,7 @@ static const struct shell_param gatt_read_params[] = { {"uuid", "read by uuid, usage: =[UUID]"}, {"start", "start handle, usage: ="}, {"end", "end handle, usage: ="}, + {"variable", "used in case of multi read, usage: =[0-1], default=0"}, {NULL, NULL} }; @@ -3485,6 +3531,43 @@ static const struct shell_cmd_help gatt_write_help = { .usage = NULL, .params = gatt_write_params, }; + +/***************************************************************************** + * $gatt-enqueue-notify * + *****************************************************************************/ + +static const struct shell_param gatt_enqueue_notif_params[] = { + {"handle", "characteristic handle, usage: ="}, + {"value", "usage: ="}, + {NULL, NULL} +}; + +static const struct shell_cmd_help gatt_enqueue_notif_help = { + .summary = "enqueue notification to be sent", + .usage = NULL, + .params = gatt_enqueue_notif_params, +}; + +/***************************************************************************** + * $gatt-send-pending-notify * + *****************************************************************************/ + +static const struct shell_param gatt_send_pending_notif_params[] = { + {"conn", "connection handle, usage: ="}, + {NULL, NULL} +}; + +static const struct shell_cmd_help gatt_send_pending_notif_help = { + .summary = "send pending notifications", + .usage = NULL, + .params = gatt_send_pending_notif_params, +}; + +static const struct shell_cmd_help gatt_clear_pending_notif_help = { + .summary = "clear pending notifications", + .usage = NULL, + .params = NULL, +}; #endif #if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) @@ -3622,7 +3705,7 @@ cmd_periodic_configure(int argc, char **argv) uint8_t instance; int rc; - rc = parse_arg_all(argc - 1, argv + 1); + rc = parse_arg_init(argc - 1, argv + 1); if (rc != 0) { return rc; } @@ -3678,7 +3761,7 @@ cmd_periodic_start(int argc, char **argv) uint8_t instance; int rc; - rc = parse_arg_all(argc - 1, argv + 1); + rc = parse_arg_init(argc - 1, argv + 1); if (rc != 0) { return rc; } @@ -3689,7 +3772,7 @@ cmd_periodic_start(int argc, char **argv) return rc; } - rc = ble_gap_periodic_adv_start(instance); + rc = ble_gap_periodic_adv_start(instance, NULL); if (rc) { console_printf("failed to start periodic advertising\n"); return rc; @@ -3704,7 +3787,7 @@ cmd_periodic_stop(int argc, char **argv) uint8_t instance; int rc; - rc = parse_arg_all(argc - 1, argv + 1); + rc = parse_arg_init(argc - 1, argv + 1); if (rc != 0) { return rc; } @@ -3771,7 +3854,7 @@ cmd_sync_create(int argc, char **argv) uint8_t sid; int rc; - rc = parse_arg_all(argc - 1, argv + 1); + rc = parse_arg_init(argc - 1, argv + 1); if (rc != 0) { return rc; } @@ -3856,7 +3939,7 @@ cmd_sync_transfer(int argc, char **argv) uint16_t sync_handle; int rc; - rc = parse_arg_all(argc - 1, argv + 1); + rc = parse_arg_init(argc - 1, argv + 1); if (rc != 0) { return rc; } @@ -3895,7 +3978,7 @@ cmd_sync_reporting(int argc, char **argv) bool enable; int rc; - rc = parse_arg_all(argc - 1, argv + 1); + rc = parse_arg_init(argc - 1, argv + 1); if (rc != 0) { return rc; } @@ -3912,7 +3995,7 @@ cmd_sync_reporting(int argc, char **argv) return rc; } - rc = ble_gap_periodic_adv_sync_reporting(sync_handle, enable); + rc = ble_gap_periodic_adv_sync_reporting(sync_handle, enable, NULL); if (rc) { console_printf("Failed to %s reporting (%d)\n", enable ? "enable" : "disable", rc); @@ -3956,7 +4039,7 @@ cmd_sync_transfer_set_info(int argc, char **argv) uint8_t instance; int rc; - rc = parse_arg_all(argc - 1, argv + 1); + rc = parse_arg_init(argc - 1, argv + 1); if (rc != 0) { return rc; } @@ -4011,7 +4094,7 @@ cmd_sync_transfer_receive(int argc, char **argv) bool disable; int rc; - rc = parse_arg_all(argc - 1, argv + 1); + rc = parse_arg_init(argc - 1, argv + 1); if (rc != 0) { return rc; } @@ -4073,13 +4156,13 @@ static const struct shell_param sync_transfer_receive_params[] = { {"reports_disabled", "disable reports, usage: =[0-1], default: 0"}, {NULL, NULL} }; -#endif static const struct shell_cmd_help sync_transfer_receive_help = { .summary = "start/stop periodic sync reception with specific parameters", .usage = NULL, .params = sync_transfer_receive_params, }; +#endif /* SHELL_CMD_HELP */ #endif static int @@ -4088,7 +4171,7 @@ cmd_sync_terminate(int argc, char **argv) uint16_t sync_handle; int rc; - rc = parse_arg_all(argc - 1, argv + 1); + rc = parse_arg_init(argc - 1, argv + 1); if (rc != 0) { return rc; } @@ -4126,7 +4209,7 @@ cmd_sync_stats(int argc, char **argv) uint16_t sync_handle; int rc; - rc = parse_arg_all(argc - 1, argv + 1); + rc = parse_arg_init(argc - 1, argv + 1); if (rc != 0) { return rc; } @@ -4156,6 +4239,140 @@ static const struct shell_cmd_help sync_stats_help = { #endif #endif +#if MYNEWT_VAL(BLE_AUDIO) && MYNEWT_VAL(BLE_ISO_BROADCAST_SOURCE) +#if MYNEWT_VAL(SHELL_CMD_HELP) +static const struct shell_param leaudio_base_add_params[] = { + {"adv_instance", "Advertising instance, usage: ="}, + { "presentation_delay", "usage: =" }, + + { NULL, NULL} +}; + +static const struct shell_cmd_help leaudio_base_add_help = { + .summary = "Add BASE configuration for broadcast", + .usage = NULL, + .params = leaudio_base_add_params, +}; + +static const struct shell_param leaudio_big_sub_add_params[] = { + {"adv_instance", "Advertising instance, usage: ="}, + { "codec_fmt", "usage: " }, + { "company_id", "usage: =" }, + { "vendor_spec", "usage: =" }, + { "codec_spec_config", "usage: =[XX:XX...]" }, + { "metadata", "usage: =[XX:XX...]" }, + + { NULL, NULL} +}; + +static const struct shell_cmd_help leaudio_big_sub_add_help = { + .summary = "Add BIG subgroup configuration for broadcast", + .usage = NULL, + .params = leaudio_big_sub_add_params, +}; + +static const struct shell_param leaudio_bis_add_params[] = { + {"adv_instance", "Advertising instance, usage: ="}, + { "codec_spec_config", "usage: =[XX:XX...]" }, + + { NULL, NULL} +}; + +static const struct shell_cmd_help leaudio_bis_add_help = { + .summary = "Add BIS configuration for broadcast announcements to last " + "added BIG subgroup", + .usage = NULL, + .params = leaudio_bis_add_params, +}; + +static const struct shell_param leaudio_broadcast_create_params[] = { + {"adv_instance", "Advertising instance, usage: ="}, + {"ext_interval_min", "usage: =[0-UINT16_MAX], default: 0"}, + {"ext_interval_max", "usage: =[0-UINT16_MAX], default: 0"}, + {"per_interval_min", "usage: =[0-UINT16_MAX], default: 0"}, + {"per_interval_max", "usage: =[0-UINT16_MAX], default: 0"}, + + {"name", "usage: =[string]"}, + + {"sdu_interval", "SDU interval, in us, usage: ="}, + {"max_sdu", "max SDU size, in octets, usage: ="}, + {"max_latency", "max transport latency, in ms, usage: ="}, + {"rtn", "RTN, usage: ="}, + {"phy", "PHY, usage: ="}, + {"packing", "packing, optional, true if not given, usage: ="}, + {"framing", "framing, optional, false if not given, usage: ="}, + {"encryption", "optional, encryption, usage: ="}, + {"broadcast_code", "optional, obligatory if encryption is enabled, " + "usage: =, len=16 octets"}, + {"extra_data", "usage: =[XX:XX...]"}, + + { NULL, NULL} +}; + +static const struct shell_cmd_help leaudio_broadcast_create_help = { + .summary = "Add BIS configuration for broadcast to last added BIG " + "subgroup", + .usage = NULL, + .params = leaudio_broadcast_create_params, +}; + +static const struct shell_param leaudio_broadcast_destroy_params[] = { + {"adv_instance", "Advertising instance, usage: ="}, + + { NULL, NULL} +}; + +static const struct shell_cmd_help leaudio_broadcast_destroy_help = { + .summary = "Destroy BASE", + .usage = NULL, + + .params = leaudio_broadcast_destroy_params, +}; + +static const struct shell_param leaudio_broadcast_update_params[] = { + {"adv_instance", "Advertising instance, usage: ="}, + {"name", "usage: =[string]"}, + {"extra_data_len", "usage: ="}, + {"extra_data", "usage: =[XX:XX...]"}, + + { NULL, NULL} +}; + +static const struct shell_cmd_help leaudio_broadcast_update_help = { + .summary = "Update broadcast", + .usage = NULL, + + .params = leaudio_broadcast_update_params, +}; + +static const struct shell_param leaudio_broadcast_start_params[] = { + {"adv_instance", "Advertising instance, usage: ="}, + + { NULL, NULL} +}; + +static const struct shell_cmd_help leaudio_broadcast_start_help = { + .summary = "Start broadcast", + .usage = NULL, + + .params = leaudio_broadcast_start_params, +}; + +static const struct shell_param leaudio_broadcast_stop_params[] = { + {"adv_instance", "Advertising instance, usage: ="}, + + { NULL, NULL} +}; + +static const struct shell_cmd_help leaudio_broadcast_stop_help = { + .summary = "Stop broadcast", + .usage = NULL, + + .params = leaudio_broadcast_stop_params, +}; +#endif +#endif /* BLE_AUDIO && BLE_ISO_BROADCAST_SOURCE */ + static const struct shell_cmd btshell_commands[] = { #if MYNEWT_VAL(BLE_EXT_ADV) { @@ -4405,6 +4622,27 @@ static const struct shell_cmd btshell_commands[] = { .sc_cmd_func = cmd_gatt_write, #if MYNEWT_VAL(SHELL_CMD_HELP) .help = &gatt_write_help, +#endif + }, + { + .sc_cmd = "gatt-enqueue-notif", + .sc_cmd_func = cmd_gatt_enqueue_notif, +#if MYNEWT_VAL(SHELL_CMD_HELP) + .help = &gatt_enqueue_notif_help, +#endif + }, + { + .sc_cmd = "gatt-send-queued-notif", + .sc_cmd_func = cmd_gatt_send_pending_notif, +#if MYNEWT_VAL(SHELL_CMD_HELP) + .help = &gatt_send_pending_notif_help, +#endif + }, + { + .sc_cmd = "gatt-clear-queued-notif", + .sc_cmd_func = cmd_gatt_clear_pending_notif, +#if MYNEWT_VAL(SHELL_CMD_HELP) + .help = &gatt_clear_pending_notif_help, #endif }, #if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) @@ -4653,6 +4891,179 @@ static const struct shell_cmd btshell_commands[] = { }, #endif #endif +#if MYNEWT_VAL(BLE_AUDIO) && MYNEWT_VAL(BLE_ISO_BROADCAST_SOURCE) + { + .sc_cmd = "base_add", + .sc_cmd_func = cmd_leaudio_base_add, +#if MYNEWT_VAL(SHELL_CMD_HELP) + .help = &leaudio_base_add_help, +#endif + }, + { + .sc_cmd = "big_sub_add", + .sc_cmd_func = cmd_leaudio_big_sub_add, +#if MYNEWT_VAL(SHELL_CMD_HELP) + .help = &leaudio_big_sub_add_help, +#endif + }, + { + .sc_cmd = "bis_add", + .sc_cmd_func = cmd_leaudio_bis_add, +#if MYNEWT_VAL(SHELL_CMD_HELP) + .help = &leaudio_bis_add_help, +#endif + }, + { + .sc_cmd = "broadcast_create", + .sc_cmd_func = cmd_leaudio_broadcast_create, +#if MYNEWT_VAL(SHELL_CMD_HELP) + .help = &leaudio_broadcast_create_help, +#endif + }, + { + .sc_cmd = "broadcast_destroy", + .sc_cmd_func = cmd_leaudio_broadcast_destroy, +#if MYNEWT_VAL(SHELL_CMD_HELP) + .help = &leaudio_broadcast_destroy_help, +#endif + }, + { + .sc_cmd = "broadcast_update", + .sc_cmd_func = cmd_leaudio_broadcast_update, +#if MYNEWT_VAL(SHELL_CMD_HELP) + .help = &leaudio_broadcast_update_help, +#endif + }, + { + .sc_cmd = "broadcast_start", + .sc_cmd_func = cmd_leaudio_broadcast_start, +#if MYNEWT_VAL(SHELL_CMD_HELP) + .help = &leaudio_broadcast_start_help, +#endif + }, + { + .sc_cmd = "broadcast_stop", + .sc_cmd_func = cmd_leaudio_broadcast_stop, +#if MYNEWT_VAL(SHELL_CMD_HELP) + .help = &leaudio_broadcast_stop_help, +#endif + }, +#endif /* BLE_AUDIO && BLE_ISO_BROADCAST_SOURCE */ +#if MYNEWT_VAL(BLE_AUDIO_BROADCAST_SINK) + { + .sc_cmd = "broadcast-sink-start", + .sc_cmd_func = cmd_leaudio_broadcast_sink_start, +#if MYNEWT_VAL(SHELL_CMD_HELP) + .help = &cmd_leaudio_broadcast_sink_start_help, +#endif + }, + { + .sc_cmd = "broadcast-sink-stop", + .sc_cmd_func = cmd_leaudio_broadcast_sink_stop, +#if MYNEWT_VAL(SHELL_CMD_HELP) + .help = &cmd_leaudio_broadcast_sink_stop_help, +#endif + }, + { + .sc_cmd = "broadcast-sink-metadata", + .sc_cmd_func = cmd_leaudio_broadcast_sink_metadata_update, +#if MYNEWT_VAL(SHELL_CMD_HELP) + .help = &cmd_leaudio_broadcast_sink_metadata_update_help, +#endif + }, + { + .sc_cmd = "broadcast-sink-set-sync-params", + .sc_cmd_func = cmd_leaudio_broadcast_sink_sync_params_set, +#if MYNEWT_VAL(SHELL_CMD_HELP) + .help = &cmd_leaudio_broadcast_sink_sync_params_set_help, +#endif + }, +#endif /* BLE_AUDIO_BROADCAST_SINK */ +#if MYNEWT_VAL(BLE_AUDIO_SCAN_DELEGATOR) + { + .sc_cmd = "scan-delegator-add", + .sc_cmd_func = cmd_leaudio_scan_delegator_receive_state_add, +#if MYNEWT_VAL(SHELL_CMD_HELP) + .help = &cmd_leaudio_scan_delegator_receive_state_add_help, +#endif + }, + { + .sc_cmd = "scan-delegator-remove", + .sc_cmd_func = cmd_leaudio_scan_delegator_receive_state_remove, +#if MYNEWT_VAL(SHELL_CMD_HELP) + .help = &cmd_leaudio_scan_delegator_receive_state_remove_help, +#endif + }, + { + .sc_cmd = "scan-delegator-set", + .sc_cmd_func = cmd_leaudio_scan_delegator_receive_state_set, +#if MYNEWT_VAL(SHELL_CMD_HELP) + .help = &cmd_leaudio_scan_delegator_receive_state_set_help, +#endif + }, + { + .sc_cmd = "scan-delegator-get", + .sc_cmd_func = cmd_leaudio_scan_delegator_receive_state_get, +#if MYNEWT_VAL(SHELL_CMD_HELP) + .help = &cmd_leaudio_scan_delegator_receive_state_get_help, +#endif + }, + { + .sc_cmd = "scan-delegator-show", + .sc_cmd_func = cmd_leaudio_scan_delegator_receive_state_show, +#if MYNEWT_VAL(SHELL_CMD_HELP) + .help = &cmd_leaudio_scan_delegator_receive_state_show_help, +#endif + }, +#endif /* BLE_AUDIO_SCAN_DELEGATOR */ +#if MYNEWT_VAL(BLE_ISO) +#if MYNEWT_VAL(BLE_ISO_BROADCAST_SOURCE) + { + .sc_cmd = "big-create", + .sc_cmd_func = cmd_iso_big_create, +#if MYNEWT_VAL(SHELL_CMD_HELP) + .help = &cmd_iso_big_create_help, +#endif + }, + { + .sc_cmd = "big-terminate", + .sc_cmd_func = cmd_iso_big_terminate, +#if MYNEWT_VAL(SHELL_CMD_HELP) + .help = &cmd_iso_big_terminate_help, +#endif + }, +#endif /* BLE_ISO_BROADCAST_SOURCE */ +#if MYNEWT_VAL(BLE_ISO_BROADCAST_SINK) + { + .sc_cmd = "big-sync-create", + .sc_cmd_func = cmd_iso_big_sync_create, +#if MYNEWT_VAL(SHELL_CMD_HELP) + .help = &cmd_iso_big_sync_create_help, +#endif + }, + { + .sc_cmd = "big-sync-terminate", + .sc_cmd_func = cmd_iso_big_sync_terminate, +#if MYNEWT_VAL(SHELL_CMD_HELP) + .help = &cmd_iso_big_sync_terminate_help, +#endif + }, +#endif /* BLE_ISO_BROADCAST_SINK */ + { + .sc_cmd = "iso-data-path-setup", + .sc_cmd_func = cmd_iso_data_path_setup, +#if MYNEWT_VAL(SHELL_CMD_HELP) + .help = &cmd_iso_data_path_setup_help, +#endif + }, + { + .sc_cmd = "iso-data-path-remove", + .sc_cmd_func = cmd_iso_data_path_remove, +#if MYNEWT_VAL(SHELL_CMD_HELP) + .help = &cmd_iso_data_path_remove_help, +#endif + }, +#endif /* BLE_ISO */ { 0 }, }; diff --git a/apps/btshell/src/cmd.h b/apps/btshell/src/cmd.h index 63bd50d1b8..c5532f34ff 100644 --- a/apps/btshell/src/cmd.h +++ b/apps/btshell/src/cmd.h @@ -22,47 +22,21 @@ #include #include "host/ble_uuid.h" +#include -struct kv_pair { - char *key; - int val; -}; - -uint32_t parse_arg_time_dflt(char *name, int step, uint32_t dflt, int *out_status); -const struct kv_pair *parse_kv_find(const struct kv_pair *kvs, char *name); -int parse_arg_find_idx(const char *key); -char *parse_arg_extract(const char *key); -long parse_arg_long_bounds(char *name, long min, long max, int *out_status); -long parse_arg_long_bounds_dflt(char *name, long min, long max, - long dflt, int *out_status); -uint64_t parse_arg_uint64_bounds(char *name, uint64_t min, - uint64_t max, int *out_status); -long parse_arg_long(char *name, int *staus); -uint8_t parse_arg_bool(char *name, int *status); -uint8_t parse_arg_bool_dflt(char *name, uint8_t dflt, int *out_status); -uint8_t parse_arg_uint8(char *name, int *status); -uint8_t parse_arg_uint8_dflt(char *name, uint8_t dflt, int *out_status); -uint16_t parse_arg_uint16(char *name, int *status); -uint16_t parse_arg_uint16_dflt(char *name, uint16_t dflt, int *out_status); -uint32_t parse_arg_uint32(char *name, int *out_status); -uint32_t parse_arg_uint32_dflt(char *name, uint32_t dflt, int *out_status); -uint64_t parse_arg_uint64(char *name, int *out_status); -int parse_arg_kv(char *name, const struct kv_pair *kvs, int *out_status); -int parse_arg_kv_dflt(char *name, const struct kv_pair *kvs, int def_val, - int *out_status); -int parse_arg_byte_stream(char *name, int max_len, uint8_t *dst, int *out_len); -int parse_arg_uint8_list_with_separator(char *name, char *separator, int max_len, - uint8_t *dst, int *out_len); -int parse_arg_byte_stream_exact_length(char *name, uint8_t *dst, int len); -int parse_arg_mac(char *name, uint8_t *dst); -int parse_arg_addr(char *name, ble_addr_t *addr); -int parse_arg_uuid(char *name, ble_uuid_any_t *uuid); -int parse_arg_all(int argc, char **argv); int parse_eddystone_url(char *full_url, uint8_t *out_scheme, char *out_body, uint8_t *out_body_len, uint8_t *out_suffix); + int cmd_parse_conn_start_end(uint16_t *out_conn, uint16_t *out_start, uint16_t *out_end); +int parse_dev_addr(const char *prefix, const struct parse_arg_kv_pair *addr_types, + ble_addr_t *addr); + +int cmd_parse_addr(const char *prefix, ble_addr_t *addr); + +const char *cmd_addr_type_str(uint8_t type); + void cmd_init(void); #endif diff --git a/apps/btshell/src/cmd_gatt.c b/apps/btshell/src/cmd_gatt.c index ba3799e56f..3011dd9cab 100644 --- a/apps/btshell/src/cmd_gatt.c +++ b/apps/btshell/src/cmd_gatt.c @@ -45,7 +45,7 @@ cmd_gatt_discover_characteristic(int argc, char **argv) ble_uuid_any_t uuid; int rc; - rc = parse_arg_all(argc - 1, argv + 1); + rc = parse_arg_init(argc - 1, argv + 1); if (rc != 0) { return rc; } @@ -56,7 +56,7 @@ cmd_gatt_discover_characteristic(int argc, char **argv) return rc; } - rc = parse_arg_uuid("uuid", &uuid); + rc = parse_arg_ble_uuid("uuid", &uuid); if (rc == 0) { rc = btshell_disc_chrs_by_uuid(conn_handle, start_handle, end_handle, &uuid.u); @@ -82,7 +82,7 @@ cmd_gatt_discover_descriptor(int argc, char **argv) uint16_t end_handle; int rc; - rc = parse_arg_all(argc - 1, argv + 1); + rc = parse_arg_init(argc - 1, argv + 1); if (rc != 0) { return rc; } @@ -109,7 +109,7 @@ cmd_gatt_discover_service(int argc, char **argv) int conn_handle; int rc; - rc = parse_arg_all(argc - 1, argv + 1); + rc = parse_arg_init(argc - 1, argv + 1); if (rc != 0) { return rc; } @@ -120,7 +120,7 @@ cmd_gatt_discover_service(int argc, char **argv) return rc; } - rc = parse_arg_uuid("uuid", &uuid); + rc = parse_arg_ble_uuid("uuid", &uuid); if (rc == 0) { rc = btshell_disc_svc_by_uuid(conn_handle, &uuid.u); } else if (rc == ENOENT) { @@ -144,7 +144,7 @@ cmd_gatt_discover_full(int argc, char **argv) int conn_handle; int rc; - rc = parse_arg_all(argc - 1, argv + 1); + rc = parse_arg_init(argc - 1, argv + 1); if (rc != 0) { return rc; } @@ -174,7 +174,7 @@ cmd_gatt_exchange_mtu(int argc, char **argv) uint16_t conn_handle; int rc; - rc = parse_arg_all(argc - 1, argv + 1); + rc = parse_arg_init(argc - 1, argv + 1); if (rc != 0) { return rc; } @@ -204,7 +204,7 @@ cmd_gatt_notify(int argc, char **argv) uint16_t attr_handle; int rc; - rc = parse_arg_all(argc - 1, argv + 1); + rc = parse_arg_init(argc - 1, argv + 1); if (rc != 0) { return rc; } @@ -238,9 +238,10 @@ cmd_gatt_read(int argc, char **argv) uint8_t num_attr_handles; int is_uuid; int is_long; + bool is_var; int rc; - rc = parse_arg_all(argc - 1, argv + 1); + rc = parse_arg_init(argc - 1, argv + 1); if (rc != 0) { return rc; } @@ -259,6 +260,12 @@ cmd_gatt_read(int argc, char **argv) return rc; } + is_var = parse_arg_bool_dflt("variable", 0, &rc); + if (rc != 0) { + console_printf("invalid 'variable' parameter\n"); + return rc; + } + for (num_attr_handles = 0; num_attr_handles < CMD_READ_MAX_ATTRS; num_attr_handles++) { @@ -272,7 +279,7 @@ cmd_gatt_read(int argc, char **argv) } } - rc = parse_arg_uuid("uuid", &uuid); + rc = parse_arg_ble_uuid("uuid", &uuid); if (rc == ENOENT) { is_uuid = 0; } else if (rc == 0) { @@ -313,7 +320,7 @@ cmd_gatt_read(int argc, char **argv) rc = btshell_read(conn_handle, attr_handles[0]); } } else if (num_attr_handles > 1) { - rc = btshell_read_mult(conn_handle, attr_handles, num_attr_handles); + rc = btshell_read_mult(conn_handle, attr_handles, num_attr_handles, is_var); } else if (is_uuid) { if (start == 0 || end == 0) { rc = EINVAL; @@ -344,7 +351,7 @@ cmd_gatt_service_changed(int argc, char **argv) uint16_t end; int rc; - rc = parse_arg_all(argc - 1, argv + 1); + rc = parse_arg_init(argc - 1, argv + 1); if (rc != 0) { return rc; } @@ -377,7 +384,7 @@ cmd_gatt_service_visibility(int argc, char **argv) bool vis; int rc; - rc = parse_arg_all(argc - 1, argv + 1); + rc = parse_arg_init(argc - 1, argv + 1); if (rc != 0) { return rc; } @@ -411,7 +418,7 @@ cmd_gatt_find_included_services(int argc, char **argv) uint16_t end_handle; int rc; - rc = parse_arg_all(argc - 1, argv + 1); + rc = parse_arg_init(argc - 1, argv + 1); if (rc != 0) { return rc; } @@ -475,13 +482,13 @@ cmd_gatt_write(int argc, char **argv) uint16_t offset; int total_attr_len; int num_attrs; - int attr_len; + unsigned int attr_len; int is_long; int no_rsp; int rc; int i; - rc = parse_arg_all(argc - 1, argv + 1); + rc = parse_arg_init(argc - 1, argv + 1); if (rc != 0) { return rc; } @@ -585,3 +592,75 @@ cmd_gatt_write(int argc, char **argv) return rc; } + +int +cmd_gatt_enqueue_notif(int argc, char **argv) +{ +#if MYNEWT_VAL(BLE_GATT_NOTIFY_MULTIPLE) + int rc; + uint16_t handle; + unsigned int len; + uint8_t value[BLE_ATT_ATTR_MAX_LEN]; + + rc = parse_arg_init(argc - 1, argv + 1); + if (rc != 0) { + return rc; + } + + handle = parse_arg_uint16("handle", &rc); + if (rc != 0) { + console_printf("invalid 'handle' parameter\n"); + return rc; + } + + if (argc > 1) { + rc = parse_arg_byte_stream("value", BLE_ATT_ATTR_MAX_LEN, value, &len); + if (rc != 0) { + console_printf("invalid 'value' parameter\n"); + return rc; + } + return btshell_enqueue_notif(handle, len, value); + } else { + return btshell_enqueue_notif(handle, 0, NULL); + } +#else + console_printf("To enable this features set BLE_GATT_NOTIFY_MULTIPLE\n"); + return ENOTSUP; +#endif +} + +int +cmd_gatt_send_pending_notif(int argc, char **argv) +{ +#if MYNEWT_VAL(BLE_GATT_NOTIFY_MULTIPLE) + uint16_t conn_handle; + int rc; + + rc = parse_arg_init(argc - 1, argv + 1); + if (rc != 0) { + return rc; + } + + conn_handle = parse_arg_uint16("conn", &rc); + if (rc != 0) { + console_printf("invalid 'conn' parameter\n"); + return rc; + } + + return btshell_send_pending_notif(conn_handle); +#else + console_printf("To enable this features set BLE_GATT_NOTIFY_MULTIPLE\n"); + return ENOTSUP; +#endif +} + +int +cmd_gatt_clear_pending_notif(int argc, char **argv) +{ +#if MYNEWT_VAL(BLE_GATT_NOTIFY_MULTIPLE) + return btshell_clear_pending_notif(); +#else + console_printf("To enable this features set BLE_GATT_NOTIFY_MULTIPLE\n"); + return ENOTSUP; +#endif +} diff --git a/apps/btshell/src/cmd_gatt.h b/apps/btshell/src/cmd_gatt.h index 70536d03ce..ae517f9a1c 100644 --- a/apps/btshell/src/cmd_gatt.h +++ b/apps/btshell/src/cmd_gatt.h @@ -35,5 +35,8 @@ int cmd_gatt_service_visibility(int argc, char **argv); int cmd_gatt_show(int argc, char **argv); int cmd_gatt_show_local(int argc, char **argv); int cmd_gatt_write(int argc, char **argv); +int cmd_gatt_enqueue_notif(int argc, char **argv); +int cmd_gatt_send_pending_notif(int argc, char **argv); +int cmd_gatt_clear_pending_notif(int argc, char **argv); #endif diff --git a/apps/btshell/src/cmd_iso.c b/apps/btshell/src/cmd_iso.c new file mode 100644 index 0000000000..cd6046082c --- /dev/null +++ b/apps/btshell/src/cmd_iso.c @@ -0,0 +1,562 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "host/ble_hs.h" +#include "host/ble_iso.h" + +#include "cmd_iso.h" + +#include "console/console.h" +#include "shell/shell.h" + +#if (MYNEWT_VAL(BLE_ISO)) +static struct iso_rx_stats { + uint16_t conn_handle; + bool ts_valid; + uint32_t ts; + uint16_t seq_num; + uint64_t total_cnt; + uint64_t valid_cnt; + uint64_t error_cnt; + uint64_t lost_cnt; +} rx_stats_pool[MYNEWT_VAL(BLE_ISO_MAX_BISES)] = { + [0 ... MYNEWT_VAL(BLE_ISO_MAX_BISES) - 1] = { + .conn_handle = BLE_HS_CONN_HANDLE_NONE + } +}; + +static struct iso_rx_stats * +iso_rx_stats_lookup_conn_handle(uint16_t conn_handle) +{ + for (size_t i = 0; i < ARRAY_SIZE(rx_stats_pool); i++) { + if (rx_stats_pool[i].conn_handle == conn_handle) { + return &rx_stats_pool[i]; + } + } + + return NULL; +} + +static struct iso_rx_stats * +iso_rx_stats_get_or_new(uint16_t conn_handle) +{ + struct iso_rx_stats *rx_stats; + + rx_stats = iso_rx_stats_lookup_conn_handle(conn_handle); + if (rx_stats == NULL) { + rx_stats = iso_rx_stats_lookup_conn_handle(BLE_HS_CONN_HANDLE_NONE); + if (rx_stats == NULL) { + return NULL; + } + } + + rx_stats->conn_handle = conn_handle; + + return rx_stats; +} + +static void +iso_rx_stats_reset(void) +{ + for (size_t i = 0; i < ARRAY_SIZE(rx_stats_pool); i++) { + memset(&rx_stats_pool[i], 0, sizeof(rx_stats_pool[i])); + rx_stats_pool[i].conn_handle = BLE_HS_CONN_HANDLE_NONE; + } +} + +static void +iso_rx_stats_update(uint16_t conn_handle, const struct ble_iso_rx_data_info *info, void *arg) +{ + struct iso_rx_stats *stats = arg; + + if (!stats) { + return; + } + + stats->ts_valid = info->ts_valid; + if (stats->ts_valid) { + stats->ts = info->ts; + } + + stats->seq_num = info->seq_num; + + if (info->status == BLE_ISO_DATA_STATUS_VALID) { + stats->valid_cnt++; + } else if (info->status == BLE_ISO_DATA_STATUS_ERROR) { + stats->error_cnt++; + } else if (info->status == BLE_ISO_DATA_STATUS_LOST) { + stats->lost_cnt++; + } + + stats->total_cnt++; + + if ((stats->total_cnt % 100) == 0) { + console_printf("conn_handle=0x%04x, seq_num=%d, num_rx=%" PRIu64 ", " + "(valid=%" PRIu64 ", error=%" PRIu64 ", lost=%" PRIu64 ") ", + stats->conn_handle, stats->seq_num, + stats->total_cnt, stats->valid_cnt, + stats->error_cnt, stats->lost_cnt); + + if (stats->ts_valid) { + console_printf("ts=10%" PRIu32, stats->ts); + } + + console_printf("\n"); + } +} + +static void +print_iso_big_desc(const struct ble_iso_big_desc *desc) +{ + console_printf(" big_handle=0x%02x, big_sync_delay=%" PRIu32 "," + " transport_latency=%" PRIu32 ", nse=%u, bn=%u, pto=%u," + " irc=%u, max_pdu=%u, iso_interval=%u num_bis=%u", + desc->big_handle, desc->big_sync_delay, + desc->transport_latency_big, desc->nse, desc->bn, desc->pto, + desc->irc, desc->max_pdu, desc->iso_interval, desc->num_bis); + + if (desc->num_bis > 0) { + console_printf(" conn_handles="); + } + + for (uint8_t i = 0; i < desc->num_bis; i++) { + console_printf("0x%04x,", desc->conn_handle[i]); + } +} + +static int +ble_iso_event_handler(struct ble_iso_event *event, void *arg) +{ + switch (event->type) { + case BLE_ISO_EVENT_BIG_CREATE_COMPLETE: + console_printf("BIG Create Completed status: %u", + event->big_created.status); + + if (event->big_created.status == 0) { + print_iso_big_desc(&event->big_created.desc); + console_printf(" phy=0x%02x", event->big_created.phy); + } + + console_printf("\n"); + break; + + case BLE_ISO_EVENT_BIG_SYNC_ESTABLISHED: + console_printf("BIG Sync Established status: %u", + event->big_sync_established.status); + + if (event->big_sync_established.status == 0) { + print_iso_big_desc(&event->big_sync_established.desc); + } + + console_printf("\n"); + break; + + case BLE_ISO_EVENT_BIG_SYNC_TERMINATED: + console_printf("BIG Sync Terminated handle=0x%02x reason: %u\n", + event->big_terminated.big_handle, + event->big_terminated.reason); + iso_rx_stats_reset(); + break; + + case BLE_ISO_EVENT_ISO_RX: + iso_rx_stats_update(event->iso_rx.conn_handle, event->iso_rx.info, arg); + os_mbuf_free_chain(event->iso_rx.om); + break; + + default: + break; + } + + return 0; +} + +#if MYNEWT_VAL(SHELL_CMD_HELP) +static const struct shell_param cmd_iso_big_create_params[] = { + {"adv_handle", "PA advertising handle, usage: ="}, + {"bis_cnt", "BIS count, usage: ="}, + {"sdu_interval", "SDU interval, usage: ="}, + {"max_sdu", "Maximum SDU size, usage: ="}, + {"max_latency", "Maximum transport latency, usage: ="}, + {"rtn", "Retransmission number, usage: ="}, + {"phy", "PHY, usage: ="}, + {"packing", "Packing, usage: =, default: 1"}, + {"framing", "Framing, usage: =, default: 0"}, + {"broadcast_code", "Broadcast Code, usage: =[string], default: NULL"}, + + { NULL, NULL} +}; + +const struct shell_cmd_help cmd_iso_big_create_help = { + .summary = "Create BIG", + .usage = NULL, + .params = cmd_iso_big_create_params, +}; +#endif /* SHELL_CMD_HELP */ + +int +cmd_iso_big_create(int argc, char **argv) +{ + struct ble_iso_create_big_params params = { 0 }; + struct ble_iso_big_params big_params = { 0 }; + uint8_t big_handle; + int rc; + + rc = parse_arg_init(argc - 1, argv + 1); + if (rc != 0) { + return rc; + } + + params.adv_handle = parse_arg_uint8("adv_handle", &rc); + if (rc != 0) { + console_printf("invalid 'adv_handle' parameter\n"); + return rc; + } + + params.cb = ble_iso_event_handler; + + params.bis_cnt = parse_arg_uint8("bis_cnt", &rc); + if (rc != 0) { + console_printf("invalid 'bis_cnt' parameter\n"); + return rc; + } + + big_params.sdu_interval = parse_arg_uint32_bounds("sdu_interval", + 0x0000FF, 0x0FFFFF, + &rc); + if (rc != 0) { + console_printf("invalid 'sdu_interval' parameter\n"); + return rc; + } + + big_params.max_sdu = parse_arg_uint16_bounds("max_sdu", 0x0001, 0x0FFF, + &rc); + if (rc != 0) { + console_printf("invalid 'max_sdu' parameter\n"); + return rc; + } + + big_params.max_transport_latency = parse_arg_uint16_bounds("max_latency", + 0x0005, 0x0FA0, + &rc); + if (rc != 0) { + console_printf("invalid 'max_latency' parameter\n"); + return rc; + } + + big_params.rtn = parse_arg_uint8_bounds("rtn", 0x00, 0x1E, &rc); + if (rc != 0) { + console_printf("invalid 'rtn' parameter\n"); + return rc; + } + + big_params.phy = parse_arg_uint8_bounds("phy", 0, 2, &rc); + if (rc != 0) { + console_printf("invalid 'phy' parameter\n"); + return rc; + } + + big_params.packing = parse_arg_uint8_bounds_dflt("packing", 0, 1, 1, &rc); + if (rc != 0) { + console_printf("invalid 'packing' parameter\n"); + return rc; + } + + big_params.framing = parse_arg_uint8_bounds_dflt("framing", 0, 1, 0, &rc); + if (rc != 0) { + console_printf("invalid 'framing' parameter\n"); + return rc; + } + + big_params.broadcast_code = parse_arg_extract("broadcast_code"); + big_params.encryption = big_params.broadcast_code ? 1 : 0; + + rc = ble_iso_create_big(¶ms, &big_params, &big_handle); + if (rc != 0) { + console_printf("BIG create failed (%d)\n", rc); + return rc; + } + + console_printf("New big_handle %u created\n", big_handle); + + return 0; +} + +#if MYNEWT_VAL(SHELL_CMD_HELP) +static const struct shell_param cmd_iso_big_terminate_params[] = { + {"big_handle", "BIG handle, usage: ="}, + + { NULL, NULL} +}; + +const struct shell_cmd_help cmd_iso_big_terminate_help = { + .summary = "Terminate BIG", + .usage = NULL, + .params = cmd_iso_big_terminate_params, +}; +#endif /* SHELL_CMD_HELP */ + +int +cmd_iso_big_terminate(int argc, char **argv) +{ + uint8_t big_handle; + int rc; + + rc = parse_arg_init(argc - 1, argv + 1); + if (rc != 0) { + return rc; + } + + big_handle = parse_arg_uint8("big_handle", &rc); + if (rc != 0) { + console_printf("invalid 'big_handle' parameter\n"); + return rc; + } + + rc = ble_iso_terminate_big(big_handle); + if (rc != 0) { + console_printf("BIG terminate failed (%d)\n", rc); + return rc; + } + + return 0; +} + +#if MYNEWT_VAL(SHELL_CMD_HELP) +static const struct shell_param cmd_iso_big_sync_create_params[] = { + {"sync_handle", "PA sync handle, usage: ="}, + {"broadcast_code", "Broadcast Code, usage: =[string], default: NULL"}, + {"mse", "Maximum Subevents to receive data, usage: ="}, + {"sync_timeout", "BIG sync timeout, usage: ="}, + {"idxs", "BIS indexes, usage: =XX,YY,..."}, + + { NULL, NULL} +}; + +const struct shell_cmd_help cmd_iso_big_sync_create_help = { + .summary = "Synchronize to BIG", + .usage = NULL, + .params = cmd_iso_big_sync_create_params, +}; +#endif /* SHELL_CMD_HELP */ + +int +cmd_iso_big_sync_create(int argc, char **argv) +{ + struct ble_iso_bis_params bis_params[MYNEWT_VAL(BLE_ISO_MAX_BISES)]; + struct ble_iso_big_sync_create_params params = { 0 }; + uint8_t bis_idxs[MYNEWT_VAL(BLE_ISO_MAX_BISES)]; + uint8_t big_handle; + int rc; + + rc = parse_arg_init(argc - 1, argv + 1); + if (rc != 0) { + return rc; + } + + params.sync_handle = parse_arg_uint16("sync_handle", &rc); + if (rc != 0) { + console_printf("invalid 'sync_handle' parameter\n"); + return rc; + } + + params.broadcast_code = parse_arg_extract("broadcast_code"); + + params.mse = parse_arg_uint8_dflt("mse", 0, &rc); + if (rc != 0) { + console_printf("invalid 'mse' parameter\n"); + return rc; + } + + params.sync_timeout = parse_arg_uint16("sync_timeout", &rc); + if (rc != 0) { + console_printf("invalid 'sync_timeout' parameter\n"); + return rc; + } + + rc = parse_arg_byte_stream_custom("idxs", ",", ARRAY_SIZE(bis_idxs), + bis_idxs, 0, + (unsigned int *)¶ms.bis_cnt); + if (rc != 0) { + console_printf("invalid 'idxs' parameter\n"); + return rc; + } + + for (uint8_t i = 0; i < params.bis_cnt; i++) { + bis_params[i].bis_index = bis_idxs[i]; + } + + params.bis_params = bis_params; + params.cb = ble_iso_event_handler; + + rc = ble_iso_big_sync_create(¶ms, &big_handle); + if (rc != 0) { + console_printf("BIG Sync create failed (%d)\n", rc); + return rc; + } + + console_printf("New big_handle %u created\n", big_handle); + + return 0; +} + +#if MYNEWT_VAL(SHELL_CMD_HELP) +static const struct shell_param cmd_iso_big_sync_terminate_params[] = { + {"big_handle", "BIG handle, usage: ="}, + + { NULL, NULL} +}; + +const struct shell_cmd_help cmd_iso_big_sync_terminate_help = { + .summary = "Terminate BIG sync", + .usage = NULL, + .params = cmd_iso_big_sync_terminate_params, +}; +#endif /* SHELL_CMD_HELP */ + +int +cmd_iso_big_sync_terminate(int argc, char **argv) +{ + uint8_t big_handle; + int rc; + + rc = parse_arg_init(argc - 1, argv + 1); + if (rc != 0) { + return rc; + } + + big_handle = parse_arg_uint8("big_handle", &rc); + if (rc != 0) { + console_printf("invalid 'big_handle' parameter\n"); + return rc; + } + + rc = ble_iso_big_sync_terminate(big_handle); + if (rc != 0) { + console_printf("BIG Sync terminate failed (%d)\n", rc); + return rc; + } + + return 0; +} + +static const struct parse_arg_kv_pair cmd_iso_data_dir[] = { + { "tx", BLE_ISO_DATA_DIR_TX }, + { "rx", BLE_ISO_DATA_DIR_RX }, + + { NULL } +}; + +#if MYNEWT_VAL(SHELL_CMD_HELP) +static const struct shell_param cmd_iso_data_path_setup_params[] = { + {"conn_handle", "Connection handle, usage: ="}, + {"dir", "Data path direction, usage: =[tx|rx]"}, + + { NULL, NULL} +}; + +const struct shell_cmd_help cmd_iso_data_path_setup_help = { + .summary = "Setup ISO Data Path", + .usage = NULL, + .params = cmd_iso_data_path_setup_params, +}; +#endif /* SHELL_CMD_HELP */ + +int +cmd_iso_data_path_setup(int argc, char **argv) +{ + struct ble_iso_data_path_setup_params params = { 0 }; + int rc; + + rc = parse_arg_init(argc - 1, argv + 1); + if (rc != 0) { + return rc; + } + + params.conn_handle = parse_arg_uint16("conn_handle", &rc); + if (rc != 0) { + console_printf("invalid 'conn_handle' parameter\n"); + return rc; + } + + params.data_path_dir = parse_arg_kv("dir", cmd_iso_data_dir, &rc); + if (rc != 0) { + console_printf("invalid 'dir' parameter\n"); + return rc; + } + + /* For now, the Data Path ID is set to HCI by default */ + params.cb = ble_iso_event_handler; + params.cb_arg = iso_rx_stats_get_or_new(params.conn_handle); + + rc = ble_iso_data_path_setup(¶ms); + if (rc != 0) { + console_printf("ISO Data Path setup failed (%d)\n", rc); + return rc; + } + + return 0; +} + +#if MYNEWT_VAL(SHELL_CMD_HELP) +static const struct shell_param cmd_iso_data_path_remove_params[] = { + {"conn_handle", "Connection handle, usage: ="}, + {"dir", "Data path direction, usage: =[tx|rx]"}, + + { NULL, NULL} +}; + +const struct shell_cmd_help cmd_iso_data_path_remove_help = { + .summary = "Remove ISO Data Path", + .usage = NULL, + .params = cmd_iso_data_path_remove_params, +}; +#endif /* SHELL_CMD_HELP */ + +int +cmd_iso_data_path_remove(int argc, char **argv) +{ + struct ble_iso_data_path_remove_params params = { 0 }; + int rc; + + rc = parse_arg_init(argc - 1, argv + 1); + if (rc != 0) { + return rc; + } + + params.conn_handle = parse_arg_uint16("conn_handle", &rc); + if (rc != 0) { + console_printf("invalid 'conn_handle' parameter\n"); + return rc; + } + + params.data_path_dir = parse_arg_kv("dir", cmd_iso_data_dir, &rc); + if (rc != 0) { + console_printf("invalid 'dir' parameter\n"); + return rc; + } + + rc = ble_iso_data_path_remove(¶ms); + if (rc != 0) { + console_printf("ISO Data Path remove failed (%d)\n", rc); + return rc; + } + + return 0; +} +#endif /* BLE_ISO */ diff --git a/apps/btshell/src/cmd_iso.h b/apps/btshell/src/cmd_iso.h new file mode 100644 index 0000000000..c027c08855 --- /dev/null +++ b/apps/btshell/src/cmd_iso.h @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_CMD_ISO_ +#define H_CMD_ISO_ + +#include "cmd.h" + +extern const struct shell_cmd_help cmd_iso_big_create_help; +extern const struct shell_cmd_help cmd_iso_big_terminate_help; +extern const struct shell_cmd_help cmd_iso_big_sync_create_help; +extern const struct shell_cmd_help cmd_iso_big_sync_terminate_help; +extern const struct shell_cmd_help cmd_iso_data_path_setup_help; +extern const struct shell_cmd_help cmd_iso_data_path_remove_help; + +int cmd_iso_big_create(int argc, char **argv); +int cmd_iso_big_terminate(int argc, char **argv); +int cmd_iso_big_sync_create(int argc, char **argv); +int cmd_iso_big_sync_terminate(int argc, char **argv); +int cmd_iso_data_path_setup(int argc, char **argv); +int cmd_iso_data_path_remove(int argc, char **argv); + +#endif /* H_CMD_ISO_ */ diff --git a/apps/btshell/src/cmd_l2cap.c b/apps/btshell/src/cmd_l2cap.c index e74e3bf33d..66965bf6fc 100644 --- a/apps/btshell/src/cmd_l2cap.c +++ b/apps/btshell/src/cmd_l2cap.c @@ -40,7 +40,7 @@ cmd_l2cap_update(int argc, char **argv) uint16_t conn_handle; int rc; - rc = parse_arg_all(argc - 1, argv + 1); + rc = parse_arg_init(argc - 1, argv + 1); if (rc != 0) { return rc; } @@ -101,7 +101,7 @@ cmd_l2cap_create_server(int argc, char **argv) int accept_response = 0; int rc; - rc = parse_arg_all(argc - 1, argv + 1); + rc = parse_arg_init(argc - 1, argv + 1); if (rc != 0) { return rc; } @@ -159,7 +159,7 @@ cmd_l2cap_connect(int argc, char **argv) uint8_t num; int rc; - rc = parse_arg_all(argc - 1, argv + 1); + rc = parse_arg_init(argc - 1, argv + 1); if (rc != 0) { return rc; } @@ -202,7 +202,7 @@ cmd_l2cap_disconnect(int argc, char **argv) uint16_t idx; int rc; - rc = parse_arg_all(argc - 1, argv + 1); + rc = parse_arg_init(argc - 1, argv + 1); if (rc != 0) { return rc; } @@ -234,7 +234,7 @@ cmd_l2cap_send(int argc, char **argv) uint16_t bytes; int rc; - rc = parse_arg_all(argc - 1, argv + 1); + rc = parse_arg_init(argc - 1, argv + 1); if (rc != 0) { return rc; } @@ -291,10 +291,10 @@ cmd_l2cap_reconfig(int argc, char **argv) uint16_t conn; uint16_t mtu; uint8_t idxs[5]; - int num; + unsigned int num; int rc; - rc = parse_arg_all(argc - 1, argv + 1); + rc = parse_arg_init(argc - 1, argv + 1); if (rc != 0) { return rc; } @@ -311,7 +311,7 @@ cmd_l2cap_reconfig(int argc, char **argv) return rc; } - rc = parse_arg_uint8_list_with_separator("idxs", ",", 5, idxs, &num); + rc = parse_arg_byte_stream_custom("idxs", ",", 5, idxs, 0, &num); if (rc != 0) { console_printf("invalid 'idxs' parameter\n"); return rc; diff --git a/apps/btshell/src/cmd_leaudio.c b/apps/btshell/src/cmd_leaudio.c new file mode 100644 index 0000000000..84545d06dc --- /dev/null +++ b/apps/btshell/src/cmd_leaudio.c @@ -0,0 +1,1125 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "cmd_leaudio.h" +#include "btshell.h" +#include "console/console.h" +#include "shell/shell.h" +#include "bsp/bsp.h" +#include "errno.h" + +#define STR_NULL "null" + +#if (MYNEWT_VAL(BLE_AUDIO)) +#if (MYNEWT_VAL(BLE_ISO_BROADCAST_SOURCE)) +#include "audio/ble_audio_broadcast_source.h" +int +cmd_leaudio_base_add(int argc, char **argv) +{ + uint32_t presentation_delay; + uint8_t adv_instance; + int rc; + + rc = parse_arg_init(argc - 1, argv + 1); + if (rc != 0) { + return rc; + } + + adv_instance = parse_arg_uint8("adv_instance", &rc); + if (rc != 0 || adv_instance >= BLE_ADV_INSTANCES) { + console_printf("invalid advertising instance\n"); + return rc; + } + + presentation_delay = parse_arg_uint32("presentation_delay", &rc); + if (rc != 0) { + return rc; + } + + return btshell_broadcast_base_add(adv_instance, presentation_delay); +} + +int +cmd_leaudio_big_sub_add(int argc, char **argv) +{ + uint8_t adv_instance; + uint8_t codec_fmt; + uint16_t company_id; + uint16_t vendor_spec; + static uint8_t metadata[CMD_ADV_DATA_METADATA_MAX_SZ]; + unsigned int metadata_len; + static uint8_t codec_spec_cfg[CMD_ADV_DATA_CODEC_SPEC_CFG_MAX_SZ]; + unsigned int codec_spec_cfg_len; + int rc; + + rc = parse_arg_init(argc - 1, argv + 1); + if (rc != 0) { + return rc; + } + + adv_instance = parse_arg_uint8("adv_instance", &rc); + if (rc != 0 || adv_instance >= BLE_ADV_INSTANCES) { + console_printf("invalid advertising instance\n"); + return rc; + } + + codec_fmt = parse_arg_uint8("codec_fmt", &rc); + if (rc != 0) { + return rc; + } + + company_id = parse_arg_uint16("company_id", &rc); + if (rc != 0) { + return rc; + } + + vendor_spec = parse_arg_uint16("vendor_spec", &rc); + if (rc != 0) { + return rc; + } + + rc = parse_arg_byte_stream("codec_spec_config", + CMD_ADV_DATA_CODEC_SPEC_CFG_MAX_SZ, + codec_spec_cfg, &codec_spec_cfg_len); + if (rc != 0 && rc != ENOENT) { + return rc; + } + + rc = parse_arg_byte_stream("metadata", CMD_ADV_DATA_METADATA_MAX_SZ, + metadata, &metadata_len); + if (rc != 0 && rc != ENOENT) { + return rc; + } + + return btshell_broadcast_big_sub_add(adv_instance, + codec_fmt, company_id, + vendor_spec, + metadata, metadata_len, + codec_spec_cfg, codec_spec_cfg_len); +} + +int +cmd_leaudio_bis_add(int argc, char **argv) +{ + uint8_t adv_instance; + static uint8_t codec_spec_cfg[CMD_ADV_DATA_CODEC_SPEC_CFG_MAX_SZ]; + unsigned int codec_spec_cfg_len; + int rc; + + rc = parse_arg_init(argc - 1, argv + 1); + if (rc != 0) { + return rc; + } + + adv_instance = parse_arg_uint8("adv_instance", &rc); + if (rc != 0 || adv_instance >= BLE_ADV_INSTANCES) { + console_printf("invalid advertising instance\n"); + return rc; + } + + rc = parse_arg_byte_stream("codec_spec_config", + CMD_ADV_DATA_CODEC_SPEC_CFG_MAX_SZ, + codec_spec_cfg, &codec_spec_cfg_len); + if (rc != 0) { + return rc; + } + + return btshell_broadcast_bis_add(adv_instance, codec_spec_cfg, + codec_spec_cfg_len); +} + +int +cmd_leaudio_broadcast_create(int argc, char **argv) +{ + struct ble_iso_big_params big_params; + uint8_t adv_instance; + const char *name; + uint8_t extra_data[CMD_ADV_DATA_EXTRA_MAX_SZ]; + static uint8_t own_addr_type; + unsigned int extra_data_len; + struct ble_gap_periodic_adv_params periodic_params; + struct ble_gap_ext_adv_params extended_params = { + .scannable = 0, + .connectable = 0, + .primary_phy = BLE_HCI_LE_PHY_1M, + }; + int rc; + + rc = ble_hs_id_infer_auto(0, &own_addr_type); + if (rc != 0) { + return rc; + } + + extended_params.own_addr_type = own_addr_type; + + rc = parse_arg_init(argc - 1, argv + 1); + if (rc != 0) { + return rc; + } + + adv_instance = parse_arg_uint8("adv_instance", &rc); + if (rc != 0 || adv_instance >= BLE_ADV_INSTANCES) { + console_printf("invalid advertising instance\n"); + return rc; + } + + extended_params.sid = adv_instance; + extended_params.itvl_min = parse_arg_uint8_dflt("ext_interval_min", + 0, &rc); + if (rc != 0 && rc != ENOENT) { + console_printf("invalid extended advertising interval (min)\n"); + return rc; + } + + extended_params.itvl_max = parse_arg_uint8_dflt("ext_interval_max", 0, + &rc); + if (rc != 0 && rc != ENOENT) { + console_printf("invalid extended advertising interval (max)\n"); + return rc; + } + + periodic_params.itvl_min = parse_arg_uint8_dflt("per_interval_min", 0, + &rc); + if (rc != 0 && rc != ENOENT) { + console_printf("invalid periodic advertising interval (min)\n"); + return rc; + } + + periodic_params.itvl_max = parse_arg_uint8_dflt("per_interval_max", 0, + &rc); + if (rc != 0 && rc != ENOENT) { + console_printf("invalid periodic advertising interval (max)\n"); + return rc; + } + + name = parse_arg_extract("name"); + + big_params.sdu_interval = parse_arg_uint32_bounds("sdu_interval", + 0x0000FF, 0x0FFFFF, + &rc); + if (rc != 0) { + console_printf("invalid SDU interval\n"); + return rc; + } + + big_params.max_sdu = parse_arg_uint16_bounds("max_sdu", 0x0001, 0x0FFF, + &rc); + if (rc != 0) { + console_printf("invalid max SDU size\n"); + return rc; + } + + big_params.max_transport_latency = parse_arg_uint16_bounds("max_latency", + 0x0005, 0x0FA0, + &rc); + if (rc != 0) { + console_printf("invalid max transport latency\n"); + return rc; + } + + big_params.rtn = parse_arg_uint8_bounds("rtn", 0x00, 0x1E, &rc); + if (rc != 0) { + console_printf("invalid RTN\n"); + return rc; + } + + big_params.phy = parse_arg_uint8_bounds("phy", 0, 2, &rc); + if (rc != 0) { + console_printf("invalid PHY\n"); + return rc; + } + + extended_params.secondary_phy = big_params.phy; + + big_params.packing = parse_arg_uint8_bounds_dflt("packing", 0, 1, 1, &rc); + if (rc != 0) { + console_printf("invalid packing\n"); + return rc; + } + + big_params.framing = parse_arg_uint8_bounds_dflt("framing", 0, 1, 0, &rc); + if (rc != 0) { + console_printf("invalid framing\n"); + return rc; + } + + big_params.encryption = parse_arg_uint8_bounds_dflt("encryption", 0, 1, 0, &rc); + if (rc != 0) { + console_printf("invalid encryption\n"); + return rc; + } + + if (big_params.encryption) { + big_params.broadcast_code = parse_arg_extract("broadcast_code"); + if (big_params.broadcast_code == NULL) { + console_printf("broadcast code missing\n"); + return ENOENT; + } + + if (strlen(big_params.broadcast_code) > 16) { + console_printf("broadcast code too long\n"); + return ENOENT; + } + } + + rc = parse_arg_byte_stream("extra_data", + CMD_ADV_DATA_EXTRA_MAX_SZ, + extra_data, &extra_data_len); + if (rc == ENOENT) { + extra_data_len = 0; + } else if (rc != 0) { + return rc; + } + + return btshell_broadcast_create(adv_instance, + &extended_params, + &periodic_params, + name, + big_params, + extra_data, + extra_data_len); +} + +int +cmd_leaudio_broadcast_destroy(int argc, char **argv) +{ + uint8_t adv_instance; + int rc; + + rc = parse_arg_init(argc - 1, argv + 1); + if (rc != 0) { + return rc; + } + + adv_instance = parse_arg_uint8("adv_instance", &rc); + if (rc != 0 || adv_instance >= BLE_ADV_INSTANCES) { + console_printf("invalid advertising instance\n"); + return rc; + } + + return btshell_broadcast_destroy(adv_instance); +} + +int +cmd_leaudio_broadcast_update(int argc, char **argv) +{ + uint8_t adv_instance; + uint8_t extra_data[CMD_ADV_DATA_EXTRA_MAX_SZ]; + unsigned int extra_data_len; + const char *name; + int rc; + + rc = parse_arg_init(argc - 1, argv + 1); + if (rc != 0) { + return rc; + } + + adv_instance = parse_arg_uint8("adv_instance", &rc); + if (rc != 0 || adv_instance >= BLE_ADV_INSTANCES) { + console_printf("invalid advertising instance\n"); + return rc; + } + + rc = parse_arg_byte_stream("extra_data", + CMD_ADV_DATA_EXTRA_MAX_SZ, + extra_data, &extra_data_len); + if (rc != 0 && rc != ENOENT) { + return rc; + } + + name = parse_arg_extract("name"); + + return btshell_broadcast_update(adv_instance, name, extra_data, extra_data_len); +} + +int +cmd_leaudio_broadcast_start(int argc, char **argv) +{ + uint8_t adv_instance; + int rc; + + rc = parse_arg_init(argc - 1, argv + 1); + if (rc != 0) { + return rc; + } + + adv_instance = parse_arg_uint8("adv_instance", &rc); + if (rc != 0 || adv_instance >= BLE_ADV_INSTANCES) { + console_printf("invalid advertising instance\n"); + return rc; + } + + return btshell_broadcast_start(adv_instance); +} + +int +cmd_leaudio_broadcast_stop(int argc, char **argv) +{ + uint8_t adv_instance; + int rc; + + rc = parse_arg_init(argc - 1, argv + 1); + if (rc != 0) { + return rc; + } + + adv_instance = parse_arg_uint8("adv_instance", &rc); + if (rc != 0 || adv_instance >= BLE_ADV_INSTANCES) { + console_printf("invalid advertising instance\n"); + return rc; + } + + return btshell_broadcast_stop(adv_instance); +} +#endif /* BLE_ISO_BROADCAST_SOURCE */ + +#if (MYNEWT_VAL(BLE_AUDIO_BROADCAST_SINK)) +#include "audio/ble_audio_broadcast_sink.h" + +#define BROADCAST_SINK_PA_SYNC_SKIP_DFLT 0x0000 +#define BROADCAST_SINK_PA_SYNC_TIMEOUT_DFLT 0x07D0 + +static struct ble_gap_periodic_sync_params broadcast_sink_periodic_sync_params = { + .skip = BROADCAST_SINK_PA_SYNC_SKIP_DFLT, + .sync_timeout = BROADCAST_SINK_PA_SYNC_TIMEOUT_DFLT, + .reports_disabled = false +}; + +static void +codec_specific_config_printf(const struct ble_audio_codec_id *unused, const uint8_t *data, + uint8_t len) +{ + console_printf("data=%p len=%u\n", data, len); +} + +static void +base_bis_printf(const struct ble_audio_codec_id *codec_id, const struct ble_audio_base_bis *bis) +{ + console_printf("BISCodecConfig:\n\t"); + codec_specific_config_printf(codec_id,bis->codec_spec_config, bis->codec_spec_config_len); +} + +static void +metadata_printf(const uint8_t *data, uint8_t len) +{ + console_printf("data=%p len=%u\n", data, len); +} + +static void +base_subgroup_printf(uint8_t subgroup_index, const struct ble_audio_base_subgroup *subgroup) +{ + console_printf("subgroup_index=%u\n", subgroup_index); + console_printf("Codec ID:\n\tformat=0x%02x company_id=0x%04x vendor_specific=0x%02x\n", + subgroup->codec_id.format, subgroup->codec_id.company_id, + subgroup->codec_id.vendor_specific); + console_printf("SubgroupCodecConfig:\n\t"); + codec_specific_config_printf(&subgroup->codec_id, + subgroup->codec_spec_config, + subgroup->codec_spec_config_len); + console_printf("Metadata:\n\t"); + metadata_printf(subgroup->metadata, subgroup->metadata_len); +} + +static int +broadcast_sink_disc_start(const struct ble_gap_ext_disc_params *params) +{ + uint8_t own_addr_type; + int rc; + + /* Figure out address to use while scanning. */ + rc = ble_hs_id_infer_auto(0, &own_addr_type); + if (rc != 0) { + console_printf("determining own address type failed (%d)", rc); + assert(0); + } + + rc = ble_gap_ext_disc(own_addr_type, 0, 0, 0, 0, 0, params, NULL, NULL, NULL); + if (rc != 0) { + console_printf("ext disc failed (%d)", rc); + } + + return rc; +} + +static int +broadcast_sink_disc_stop(void) +{ + int rc; + + rc = ble_gap_disc_cancel(); + if (rc != 0) { + console_printf("disc cancel failed (%d)", rc); + } + + return rc; +} + +static int +broadcast_sink_action_fn(struct ble_audio_broadcast_sink_action *action, void *arg) +{ + switch (action->type) { + case BLE_AUDIO_BROADCAST_SINK_ACTION_PA_SYNC: + console_printf("PA Sync:\n"); + *action->pa_sync.out_params = broadcast_sink_periodic_sync_params; + break; + case BLE_AUDIO_BROADCAST_SINK_ACTION_BIG_SYNC: + console_printf("BIG Sync:\nsource_id=0x%02x iso_interval=0x%04x" + " presentation_delay=%" PRIu32 "[us]\n", + action->big_sync.source_id, action->big_sync.iso_interval, + action->big_sync.presentation_delay); + break; + case BLE_AUDIO_BROADCAST_SINK_ACTION_BIS_SYNC: + console_printf("BIS Sync:\n\tsource_id=0x%02x bis_index=0x%02x\n", + action->bis_sync.source_id, action->bis_sync.bis->index); + base_subgroup_printf(action->bis_sync.subgroup_index, action->bis_sync.subgroup); + base_bis_printf(&action->bis_sync.subgroup->codec_id, action->bis_sync.bis); + return 0; + case BLE_AUDIO_BROADCAST_SINK_ACTION_DISC_START: + return broadcast_sink_disc_start(action->disc_start.params_preferred); + case BLE_AUDIO_BROADCAST_SINK_ACTION_DISC_STOP: + return broadcast_sink_disc_stop(); + default: + assert(false); + return ENOTSUP; + } + + return 0; +} + +#if MYNEWT_VAL(SHELL_CMD_HELP) +static const struct shell_param cmd_leaudio_broadcast_sink_start_params[] = { + {"source_id", "usage: ="}, + {"broadcast_code", "usage: =[string], default: NULL"}, + {NULL, NULL} +}; + +const struct shell_cmd_help cmd_leaudio_broadcast_sink_start_help = { + .summary = "Start audio Broadcast Sink", + .usage = NULL, + .params = cmd_leaudio_broadcast_sink_start_params +}; +#endif /* SHELL_CMD_HELP */ + +int +cmd_leaudio_broadcast_sink_start(int argc, char **argv) +{ + struct ble_audio_broadcast_sink_add_params params = {0}; + char *broadcast_code; + uint8_t source_id; + int rc; + + rc = parse_arg_init(argc - 1, argv + 1); + if (rc != 0) { + return rc; + } + + source_id = parse_arg_uint8("source_id", &rc); + if (rc != 0) { + console_printf("invalid 'source_id' parameter\n"); + return rc; + } + + broadcast_code = parse_arg_extract("broadcast_code"); + if (broadcast_code != NULL) { + strncpy((char *)params.broadcast_code, broadcast_code, BLE_AUDIO_BROADCAST_CODE_SIZE); + params.broadcast_code_is_valid = true; + } + + rc = ble_audio_broadcast_sink_start(source_id, ¶ms); + if (rc != 0) { + console_printf("start failed (%d)\n", rc); + } + + return rc; +} + +#if MYNEWT_VAL(SHELL_CMD_HELP) +static const struct shell_param cmd_leaudio_broadcast_sink_stop_params[] = { + {"source_id", "usage: ="}, + {NULL, NULL} +}; + +const struct shell_cmd_help cmd_leaudio_broadcast_sink_stop_help = { + .summary = "Stop audio Broadcast Sink", + .usage = NULL, + .params = cmd_leaudio_broadcast_sink_stop_params +}; +#endif /* SHELL_CMD_HELP */ + +int +cmd_leaudio_broadcast_sink_stop(int argc, char **argv) +{ + uint8_t source_id; + int rc; + + rc = parse_arg_init(argc - 1, argv + 1); + if (rc != 0) { + return rc; + } + + source_id = parse_arg_uint8("source_id", &rc); + if (rc != 0) { + console_printf("invalid 'source_id' parameter\n"); + return rc; + } + + rc = ble_audio_broadcast_sink_stop(source_id); + if (rc != 0) { + console_printf("stop failed (%d)\n", rc); + } + + return rc; +} + +#if MYNEWT_VAL(SHELL_CMD_HELP) +static const struct shell_param cmd_leaudio_broadcast_sink_metadata_update_params[] = { + {"source_id", "usage: ="}, + {"subgroup_index", "usage: ="}, + {"metadata", "usage: =[XX:XX...]"}, + {NULL, NULL} +}; + +const struct shell_cmd_help cmd_leaudio_broadcast_sink_metadata_update_help = { + .summary = "Update Broadcast Sink metadata", + .usage = NULL, + .params = cmd_leaudio_broadcast_sink_metadata_update_params +}; +#endif /* SHELL_CMD_HELP */ + +int +cmd_leaudio_broadcast_sink_metadata_update(int argc, char **argv) +{ + struct ble_audio_broadcast_sink_metadata_update_params params = {0}; + static bssnz_t uint8_t metadata[UINT8_MAX]; + unsigned int metadata_len; + uint8_t source_id; + int rc; + + rc = parse_arg_init(argc - 1, argv + 1); + if (rc != 0) { + return rc; + } + + source_id = parse_arg_uint8("source_id", &rc); + if (rc != 0) { + console_printf("invalid 'source_id' parameter\n"); + return rc; + } + + params.subgroup_index = parse_arg_uint8("subgroup_index", &rc); + if (rc != 0) { + console_printf("invalid 'subgroup_index' parameter\n"); + return rc; + } + + rc = parse_arg_byte_stream("metadata", UINT8_MAX, metadata, &metadata_len); + if (rc == 0) { + params.metadata = metadata; + params.metadata_length = metadata_len; + } else if (rc != ENOENT) { + console_printf("invalid 'metadata' parameter\n"); + return rc; + } + + rc = ble_audio_broadcast_sink_metadata_update(source_id, ¶ms); + if (rc != 0) { + console_printf("metadata update failed (%d)\n", rc); + } + + return rc; +} + +#if MYNEWT_VAL(SHELL_CMD_HELP) +static const struct shell_param cmd_leaudio_broadcast_sink_sync_params_set_params[] = { + {"skip", "usage: =[0x0000-0x01F3], default: 0x0000"}, + {"sync_timeout", "usage: =[0x000A-0x4000], default: 0x07D0"}, + {NULL, NULL} +}; + +const struct shell_cmd_help cmd_leaudio_broadcast_sink_sync_params_set_help = { + .summary = "Set Broadcast Sink sync parameters", + .usage = NULL, + .params = cmd_leaudio_broadcast_sink_sync_params_set_params +}; +#endif /* SHELL_CMD_HELP */ + +int +cmd_leaudio_broadcast_sink_sync_params_set(int argc, char **argv) +{ + int rc; + + rc = parse_arg_init(argc - 1, argv + 1); + if (rc != 0) { + return rc; + } + + broadcast_sink_periodic_sync_params.skip = parse_arg_uint16_dflt("skip", BROADCAST_SINK_PA_SYNC_SKIP_DFLT, &rc); + if (rc != 0) { + console_printf("invalid 'skip' parameter\n"); + return rc; + } + + broadcast_sink_periodic_sync_params.sync_timeout = parse_arg_time_dflt("sync_timeout", 10000, + BROADCAST_SINK_PA_SYNC_TIMEOUT_DFLT, &rc); + if (rc != 0) { + console_printf("invalid 'sync_timeout' parameter\n"); + return rc; + } + + return rc; +} + +static int +broadcast_sink_audio_event_handler(struct ble_audio_event *event, void *arg) +{ + switch (event->type) { + case BLE_AUDIO_EVENT_BROADCAST_SINK_PA_SYNC_STATE: + console_printf("source_id=0x%02x PA sync: %s\n", + event->broadcast_sink_pa_sync_state.source_id, + ble_audio_broadcast_sink_sync_state_str( + event->broadcast_sink_pa_sync_state.state)); + break; + case BLE_AUDIO_EVENT_BROADCAST_SINK_BIS_SYNC_STATE: + console_printf("source_id=0x%02x bis_index=0x%02x BIS sync: %s\n", + event->broadcast_sink_bis_sync_state.source_id, + event->broadcast_sink_bis_sync_state.bis_index, + ble_audio_broadcast_sink_sync_state_str( + event->broadcast_sink_bis_sync_state.state)); + if (event->broadcast_sink_bis_sync_state.state == + BLE_AUDIO_BROADCAST_SINK_SYNC_STATE_ESTABLISHED) { + console_printf("conn_handle=0x%04x\n", + event->broadcast_sink_bis_sync_state.conn_handle); + } + break; + default: + break; + } + + return 0; +} +#endif /* BLE_AUDIO_BROADCAST_SINK */ + +#if MYNEWT_VAL(BLE_AUDIO_SCAN_DELEGATOR) +#include "audio/ble_audio_scan_delegator.h" + +static void +scan_delegator_source_desc_printf(const struct ble_audio_scan_delegator_source_desc *source_desc) +{ + console_printf("broadcast_id=0x%06" PRIx32 " adv_sid=%d adv_addr_type=%s adv_addr=", + source_desc->broadcast_id, source_desc->adv_sid, + cmd_addr_type_str(source_desc->addr.type)); + print_addr(source_desc->addr.val); + console_printf("\n"); +} + +static void +scan_delegator_sync_opt_printf(const struct ble_audio_scan_delegator_sync_opt *sync_opt) +{ + console_printf("pa_sync=%d pa_interval=0x%04x num_subgroups=%d", + sync_opt->pa_sync, sync_opt->pa_interval, sync_opt->num_subgroups); + for (uint8_t i = 0; i < sync_opt->num_subgroups; i++) { + console_printf("\n\tbis_sync=0x%04" PRIx32 " metadata_length=%d metadata=", + sync_opt->subgroups[i].bis_sync, sync_opt->subgroups[i].metadata_length); + print_bytes(sync_opt->subgroups[i].metadata, sync_opt->subgroups[i].metadata_length); + } + console_printf("\n"); +} + +static int +scan_delegator_pick_source_id_to_swap(uint8_t *out_source_id_to_swap) +{ + /* TODO: Add some logic here */ + *out_source_id_to_swap = 0; + + return 0; +} + +static int +scan_delegator_action_fn(struct ble_audio_scan_delegator_action *action, void *arg) +{ + switch (action->type) { + case BLE_AUDIO_SCAN_DELEGATOR_ACTION_SOURCE_ADD: + console_printf("Source Add:\nsource_id=%u\n", action->source_add.source_id); + scan_delegator_source_desc_printf(&action->source_add.source_desc); + scan_delegator_sync_opt_printf(&action->source_add.sync_opt); + if (action->source_add.out_source_id_to_swap == NULL) { + return 0; + } else { + return scan_delegator_pick_source_id_to_swap(action->source_add.out_source_id_to_swap); + } + case BLE_AUDIO_SCAN_DELEGATOR_ACTION_SOURCE_MODIFY: + console_printf("Source Modify:\nsource_id=%u\n", action->source_modify.source_id); + scan_delegator_sync_opt_printf(&action->source_modify.sync_opt); + break; + case BLE_AUDIO_SCAN_DELEGATOR_ACTION_SOURCE_REMOVE: + console_printf("Source Remove:\nsource_id=%u\n", action->source_remove.source_id); + break; + default: + assert(false); + return ENOTSUP; + } + + return 0; +} + +#if MYNEWT_VAL(SHELL_CMD_HELP) +static const struct shell_param cmd_leaudio_scan_delegator_receive_state_add_params[] = { + {"addr_type", "usage: =[public|random], default: public"}, + {"addr", "usage: =[XX:XX:XX:XX:XX:XX]"}, + {"broadcast_id", "usage: =[0-0xFFFFFF]"}, + {"adv_sid", "usage: =[UINT8], default: 0"}, + {NULL, NULL} +}; + +const struct shell_cmd_help cmd_leaudio_scan_delegator_receive_state_add_help = { + .summary = "Add receive state", + .usage = NULL, + .params = cmd_leaudio_scan_delegator_receive_state_add_params +}; +#endif /* SHELL_CMD_HELP */ + +int +cmd_leaudio_scan_delegator_receive_state_add(int argc, char **argv) +{ + struct ble_audio_scan_delegator_receive_state_add_params params = {0}; + uint8_t source_id; + int rc; + + rc = parse_arg_init(argc - 1, argv + 1); + if (rc != 0) { + return rc; + } + + rc = cmd_parse_addr(NULL, ¶ms.source_desc.addr); + if (rc != 0) { + console_printf("invalid 'adv_addr' parameter\n"); + return rc; + } + + params.source_desc.broadcast_id = parse_arg_uint32("broadcast_id", &rc); + if (rc != 0) { + console_printf("invalid 'broadcast_id' parameter\n"); + return rc; + } + + params.source_desc.adv_sid = parse_arg_uint8_dflt("adv_sid", 0, &rc); + if (rc != 0) { + console_printf("invalid 'adv_sid' parameter\n"); + return rc; + } + + rc = ble_audio_scan_delegator_receive_state_add(¶ms, &source_id); + if (rc != 0) { + console_printf("Failed to add receive state (%d)\n", rc); + } else { + console_printf("New source_id=%u created\n", source_id); + } + + return rc; +} + +#if MYNEWT_VAL(SHELL_CMD_HELP) +static const struct shell_param cmd_leaudio_scan_delegator_receive_state_remove_params[] = { + {"source_id", "usage: ="}, + {NULL, NULL} +}; + +const struct shell_cmd_help cmd_leaudio_scan_delegator_receive_state_remove_help = { + .summary = "Remove receive state", + .usage = NULL, + .params = cmd_leaudio_scan_delegator_receive_state_remove_params +}; +#endif /* SHELL_CMD_HELP */ + +int +cmd_leaudio_scan_delegator_receive_state_remove(int argc, char **argv) +{ + uint8_t source_id; + int rc; + + rc = parse_arg_init(argc - 1, argv + 1); + if (rc != 0) { + return rc; + } + + source_id = parse_arg_uint8("source_id", &rc); + if (rc != 0) { + console_printf("invalid 'source_id' parameter\n"); + return rc; + } + + rc = ble_audio_scan_delegator_receive_state_remove(source_id); + if (rc != 0) { + console_printf("remove failed (%d)\n", rc); + } + + return rc; +} + +const struct parse_arg_kv_pair cmd_pa_sync_type[] = { + { "not_synced", BLE_AUDIO_SCAN_DELEGATOR_PA_SYNC_STATE_NOT_SYNCED }, + { "sync_info_req", BLE_AUDIO_SCAN_DELEGATOR_PA_SYNC_STATE_SYNC_INFO_REQ }, + { "synced", BLE_AUDIO_SCAN_DELEGATOR_PA_SYNC_STATE_SYNCED }, + { "failed", BLE_AUDIO_SCAN_DELEGATOR_PA_SYNC_STATE_ERROR }, + { "no_past", BLE_AUDIO_SCAN_DELEGATOR_PA_SYNC_STATE_NO_PAST }, + { NULL } +}; + +const struct parse_arg_kv_pair cmd_big_enc_type[] = { + { "not_encrypted", BLE_AUDIO_SCAN_DELEGATOR_BIG_ENC_NONE }, + { "code_req", BLE_AUDIO_SCAN_DELEGATOR_BIG_ENC_BROADCAST_CODE_MISSING }, + { "decrypting", BLE_AUDIO_SCAN_DELEGATOR_BIG_ENC_DECRYPTING }, + { "bad_code", BLE_AUDIO_SCAN_DELEGATOR_BIG_ENC_BROADCAST_CODE_INVALID }, + { NULL } +}; + +#if MYNEWT_VAL(SHELL_CMD_HELP) +static const struct shell_param cmd_leaudio_scan_delegator_receive_state_set_params[] = { + {"source_id", "usage: ="}, + {"pa_sync_state", "usage: =[not_synced|sync_info_req|synced|failed|no_past], default: not_synced"}, + {"big_enc", "usage: =[not_encrypted|code_req|decrypting|bad_code], default: not_encrypted"}, + {"bad_code", "usage: =[string], default: NULL"}, + {NULL, NULL} +}; + +const struct shell_cmd_help cmd_leaudio_scan_delegator_receive_state_set_help = { + .summary = "Set receive state", + .usage = NULL, + .params = cmd_leaudio_scan_delegator_receive_state_set_params +}; +#endif /* SHELL_CMD_HELP */ + +int +cmd_leaudio_scan_delegator_receive_state_set(int argc, char **argv) +{ + struct ble_audio_scan_delegator_receive_state state = {0}; + char *bad_code; + uint8_t source_id; + int rc; + + rc = parse_arg_init(argc - 1, argv + 1); + if (rc != 0) { + return rc; + } + + source_id = parse_arg_uint8("source_id", &rc); + if (rc != 0) { + console_printf("invalid 'source_id' parameter\n"); + return rc; + } + + state.pa_sync_state = parse_arg_kv_dflt("pa_sync_state", cmd_pa_sync_type, + BLE_AUDIO_SCAN_DELEGATOR_PA_SYNC_STATE_NOT_SYNCED, &rc); + if (rc != 0) { + console_printf("invalid 'pa_sync_state' parameter\n"); + return rc; + } + + state.big_enc = parse_arg_kv_dflt("big_enc", cmd_big_enc_type, + BLE_AUDIO_SCAN_DELEGATOR_BIG_ENC_NONE, &rc); + if (rc != 0) { + console_printf("invalid 'big_enc' parameter\n"); + return rc; + } + + bad_code = parse_arg_extract("bad_code"); + if (bad_code != NULL) { + strncpy((char *)state.bad_code, bad_code, BLE_AUDIO_BROADCAST_CODE_SIZE); + } + + /* TODO: initialize state.subgroups */ + state.num_subgroups = 0; + + rc = ble_audio_scan_delegator_receive_state_set(source_id, &state); + if (rc != 0) { + console_printf("set failed (%d)\n", rc); + } + + return rc; +} + +static const char * +pa_sync_type_str(enum ble_audio_scan_delegator_pa_sync_state pa_sync_state) +{ + for (size_t i = 0; i < ARRAY_SIZE(cmd_pa_sync_type); i++) { + if (cmd_pa_sync_type[i].val == pa_sync_state) { + return cmd_pa_sync_type[i].key; + } + } + + return STR_NULL; +} + +static const char * +big_enc_type_str(enum ble_audio_scan_delegator_big_enc big_enc) +{ + for (size_t i = 0; i < ARRAY_SIZE(cmd_big_enc_type); i++) { + if (cmd_big_enc_type[i].val == big_enc) { + return cmd_big_enc_type[i].key; + } + } + + return STR_NULL; +} + +static void +scan_delegator_receive_state_printf(const struct ble_audio_scan_delegator_receive_state *state) +{ + console_printf("pa_sync_state=%s big_enc=%s num_subgroups=%d", + pa_sync_type_str(state->pa_sync_state), big_enc_type_str(state->big_enc), + state->num_subgroups); + + if (state->big_enc == BLE_AUDIO_SCAN_DELEGATOR_BIG_ENC_BROADCAST_CODE_INVALID) { + console_printf("bad_code="); + print_bytes(state->bad_code, sizeof(state->bad_code)); + console_printf("\n"); + } + + for (uint8_t i = 0; i < state->num_subgroups; i++) { + console_printf("\n\tbis_sync=0x%04" PRIu32 " metadata_length=%d metadata=", + state->subgroups[i].bis_sync, state->subgroups[i].metadata_length); + print_bytes(state->subgroups[i].metadata, state->subgroups[i].metadata_length); + console_printf("\n"); + } +} + +#if MYNEWT_VAL(SHELL_CMD_HELP) +static const struct shell_param cmd_leaudio_scan_delegator_receive_state_get_params[] = { + {"source_id", "usage: ="}, + {NULL, NULL} +}; + +const struct shell_cmd_help cmd_leaudio_scan_delegator_receive_state_get_help = { + .summary = "Get receive state", + .usage = NULL, + .params = cmd_leaudio_scan_delegator_receive_state_get_params +}; +#endif /* SHELL_CMD_HELP */ + +int +cmd_leaudio_scan_delegator_receive_state_get(int argc, char **argv) +{ + struct ble_audio_scan_delegator_receive_state state = {0}; + uint8_t source_id; + int rc; + + rc = parse_arg_init(argc - 1, argv + 1); + if (rc != 0) { + return rc; + } + + source_id = parse_arg_uint8("source_id", &rc); + if (rc != 0) { + console_printf("invalid 'source_id' parameter\n"); + return rc; + } + + rc = ble_audio_scan_delegator_receive_state_get(source_id, &state); + if (rc != 0) { + console_printf("get failed (%d)\n", rc); + } else { + console_printf("source_id=%u\n", source_id); + scan_delegator_receive_state_printf(&state); + } + + return rc; +} + +static int +scan_delegator_receive_state_foreach_fn(struct ble_audio_scan_delegator_receive_state_entry *entry, + void *arg) +{ + console_printf("source_id=%u\n", entry->source_id); + scan_delegator_source_desc_printf(&entry->source_desc); + scan_delegator_receive_state_printf(&entry->state); + + return 0; +} + +#if MYNEWT_VAL(SHELL_CMD_HELP) +const struct shell_cmd_help cmd_leaudio_scan_delegator_receive_state_show_help = { + .summary = "List receive states", + .usage = NULL, + .params = NULL +}; +#endif /* SHELL_CMD_HELP */ + +int +cmd_leaudio_scan_delegator_receive_state_show(int argc, char **argv) +{ + uint8_t num_entries = 0; + + ble_audio_scan_delegator_receive_state_foreach(scan_delegator_receive_state_foreach_fn, + &num_entries); + if (num_entries == 0) { + console_printf("No receive state\n"); + } + + return 0; +} + +static int +scan_delegator_audio_event_handler(struct ble_audio_event *event, void *arg) +{ + switch (event->type) { + case BLE_AUDIO_EVENT_BROADCAST_ANNOUNCEMENT: + console_printf("Broadcast Announcement\n"); + console_printf("broadcast_id=0x%06" PRIx32 " adv_sid=%d addr_type=%s addr=", + event->broadcast_announcement.broadcast_id, + event->broadcast_announcement.ext_disc->sid, + cmd_addr_type_str(event->broadcast_announcement.ext_disc->addr.type)); + print_addr(event->broadcast_announcement.ext_disc->addr.val); + console_printf("\n"); + break; + default: + break; + } + + return 0; +} +#endif /* BLE_AUDIO_SCAN_DELEGATOR */ + +void +btshell_leaudio_init(void) +{ + int rc = 0; + +#if (MYNEWT_VAL(BLE_AUDIO_SCAN_DELEGATOR)) + static struct ble_audio_event_listener scan_delegator_listener; + + rc = ble_audio_scan_delegator_action_fn_set(scan_delegator_action_fn, NULL); + assert(rc == 0); + + rc = ble_audio_event_listener_register(&scan_delegator_listener, + scan_delegator_audio_event_handler, NULL); + assert(rc == 0); +#endif /* BLE_AUDIO_SCAN_DELEGATOR */ + +#if (MYNEWT_VAL(BLE_AUDIO_BROADCAST_SINK)) + static struct ble_audio_event_listener broadcast_sink_listener; + + rc = ble_audio_broadcast_sink_cb_set(broadcast_sink_action_fn, NULL); + assert(rc == 0); + + rc = ble_audio_event_listener_register(&broadcast_sink_listener, + broadcast_sink_audio_event_handler, NULL); +#endif /* BLE_AUDIO_BROADCAST_SINK */ + assert(rc == 0); +} +#endif /* BLE_AUDIO */ diff --git a/apps/btshell/src/cmd_leaudio.h b/apps/btshell/src/cmd_leaudio.h new file mode 100644 index 0000000000..1704c6f4da --- /dev/null +++ b/apps/btshell/src/cmd_leaudio.h @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_CMD_LEAUDIO_ +#define H_CMD_LEAUDIO_ + +#include "cmd.h" + +#define CMD_ADV_DATA_CODEC_SPEC_CFG_MAX_SZ (9) +/** + * Maximum Metadata size is maximum adv size minus minimum size of other + * fields in BASE advertising + */ +#define CMD_ADV_DATA_METADATA_MAX_SZ (MYNEWT_VAL(BLE_EXT_ADV_MAX_SIZE) - 27) +/** + * Maximum size of extra data included in BASE advertising. Assumes minimum + * size of other fields. + */ +#define CMD_ADV_DATA_EXTRA_MAX_SZ (MYNEWT_VAL(BLE_EXT_ADV_MAX_SIZE) - 27) + +int cmd_leaudio_base_add(int argc, char **argv); +int cmd_leaudio_big_sub_add(int argc, char **argv); +int cmd_leaudio_bis_add(int argc, char **argv); +int cmd_leaudio_broadcast_create(int argc, char **argv); +int cmd_leaudio_broadcast_destroy(int argc, char **argv); +int cmd_leaudio_broadcast_update(int argc, char **argv); +int cmd_leaudio_broadcast_start(int argc, char **argv); +int cmd_leaudio_broadcast_stop(int argc, char **argv); + +extern const struct shell_cmd_help cmd_leaudio_broadcast_sink_start_help; +extern const struct shell_cmd_help cmd_leaudio_broadcast_sink_stop_help; +extern const struct shell_cmd_help cmd_leaudio_broadcast_sink_metadata_update_help; +extern const struct shell_cmd_help cmd_leaudio_broadcast_sink_sync_params_set_help; + +int cmd_leaudio_broadcast_sink_start(int argc, char **argv); +int cmd_leaudio_broadcast_sink_stop(int argc, char **argv); +int cmd_leaudio_broadcast_sink_metadata_update(int argc, char **argv); +int cmd_leaudio_broadcast_sink_sync_params_set(int argc, char **argv); + +extern const struct shell_cmd_help cmd_leaudio_scan_delegator_receive_state_add_help; +extern const struct shell_cmd_help cmd_leaudio_scan_delegator_receive_state_remove_help; +extern const struct shell_cmd_help cmd_leaudio_scan_delegator_receive_state_set_help; +extern const struct shell_cmd_help cmd_leaudio_scan_delegator_receive_state_get_help; +extern const struct shell_cmd_help cmd_leaudio_scan_delegator_receive_state_show_help; + +int cmd_leaudio_scan_delegator_receive_state_add(int argc, char **argv); +int cmd_leaudio_scan_delegator_receive_state_remove(int argc, char **argv); +int cmd_leaudio_scan_delegator_receive_state_set(int argc, char **argv); +int cmd_leaudio_scan_delegator_receive_state_get(int argc, char **argv); +int cmd_leaudio_scan_delegator_receive_state_show(int argc, char **argv); + +#endif /* H_CMD_LEAUDIO_ */ diff --git a/apps/btshell/src/main.c b/apps/btshell/src/main.c index 99f0a7979f..0db012e98c 100644 --- a/apps/btshell/src/main.c +++ b/apps/btshell/src/main.c @@ -25,7 +25,6 @@ #include "bsp/bsp.h" #include "log/log.h" #include "stats/stats.h" -#include "bsp/bsp.h" #include "hal/hal_gpio.h" #include "console/console.h" #include "btshell.h" @@ -34,7 +33,6 @@ /* BLE */ #include "nimble/ble.h" #include "nimble/nimble_opt.h" -#include "nimble/ble_hci_trans.h" #include "host/ble_hs.h" #include "host/ble_hs_adv.h" #include "host/ble_uuid.h" @@ -43,6 +41,10 @@ #include "host/ble_gatt.h" #include "host/ble_store.h" #include "host/ble_sm.h" +#if MYNEWT_VAL(BLE_AUDIO) && MYNEWT_VAL(BLE_ISO_BROADCAST_SOURCE) +#include "audio/ble_audio_broadcast_source.h" +#include "audio/ble_audio.h" +#endif /* BLE_AUDIO && BLE_ISO_BROADCAST_SOURCE */ #include "host/util/util.h" /* Mandatory services. */ @@ -56,6 +58,10 @@ #include "../src/ble_hs_atomic_priv.h" #include "../src/ble_hs_priv.h" +#ifndef min +#define min(a, b) ((a) < (b) ? (a) : (b)) +#endif + #if MYNEWT_VAL(BLE_ROLE_CENTRAL) #define BTSHELL_MAX_SVCS 32 #define BTSHELL_MAX_CHRS 64 @@ -78,6 +84,8 @@ bssnz_t struct btshell_conn btshell_conns[MYNEWT_VAL(BLE_MAX_CONNECTIONS)]; int btshell_num_conns; +static uint8_t default_own_addr_type; + static os_membuf_t btshell_svc_mem[ OS_MEMPOOL_SIZE(BTSHELL_MAX_SVCS, sizeof(struct btshell_svc)) ]; @@ -107,6 +115,11 @@ struct os_mbuf_pool sdu_os_mbuf_pool; static struct os_mempool sdu_coc_mbuf_mempool; #endif +#if MYNEWT_VAL(BLE_GATT_NOTIFY_MULTIPLE) +static struct ble_gatt_notif pending_notif[BTSHELL_MAX_CHRS]; +static size_t pending_notif_cnt; +#endif + static struct os_callout btshell_tx_timer; struct btshell_tx_data_s { @@ -123,6 +136,57 @@ int btshell_full_disc_prev_chr_val; struct ble_sm_sc_oob_data oob_data_local; struct ble_sm_sc_oob_data oob_data_remote; +#if MYNEWT_VAL(BLE_AUDIO) && MYNEWT_VAL(BLE_ISO_BROADCAST_SOURCE) +static struct {struct ble_audio_base *base; uint8_t adv_instance;} +btshell_base_list[MYNEWT_VAL(BLE_ISO_MAX_BIGS)]; + +static os_membuf_t btshell_base_mem[ + OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_ISO_MAX_BIGS), + sizeof(struct ble_audio_base)) +]; +static struct os_mempool btshell_base_pool; + +static os_membuf_t btshell_big_params_mem[ + OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_ISO_MAX_BIGS), + sizeof(struct ble_iso_big_params)) +]; +static struct os_mempool btshell_big_params_pool; + +/** Mempool size: in worst case every BIS is in separate subgroup */ +static os_membuf_t btshell_big_sub_mem[ + OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_ISO_MAX_BISES), + sizeof(struct ble_audio_big_subgroup)) +]; +static struct os_mempool btshell_big_sub_pool; + +static os_membuf_t btshell_bis_mem[ + OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_ISO_MAX_BISES), + sizeof(struct ble_audio_bis)) +]; +static struct os_mempool btshell_bis_pool; + +static os_membuf_t btshell_metadata_mem[ + OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_ISO_MAX_BISES), + MYNEWT_VAL(BLE_EXT_ADV_MAX_SIZE) - 27) +]; +static struct os_mempool btshell_metadata_pool; + +/** + * Mempool size: theoretically it is possible that every BIG Subgroup has + * codec specific configuration, every BIS is in separate subgroup and also + * has one. This is inefficient but possible and should not cause error if + * used that way */ +static os_membuf_t btshell_codec_spec_mem[ + OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_ISO_MAX_BISES) * 2, 9) +]; +static struct os_mempool btshell_codec_spec_pool; + +static os_membuf_t btshell_big_params_mem[ + OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_ISO_MAX_BIGS), sizeof(struct ble_iso_big_params)) +]; +static struct os_mempool btshell_big_params_pool; +#endif /* BLE_AUDIO && BLE_ISO_BROADCAST_SOURCE */ + #define XSTR(s) STR(s) #ifndef STR #define STR(s) #s @@ -869,6 +933,35 @@ btshell_on_disc_d(uint16_t conn_handle, const struct ble_gatt_error *error, return 0; } +static int +btshell_on_read_var(uint16_t conn_handle, const struct ble_gatt_error *error, + struct ble_gatt_attr *attr, uint8_t num_attrs, void *arg) +{ + int i; + + switch (error->status) { + case 0: + console_printf("characteristic read; conn_handle=%d , number of attributes=%d\n", conn_handle, num_attrs); + + for (i = 0; i < num_attrs; i++) { + console_printf("\t attr_handle=%d, len=%d value=", + attr[i].handle, OS_MBUF_PKTLEN(attr[i].om)); + print_mbuf(attr[i].om); + console_printf("\n"); + } + break; + + case BLE_HS_EDONE: + console_printf("characteristic read complete\n"); + break; + + default: + btshell_print_error(NULL, conn_handle, error); + break; + } + + return 0; +} static int btshell_on_read(uint16_t conn_handle, const struct ble_gatt_error *error, @@ -965,9 +1058,31 @@ btshell_decode_adv_data(const uint8_t *adv_data, uint8_t adv_data_len, void *arg static void btshell_decode_event_type(struct ble_gap_ext_disc_desc *desc, void *arg) { + const struct ble_hs_adv_field *ad_name = NULL; struct btshell_scan_opts *scan_opts = arg; uint8_t directed = 0; + if (scan_opts && scan_opts->name_filter_len) { + if (ble_hs_adv_find_field(BLE_HS_ADV_TYPE_COMP_NAME, desc->data, + desc->length_data, &ad_name)) { + ble_hs_adv_find_field(BLE_HS_ADV_TYPE_INCOMP_NAME, desc->data, + desc->length_data, &ad_name); + } + + if (!ad_name) { + return; + } + + if (ad_name->length < scan_opts->name_filter_len) { + return; + } + + if (strncasecmp(scan_opts->name_filter, (const char *)ad_name->value, + scan_opts->name_filter_len)) { + return; + } + } + if (desc->props & BLE_HCI_ADV_LEGACY_MASK) { if (scan_opts && scan_opts->ignore_legacy) { return; @@ -1206,11 +1321,23 @@ btshell_gap_event(struct ble_gap_event *event, void *arg) return btshell_restart_adv(event); #if MYNEWT_VAL(BLE_EXT_ADV) - case BLE_GAP_EVENT_EXT_DISC: - btshell_decode_event_type(&event->ext_disc, arg); + case BLE_GAP_EVENT_EXT_DISC: { + struct btshell_scan_opts *scan_opts = arg; + + if (!scan_opts->silent) { + btshell_decode_event_type(&event->ext_disc, arg); + } + return 0; + } #endif - case BLE_GAP_EVENT_DISC: + case BLE_GAP_EVENT_DISC: { + struct btshell_scan_opts *scan_opts = arg; + + if (scan_opts->silent) { + return 0; + } + console_printf("received advertisement; event_type=%d rssi=%d " "addr_type=%d addr=", event->disc.event_type, event->disc.rssi, event->disc.addr.type); @@ -1228,6 +1355,7 @@ btshell_gap_event(struct ble_gap_event *event, void *arg) btshell_decode_adv_data(event->disc.data, event->disc.length_data, arg); return 0; + } case BLE_GAP_EVENT_CONN_UPDATE: console_printf("connection updated; status=%d ", @@ -1648,13 +1776,17 @@ btshell_read_by_uuid(uint16_t conn_handle, uint16_t start_handle, int btshell_read_mult(uint16_t conn_handle, uint16_t *attr_handles, - int num_attr_handles) + int num_attr_handles, bool variable) { - int rc; + if (variable) { + return ble_gattc_read_mult_var(conn_handle, attr_handles, num_attr_handles, + btshell_on_read_var, NULL); + } + + return ble_gattc_read_mult(conn_handle, attr_handles, + num_attr_handles, + btshell_on_read, NULL); - rc = ble_gattc_read_mult(conn_handle, attr_handles, num_attr_handles, - btshell_on_read, NULL); - return rc; } int @@ -1706,6 +1838,79 @@ btshell_write_reliable(uint16_t conn_handle, return rc; } +#if MYNEWT_VAL(BLE_GATT_NOTIFY_MULTIPLE) +int +btshell_enqueue_notif(uint16_t handle, uint16_t len, uint8_t *value) +{ + struct ble_gatt_notif *notify = NULL; + struct os_mbuf *val_ptr; + int i; + + for (i = 0; i < BTSHELL_MAX_CHRS; i++) { + if (pending_notif[i].handle == 0) { + notify = &pending_notif[i]; + break; + } + } + + if (notify == NULL) { + return ENOMEM; + } + + notify->handle = handle; + if (value != NULL) { + notify->value = os_msys_get(0, 0); + + val_ptr = os_mbuf_extend(notify->value, len); + if (val_ptr == NULL) { + return ENOMEM; + } + memcpy(val_ptr, value, len); + } + + pending_notif_cnt++; + + return 0; +} + +int +btshell_send_pending_notif(uint16_t conn_handle) +{ + int rc = 0; + int i; + + if (pending_notif_cnt == 0) { + return EALREADY; + } + + rc = ble_gatts_notify_multiple_custom(conn_handle, pending_notif_cnt, + pending_notif); + for (i = 0; i < pending_notif_cnt; i++) { + pending_notif[i].handle = 0; + pending_notif[i].value = NULL; + } + + pending_notif_cnt = 0; + + return rc; +} + +int +btshell_clear_pending_notif(void) +{ + int i; + + for (i = 0; i < pending_notif_cnt; i++) { + pending_notif[i].handle = 0; + pending_notif[i].value = NULL; + } + + pending_notif_cnt = 0; + + return 0; +} +#endif + #if MYNEWT_VAL(BLE_EXT_ADV) int btshell_ext_adv_configure(uint8_t instance, @@ -1877,6 +2082,10 @@ btshell_ext_scan(uint8_t own_addr_type, uint16_t duration, uint16_t period, const struct ble_gap_ext_disc_params *coded_params, void *cb_args) { + struct btshell_scan_opts *scan_opts = cb_args; + + console_printf("silent %d.", scan_opts->silent); + #if !MYNEWT_VAL(BLE_EXT_ADV) console_printf("BLE extended advertising not supported."); console_printf(" Configure nimble host to enable it\n"); @@ -2111,6 +2320,8 @@ btshell_on_sync(void) console_printf("Failed to set identity address\n"); } + ble_hs_id_infer_auto(0, &default_own_addr_type); + #if MYNEWT_VAL(BLE_SM_SC) int rc; @@ -2186,8 +2397,8 @@ btshell_l2cap_coc_remove(uint16_t conn_handle, struct ble_l2cap_chan *chan) static void btshell_l2cap_coc_recv(struct ble_l2cap_chan *chan, struct os_mbuf *sdu) { - console_printf("LE CoC SDU received, chan: 0x%08lx, data len %d\n", - (uint32_t) chan, OS_MBUF_PKTLEN(sdu)); + console_printf("LE CoC SDU received, chan: %p, data len %d\n", + chan, OS_MBUF_PKTLEN(sdu)); os_mbuf_free_chain(sdu); sdu = os_mbuf_get_pkthdr(&sdu_os_mbuf_pool, 0); @@ -2200,19 +2411,25 @@ btshell_l2cap_coc_recv(struct ble_l2cap_chan *chan, struct os_mbuf *sdu) static int btshell_l2cap_coc_accept(uint16_t conn_handle, uint16_t peer_mtu, - struct ble_l2cap_chan *chan) + struct ble_l2cap_chan *chan) { struct os_mbuf *sdu_rx; + int rc; + + console_printf("LE CoC accepting, chan: %p, peer_mtu %d\n", + chan, peer_mtu); - console_printf("LE CoC accepting, chan: 0x%08lx, peer_mtu %d\n", - (uint32_t) chan, peer_mtu); + for (int i = 0; i < MYNEWT_VAL(BLE_L2CAP_COC_SDU_BUFF_COUNT); i++) { + sdu_rx = os_mbuf_get_pkthdr(&sdu_os_mbuf_pool, 0); + if (!sdu_rx) { + return BLE_HS_ENOMEM; + } - sdu_rx = os_mbuf_get_pkthdr(&sdu_os_mbuf_pool, 0); - if (!sdu_rx) { - return BLE_HS_ENOMEM; + rc = ble_l2cap_recv_ready(chan, sdu_rx); + assert(rc == 0); } - return ble_l2cap_recv_ready(chan, sdu_rx); + return rc; } static void @@ -2549,6 +2766,282 @@ btshell_init_ext_adv_restart(void) #endif } +uint8_t +btshell_get_default_own_addr_type(void) +{ + return default_own_addr_type; +} + +#if MYNEWT_VAL(BLE_AUDIO) && MYNEWT_VAL(BLE_ISO_BROADCAST_SOURCE) +static int +btshell_base_find_free(void) +{ + int i; + for (i = 0; i < MYNEWT_VAL(BLE_ISO_MAX_BIGS); i++) { + if (btshell_base_list[i].base == NULL) { + return i; + } + } + + return -ENOMEM; +} + +static struct ble_audio_base * +btshell_base_find(uint8_t adv_instance) +{ + int i; + for (i = 0; i < MYNEWT_VAL(BLE_ISO_MAX_BIGS); i++) { + if (btshell_base_list[i].adv_instance == adv_instance) { + return btshell_base_list[i].base; + } + } + + return NULL; +} + +static int +btshell_broadcast_destroy_fn(struct ble_audio_base *base, void *args) +{ + struct ble_iso_big_params *big_params = + (struct ble_iso_big_params *)args; + struct ble_audio_big_subgroup *big_sub; + struct ble_audio_bis *bis; + + STAILQ_FOREACH(big_sub, &base->subs, next) { + STAILQ_FOREACH(bis, &big_sub->bises, next) { + os_memblock_put(&btshell_bis_pool, bis); + os_memblock_put(&btshell_codec_spec_pool, bis->codec_spec_config); + STAILQ_REMOVE(&big_sub->bises, bis, ble_audio_bis, next); + } + os_memblock_put(&btshell_big_sub_pool, big_sub); + os_memblock_put(&btshell_codec_spec_pool, big_sub->codec_spec_config); + os_memblock_put(&btshell_metadata_pool, big_sub->metadata); + STAILQ_REMOVE(&base->subs, big_sub, ble_audio_big_subgroup, next); + } + + os_memblock_put(&btshell_big_params_pool, big_params); + + return 0; +} + +int +btshell_broadcast_base_add(uint8_t adv_instance, uint32_t presentation_delay) +{ + struct ble_audio_base *base; + int free_base_idx; + + base = os_memblock_get(&btshell_base_pool); + if (!base) { + return ENOMEM; + } + + free_base_idx = btshell_base_find_free(); + if (free_base_idx < 0) { + return ENOMEM; + } + + base->presentation_delay = presentation_delay; + + btshell_base_list[free_base_idx].base = base; + btshell_base_list[free_base_idx].adv_instance = adv_instance; + + return 0; +} + +int +btshell_broadcast_big_sub_add(uint8_t adv_instance, + uint8_t codec_fmt, uint16_t company_id, + uint16_t vendor_spec, + uint8_t *metadata, + unsigned int metadata_len, + uint8_t *codec_spec_cfg, + unsigned int codec_spec_cfg_len) +{ + struct ble_audio_big_subgroup *big_sub; + struct ble_audio_base *base; + uint8_t *new_metadata = NULL; + uint8_t *new_codec_spec_cfg = NULL; + + big_sub = os_memblock_get(&btshell_big_sub_pool); + if (!big_sub) { + return ENOMEM; + } + + base = btshell_base_find(adv_instance); + if (!base) { + os_memblock_put(&btshell_big_sub_pool, big_sub); + return ENOENT; + } + + if (metadata_len > 0) { + new_metadata = os_memblock_get(&btshell_metadata_pool); + if (!new_metadata) { + os_memblock_put(&btshell_big_sub_pool, big_sub); + return ENOMEM; + } + memcpy(new_metadata, metadata, metadata_len); + } + + if (codec_spec_cfg_len > 0) { + new_codec_spec_cfg = os_memblock_get(&btshell_codec_spec_pool); + if (!new_codec_spec_cfg) { + os_memblock_put(&btshell_big_sub_pool, big_sub); + os_memblock_put(&btshell_metadata_pool, new_metadata); + return ENOMEM; + } + memcpy(new_codec_spec_cfg, codec_spec_cfg, codec_spec_cfg_len); + } + + big_sub->codec_id.format = codec_fmt; + big_sub->codec_id.company_id = company_id; + big_sub->codec_id.vendor_specific = vendor_spec; + big_sub->codec_id.vendor_specific = vendor_spec; + big_sub->codec_spec_config = codec_spec_cfg_len > 0 ? + new_codec_spec_cfg : NULL; + big_sub->codec_spec_config_len = codec_spec_cfg_len; + big_sub->metadata = metadata_len > 0 ? new_metadata : NULL; + big_sub->metadata_len = metadata_len; + + if (STAILQ_EMPTY(&base->subs)) { + STAILQ_INSERT_HEAD(&base->subs, big_sub, next); + } else { + STAILQ_INSERT_TAIL(&base->subs, big_sub, next); + } + + base->num_subgroups++; + + return 0; +} + +int +btshell_broadcast_bis_add(uint8_t adv_instance, + uint8_t *codec_spec_cfg, + unsigned int codec_spec_cfg_len) +{ + struct ble_audio_bis *bis; + struct ble_audio_base *base; + struct ble_audio_big_subgroup *big_sub; + uint8_t *new_codec_spec_cfg; + + base = btshell_base_find(adv_instance); + if (!base) { + return ENOENT; + } + + big_sub = STAILQ_LAST(&base->subs, ble_audio_big_subgroup, next); + if (!big_sub) { + return ENOENT; + } + + bis = os_memblock_get(&btshell_bis_pool); + if (!bis) { + return ENOMEM; + } + + if (codec_spec_cfg_len > 0) { + new_codec_spec_cfg = os_memblock_get(&btshell_codec_spec_pool); + if (!new_codec_spec_cfg) { + os_memblock_put(&btshell_bis_pool, bis); + return ENOMEM; + } + memcpy(new_codec_spec_cfg, codec_spec_cfg, codec_spec_cfg_len); + } + + bis->codec_spec_config = codec_spec_cfg_len > 0 ? + new_codec_spec_cfg : NULL; + bis->codec_spec_config_len = codec_spec_cfg_len; + + if (STAILQ_EMPTY(&big_sub->bises)) { + STAILQ_INSERT_HEAD(&big_sub->bises, bis, next); + } else { + STAILQ_INSERT_TAIL(&big_sub->bises, bis, next); + } + + big_sub->bis_cnt++; + return 0; +} + +int +btshell_broadcast_create(uint8_t adv_instance, + struct ble_gap_ext_adv_params *ext_params, + struct ble_gap_periodic_adv_params *per_params, + const char *name, + struct ble_iso_big_params big_params, + uint8_t *extra_data, + unsigned int extra_data_len) +{ + struct ble_audio_base *base; + struct ble_broadcast_create_params create_params; + struct ble_iso_big_params *big_params_ptr; + int rc; + + base = btshell_base_find(adv_instance); + if (!base) { + return ENOENT; + } + + big_params_ptr = os_memblock_get(&btshell_big_params_pool); + if (!big_params_ptr) { + return ENOMEM; + } + + *big_params_ptr = big_params; + + create_params.base = base; + create_params.extended_params = ext_params; + create_params.periodic_params = per_params; + create_params.name = name; + create_params.adv_instance = adv_instance; + create_params.big_params = big_params_ptr; + create_params.svc_data = extra_data; + create_params.svc_data_len = extra_data_len; + + rc = ble_audio_broadcast_create(&create_params, + btshell_broadcast_destroy_fn, + (void *)big_params_ptr, + btshell_gap_event); + return rc; +} + +int +btshell_broadcast_destroy(uint8_t adv_instance) +{ + return ble_audio_broadcast_destroy(adv_instance); +} + +int +btshell_broadcast_update(uint8_t adv_instance, + const char *name, + uint8_t *extra_data, + unsigned int extra_data_len) +{ + struct ble_audio_base *base; + struct ble_broadcast_update_params params; + + base = btshell_base_find(adv_instance); + + params.name = name; + params.adv_instance = adv_instance; + params.svc_data = extra_data; + params.svc_data_len = extra_data_len; + params.broadcast_id = base->broadcast_id; + + return ble_audio_broadcast_update(¶ms); +} + +int +btshell_broadcast_start(uint8_t adv_instance) +{ + return ble_audio_broadcast_start(adv_instance, NULL, NULL); +} + +int +btshell_broadcast_stop(uint8_t adv_instance) +{ + return ble_audio_broadcast_stop(adv_instance); +} +#endif /* BLE_AUDIO && BLE_ISO_BROADCAST_SOURCE */ + /** * main * @@ -2558,14 +3051,10 @@ btshell_init_ext_adv_restart(void) * @return int NOTE: this function should never return! */ int -main(int argc, char **argv) +mynewt_main(int argc, char **argv) { int rc; -#ifdef ARCH_sim - mcu_sim_parse_args(argc, argv); -#endif - /* Initialize OS */ sysinit(); @@ -2602,7 +3091,43 @@ main(int argc, char **argv) "btshell_coc_conn_pool"); assert(rc == 0); #endif +#if MYNEWT_VAL(BLE_AUDIO) && MYNEWT_VAL(BLE_ISO_BROADCAST_SOURCE) + rc = os_mempool_init(&btshell_base_pool, MYNEWT_VAL(BLE_ISO_MAX_BIGS), + sizeof(struct ble_audio_base), + btshell_base_mem, + "btshell_base_pool"); + assert(rc == 0); + rc = os_mempool_init(&btshell_big_params_pool, MYNEWT_VAL(BLE_ISO_MAX_BIGS), + sizeof(struct ble_iso_big_params), + btshell_big_params_mem, + "btshell_big_params_pool"); + assert(rc == 0); + rc = os_mempool_init(&btshell_big_sub_pool, MYNEWT_VAL(BLE_ISO_MAX_BISES), + sizeof(struct ble_audio_big_subgroup), + btshell_big_sub_mem, + "btshell_big_sub_pool"); + assert(rc == 0); + rc = os_mempool_init(&btshell_bis_pool, MYNEWT_VAL(BLE_ISO_MAX_BISES), + sizeof(struct ble_audio_bis), btshell_bis_mem, + "btshell_bis_pool"); + assert(rc == 0); + + rc = os_mempool_init(&btshell_metadata_pool, MYNEWT_VAL(BLE_ISO_MAX_BISES), + MYNEWT_VAL(BLE_EXT_ADV_MAX_SIZE) - 27, + btshell_metadata_mem, "btshell_metadata_pool"); + assert(rc == 0); + rc = os_mempool_init(&btshell_codec_spec_pool, + MYNEWT_VAL(BLE_ISO_MAX_BISES) * 2, 19, + btshell_codec_spec_mem, "btshell_codec_spec_pool"); + assert(rc == 0); + + rc = os_mempool_init(&btshell_big_params_pool, + MYNEWT_VAL(BLE_ISO_MAX_BIGS), + sizeof(struct ble_iso_big_params), + btshell_big_params_mem, "btshell_big_params_pool"); + assert(rc == 0); +#endif /* BLE_AUDIO && BLE_ISO_BROADCAST_SOURCE */ /* Initialize the NimBLE host configuration. */ ble_hs_cfg.reset_cb = btshell_on_reset; ble_hs_cfg.sync_cb = btshell_on_sync; @@ -2626,6 +3151,8 @@ main(int argc, char **argv) btshell_init_ext_adv_restart(); + btshell_leaudio_init(); + while (1) { os_eventq_run(os_eventq_dflt_get()); } diff --git a/apps/btshell/src/parse.c b/apps/btshell/src/parse.c index e4dbade420..d759511adc 100644 --- a/apps/btshell/src/parse.c +++ b/apps/btshell/src/parse.c @@ -19,633 +19,9 @@ #include #include -#include -#include -#include -#include -#include -#include "console/console.h" #include "host/ble_hs.h" -#include "host/ble_uuid.h" #include "host/ble_eddystone.h" #include "cmd.h" -#include "btshell.h" - -#define CMD_MAX_ARGS 16 - -static char *cmd_args[CMD_MAX_ARGS][2]; -static int cmd_num_args; - -int -parse_arg_find_idx(const char *key) -{ - int i; - - for (i = 0; i < cmd_num_args; i++) { - if (strcmp(cmd_args[i][0], key) == 0) { - return i; - } - } - - return -1; -} - -char * -parse_arg_peek(const char *key) -{ - int i; - - for (i = 0; i < cmd_num_args; i++) { - if (strcmp(cmd_args[i][0], key) == 0) { - return cmd_args[i][1]; - } - } - - return NULL; -} - -char * -parse_arg_extract(const char *key) -{ - int i; - - for (i = 0; i < cmd_num_args; i++) { - if (strcmp(cmd_args[i][0], key) == 0) { - /* Erase parameter. */ - cmd_args[i][0][0] = '\0'; - - return cmd_args[i][1]; - } - } - - return NULL; -} - -/** - * Determines which number base to use when parsing the specified numeric - * string. This just avoids base '0' so that numbers don't get interpreted as - * octal. - */ -static int -parse_arg_long_base(char *sval) -{ - if (sval[0] == '0' && sval[1] == 'x') { - return 0; - } else { - return 10; - } -} - -long -parse_long_bounds(char *sval, long min, long max, int *out_status) -{ - char *endptr; - long lval; - - lval = strtol(sval, &endptr, parse_arg_long_base(sval)); - if (sval[0] != '\0' && *endptr == '\0' && - lval >= min && lval <= max) { - - *out_status = 0; - return lval; - } - - *out_status = EINVAL; - return 0; -} - -long -parse_arg_long_bounds_peek(char *name, long min, long max, int *out_status) -{ - char *sval; - - sval = parse_arg_peek(name); - if (sval == NULL) { - *out_status = ENOENT; - return 0; - } - return parse_long_bounds(sval, min, max, out_status); -} - -long -parse_arg_long_bounds(char *name, long min, long max, int *out_status) -{ - char *sval; - - sval = parse_arg_extract(name); - if (sval == NULL) { - *out_status = ENOENT; - return 0; - } - return parse_long_bounds(sval, min, max, out_status); -} - -long -parse_arg_long_bounds_dflt(char *name, long min, long max, - long dflt, int *out_status) -{ - long val; - int rc; - - val = parse_arg_long_bounds(name, min, max, &rc); - if (rc == ENOENT) { - rc = 0; - val = dflt; - } - - *out_status = rc; - - return val; -} - -uint64_t -parse_arg_uint64_bounds(char *name, uint64_t min, uint64_t max, int *out_status) -{ - char *endptr; - char *sval; - uint64_t lval; - - sval = parse_arg_extract(name); - if (sval == NULL) { - *out_status = ENOENT; - return 0; - } - - lval = strtoull(sval, &endptr, parse_arg_long_base(sval)); - if (sval[0] != '\0' && *endptr == '\0' && - lval >= min && lval <= max) { - - *out_status = 0; - return lval; - } - - *out_status = EINVAL; - return 0; -} - -long -parse_arg_long(char *name, int *out_status) -{ - return parse_arg_long_bounds(name, LONG_MIN, LONG_MAX, out_status); -} - -uint8_t -parse_arg_bool(char *name, int *out_status) -{ - return parse_arg_long_bounds(name, 0, 1, out_status); -} - -uint8_t -parse_arg_bool_dflt(char *name, uint8_t dflt, int *out_status) -{ - return parse_arg_long_bounds_dflt(name, 0, 1, dflt, out_status); -} - -uint8_t -parse_arg_uint8(char *name, int *out_status) -{ - return parse_arg_long_bounds(name, 0, UINT8_MAX, out_status); -} - -uint16_t -parse_arg_uint16(char *name, int *out_status) -{ - return parse_arg_long_bounds(name, 0, UINT16_MAX, out_status); -} - -uint16_t -parse_arg_uint16_peek(char *name, int *out_status) -{ - return parse_arg_long_bounds_peek(name, 0, UINT16_MAX, out_status); -} - -uint32_t -parse_arg_uint32(char *name, int *out_status) -{ - return parse_arg_uint64_bounds(name, 0, UINT32_MAX, out_status); -} - -uint64_t -parse_arg_uint64(char *name, int *out_status) -{ - return parse_arg_uint64_bounds(name, 0, UINT64_MAX, out_status); -} - -uint8_t -parse_arg_uint8_dflt(char *name, uint8_t dflt, int *out_status) -{ - uint8_t val; - int rc; - - val = parse_arg_uint8(name, &rc); - if (rc == ENOENT) { - val = dflt; - rc = 0; - } - - *out_status = rc; - return val; -} - -uint16_t -parse_arg_uint16_dflt(char *name, uint16_t dflt, int *out_status) -{ - uint16_t val; - int rc; - - val = parse_arg_uint16(name, &rc); - if (rc == ENOENT) { - val = dflt; - rc = 0; - } - - *out_status = rc; - return val; -} - -uint32_t -parse_arg_uint32_dflt(char *name, uint32_t dflt, int *out_status) -{ - uint32_t val; - int rc; - - val = parse_arg_uint32(name, &rc); - if (rc == ENOENT) { - val = dflt; - rc = 0; - } - - *out_status = rc; - return val; -} - -static uint32_t -parse_time_unit_mult(const char *str) -{ - if (!strcasecmp(str, "us")) { - return 1; - } else if (!strcasecmp(str, "ms")) { - return 1000; - } else if (!strcasecmp(str, "s")) { - return 1000000; - } - - return 0; -} - -static uint32_t -parse_time_us(const char *str, int *out_status) -{ - uint32_t val = 0; - uint32_t val_div = 1; - uint32_t val_mult = 1; - uint32_t val_us; - - while (isdigit((unsigned char)*str)) { - val *= 10; - val += *str - '0'; - str++; - } - - if (*str == '.') { - str++; - while (isdigit((unsigned char)*str)) { - val *= 10; - val += *str - '0'; - val_div *= 10; - str++; - } - } - - val_mult = parse_time_unit_mult(str); - if (val_mult == 0) { - *out_status = EINVAL; - return 0; - } - - if (val_mult > val_div) { - val_us = val * (val_mult / val_div); - } else { - val_us = val * (val_div / val_mult); - } - - *out_status = 0; - - return val_us; -} - -uint32_t -parse_arg_time_dflt(char *name, int step_us, uint32_t dflt, int *out_status) -{ - const char *arg; - uint32_t val; - int rc; - - arg = parse_arg_peek(name); - if (!arg) { - *out_status = 0; - return dflt; - } - - val = parse_time_us(arg, &rc); - if (rc) { - val = parse_arg_uint32(name, &rc); - if (rc == ENOENT) { - *out_status = 0; - return dflt; - } - } else { - val /= step_us; - parse_arg_extract(name); - } - - *out_status = rc; - return val; -} - -const struct kv_pair * -parse_kv_find(const struct kv_pair *kvs, char *name) -{ - const struct kv_pair *kv; - int i; - - for (i = 0; kvs[i].key != NULL; i++) { - kv = kvs + i; - if (strcmp(name, kv->key) == 0) { - return kv; - } - } - - return NULL; -} - -int -parse_arg_kv(char *name, const struct kv_pair *kvs, int *out_status) -{ - const struct kv_pair *kv; - char *sval; - - sval = parse_arg_extract(name); - if (sval == NULL) { - *out_status = ENOENT; - return -1; - } - - kv = parse_kv_find(kvs, sval); - if (kv == NULL) { - *out_status = EINVAL; - return -1; - } - - *out_status = 0; - return kv->val; -} - -int -parse_arg_kv_dflt(char *name, const struct kv_pair *kvs, int def_val, - int *out_status) -{ - int val; - int rc; - - val = parse_arg_kv(name, kvs, &rc); - if (rc == ENOENT) { - rc = 0; - val = def_val; - } - - *out_status = rc; - - return val; -} - - -static int -parse_arg_byte_stream_delim(char *sval, char *delims, int max_len, - uint8_t *dst, int *out_len) -{ - unsigned long ul; - char *endptr; - char *token; - int i; - char *tok_ptr; - - i = 0; - for (token = strtok_r(sval, delims, &tok_ptr); - token != NULL; - token = strtok_r(NULL, delims, &tok_ptr)) { - - if (i >= max_len) { - return EINVAL; - } - - ul = strtoul(token, &endptr, 16); - if (sval[0] == '\0' || *endptr != '\0' || ul > UINT8_MAX) { - return -1; - } - - dst[i] = ul; - i++; - } - - *out_len = i; - - return 0; -} - -int -parse_arg_byte_stream(char *name, int max_len, uint8_t *dst, int *out_len) -{ - char *sval; - - sval = parse_arg_extract(name); - if (sval == NULL) { - return ENOENT; - } - - return parse_arg_byte_stream_delim(sval, ":-", max_len, dst, out_len); -} - -int -parse_arg_uint8_list_with_separator(char *name, char *separator, int max_len, - uint8_t *dst, int *out_len) -{ - char *sval; - - sval = parse_arg_extract(name); - if (sval == NULL) { - return ENOENT; - } - - return parse_arg_byte_stream_delim(sval, separator, max_len, dst, out_len); -} - -int -parse_arg_byte_stream_exact_length(char *name, uint8_t *dst, int len) -{ - int actual_len; - int rc; - - rc = parse_arg_byte_stream(name, len, dst, &actual_len); - if (rc != 0) { - return rc; - } - - if (actual_len != len) { - return EINVAL; - } - - return 0; -} - -static void -parse_reverse_bytes(uint8_t *bytes, int len) -{ - uint8_t tmp; - int i; - - for (i = 0; i < len / 2; i++) { - tmp = bytes[i]; - bytes[i] = bytes[len - i - 1]; - bytes[len - i - 1] = tmp; - } -} - -int -parse_arg_mac(char *name, uint8_t *dst) -{ - int rc; - - rc = parse_arg_byte_stream_exact_length(name, dst, 6); - if (rc != 0) { - return rc; - } - - parse_reverse_bytes(dst, 6); - - return 0; -} - -int -parse_arg_addr(char *name, ble_addr_t *addr) -{ - char *arg; - size_t len; - uint8_t addr_type; - bool addr_type_found; - int rc; - - arg = parse_arg_peek(name); - if (!arg) { - return ENOENT; - } - - len = strlen(arg); - if (len < 2) { - return EINVAL; - } - - addr_type_found = false; - if ((arg[len - 2] == ':') || (arg[len - 2] == '-')) { - if (tolower(arg[len - 1]) == 'p') { - addr_type = BLE_ADDR_PUBLIC; - addr_type_found = true; - } else if (tolower(arg[len - 1]) == 'r') { - addr_type = BLE_ADDR_RANDOM; - addr_type_found = true; - } - - if (addr_type_found) { - arg[len - 2] = '\0'; - } -} - - rc = parse_arg_mac(name, addr->val); - if (rc != 0) { - return rc; - } - - if (addr_type_found) { - addr->type = addr_type; - } else { - rc = EAGAIN; - } - - return rc; -} - -int -parse_arg_uuid(char *str, ble_uuid_any_t *uuid) -{ - uint16_t uuid16; - uint8_t val[16]; - int len; - int rc; - - uuid16 = parse_arg_uint16_peek(str, &rc); - switch (rc) { - case ENOENT: - parse_arg_extract(str); - return ENOENT; - - case 0: - len = 2; - val[0] = uuid16; - val[1] = uuid16 >> 8; - parse_arg_extract(str); - break; - - default: - len = 16; - rc = parse_arg_byte_stream_exact_length(str, val, 16); - if (rc != 0) { - return EINVAL; - } - parse_reverse_bytes(val, 16); - break; - } - - rc = ble_uuid_init_from_buf(uuid, val, len); - if (rc != 0) { - return EINVAL; - } else { - return 0; - } -} - -int -parse_arg_all(int argc, char **argv) -{ - char *key; - char *val; - int i; - char *tok_ptr; - - cmd_num_args = 0; - - for (i = 0; i < argc; i++) { - key = strtok_r(argv[i], "=", &tok_ptr); - val = strtok_r(NULL, "=", &tok_ptr); - - if (key != NULL && val != NULL) { - if (strlen(key) == 0) { - console_printf("Error: invalid argument: %s\n", argv[i]); - return -1; - } - - if (cmd_num_args >= CMD_MAX_ARGS) { - console_printf("Error: too many arguments"); - return -1; - } - - cmd_args[cmd_num_args][0] = key; - cmd_args[cmd_num_args][1] = val; - cmd_num_args++; - } - } - - return 0; -} int parse_eddystone_url(char *full_url, uint8_t *out_scheme, char *out_body, diff --git a/apps/btshell/syscfg.yml b/apps/btshell/syscfg.yml index 1535b336d9..3bdfb34ac6 100644 --- a/apps/btshell/syscfg.yml +++ b/apps/btshell/syscfg.yml @@ -22,6 +22,10 @@ syscfg.defs: value: 1 syscfg.vals: + CONSOLE_IMPLEMENTATION: full + LOG_IMPLEMENTATION: full + STATS_IMPLEMENTATION: full + # Enable the shell task. SHELL_TASK: 1 @@ -41,5 +45,11 @@ syscfg.vals: # Whether to save data to sys/config, or just keep it in RAM. BLE_STORE_CONFIG_PERSIST: 0 + # L2CAP COC SDU buffers in RX endpoint + BLE_L2CAP_COC_SDU_BUFF_COUNT: 1 + syscfg.vals.BLE_MESH: MSYS_1_BLOCK_COUNT: 16 + +syscfg.vals.BLE_AUDIO_BROADCAST_SINK: + BLE_AUDIO_BROADCAST_SINK_MAX: 1 diff --git a/apps/bttester/pkg.yml b/apps/bttester/pkg.yml index ba2b7fb1be..ae05f1c9de 100644 --- a/apps/bttester/pkg.yml +++ b/apps/bttester/pkg.yml @@ -26,19 +26,22 @@ pkg.keywords: pkg.deps: - "@apache-mynewt-core/kernel/os" - - "@apache-mynewt-core/sys/console/full" - - "@apache-mynewt-core/sys/log/full" + - "@apache-mynewt-core/sys/console" + - "@apache-mynewt-core/sys/log" - "@apache-mynewt-core/sys/log/modlog" - - "@apache-mynewt-core/sys/stats/full" + - "@apache-mynewt-core/sys/stats" - "@apache-mynewt-core/sys/shell" - - "@apache-mynewt-nimble/nimble/controller" - "@apache-mynewt-nimble/nimble/host" - "@apache-mynewt-nimble/nimble/host/util" - "@apache-mynewt-nimble/nimble/host/services/gap" - "@apache-mynewt-nimble/nimble/host/services/gatt" - "@apache-mynewt-nimble/nimble/host/services/dis" - "@apache-mynewt-nimble/nimble/host/store/config" - - "@apache-mynewt-nimble/nimble/transport/ram" - "@apache-mynewt-core/hw/drivers/uart" - "@apache-mynewt-core/hw/drivers/rtt" +pkg.deps.BLE_AUDIO: + - "@apache-mynewt-nimble/nimble/host/audio" + - "@apache-mynewt-nimble/nimble/host/audio/services/bass" + - "@apache-mynewt-nimble/nimble/host/audio/services/pacs" + - "@apache-mynewt-nimble/nimble/host/audio/services/pacs/lc3" diff --git a/apps/bttester/src/atomic.h b/apps/bttester/src/atomic.h deleted file mode 100644 index 66283e9ac3..0000000000 --- a/apps/bttester/src/atomic.h +++ /dev/null @@ -1,405 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -/* atomic operations */ - -/* - * Copyright (c) 1997-2015, Wind River Systems, Inc. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef __ATOMIC_H__ -#define __ATOMIC_H__ - -#ifdef __cplusplus -extern "C" -{ -#endif - -typedef int atomic_t; -typedef atomic_t atomic_val_t; - -/** - * @defgroup atomic_apis Atomic Services APIs - * @ingroup kernel_apis - * @{ - */ - -/** - * @brief Atomic compare-and-set. - * - * This routine performs an atomic compare-and-set on @a target. If the current - * value of @a target equals @a old_value, @a target is set to @a new_value. - * If the current value of @a target does not equal @a old_value, @a target - * is left unchanged. - * - * @param target Address of atomic variable. - * @param old_value Original value to compare against. - * @param new_value New value to store. - * @return 1 if @a new_value is written, 0 otherwise. - */ -static inline int atomic_cas(atomic_t *target, atomic_val_t old_value, - atomic_val_t new_value) -{ - return __atomic_compare_exchange_n(target, &old_value, new_value, - 0, __ATOMIC_SEQ_CST, - __ATOMIC_SEQ_CST); -} - -/** - * - * @brief Atomic addition. - * - * This routine performs an atomic addition on @a target. - * - * @param target Address of atomic variable. - * @param value Value to add. - * - * @return Previous value of @a target. - */ -static inline atomic_val_t atomic_add(atomic_t *target, atomic_val_t value) -{ - return __atomic_fetch_add(target, value, __ATOMIC_SEQ_CST); -} - -/** - * - * @brief Atomic subtraction. - * - * This routine performs an atomic subtraction on @a target. - * - * @param target Address of atomic variable. - * @param value Value to subtract. - * - * @return Previous value of @a target. - */ - -static inline atomic_val_t atomic_sub(atomic_t *target, atomic_val_t value) -{ - return __atomic_fetch_sub(target, value, __ATOMIC_SEQ_CST); -} - -/** - * - * @brief Atomic increment. - * - * This routine performs an atomic increment by 1 on @a target. - * - * @param target Address of atomic variable. - * - * @return Previous value of @a target. - */ - -static inline atomic_val_t atomic_inc(atomic_t *target) -{ - return atomic_add(target, 1); -} - -/** - * - * @brief Atomic decrement. - * - * This routine performs an atomic decrement by 1 on @a target. - * - * @param target Address of atomic variable. - * - * @return Previous value of @a target. - */ - -static inline atomic_val_t atomic_dec(atomic_t *target) -{ - return atomic_sub(target, 1); -} - -/** - * - * @brief Atomic get. - * - * This routine performs an atomic read on @a target. - * - * @param target Address of atomic variable. - * - * @return Value of @a target. - */ - -static inline atomic_val_t atomic_get(const atomic_t *target) -{ - return __atomic_load_n(target, __ATOMIC_SEQ_CST); -} - -/** - * - * @brief Atomic get-and-set. - * - * This routine atomically sets @a target to @a value and returns - * the previous value of @a target. - * - * @param target Address of atomic variable. - * @param value Value to write to @a target. - * - * @return Previous value of @a target. - */ - -static inline atomic_val_t atomic_set(atomic_t *target, atomic_val_t value) -{ - /* This builtin, as described by Intel, is not a traditional - * test-and-set operation, but rather an atomic exchange operation. It - * writes value into *ptr, and returns the previous contents of *ptr. - */ - return __atomic_exchange_n(target, value, __ATOMIC_SEQ_CST); -} - -/** - * - * @brief Atomic clear. - * - * This routine atomically sets @a target to zero and returns its previous - * value. (Hence, it is equivalent to atomic_set(target, 0).) - * - * @param target Address of atomic variable. - * - * @return Previous value of @a target. - */ - -static inline atomic_val_t atomic_clear(atomic_t *target) -{ - return atomic_set(target, 0); -} - -/** - * - * @brief Atomic bitwise inclusive OR. - * - * This routine atomically sets @a target to the bitwise inclusive OR of - * @a target and @a value. - * - * @param target Address of atomic variable. - * @param value Value to OR. - * - * @return Previous value of @a target. - */ - -static inline atomic_val_t atomic_or(atomic_t *target, atomic_val_t value) -{ - return __atomic_fetch_or(target, value, __ATOMIC_SEQ_CST); -} - -/** - * - * @brief Atomic bitwise exclusive OR (XOR). - * - * This routine atomically sets @a target to the bitwise exclusive OR (XOR) of - * @a target and @a value. - * - * @param target Address of atomic variable. - * @param value Value to XOR - * - * @return Previous value of @a target. - */ - -static inline atomic_val_t atomic_xor(atomic_t *target, atomic_val_t value) -{ - return __atomic_fetch_xor(target, value, __ATOMIC_SEQ_CST); -} - -/** - * - * @brief Atomic bitwise AND. - * - * This routine atomically sets @a target to the bitwise AND of @a target - * and @a value. - * - * @param target Address of atomic variable. - * @param value Value to AND. - * - * @return Previous value of @a target. - */ - -static inline atomic_val_t atomic_and(atomic_t *target, atomic_val_t value) -{ - return __atomic_fetch_and(target, value, __ATOMIC_SEQ_CST); -} - -/** - * - * @brief Atomic bitwise NAND. - * - * This routine atomically sets @a target to the bitwise NAND of @a target - * and @a value. (This operation is equivalent to target = ~(target & value).) - * - * @param target Address of atomic variable. - * @param value Value to NAND. - * - * @return Previous value of @a target. - */ - -static inline atomic_val_t atomic_nand(atomic_t *target, atomic_val_t value) -{ - return __atomic_fetch_nand(target, value, __ATOMIC_SEQ_CST); -} - - /** - * @brief Initialize an atomic variable. - * - * This macro can be used to initialize an atomic variable. For example, - * @code atomic_t my_var = ATOMIC_INIT(75); @endcode - * - * @param i Value to assign to atomic variable. - */ -#define ATOMIC_INIT(i) (i) - - /** - * @cond INTERNAL_HIDDEN - */ - -#define ATOMIC_BITS (sizeof(atomic_val_t) * 8) -#define ATOMIC_MASK(bit) (1 << ((bit) & (ATOMIC_BITS - 1))) -#define ATOMIC_ELEM(addr, bit) ((addr) + ((bit) / ATOMIC_BITS)) - - /** - * INTERNAL_HIDDEN @endcond - */ - - /** - * @brief Define an array of atomic variables. - * - * This macro defines an array of atomic variables containing at least - * @a num_bits bits. - * - * @note - * If used from file scope, the bits of the array are initialized to zero; - * if used from within a function, the bits are left uninitialized. - * - * @param name Name of array of atomic variables. - * @param num_bits Number of bits needed. - */ -#define ATOMIC_DEFINE(name, num_bits) \ - atomic_t name[1 + ((num_bits) - 1) / ATOMIC_BITS] - - /** - * @brief Atomically test a bit. - * - * This routine tests whether bit number @a bit of @a target is set or not. - * The target may be a single atomic variable or an array of them. - * - * @param target Address of atomic variable or array. - * @param bit Bit number (starting from 0). - * - * @return 1 if the bit was set, 0 if it wasn't. - */ - static inline int - atomic_test_bit(const atomic_t *target, int bit) - { - atomic_val_t val = atomic_get(ATOMIC_ELEM(target, bit)); - - return (1 & (val >> (bit & (ATOMIC_BITS - 1)))); - } - - /** - * @brief Atomically test and clear a bit. - * - * Atomically clear bit number @a bit of @a target and return its old value. - * The target may be a single atomic variable or an array of them. - * - * @param target Address of atomic variable or array. - * @param bit Bit number (starting from 0). - * - * @return 1 if the bit was set, 0 if it wasn't. - */ - static inline int - atomic_test_and_clear_bit(atomic_t *target, int bit) - { - atomic_val_t mask = ATOMIC_MASK(bit); - atomic_val_t old; - - old = atomic_and(ATOMIC_ELEM(target, bit), ~mask); - - return (old & mask) != 0; - } - - /** - * @brief Atomically set a bit. - * - * Atomically set bit number @a bit of @a target and return its old value. - * The target may be a single atomic variable or an array of them. - * - * @param target Address of atomic variable or array. - * @param bit Bit number (starting from 0). - * - * @return 1 if the bit was set, 0 if it wasn't. - */ - static inline int - atomic_test_and_set_bit(atomic_t *target, int bit) - { - atomic_val_t mask = ATOMIC_MASK(bit); - atomic_val_t old; - - old = atomic_or(ATOMIC_ELEM(target, bit), mask); - - return (old & mask) != 0; - } - - /** - * @brief Atomically clear a bit. - * - * Atomically clear bit number @a bit of @a target. - * The target may be a single atomic variable or an array of them. - * - * @param target Address of atomic variable or array. - * @param bit Bit number (starting from 0). - * - * @return N/A - */ - static inline void - atomic_clear_bit(atomic_t *target, int bit) - { - atomic_val_t mask = ATOMIC_MASK(bit); - - atomic_and(ATOMIC_ELEM(target, bit), ~mask); - } - - /** - * @brief Atomically set a bit. - * - * Atomically set bit number @a bit of @a target. - * The target may be a single atomic variable or an array of them. - * - * @param target Address of atomic variable or array. - * @param bit Bit number (starting from 0). - * - * @return N/A - */ - static inline void - atomic_set_bit(atomic_t *target, int bit) - { - atomic_val_t mask = ATOMIC_MASK(bit); - - atomic_or(ATOMIC_ELEM(target, bit), mask); - } - -/** - * @} - */ - -#ifdef __cplusplus -} -#endif - -#endif /* __ATOMIC_H__ */ diff --git a/apps/bttester/src/btp/btp.h b/apps/bttester/src/btp/btp.h new file mode 100644 index 0000000000..17fe388767 --- /dev/null +++ b/apps/bttester/src/btp/btp.h @@ -0,0 +1,90 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* btp.h - Bluetooth tester btp headers */ + +/* + * Copyright (c) 2015-2016 Intel Corporation + * Copyright (C) 2023 Codecoup + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "bttester.h" +#include "btp_core.h" +#include "btp_gap.h" +#include "btp_gatt.h" +#include "btp_gattc.h" +#include "btp_l2cap.h" +#include "btp_mesh.h" +#include "btp_pacs.h" +#include "btp_bap.h" + +#define BTP_MTU MYNEWT_VAL(BTTESTER_BTP_DATA_SIZE_MAX) +#define BTP_DATA_MAX_SIZE (BTP_MTU - sizeof(struct btp_hdr)) + +#define BTP_INDEX_NONE 0xff +#define BTP_INDEX 0x00 + +#define BTP_SERVICE_ID_CORE 0 +#define BTP_SERVICE_ID_GAP 1 +#define BTP_SERVICE_ID_GATT 2 +#define BTP_SERVICE_ID_L2CAP 3 +#define BTP_SERVICE_ID_MESH 4 +#define BTP_SERVICE_ID_GATTC 6 +#define BTP_SERVICE_ID_PACS 12 +#define BTP_SERVICE_ID_BAP 14 + +#define BTP_SERVICE_ID_MAX BTP_SERVICE_ID_BAP + +#define BTP_STATUS_SUCCESS 0x00 +#define BTP_STATUS_FAILED 0x01 +#define BTP_STATUS_UNKNOWN_CMD 0x02 +#define BTP_STATUS_NOT_READY 0x03 + +/* TODO indicate delay response, should be removed when all commands are + * converted to cmd+status+ev pattern + */ +#define BTP_STATUS_DELAY_REPLY 0xFF + +#define SYS_LOG_DBG(fmt, ...) \ + if (MYNEWT_VAL(BTTESTER_DEBUG)) { \ + console_printf("[DBG] %s: " fmt "\n", \ + __func__, ## __VA_ARGS__); \ + } +#define SYS_LOG_INF(fmt, ...) console_printf("[INF] %s: " fmt "\n", \ + __func__, ## __VA_ARGS__); +#define SYS_LOG_ERR(fmt, ...) console_printf("[WRN] %s: " fmt "\n", \ + __func__, ## __VA_ARGS__); + +#define SYS_LOG_LEVEL SYS_LOG_LEVEL_DEBUG +#define SYS_LOG_DOMAIN "bttester" + +struct btp_hdr { + uint8_t service; + uint8_t opcode; + uint8_t index; + uint16_t len; + uint8_t data[0]; +} __packed; + +#define BTP_STATUS 0x00 +struct btp_status { + uint8_t code; +} __packed; diff --git a/apps/bttester/src/btp/btp_bap.h b/apps/bttester/src/btp/btp_bap.h new file mode 100644 index 0000000000..ea117ac4a5 --- /dev/null +++ b/apps/bttester/src/btp/btp_bap.h @@ -0,0 +1,301 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_BTP_BAP_ +#define H_BTP_BAP_ + +#include "nimble/ble.h" +#include + +#ifndef __packed +#define __packed __attribute__((__packed__)) +#endif + +/* BAP Service */ +/* commands */ +#define BTP_BAP_READ_SUPPORTED_COMMANDS 0x01 +struct btp_bap_read_supported_commands_rp { + uint8_t data[0]; +} __packed; + +#define BTP_BAP_DISCOVER 0x02 +#define BTP_BAP_SEND 0x03 +#define BTP_BAP_BROADCAST_SOURCE_SETUP 0x04 +struct bap_broadcast_source_setup_cmd { + uint8_t streams_per_subgroup; + uint8_t subgroups; + uint8_t sdu_interval[3]; + uint8_t framing; + uint16_t max_sdu; + uint8_t rtn; + uint16_t max_transport_lat; + uint8_t presentation_delay[3]; + uint8_t coding_fmt; + uint16_t vid; + uint16_t cid; + uint8_t cc_ltvs_len; + uint8_t cc_ltvs[]; +} __packed; + +struct bap_broadcast_source_setup_rp { + uint32_t gap_settings; + uint8_t broadcast_id[3]; +} __packed; + +#define BTP_BAP_BROADCAST_SOURCE_RELEASE 0x05 +struct bap_bap_broadcast_source_release_cmd { + uint8_t broadcast_id[3]; +} __packed; + +#define BTP_BAP_BROADCAST_ADV_START 0x06 +struct bap_bap_broadcast_adv_start_cmd { + uint8_t broadcast_id[3]; +} __packed; + +#define BTP_BAP_BROADCAST_ADV_STOP 0x07 +struct bap_bap_broadcast_adv_stop_cmd { + uint8_t broadcast_id[3]; +} __packed; + +#define BTP_BAP_BROADCAST_SOURCE_START 0x08 +struct bap_bap_broadcast_source_start_cmd { + uint8_t broadcast_id[3]; +} __packed; + +#define BTP_BAP_BROADCAST_SOURCE_STOP 0x09 +struct bap_bap_broadcast_source_stop_cmd { + uint8_t broadcast_id[3]; +} __packed; + +#define BTP_BAP_BROADCAST_SINK_SETUP 0x0a +struct btp_bap_broadcast_sink_setup_cmd { +} __packed; + +#define BTP_BAP_BROADCAST_SINK_RELEASE 0x0b +struct btp_bap_broadcast_sink_release_cmd { +} __packed; + +#define BTP_BAP_BROADCAST_SCAN_START 0x0c +struct btp_bap_broadcast_scan_start_cmd { +} __packed; + +#define BTP_BAP_BROADCAST_SCAN_STOP 0x0d +struct btp_bap_broadcast_scan_stop_cmd { +} __packed; + +#define BTP_BAP_BROADCAST_SINK_SYNC 0x0e +struct btp_bap_broadcast_sink_sync_cmd { + ble_addr_t addr; + uint8_t broadcast_id[3]; + uint8_t advertiser_sid; + uint16_t skip; + uint16_t sync_timeout; + uint8_t past_avail; + uint8_t src_id; +} __packed; + +#define BTP_BAP_BROADCAST_SINK_STOP 0x0f +struct btp_bap_broadcast_sink_stop_cmd { + ble_addr_t address; + uint8_t broadcast_id[3]; +} __packed; + +#define BTP_BAP_BROADCAST_SINK_BIS_SYNC 0x10 +struct btp_bap_broadcast_sink_bis_sync_cmd { + ble_addr_t address; + uint8_t broadcast_id[3]; + uint32_t requested_bis_sync; +} __packed; + +#define BTP_BAP_DISCOVER_SCAN_DELEGATOR 0x11 +struct btp_bap_discover_scan_delegator_cmd { + ble_addr_t address; +} __packed; + +#define BTP_BAP_BROADCAST_ASSISTANT_SCAN_START 0x12 +struct btp_bap_broadcast_assistant_scan_start_cmd { + ble_addr_t address; +} __packed; + +#define BTP_BAP_BROADCAST_ASSISTANT_SCAN_STOP 0x13 +struct btp_bap_broadcast_assistant_scan_stop_cmd { + ble_addr_t address; +} __packed; + +#define BTP_BAP_ADD_BROADCAST_SRC 0x14 +struct btp_bap_add_broadcast_src_cmd { + ble_addr_t address; + ble_addr_t broadcaster_address; + uint8_t advertiser_sid; + uint8_t broadcast_id[3]; + uint8_t padv_sync; + uint16_t padv_interval; + uint8_t num_subgroups; + uint8_t subgroups[0]; +} __packed; + +#define BTP_BAP_REMOVE_BROADCAST_SRC 0x15 +struct btp_bap_remove_broadcast_src_cmd { + ble_addr_t address; + uint8_t source_id; +} __packed; + +#define BTP_BAP_MODIFY_BROADCAST_SRC 0x16 +struct btp_bap_modify_broadcast_src_cmd { + ble_addr_t address; + uint8_t source_id; + uint8_t padv_sync; + uint16_t padv_interval; + uint8_t num_subgroups; + uint8_t subgroups[0]; +} __packed; + +#define BTP_BAP_SET_BROADCAST_CODE 0x17 +struct btp_bap_set_broadcast_code_cmd { + ble_addr_t addr; + uint8_t source_id; + uint8_t broadcast_code[16]; +} __packed; + +#define BTP_BAP_SEND_PAST 0x18 +struct btp_bap_send_past_cmd { + ble_addr_t address; + uint8_t src_id; +} __packed; + +#define BTP_BAP_BROADCAST_SOURCE_SETUP_V2 0x19 +struct btp_bap_broadcast_source_setup_v2_cmd { + uint8_t broadcast_id[3]; + uint8_t streams_per_subgroup; + uint8_t subgroups; + uint8_t sdu_interval[3]; + uint8_t framing; + uint16_t max_sdu; + uint8_t retransmission_num; + uint16_t max_transport_latency; + uint8_t presentation_delay[3]; + uint8_t coding_format; + uint16_t vid; + uint16_t cid; + uint8_t cc_ltvs_len; + uint8_t cc_ltvs[]; +} __packed; +struct btp_bap_broadcast_source_setup_v2_rp { + uint32_t gap_settings; +} __packed; + +#define BTP_BAP_EV_DISCOVERY_COMPLETED 0x80 +struct btp_bap_discovery_completed_ev { + ble_addr_t address; + uint8_t status; +} __packed; + +#define BTP_BAP_EV_CODEC_CAP_FOUND 0x81 +struct btp_bap_codec_cap_found_ev { + ble_addr_t address; + uint8_t dir; + uint8_t coding_format; + uint16_t frequencies; + uint8_t frame_durations; + uint32_t octets_per_frame; + uint8_t channel_counts; +} __packed; + +#define BTP_BAP_EV_ASE_FOUND 0x82 +struct btp_bap_ase_found_ev { + ble_addr_t address; + uint8_t dir; + uint8_t ase_id; +} __packed; + +#define BTP_BAP_EV_STREAM_RECEIVED 0x83 +struct btp_bap_stream_received_ev { + ble_addr_t address; + uint8_t ase_id; + uint8_t data_len; + uint8_t data[]; +} __packed; + +#define BTP_BAP_EV_BAA_FOUND 0x84 +struct btp_bap_baa_found_ev { + ble_addr_t address; + uint8_t broadcast_id[3]; + uint8_t advertiser_sid; + uint16_t padv_interval; +} __packed; + +#define BTP_BAP_EV_BIS_FOUND 0x85 +struct btp_bap_bis_found_ev { + ble_addr_t address; + uint8_t broadcast_id[3]; + uint8_t presentation_delay[3]; + uint8_t subgroup_id; + uint8_t bis_id; + uint8_t coding_format; + uint16_t vid; + uint16_t cid; + uint8_t cc_ltvs_len; + uint8_t cc_ltvs[]; +} __packed; + +#define BTP_BAP_EV_BIS_SYNCED 0x86 +struct btp_bap_bis_synced_ev { + ble_addr_t address; + uint8_t broadcast_id[3]; + uint8_t bis_id; +} __packed; + +#define BTP_BAP_EV_BIS_STREAM_RECEIVED 0x87 +struct btp_bap_bis_stream_received_ev { + ble_addr_t address; + uint8_t broadcast_id[3]; + uint8_t bis_id; + uint8_t data_len; + uint8_t data[]; +} __packed; + +#define BTP_BAP_EV_SCAN_DELEGATOR_FOUND 0x88 +struct btp_bap_scan_delegator_found_ev { + ble_addr_t address; +} __packed; + +#define BTP_BAP_EV_BROADCAST_RECEIVE_STATE 0x89 +struct btp_bap_broadcast_receive_state_ev { + ble_addr_t address; + uint8_t source_id; + ble_addr_t broadcaster_address; + uint8_t advertiser_sid; + uint8_t broadcast_id[3]; + uint8_t pa_sync_state; + uint8_t big_encryption; + uint8_t num_subgroups; + uint8_t subgroups[0]; +} __packed; + +#define BTP_BAP_EV_PA_SYNC_REQ 0x8a +struct btp_bap_pa_sync_req_ev { + ble_addr_t address; + uint8_t source_id; + uint8_t advertiser_sid; + uint8_t broadcast_id[3]; + uint8_t past_avail; + uint16_t pa_interval; +} __packed; + +#endif /* H_BTP_BAP_ */ diff --git a/apps/bttester/src/btp/btp_core.h b/apps/bttester/src/btp/btp_core.h new file mode 100644 index 0000000000..cbf309ce88 --- /dev/null +++ b/apps/bttester/src/btp/btp_core.h @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* btp_core.h - Bluetooth tester Core service headers */ + +/* + * Copyright (c) 2015-2016 Intel Corporation + * Copyright (C) 2023 Codecoup + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* Core Service */ +#define BTP_CORE_READ_SUPPORTED_COMMANDS 0x01 +struct btp_core_read_supported_commands_rp { + uint8_t data[0]; +} __packed; + +#define BTP_CORE_READ_SUPPORTED_SERVICES 0x02 +struct btp_core_read_supported_services_rp { + uint8_t data[0]; +} __packed; + +#define BTP_CORE_REGISTER_SERVICE 0x03 +struct btp_core_register_service_cmd { + uint8_t id; +} __packed; + +#define BTP_CORE_UNREGISTER_SERVICE 0x04 +struct btp_core_unregister_service_cmd { + uint8_t id; +} __packed; + +/* events */ +#define BTP_CORE_EV_IUT_READY 0x80 \ No newline at end of file diff --git a/apps/bttester/src/btp/btp_gap.h b/apps/bttester/src/btp/btp_gap.h new file mode 100644 index 0000000000..c95a0d219f --- /dev/null +++ b/apps/bttester/src/btp/btp_gap.h @@ -0,0 +1,468 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* btp_gap.h - Bluetooth tester GAP service headers */ + +/* + * Copyright (c) 2015-2016 Intel Corporation + * Copyright (C) 2023 Codecoup + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "nimble/ble.h" + +struct adv_data { + uint8_t type; + uint8_t data_len; + const uint8_t *data; +}; + +#define ADV_DATA(_type, _data, _data_len) \ + { \ + .type = (_type), \ + .data_len = (_data_len), \ + .data = (const uint8_t *)(_data), \ + } + +/* GAP Service */ +/* commands */ +#define BTP_GAP_READ_SUPPORTED_COMMANDS 0x01 +struct btp_gap_read_supported_commands_rp { + uint8_t data[0]; +} __packed; + +#define BTP_GAP_READ_CONTROLLER_INDEX_LIST 0x02 +struct btp_gap_read_controller_index_list_rp { + uint8_t num; + uint8_t index[0]; +} __packed; + +#define BTP_GAP_SETTINGS_POWERED 0 +#define BTP_GAP_SETTINGS_CONNECTABLE 1 +#define BTP_GAP_SETTINGS_FAST_CONNECTABLE 2 +#define BTP_GAP_SETTINGS_DISCOVERABLE 3 +#define BTP_GAP_SETTINGS_BONDABLE 4 +#define BTP_GAP_SETTINGS_LINK_SEC_3 5 +#define BTP_GAP_SETTINGS_SSP 6 +#define BTP_GAP_SETTINGS_BREDR 7 +#define BTP_GAP_SETTINGS_HS 8 +#define BTP_GAP_SETTINGS_LE 9 +#define BTP_GAP_SETTINGS_ADVERTISING 10 +#define BTP_GAP_SETTINGS_SC 11 +#define BTP_GAP_SETTINGS_DEBUG_KEYS 12 +#define BTP_GAP_SETTINGS_PRIVACY 13 +#define BTP_GAP_SETTINGS_CONTROLLER_CONFIG 14 +#define BTP_GAP_SETTINGS_STATIC_ADDRESS 15 +#define BTP_GAP_SETTINGS_EXTENDED_ADVERTISING 17 +#define BTP_GAP_SETTINGS_PERIODIC_ADVERTISING 18 + +#define BTP_GAP_READ_CONTROLLER_INFO 0x03 +struct btp_gap_read_controller_info_rp { + uint8_t address[6]; + uint32_t supported_settings; + uint32_t current_settings; + uint8_t cod[3]; + uint8_t name[249]; + uint8_t short_name[11]; +} __packed; + +#define BTP_GAP_RESET 0x04 +struct btp_gap_reset_rp { + uint32_t current_settings; +} __packed; + +#define BTP_GAP_SET_POWERED 0x05 +struct btp_gap_set_powered_cmd { + uint8_t powered; +} __packed; +struct btp_gap_set_powered_rp { + uint32_t current_settings; +} __packed; + +#define BTP_GAP_SET_CONNECTABLE 0x06 +struct btp_gap_set_connectable_cmd { + uint8_t connectable; +} __packed; +struct btp_gap_set_connectable_rp { + uint32_t current_settings; +} __packed; + +#define BTP_GAP_SET_FAST_CONNECTABLE 0x07 +struct btp_gap_set_fast_connectable_cmd { + uint8_t fast_connectable; +} __packed; +struct btp_gap_set_fast_connectable_rp { + uint32_t current_settings; +} __packed; + +#define BTP_GAP_NON_DISCOVERABLE 0x00 +#define BTP_GAP_GENERAL_DISCOVERABLE 0x01 +#define BTP_GAP_LIMITED_DISCOVERABLE 0x02 + +#define BTP_GAP_SET_DISCOVERABLE 0x08 +struct btp_gap_set_discoverable_cmd { + uint8_t discoverable; +} __packed; +struct btp_gap_set_discoverable_rp { + uint32_t current_settings; +} __packed; + +#define BTP_GAP_SET_BONDABLE 0x09 +struct btp_gap_set_bondable_cmd { + uint8_t bondable; +} __packed; +struct btp_gap_set_bondable_rp { + uint32_t current_settings; +} __packed; + +#define BTP_GAP_START_ADVERTISING 0x0a +struct btp_gap_start_advertising_cmd { + uint8_t adv_data_len; + uint8_t scan_rsp_len; + uint8_t adv_sr_data[]; +/* + * This command is very unfortunate because it has two fields after variable + * data. Those needs to be handled explicitly by handler. + * uint32_t duration; + * uint8_t own_addr_type; + */ +} __packed; +struct btp_gap_start_advertising_rp { + uint32_t current_settings; +} __packed; + +#define BTP_GAP_STOP_ADVERTISING 0x0b +struct btp_gap_stop_advertising_rp { + uint32_t current_settings; +} __packed; + +#define BTP_GAP_DISCOVERY_FLAG_LE 0x01 +#define BTP_GAP_DISCOVERY_FLAG_BREDR 0x02 +#define BTP_GAP_DISCOVERY_FLAG_LIMITED 0x04 +#define BTP_GAP_DISCOVERY_FLAG_LE_ACTIVE_SCAN 0x08 +#define BTP_GAP_DISCOVERY_FLAG_LE_OBSERVE 0x10 + +#define BTP_GAP_START_DISCOVERY 0x0c +struct btp_gap_start_discovery_cmd { + uint8_t flags; +} __packed; + +#define BTP_GAP_STOP_DISCOVERY 0x0d + +#define BTP_GAP_CONNECT 0x0e +struct btp_gap_connect_cmd { + ble_addr_t address; + uint8_t own_addr_type; +} __packed; + +#define BTP_GAP_DISCONNECT 0x0f +struct btp_gap_disconnect_cmd { + ble_addr_t address; +} __packed; + +#define BTP_GAP_IO_CAP_DISPLAY_ONLY 0 +#define BTP_GAP_IO_CAP_DISPLAY_YESNO 1 +#define BTP_GAP_IO_CAP_KEYBOARD_ONLY 2 +#define BTP_GAP_IO_CAP_NO_INPUT_OUTPUT 3 +#define BTP_GAP_IO_CAP_KEYBOARD_DISPLAY 4 + +#define BTP_GAP_SET_IO_CAP 0x10 +struct btp_gap_set_io_cap_cmd { + uint8_t io_cap; +} __packed; + +#define BTP_GAP_PAIR 0x11 +struct btp_gap_pair_cmd { + ble_addr_t address; +} __packed; + +#define BTP_GAP_UNPAIR 0x12 +struct btp_gap_unpair_cmd { + ble_addr_t address; +} __packed; + +#define BTP_GAP_PASSKEY_ENTRY 0x13 +struct btp_gap_passkey_entry_cmd { + ble_addr_t address; + uint32_t passkey; +} __packed; + +#define BTP_GAP_PASSKEY_CONFIRM 0x14 +struct btp_gap_passkey_confirm_cmd { + ble_addr_t address; + uint8_t match; +} __packed; + +#define BTP_GAP_START_DIRECT_ADV 0x15 +struct btp_gap_start_direct_adv_cmd { + ble_addr_t address; + uint16_t options; +} __packed; + +#define BTP_GAP_CONN_PARAM_UPDATE 0x16 +struct btp_gap_conn_param_update_cmd { + ble_addr_t address; + uint16_t conn_itvl_min; + uint16_t conn_itvl_max; + uint16_t conn_latency; + uint16_t supervision_timeout; +} __packed; + +#define BTP_GAP_PAIRING_CONSENT_RSP 0x17 +struct btp_gap_pairing_consent_rsp_cmd { + ble_addr_t address; + uint8_t consent; +} __packed; + +#define BTP_GAP_OOB_LEGACY_SET_DATA 0x18 +struct btp_gap_oob_legacy_set_data_cmd { + uint8_t oob_data[16]; +} __packed; + +#define BTP_GAP_OOB_SC_GET_LOCAL_DATA 0x19 +struct btp_gap_oob_sc_get_local_data_rp { + uint8_t r[16]; + uint8_t c[16]; +} __packed; + +#define BTP_GAP_OOB_SC_SET_REMOTE_DATA 0x1a +struct btp_gap_oob_sc_set_remote_data_cmd { + uint8_t r[16]; + uint8_t c[16]; +} __packed; + +#define BTP_GAP_SET_MITM 0x1b +struct btp_gap_set_mitm_cmd { + uint8_t mitm; +} __packed; + +#define BTP_GAP_SET_FILTER_ACCEPT_LIST 0x1c +struct btp_gap_set_filter_accept_list_cmd { + uint8_t list_len; + ble_addr_t addrs[]; +} __packed; + +#define GAP_SET_EXT_ADV 0x21 +struct btp_gap_set_ext_advertising_cmd { + uint8_t setting; +} __packed; + +struct btp_gap_set_ext_advertising_rp { + uint32_t current_settings; +} __packed; + +#define GAP_PADV_CONFIGURE 0x22 +struct gap_periodic_adv_configure_cmd { + uint8_t flags; + uint16_t itvl_min; + uint16_t itvl_max; +} __packed; + +struct btp_gap_periodic_adv_configure_rp { + uint32_t current_settings; +} __packed; + +#define GAP_PADV_START 0x23 +struct gap_periodic_adv_start_cmd { + uint8_t flags; +} __packed; + +struct btp_gap_periodic_adv_start_rp { + uint32_t current_settings; +} __packed; + +#define GAP_PADV_STOP 0x24 +struct btp_gap_periodic_adv_stop_rp { + uint32_t current_settings; +} __packed; + +#define GAP_PADV_SET_DATA 0x25 +struct gap_periodic_adv_set_data_cmd { + uint16_t adv_data_len; + uint8_t adv_data[0]; +} __packed; + +#define GAP_PADV_CREATE_SYNC 0x26 +struct gap_periodic_adv_create_sync_cmd { + ble_addr_t addr; + uint8_t adv_sid; + uint16_t skip; + uint16_t sync_timeout; + uint8_t flags; +} __packed; + +#define GAP_PADV_SYNC_TRANSFER_SET_INFO 0x27 +struct gap_periodic_adv_sync_transfer_set_info_cmd { + ble_addr_t addr; + uint16_t svc_data; +} __packed; + +#define GAP_PADV_SYNC_TRANSFER_START 0x28 +struct gap_periodic_adv_sync_transfer_start_cmd { + uint16_t sync_handle; + ble_addr_t addr; + uint16_t svc_data; +} __packed; + +#define GAP_PADV_SYNC_TRANSFER_RECV 0x29 +struct gap_periodic_adv_sync_transfer_recv_cmd { + ble_addr_t addr; + uint16_t skip; + uint16_t sync_timeout; + uint8_t flags; +} __packed; + +#define GAP_SUBRATE_REQUEST 0x2b +struct gap_subrate_request_cmd { + ble_addr_t address; + uint16_t subrate_min; + uint16_t subrate_max; + uint16_t max_latency; + uint16_t cont_num; + uint16_t supervision_timeout; +} __packed; + +/* events */ +#define BTP_GAP_EV_NEW_SETTINGS 0x80 +struct btp_gap_new_settings_ev { + uint32_t current_settings; +} __packed; + +#define BTP_GAP_DEVICE_FOUND_FLAG_RSSI 0x01 +#define BTP_GAP_DEVICE_FOUND_FLAG_AD 0x02 +#define BTP_GAP_DEVICE_FOUND_FLAG_SD 0x04 + +#define BTP_GAP_EV_DEVICE_FOUND 0x81 +struct btp_gap_device_found_ev { + ble_addr_t address; + int8_t rssi; + uint8_t flags; + uint16_t eir_data_len; + uint8_t eir_data[0]; +} __packed; + +#define BTP_GAP_EV_DEVICE_CONNECTED 0x82 +struct btp_gap_device_connected_ev { + ble_addr_t address; + uint16_t conn_itvl; + uint16_t conn_latency; + uint16_t supervision_timeout; +} __packed; + +#define BTP_GAP_EV_DEVICE_DISCONNECTED 0x83 +struct btp_gap_device_disconnected_ev { + ble_addr_t address; +} __packed; + +#define BTP_GAP_EV_PASSKEY_DISPLAY 0x84 +struct btp_gap_passkey_display_ev { + ble_addr_t address; + uint32_t passkey; +} __packed; + +#define BTP_GAP_EV_PASSKEY_ENTRY_REQ 0x85 +struct btp_gap_passkey_entry_req_ev { + ble_addr_t address; +} __packed; + +#define BTP_GAP_EV_PASSKEY_CONFIRM_REQ 0x86 +struct btp_gap_passkey_confirm_req_ev { + ble_addr_t address; + uint32_t passkey; +} __packed; + +#define BTP_GAP_EV_IDENTITY_RESOLVED 0x87 +struct btp_gap_identity_resolved_ev { + ble_addr_t address; + ble_addr_t identity_address; +} __packed; + +#define BTP_GAP_EV_CONN_PARAM_UPDATE 0x88 +struct btp_gap_conn_param_update_ev { + ble_addr_t address; + uint16_t conn_itvl; + uint16_t conn_latency; + uint16_t supervision_timeout; +} __packed; + +#define BTP_GAP_EV_SEC_LEVEL_CHANGED 0x89 +struct btp_gap_sec_level_changed_ev { + ble_addr_t address; + uint8_t level; +} __packed; + +#define BTP_GAP_EV_PAIRING_CONSENT_REQ 0x8a +struct btp_gap_pairing_consent_req_ev { + ble_addr_t address; +} __packed; + +#define BTP_GAP_EV_BOND_LOST 0x8b +struct btp_gap_bond_lost_ev { + ble_addr_t address; +} __packed; + +#define BTP_GAP_EV_SEC_PAIRING_FAILED 0x8c +struct btp_gap_sec_pairing_failed_ev { + ble_addr_t address; + uint8_t reason; +} __packed; + +#define GAP_EV_PERIODIC_SYNC_ESTABLISHED 0x8d +struct gap_periodic_sync_est_ev { + ble_addr_t peer_addr; + uint16_t sync_handle; + uint8_t status; +} __packed; + +#define GAP_EV_PERIODIC_SYNC_LOST 0x8e +struct gap_periodic_sync_lost_ev { + uint16_t sync_handle; + uint8_t reason; +} __packed; + +#define GAP_EV_PERIODIC_REPORT 0x8f +struct gap_periodic_report_ev { + uint16_t sync_handle; + int8_t tx_power; + int8_t rssi; + uint8_t cte_type; + uint8_t data_status; + uint8_t data_length; + uint8_t data[247]; +} __packed; + +#define GAP_EV_PERIODIC_TRANSFER_RECEIVED 0x90 +struct gap_periodic_transfer_recieved_ev { + ble_addr_t adv_addr; + uint16_t sync_handle; + uint8_t status; + ble_addr_t peer_addr; +} __packed; + +#define GAP_EV_SUBRATE_CHANGE 0x92 +struct gap_subrate_change_ev { + ble_addr_t addr; + uint8_t status; + uint16_t conn_handle; + uint16_t subrate_factor; + uint16_t periph_latency; + uint16_t cont_num; + uint16_t supervision_tmo; +} __packed; diff --git a/apps/bttester/src/btp/btp_gatt.h b/apps/bttester/src/btp/btp_gatt.h new file mode 100644 index 0000000000..6c57ade092 --- /dev/null +++ b/apps/bttester/src/btp/btp_gatt.h @@ -0,0 +1,339 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* btp_gatt.h - Bluetooth tester GATT service headers */ + +/* + * Copyright (c) 2015-2016 Intel Corporation + * Copyright (C) 2023 Codecoup + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* GATT Service */ +/* commands */ +#define BTP_GATT_READ_SUPPORTED_COMMANDS 0x01 +struct btp_gatt_read_supported_commands_rp { + uint8_t data[0]; +} __packed; + +#define BTP_GATT_SERVICE_PRIMARY 0x00 +#define BTP_GATT_SERVICE_SECONDARY 0x01 + +#define BTP_GATT_ADD_SERVICE 0x02 +struct btp_gatt_add_service_cmd { + uint8_t type; + uint8_t uuid_length; + uint8_t uuid[0]; +} __packed; +struct btp_gatt_add_service_rp { + uint16_t svc_id; +} __packed; + +#define BTP_GATT_ADD_CHARACTERISTIC 0x03 +struct btp_gatt_add_characteristic_cmd { + uint16_t svc_id; + uint8_t properties; + uint8_t permissions; + uint8_t uuid_length; + uint8_t uuid[0]; +} __packed; +struct btp_gatt_add_characteristic_rp { + uint16_t char_id; +} __packed; + +#define BTP_GATT_ADD_DESCRIPTOR 0x04 +struct btp_gatt_add_descriptor_cmd { + uint16_t char_id; + uint8_t permissions; + uint8_t uuid_length; + uint8_t uuid[0]; +} __packed; +struct btp_gatt_add_descriptor_rp { + uint16_t desc_id; +} __packed; + +#define BTP_GATT_ADD_INCLUDED_SERVICE 0x05 +struct btp_gatt_add_included_service_cmd { + uint16_t svc_id; +} __packed; +struct btp_gatt_add_included_service_rp { + uint16_t included_service_id; +} __packed; + +#define BTP_GATT_SET_VALUE 0x06 +struct btp_gatt_set_value_cmd { + uint16_t attr_id; + uint16_t len; + uint8_t value[0]; +} __packed; + +#define BTP_GATT_START_SERVER 0x07 +struct btp_gatt_start_server_rp { + uint16_t db_attr_off; + uint8_t db_attr_cnt; +} __packed; + +#define BTP_GATT_SET_ENC_KEY_SIZE 0x09 +struct btp_gatt_set_enc_key_size_cmd { + uint16_t attr_id; + uint8_t key_size; +} __packed; + +struct btp_gatt_service { + uint16_t start_handle; + uint16_t end_handle; + uint8_t uuid_length; + uint8_t uuid[0]; +} __packed; + +struct btp_gatt_included { + uint16_t included_handle; + struct btp_gatt_service service; +} __packed; + +struct btp_gatt_read_uuid_chr { + uint16_t handle; + uint8_t data[0]; +} __packed; + +struct btp_gatt_characteristic { + uint16_t characteristic_handle; + uint16_t value_handle; + uint8_t properties; + uint8_t uuid_length; + uint8_t uuid[0]; +} __packed; + +struct btp_gatt_descriptor { + uint16_t descriptor_handle; + uint8_t uuid_length; + uint8_t uuid[0]; +} __packed; + +#define BTP_GATT_EXCHANGE_MTU 0x0a +struct btp_gatt_exchange_mtu_cmd { + ble_addr_t address; +} __packed; + +#define BTP_GATT_DISC_ALL_PRIM_SVCS 0x0b +struct btp_gatt_disc_all_prim_svcs_cmd { + ble_addr_t address; +} __packed; +struct btp_gatt_disc_all_prim_svcs_rp { + uint8_t services_count; + struct btp_gatt_service services[0]; +} __packed; + +#define BTP_GATT_DISC_PRIM_UUID 0x0c +struct btp_gatt_disc_prim_uuid_cmd { + ble_addr_t address; + uint8_t uuid_length; + uint8_t uuid[0]; +} __packed; +struct btp_gatt_disc_prim_uuid_rp { + uint8_t services_count; + struct btp_gatt_service services[0]; +} __packed; + +#define BTP_GATT_FIND_INCLUDED 0x0d +struct btp_gatt_find_included_cmd { + ble_addr_t address; + uint16_t start_handle; + uint16_t end_handle; +} __packed; +struct btp_gatt_find_included_rp { + uint8_t services_count; + struct btp_gatt_included included[0]; +} __packed; + +#define BTP_GATT_DISC_ALL_CHRC 0x0e +struct btp_gatt_disc_all_chrc_cmd { + ble_addr_t address; + uint16_t start_handle; + uint16_t end_handle; +} __packed; +struct btp_gatt_disc_chrc_rp { + uint8_t characteristics_count; + struct btp_gatt_characteristic characteristics[0]; +} __packed; + +#define BTP_GATT_DISC_CHRC_UUID 0x0f +struct btp_gatt_disc_chrc_uuid_cmd { + ble_addr_t address; + uint16_t start_handle; + uint16_t end_handle; + uint8_t uuid_length; + uint8_t uuid[0]; +} __packed; + +#define BTP_GATT_DISC_ALL_DESC 0x10 +struct btp_gatt_disc_all_desc_cmd { + ble_addr_t address; + uint16_t start_handle; + uint16_t end_handle; +} __packed; +struct btp_gatt_disc_all_desc_rp { + uint8_t descriptors_count; + struct btp_gatt_descriptor descriptors[0]; +} __packed; + +#define BTP_GATT_READ 0x11 +struct btp_gatt_read_cmd { + ble_addr_t address; + uint16_t handle; +} __packed; +struct btp_gatt_read_rp { + uint8_t att_response; + uint16_t data_length; + uint8_t data[0]; +} __packed; + +#define BTP_GATT_READ_UUID 0x12 +struct btp_gatt_read_uuid_cmd { + ble_addr_t address; + uint16_t start_handle; + uint16_t end_handle; + uint8_t uuid_length; + uint8_t uuid[0]; +} __packed; + +#define BTP_GATT_READ_LONG 0x13 +struct btp_gatt_read_long_cmd { + ble_addr_t address; + uint16_t handle; + uint16_t offset; +} __packed; + +#define BTP_GATT_READ_MULTIPLE 0x14 +struct btp_gatt_read_multiple_cmd { + ble_addr_t address; + uint8_t handles_count; + uint16_t handles[0]; +} __packed; + +#define BTP_GATT_WRITE_WITHOUT_RSP 0x15 +struct btp_gatt_write_without_rsp_cmd { + ble_addr_t address; + uint16_t handle; + uint16_t data_length; + uint8_t data[0]; +} __packed; + +#define BTP_GATT_SIGNED_WRITE_WITHOUT_RSP 0x16 +struct btp_gatt_signed_write_without_rsp_cmd { + ble_addr_t address; + uint16_t handle; + uint16_t data_length; + uint8_t data[0]; +} __packed; + +#define BTP_GATT_WRITE 0x17 +struct btp_gatt_write_cmd { + ble_addr_t address; + uint16_t handle; + uint16_t data_length; + uint8_t data[0]; +} __packed; + +#define BTP_GATT_WRITE_LONG 0x18 +struct btp_gatt_write_long_cmd { + ble_addr_t address; + uint16_t handle; + uint16_t offset; + uint16_t data_length; + uint8_t data[0]; +} __packed; + +#define BTP_GATT_RELIABLE_WRITE 0x19 +struct btp_gatt_reliable_write_cmd { + ble_addr_t address; + uint16_t handle; + uint16_t offset; + uint16_t data_length; + uint8_t data[0]; +} __packed; + +#define BTP_GATT_CFG_NOTIFY 0x1a +#define BTP_GATT_CFG_INDICATE 0x1b +struct btp_gatt_cfg_notify_cmd { + ble_addr_t address; + uint8_t enable; + uint16_t ccc_handle; +} __packed; + +#define BTP_GATT_GET_ATTRIBUTES 0x1c +struct btp_gatt_get_attributes_cmd { + uint16_t start_handle; + uint16_t end_handle; + uint8_t type_length; + uint8_t type[0]; +} __packed; +struct btp_gatt_get_attributes_rp { + uint8_t attrs_count; + uint8_t attrs[0]; +} __packed; +struct btp_gatt_attr { + uint16_t handle; + uint8_t permission; + uint8_t type_length; + uint8_t type[0]; +} __packed; + +#define BTP_GATT_GET_ATTRIBUTE_VALUE 0x1d +struct btp_gatt_get_attribute_value_cmd { + ble_addr_t address; + uint16_t handle; +} __packed; +struct btp_gatt_get_attribute_value_rp { + uint8_t att_response; + uint16_t value_length; + uint8_t value[0]; +} __packed; + +#define BTP_GATT_CHANGE_DATABASE 0x1e +struct btp_gatt_change_database_cmd { + uint16_t start_handle; + uint16_t end_handle; + uint8_t visibility; +} __packed; + +#define BTP_GATT_NOTIFY_MULTIPLE 0x21 +struct btp_gatt_notify_mult_val_cmd { + ble_addr_t addr; + uint16_t count; + uint16_t handles[0]; +} __packed; + +/* GATT events */ +#define BTP_GATT_EV_NOTIFICATION 0x80 +struct btp_gatt_notification_ev { + ble_addr_t address; + uint8_t type; + uint16_t handle; + uint16_t data_length; + uint8_t data[0]; +} __packed; + +#define BTP_GATT_EV_ATTR_VALUE_CHANGED 0x81 +struct btp_gatt_attr_value_changed_ev { + uint16_t handle; + uint16_t data_length; + uint8_t data[0]; +} __packed; diff --git a/apps/bttester/src/btp/btp_gattc.h b/apps/bttester/src/btp/btp_gattc.h new file mode 100644 index 0000000000..df90ef0d96 --- /dev/null +++ b/apps/bttester/src/btp/btp_gattc.h @@ -0,0 +1,252 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* btp_gattc.h - Bluetooth tester GATT Client service headers */ + +/* + * Copyright (c) 2015-2016 Intel Corporation + * Copyright (C) 2023 Codecoup + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* GATT Client Service */ +/* commands */ +#define BTP_GATTC_READ_SUPPORTED_COMMANDS 0x01 +struct btp_gattc_read_supported_commands_rp { + uint8_t data[0]; +} __packed; + +#define BTP_GATTC_EXCHANGE_MTU 0x02 +struct btp_gattc_exchange_mtu_cmd { + ble_addr_t address; +} __packed; + +#define BTP_GATTC_DISC_ALL_PRIM_SVCS 0x03 +struct btp_gattc_disc_all_prim_svcs_cmd { + ble_addr_t address; +} __packed; + +#define BTP_GATTC_DISC_PRIM_UUID 0x04 +struct btp_gattc_disc_prim_uuid_cmd { + ble_addr_t address; + uint8_t uuid_length; + uint8_t uuid[0]; +} __packed; + +#define BTP_GATTC_FIND_INCLUDED 0x05 +struct btp_gattc_find_included_cmd { + ble_addr_t address; + uint16_t start_handle; + uint16_t end_handle; +} __packed; + +#define BTP_GATTC_DISC_ALL_CHRC 0x06 +struct btp_gattc_disc_all_chrc_cmd { + ble_addr_t address; + uint16_t start_handle; + uint16_t end_handle; +} __packed; + +#define BTP_GATTC_DISC_CHRC_UUID 0x07 +struct btp_gattc_disc_chrc_uuid_cmd { + ble_addr_t address; + uint16_t start_handle; + uint16_t end_handle; + uint8_t uuid_length; + uint8_t uuid[0]; +} __packed; + +#define BTP_GATTC_DISC_ALL_DESC 0x08 +struct btp_gattc_disc_all_desc_cmd { + ble_addr_t address; + uint16_t start_handle; + uint16_t end_handle; +} __packed; + +#define BTP_GATTC_READ 0x09 +struct btp_gattc_read_cmd { + ble_addr_t address; + uint16_t handle; +} __packed; + +#define BTP_GATTC_READ_UUID 0x0a +struct btp_gattc_read_uuid_cmd { + ble_addr_t address; + uint16_t start_handle; + uint16_t end_handle; + uint8_t uuid_length; + uint8_t uuid[0]; +} __packed; +struct btp_gattc_read_uuid_rp { + ble_addr_t address; + uint8_t status; + uint16_t data_length; + uint8_t value_length; + uint8_t data[0]; +} __packed; + +#define BTP_GATTC_READ_LONG 0x0b +struct btp_gattc_read_long_cmd { + ble_addr_t address; + uint16_t handle; + uint16_t offset; +} __packed; + +#define BTP_GATTC_READ_MULTIPLE 0x0c +struct btp_gattc_read_multiple_cmd { + ble_addr_t address; + uint8_t handles_count; + uint16_t handles[0]; +} __packed; + +#define BTP_GATTC_WRITE_WITHOUT_RSP 0x0d +struct btp_gattc_write_without_rsp_cmd { + ble_addr_t address; + uint16_t handle; + uint16_t data_length; + uint8_t data[0]; +} __packed; + +#define BTP_GATTC_SIGNED_WRITE_WITHOUT_RSP 0x0e +struct btp_gattc_signed_write_without_rsp_cmd { + ble_addr_t address; + uint16_t handle; + uint16_t data_length; + uint8_t data[0]; +} __packed; + +#define BTP_GATTC_WRITE 0x0f +struct btp_gattc_write_cmd { + ble_addr_t address; + uint16_t handle; + uint16_t data_length; + uint8_t data[0]; +} __packed; + +#define BTP_GATTC_WRITE_LONG 0x10 +struct btp_gattc_write_long_cmd { + ble_addr_t address; + uint16_t handle; + uint16_t offset; + uint16_t data_length; + uint8_t data[0]; +} __packed; + +#define BTP_GATTC_RELIABLE_WRITE 0x11 +struct btp_gattc_reliable_write_cmd { + ble_addr_t address; + uint16_t handle; + uint16_t offset; + uint16_t data_length; + uint8_t data[0]; +} __packed; + +#define BTP_GATTC_CFG_NOTIFY 0x12 +#define BTP_GATTC_CFG_INDICATE 0x13 +struct btp_gattc_cfg_notify_cmd { + ble_addr_t address; + uint8_t enable; + uint16_t ccc_handle; +} __packed; + +#define BTP_GATTC_READ_MULTIPLE_VAR 0x14 +struct btp_gattc_read_multiple_var_cmd { + ble_addr_t address; + uint8_t handles_count; + uint16_t handles[0]; +} __packed; + +/* events */ +#define BTP_GATTC_EV_MTU_EXCHANGED 0x80 +struct btp_gattc_exchange_mtu_ev { + ble_addr_t address; + uint16_t mtu; +} __packed; + +#define BTP_GATTC_DISC_ALL_PRIM_RP 0x81 +struct btp_gattc_disc_prim_svcs_rp { + ble_addr_t address; + uint8_t status; + uint8_t services_count; + uint8_t data[0]; +} __packed; + +#define BTP_GATTC_DISC_PRIM_UUID_RP 0x82 + +#define BTP_GATTC_FIND_INCLUDED_RP 0x83 +struct btp_gattc_find_included_rp { + ble_addr_t address; + uint8_t status; + uint8_t services_count; + struct btp_gatt_included included[0]; +} __packed; + +#define BTP_GATTC_DISC_ALL_CHRC_RP 0x84 +#define BTP_GATTC_DISC_CHRC_UUID_RP 0x85 +struct btp_gattc_disc_chrc_rp { + ble_addr_t address; + uint8_t status; + uint8_t characteristics_count; + struct btp_gatt_characteristic characteristics[0]; +} __packed; + +#define BTP_GATTC_DISC_ALL_DESC_RP 0x86 +struct btp_gattc_disc_all_desc_rp { + ble_addr_t address; + uint8_t status; + uint8_t descriptors_count; + struct btp_gatt_descriptor descriptors[0]; +} __packed; + +#define BTP_GATTC_READ_RP 0x87 +#define BTP_GATTC_READ_UUID_RP 0x88 +#define BTP_GATTC_READ_LONG_RP 0x89 +#define BTP_GATTC_READ_MULTIPLE_RP 0x8a +struct btp_gattc_read_rp { + ble_addr_t address; + uint8_t status; + uint16_t data_length; + uint8_t data[0]; +} __packed; + +#define BTP_GATTC_WRITE_RP 0x8b +struct btp_gattc_write_rp { + ble_addr_t address; + uint8_t status; +} __packed; +#define BTP_GATTC_WRITE_LONG_RP 0x8c +#define BTP_GATTC_RELIABLE_WRITE_RP 0x8d +#define BTP_GATTC_CFG_NOTIFY_RP 0x8e +#define BTP_GATTC_CFG_INDICATE_RP 0x8f +struct btp_subscribe_rp { + ble_addr_t address; + uint8_t status; +} __packed; + +#define BTP_GATTC_EV_NOTIFICATION_RXED 0x90 +struct btp_gattc_notification_ev { + ble_addr_t address; + uint8_t type; + uint16_t handle; + uint16_t data_length; + uint8_t data[0]; +} __packed; + +#define BTP_GATTC_READ_MULTIPLE_VAR_RP 0x91 diff --git a/apps/bttester/src/btp/btp_l2cap.h b/apps/bttester/src/btp/btp_l2cap.h new file mode 100644 index 0000000000..7d2adcaea6 --- /dev/null +++ b/apps/bttester/src/btp/btp_l2cap.h @@ -0,0 +1,136 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* btp_l2cap.h - Bluetooth tester L2CAP service headers */ + +/* + * Copyright (c) 2015-2016 Intel Corporation + * Copyright (C) 2023 Codecoup + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* L2CAP Service */ +/* commands */ +#define BTP_L2CAP_READ_SUPPORTED_COMMANDS 0x01 +struct btp_l2cap_read_supported_commands_rp { + uint8_t data[0]; +} __packed; + +#define BTP_L2CAP_CONNECT_OPT_ECFC 0x01 +#define BTP_L2CAP_CONNECT_OPT_HOLD_CREDIT 0x02 + +#define BTP_L2CAP_CONNECT 0x02 +struct btp_l2cap_connect_cmd { + ble_addr_t address; + uint16_t psm; + uint16_t mtu; + uint8_t num; + uint8_t options; +} __packed; + +struct btp_l2cap_connect_rp { + uint8_t num; + uint8_t chan_ids[0]; +} __packed; + +#define BTP_L2CAP_DISCONNECT 0x03 +struct btp_l2cap_disconnect_cmd { + uint8_t chan_id; +} __packed; + +#define BTP_L2CAP_SEND_DATA 0x04 +struct btp_l2cap_send_data_cmd { + uint8_t chan_id; + uint16_t data_len; + uint8_t data[]; +} __packed; + +#define BTP_L2CAP_TRANSPORT_BREDR 0x00 +#define BTP_L2CAP_TRANSPORT_LE 0x01 + +#define BTP_L2CAP_LISTEN 0x05 +struct btp_l2cap_listen_cmd { + uint16_t psm; + uint8_t transport; + uint16_t mtu; + uint16_t response; +} __packed; + +#define BTP_L2CAP_ACCEPT_CONNECTION 0x06 +struct l2cap_accept_connection_cmd { + uint8_t chan_id; + uint16_t result; +} __packed; + +#define BTP_L2CAP_RECONFIGURE 0x07 +struct btp_l2cap_reconfigure_cmd { + ble_addr_t address; + uint16_t mtu; + uint8_t num; + uint8_t idxs[]; +} __packed; + +#define BTP_L2CAP_CREDITS 0x08 +struct btp_l2cap_credits_cmd { + uint8_t chan_id; +} __packed; + +/* events */ +#define BTP_L2CAP_EV_CONNECTION_REQ 0x80 +struct btp_l2cap_connection_req_ev { + uint8_t chan_id; + uint16_t psm; + ble_addr_t address; +} __packed; + +#define BTP_L2CAP_EV_CONNECTED 0x81 +struct btp_l2cap_connected_ev { + uint8_t chan_id; + uint16_t psm; + uint16_t peer_mtu; + uint16_t peer_mps; + uint16_t our_mtu; + uint16_t our_mps; + ble_addr_t address; +} __packed; + +#define BTP_L2CAP_EV_DISCONNECTED 0x82 +struct btp_l2cap_disconnected_ev { + uint16_t result; + uint8_t chan_id; + uint16_t psm; + ble_addr_t address; +} __packed; + +#define BTP_L2CAP_EV_DATA_RECEIVED 0x83 +struct btp_l2cap_data_received_ev { + uint8_t chan_id; + uint16_t data_length; + uint8_t data[0]; +} __packed; + +#define BTP_L2CAP_EV_RECONFIGURED 0x84 +struct btp_l2cap_reconfigured_ev { + uint8_t chan_id; + uint16_t peer_mtu; + uint16_t peer_mps; + uint16_t our_mtu; + uint16_t our_mps; +} __packed; diff --git a/apps/bttester/src/btp/btp_mesh.h b/apps/bttester/src/btp/btp_mesh.h new file mode 100644 index 0000000000..096c398060 --- /dev/null +++ b/apps/bttester/src/btp/btp_mesh.h @@ -0,0 +1,212 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* btp_mesh.h - Bluetooth tester MESH service headers */ + +/* + * Copyright (c) 2015-2016 Intel Corporation + * Copyright (C) 2023 Codecoup + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* MESH Service */ +/* commands */ +#define BTP_MESH_READ_SUPPORTED_COMMANDS 0x01 +struct btp_mesh_read_supported_commands_rp { + uint8_t data[0]; +} __packed; + +#define BTP_MESH_OUT_BLINK BIT(0) +#define BTP_MESH_OUT_BEEP BIT(1) +#define BTP_MESH_OUT_VIBRATE BIT(2) +#define BTP_MESH_OUT_DISPLAY_NUMBER BIT(3) +#define BTP_MESH_OUT_DISPLAY_STRING BIT(4) + +#define BTP_MESH_IN_PUSH BIT(0) +#define BTP_MESH_IN_TWIST BIT(1) +#define BTP_MESH_IN_ENTER_NUMBER BIT(2) +#define BTP_MESH_IN_ENTER_STRING BIT(3) + +#define BTP_MESH_CONFIG_PROVISIONING 0x02 +struct btp_mesh_config_provisioning_cmd { + uint8_t uuid[16]; + uint8_t static_auth[32]; + uint8_t static_auth_length; + uint8_t out_size; + uint16_t out_actions; + uint8_t in_size; + uint16_t in_actions; +} __packed; + +#define BTP_MESH_PROVISION_NODE 0x03 +struct btp_mesh_provision_node_cmd { + uint8_t net_key[16]; + uint16_t net_key_idx; + uint8_t flags; + uint32_t iv_index; + uint32_t seq_num; + uint16_t addr; + uint8_t dev_key[16]; +} __packed; + +#define BTP_MESH_INIT 0x04 +struct btp_mesh_init_cmd { + uint8_t comp; +} __packed; + +#define BTP_MESH_RESET 0x05 +#define BTP_MESH_INPUT_NUMBER 0x06 +struct btp_mesh_input_number_cmd { + uint32_t number; +} __packed; + +#define BTP_MESH_INPUT_STRING 0x07 +struct btp_mesh_input_string_cmd { + uint8_t string_len; + uint8_t string[0]; +} __packed; + +#define BTP_MESH_IVU_TEST_MODE 0x08 +struct btp_mesh_ivu_test_mode_cmd { + uint8_t enable; +} __packed; + +#define BTP_MESH_IVU_TOGGLE_STATE 0x09 + +#define BTP_MESH_NET_SEND 0x0a +struct btp_mesh_net_send_cmd { + uint8_t ttl; + uint16_t src; + uint16_t dst; + uint8_t payload_len; + uint8_t payload[0]; +} __packed; + +#define BTP_MESH_HEALTH_GENERATE_FAULTS 0x0b +struct btp_mesh_health_generate_faults_rp { + uint8_t test_id; + uint8_t cur_faults_count; + uint8_t reg_faults_count; + uint8_t current_faults[0]; + uint8_t registered_faults[0]; +} __packed; + +#define BTP_MESH_HEALTH_CLEAR_FAULTS 0x0c + +#define BTP_MESH_LPN 0x0d +struct btp_mesh_lpn_set_cmd { + uint8_t enable; +} __packed; + +#define BTP_MESH_LPN_POLL 0x0e + +#define BTP_MESH_MODEL_SEND 0x0f +struct btp_mesh_model_send_cmd { + uint8_t ttl; + uint16_t src; + uint16_t dst; + uint8_t payload_len; + uint8_t payload[0]; +} __packed; + +#define BTP_MESH_LPN_SUBSCRIBE 0x10 +struct btp_mesh_lpn_subscribe_cmd { + uint16_t address; +} __packed; + +#define BTP_MESH_LPN_UNSUBSCRIBE 0x11 +struct btp_mesh_lpn_unsubscribe_cmd { + uint16_t address; +} __packed; + +#define BTP_MESH_RPL_CLEAR 0x12 +#define BTP_MESH_PROXY_IDENTITY 0x13 +#define BTP_MESH_START 0x78 + +/* events */ +#define BTP_MESH_EV_OUT_NUMBER_ACTION 0x80 +struct btp_mesh_out_number_action_ev { + uint16_t action; + uint32_t number; +} __packed; + +#define BTP_MESH_EV_OUT_STRING_ACTION 0x81 +struct btp_mesh_out_string_action_ev { + uint8_t string_len; + uint8_t string[0]; +} __packed; + +#define BTP_MESH_EV_IN_ACTION 0x82 +struct btp_mesh_in_action_ev { + uint16_t action; + uint8_t size; +} __packed; + +#define BTP_MESH_EV_PROVISIONED 0x83 + +#define BTP_MESH_PROV_BEARER_PB_ADV 0x00 +#define BTP_MESH_PROV_BEARER_PB_GATT 0x01 +#define BTP_MESH_EV_PROV_LINK_OPEN 0x84 +struct btp_mesh_prov_link_open_ev { + uint8_t bearer; +} __packed; + +#define BTP_MESH_EV_PROV_LINK_CLOSED 0x85 +struct btp_mesh_prov_link_closed_ev { + uint8_t bearer; +} __packed; + +#define BTP_MESH_EV_NET_RECV 0x86 +struct btp_mesh_net_recv_ev { + uint8_t ttl; + uint8_t ctl; + uint16_t src; + uint16_t dst; + uint8_t payload_len; + uint8_t payload[0]; +} __packed; + +#define BTP_MESH_EV_INVALID_BEARER 0x87 +struct btp_mesh_invalid_bearer_ev { + uint8_t opcode; +} __packed; + +#define BTP_MESH_EV_INCOMP_TIMER_EXP 0x88 + +#define BTP_MESH_EV_LPN_ESTABLISHED 0x8b +struct btp_mesh_lpn_established_ev { + uint16_t net_idx; + uint16_t friend_addr; + uint8_t queue_size; + uint8_t recv_win; +} __packed; + +#define BTP_MESH_EV_LPN_TERMINATED 0x8c +struct btp_mesh_lpn_terminated_ev { + uint16_t net_idx; + uint16_t friend_addr; +} __packed; + +#define BTP_MESH_EV_LPN_POLLED 0x8d +struct btp_mesh_lpn_polled_ev { + uint16_t net_idx; + uint16_t friend_addr; + uint8_t retry; +} __packed; diff --git a/apps/bttester/src/btp/btp_pacs.h b/apps/bttester/src/btp/btp_pacs.h new file mode 100644 index 0000000000..3b9b5b06ce --- /dev/null +++ b/apps/bttester/src/btp/btp_pacs.h @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef BTP_PACS_H +#define BTP_PACS_H + +#include + +#ifndef __packed +#define __packed __attribute__((__packed__)) +#endif + +#define BTP_PACS_READ_SUPPORTED_COMMANDS 0x01 +struct btp_pacs_read_supported_commands_rp { + uint8_t data[0]; +} __packed; + +#define BTP_PACS_UPDATE_CHARACTERISTIC 0x02 +struct btp_pacs_update_characteristic_cmd { + uint8_t char_id; +} __packed; + +#define BTP_PACS_SET_LOCATION 0x03 + +#define BTP_PACS_SET_AVAILABLE_CONTEXTS 0x04 +struct btp_pacs_set_available_contexts_cmd { + uint16_t sink_contexts; + uint16_t source_contexts; +} __packed; + +#define BTP_PACS_SET_SUPPORTED_CONTEXTS 0x05 +struct btp_pacs_set_supported_contexts_cmd { + uint16_t sink_contexts; + uint16_t source_contexts; +} __packed; + +#define BTP_PACS_CHARACTERISTIC_SINK_PAC 0x01 +#define BTP_PACS_CHARACTERISTIC_SOURCE_PAC 0x02 +#define BTP_PACS_CHARACTERISTIC_SINK_AUDIO_LOCATIONS 0x03 +#define BTP_PACS_CHARACTERISTIC_SOURCE_AUDIO_LOCATIONS 0x04 +#define BTP_PACS_CHARACTERISTIC_AVAILABLE_AUDIO_CONTEXTS 0x05 + +#endif /* BTP_PACS_H*/ diff --git a/apps/bttester/src/btp/bttester.h b/apps/bttester/src/btp/bttester.h new file mode 100644 index 0000000000..ac56d8846d --- /dev/null +++ b/apps/bttester/src/btp/bttester.h @@ -0,0 +1,163 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* bttester.h - Bluetooth tester headers */ + +/* + * Copyright (c) 2015-2016 Intel Corporation + * Copyright (C) 2023 Codecoup + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __BTTESTER_H__ +#define __BTTESTER_H__ + +#include "syscfg/syscfg.h" +#include "host/ble_gatt.h" +#include "os/os_mbuf.h" +#include + +#define BIT(n) (1UL << (n)) + +/* Reset os_mbuf to reusable state */ +void +tester_mbuf_reset(struct os_mbuf *buf); + +const char * +string_from_bytes(const void *buf, size_t len); + +static inline void +tester_set_bit(uint8_t *addr, unsigned int bit) +{ + uint8_t *p = addr + (bit / 8); + + *p |= BIT(bit % 8); +} + +static inline uint8_t +tester_test_bit(const uint8_t *addr, unsigned int bit) +{ + const uint8_t *p = addr + (bit / 8); + + return *p & BIT(bit % 8); +} + +static inline void +tester_clear_bit(uint8_t *addr, unsigned int bit) +{ + uint8_t *p = addr + (bit / 8); + + *p &= ~BIT(bit % 8); +} + + +void +tester_init(void); +void +tester_rsp(uint8_t service, uint8_t opcode, uint8_t status); +void +tester_rsp_full(uint8_t service, uint8_t opcode, const void *rsp, size_t len); +void +tester_event(uint8_t service, uint8_t opcode, const void *data, size_t len); + +/* Used to indicate that command length is variable and that validation will + * be done in handler. + */ +#define BTP_HANDLER_LENGTH_VARIABLE (-1) + +struct btp_handler { + uint8_t opcode; + uint8_t index; + ssize_t expect_len; + uint8_t (*func)(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len); +}; + +void tester_register_command_handlers(uint8_t service, + const struct btp_handler *handlers, + size_t num); + +uint16_t tester_supported_commands(uint8_t service, uint8_t *cmds); + +void +tester_send_buf(uint8_t service, uint8_t opcode, uint8_t index, + struct os_mbuf *buf); + +uint8_t +tester_init_gap(void); +uint8_t +tester_unregister_gap(void); +void +tester_init_core(void); +uint8_t +tester_init_gatt(void); +uint8_t +tester_unregister_gatt(void); +int +tester_gattc_notify_rx_ev(uint16_t conn_handle, uint16_t attr_handle, + uint8_t indication, struct os_mbuf *om); +int +tester_gatt_subscribe_ev(uint16_t conn_handle, + uint16_t attr_handle, + uint8_t reason, + uint8_t prev_notify, + uint8_t cur_notify, + uint8_t prev_indicate, + uint8_t cur_indicate); + +#if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) +uint8_t +tester_init_l2cap(void); +uint8_t +tester_unregister_l2cap(void); +#endif + +#if MYNEWT_VAL(BLE_MESH) +uint8_t +tester_init_mesh(void); +uint8_t +tester_unregister_mesh(void); +#endif /* MYNEWT_VAL(BLE_MESH) */ +uint8_t +tester_init_gatt_cl(void); +uint8_t +tester_unregister_gatt_cl(void); +void +gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg); + +int +gatt_svr_init(void); + +#if MYNEWT_VAL(BLE_AUDIO) +uint8_t +tester_init_bap(void); +uint8_t +tester_unregister_bap(void); +#endif /* MYNEWT_VAL(BLE_AUDIO) */ + +#if MYNEWT_VAL(BLE_AUDIO) +uint8_t +tester_init_pacs(void); +uint8_t +tester_unregister_pacs(void); +#endif /* MYNEWT_VAL(BLE_AUDIO) */ + +#endif /* __BTTESTER_H__ */ + diff --git a/apps/bttester/src/btp_bap.c b/apps/bttester/src/btp_bap.c new file mode 100644 index 0000000000..7ff489bb92 --- /dev/null +++ b/apps/bttester/src/btp_bap.c @@ -0,0 +1,669 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* btp_bap.c - Bluetooth Basic Audio Profile Tester */ + +#include "btp/bttester.h" +#include "syscfg/syscfg.h" +#include + + +#if MYNEWT_VAL(BLE_ISO_BROADCAST_SOURCE) + +#include "btp/btp_bap.h" + +#include "btp/btp.h" +#include "console/console.h" + +#include "host/ble_hs.h" +#include "host/util/util.h" +#include "math.h" + +#include "audio/ble_audio_broadcast_source.h" +#include "audio/ble_audio_broadcast_sink.h" +#include "audio/ble_audio.h" +#include "host/ble_iso.h" + +#define BROADCAST_ADV_INSTANCE 1 + +static struct ble_audio_big_subgroup big_subgroup; + +static struct broadcast_sink { + ble_addr_t addr; + uint8_t source_id; + uint8_t broadcast_code[BLE_AUDIO_BROADCAST_CODE_SIZE]; +} sinks[MYNEWT_VAL(BLE_AUDIO_BROADCAST_SINK_MAX)]; + +static uint8_t sink_num = 0; +static uint8_t id_addr_type; +static uint8_t audio_data[155]; +static uint16_t max_sdu; +static uint32_t sdu_interval; + +static struct ble_audio_base tester_base; + +static os_membuf_t bis_mem[ + OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_ISO_MAX_BISES), + sizeof(struct ble_audio_bis)) +]; +static struct os_mempool bis_pool; + +static os_membuf_t codec_spec_mem[ + OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_ISO_MAX_BISES) * 2, 19) +]; +static struct os_mempool codec_spec_pool; + +static uint16_t bis_handles[MYNEWT_VAL(BLE_ISO_MAX_BISES)]; +/* The timer callout */ +static struct os_callout audio_broadcast_callout; + +struct ble_iso_big_params big_params; + +static int audio_data_offset; + +static void +audio_broadcast_event_cb(struct os_event *ev) +{ + assert(ev != NULL); + uint32_t ev_start_time = os_cputime_ticks_to_usecs(os_cputime_get32()); + + if (audio_data_offset + 2 * max_sdu >= sizeof(audio_data)) { + audio_data_offset = 0; + } + + uint8_t lr_payload[max_sdu * 2]; + memcpy(lr_payload, audio_data + audio_data_offset, max_sdu); + memcpy(lr_payload + max_sdu, audio_data + audio_data_offset, + max_sdu); + ble_iso_tx(bis_handles[0], (void *)(lr_payload), + max_sdu * 2); + + audio_data_offset += max_sdu; + + /** Use cputime to time BROADCAST_SDU_INTVL, as these ticks are more + * accurate than os_time ones. This assures that we do not push + * LC3 data to ISO before interval, which could lead to + * controller running out of buffers. This is only needed because + * we already have data in an array - in real world application + * we usually wait for new audio to arrive, and lose time to code it too. + */ + while (os_cputime_ticks_to_usecs(os_cputime_get32()) - ev_start_time < + (sdu_interval)); + + os_callout_reset(&audio_broadcast_callout, 0); +} + +static int +iso_event(struct ble_iso_event *event, void *arg) +{ + int i; + + switch (event->type) { + case BLE_ISO_EVENT_BIG_CREATE_COMPLETE: + console_printf("%s: BIG created\n", __func__); + if (event->big_created.desc.num_bis > + MYNEWT_VAL(BROADCASTER_CHAN_NUM)) { + return BLE_HS_EINVAL; + } + for (i = 0; i < MYNEWT_VAL(BROADCASTER_CHAN_NUM); i++) { + bis_handles[i] = event->big_created.desc.conn_handle[i]; + } + return 0; + case BLE_ISO_EVENT_BIG_TERMINATE_COMPLETE: + console_printf("%s: BIG terminated\n", __func__); + return 0; + default: + return BLE_HS_ENOTSUP; + } +} + +static uint8_t +supported_commands(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + struct btp_bap_read_supported_commands_rp *rp = rsp; + + *rsp_len = tester_supported_commands(BTP_SERVICE_ID_BAP, rp->data); + *rsp_len += sizeof(*rp); + + return BTP_STATUS_SUCCESS; +} + +static int +base_create(const struct bap_broadcast_source_setup_cmd *cmd) +{ + struct ble_audio_bis *bis; + uint8_t sampling_freq = cmd->cc_ltvs[2]; + uint8_t frame_duration = cmd->cc_ltvs[5]; + uint16_t chan_loc = BLE_AUDIO_LOCATION_FRONT_LEFT | + BLE_AUDIO_LOCATION_FRONT_RIGHT; + + uint8_t codec_spec_config[] = + BLE_AUDIO_BUILD_CODEC_CONFIG(sampling_freq, frame_duration, chan_loc, + max_sdu, ); + + tester_base.broadcast_id = sampling_freq; + tester_base.presentation_delay = sampling_freq * 10000; + + big_subgroup.bis_cnt = MYNEWT_VAL(BLE_ISO_MAX_BISES); + + /** LC3 */ + big_subgroup.codec_id.format = 0x06; + + big_subgroup.codec_spec_config_len = 0; + + bis = os_memblock_get(&bis_pool); + if (!bis) { + return BLE_HS_ENOMEM; + } + + bis->codec_spec_config = os_memblock_get(&codec_spec_pool); + memcpy(bis->codec_spec_config, + codec_spec_config, + sizeof(codec_spec_config)); + bis->codec_spec_config_len = sizeof(codec_spec_config); + bis->idx = 1; + + STAILQ_INSERT_HEAD(&big_subgroup.bises, bis, next); + STAILQ_INSERT_HEAD(&tester_base.subs, &big_subgroup, next); + + tester_base.num_subgroups++; + + return 0; +} + +static int +broadcast_destroy_fn(struct ble_audio_base *base, void *args) +{ + struct ble_audio_bis *bis; + + STAILQ_FOREACH(bis, &big_subgroup.bises, next) { + os_memblock_put(&codec_spec_pool, bis->codec_spec_config); + os_memblock_put(&bis_pool, bis); + } + + memset(&big_subgroup, 0, sizeof(big_subgroup)); + + return 0; +} + +static uint8_t +broadcast_source_setup(const void *cmd, uint16_t cmd_len, void *rsp, + uint16_t *rsp_len) +{ + int rc; + + const struct bap_broadcast_source_setup_cmd *source_config = cmd; + max_sdu = source_config->max_sdu; + sdu_interval = get_le24(source_config->sdu_interval); + + base_create(source_config); + + big_params.sdu_interval = sdu_interval; + big_params.max_sdu = max_sdu; + big_params.max_transport_latency = 8; + big_params.rtn = source_config->rtn; + big_params.phy = BLE_HCI_LE_PHY_2M; + big_params.packing = 0; + big_params.framing = source_config->framing; + big_params.encryption = 0; + + struct ble_gap_periodic_adv_params periodic_params = { + .itvl_min = 30, + .itvl_max = 30, + }; + + struct ble_gap_ext_adv_params extended_params = { + .itvl_min = 50, + .itvl_max = 50, + .scannable = 0, + .connectable = 0, + .primary_phy = BLE_HCI_LE_PHY_1M, + .secondary_phy = BLE_HCI_LE_PHY_2M, + .own_addr_type = id_addr_type, + .sid = BROADCAST_ADV_INSTANCE, + }; + + struct ble_broadcast_create_params create_params = { + .base = &tester_base, + .extended_params = &extended_params, + .periodic_params = &periodic_params, + .name = MYNEWT_VAL(BROADCASTER_BROADCAST_NAME), + .adv_instance = BROADCAST_ADV_INSTANCE, + .big_params = &big_params, + .svc_data = NULL, + .svc_data_len = 0, + }; + + rc = ble_audio_broadcast_create(&create_params, + broadcast_destroy_fn, + NULL, + NULL); + if (rc) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +broadcast_source_release(const void *cmd, uint16_t cmd_len, void *rsp, + uint16_t *rsp_len) +{ + int rc; + + rc = ble_audio_broadcast_destroy(BROADCAST_ADV_INSTANCE); + if (rc) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +broadcast_adv_start(const void *cmd, uint16_t cmd_len, void *rsp, + uint16_t *rsp_len) +{ + int rc; + + rc = ble_audio_broadcast_start(BROADCAST_ADV_INSTANCE, iso_event, NULL); + if (rc) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +broadcast_adv_stop(const void *cmd, uint16_t cmd_len, void *rsp, + uint16_t *rsp_len) +{ + int rc; + + rc = ble_audio_broadcast_stop(BROADCAST_ADV_INSTANCE); + if (rc) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +broadcast_source_start(const void *cmd, uint16_t cmd_len, void *rsp, + uint16_t *rsp_len) +{ + int rc; + + rc = os_callout_reset(&audio_broadcast_callout, 0); + if (rc) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +broadcast_code_set(const void *cmd, uint16_t cmd_len, void *rsp, + uint16_t *rsp_len) +{ + const struct btp_bap_set_broadcast_code_cmd *cp = cmd; + + if (sink_num > MYNEWT_VAL(BLE_AUDIO_BROADCAST_SINK_MAX)) { + return BTP_STATUS_FAILED; + } + + sinks[sink_num].addr = cp->addr; + sinks[sink_num].addr.type = cp->addr.type; + sinks[sink_num].source_id = cp->source_id; + + memcpy(sinks[sink_num].broadcast_code, cp->broadcast_code, + BLE_AUDIO_BROADCAST_CODE_SIZE); + + sink_num++; + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +broadcast_sink_setup(const void *cmd, uint16_t cmd_len, void *rsp, + uint16_t *rsp_len) +{ + int rc, i; + struct ble_audio_broadcast_sink_add_params params = {0}; + + for (i = 0; i < sink_num; i++) { + memcpy(params.broadcast_code, sinks[i].broadcast_code, + BLE_AUDIO_BROADCAST_CODE_SIZE); + params.broadcast_code_is_valid = true; + rc = ble_audio_broadcast_sink_start(sinks[i].source_id, ¶ms); + if (rc) { + return BTP_STATUS_FAILED; + } + } + + return BTP_STATUS_SUCCESS; +} + +static int +scan_delegator_receive_state_foreach_fn(struct ble_audio_scan_delegator_receive_state_entry *entry, + void *addr) +{ + if (ble_addr_cmp(addr, &entry->source_desc.addr)) { + ble_audio_broadcast_sink_stop(entry->source_id); + } + + return 0; +} + +static uint8_t +broadcast_sink_stop(const void *cmd, uint16_t cmd_len, void *rsp, + uint16_t *rsp_len) +{ + ble_addr_t addr; + const struct btp_bap_broadcast_sink_stop_cmd *cp = cmd; + + addr = cp->address; + + ble_audio_scan_delegator_receive_state_foreach(scan_delegator_receive_state_foreach_fn, + &addr); + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +broadcast_source_stop(const void *cmd, uint16_t cmd_len, void *rsp, + uint16_t *rsp_len) +{ + os_callout_stop(&audio_broadcast_callout); + + return BTP_STATUS_SUCCESS; +} + +static const struct btp_handler handlers[] = { + { + .opcode = BTP_BAP_READ_SUPPORTED_COMMANDS, + .index = BTP_INDEX_NONE, + .expect_len = 0, + .func = supported_commands, + }, + { + .opcode = BTP_BAP_BROADCAST_SOURCE_SETUP, + .index = BTP_INDEX, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = broadcast_source_setup, + }, + { + .opcode = BTP_BAP_BROADCAST_SOURCE_RELEASE, + .index = BTP_INDEX, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = broadcast_source_release, + }, + { + .opcode = BTP_BAP_BROADCAST_ADV_START, + .index = BTP_INDEX, + .expect_len = sizeof(struct bap_bap_broadcast_adv_start_cmd), + .func = broadcast_adv_start, + }, + { + .opcode = BTP_BAP_BROADCAST_ADV_STOP, + .index = BTP_INDEX, + .expect_len = sizeof(struct bap_bap_broadcast_adv_stop_cmd), + .func = broadcast_adv_stop, + }, + { + .opcode = BTP_BAP_BROADCAST_SOURCE_START, + .index = BTP_INDEX, + .expect_len = sizeof(struct bap_bap_broadcast_source_start_cmd), + .func = broadcast_source_start, + }, + { + .opcode = BTP_BAP_BROADCAST_SOURCE_STOP, + .index = BTP_INDEX, + .expect_len = sizeof(struct bap_bap_broadcast_source_stop_cmd), + .func = broadcast_source_stop, + }, + { + .opcode = BTP_BAP_SET_BROADCAST_CODE, + .index = BTP_INDEX, + .expect_len = sizeof(struct btp_bap_set_broadcast_code_cmd), + .func = broadcast_code_set, + }, + { + .opcode = BTP_BAP_BROADCAST_SINK_SETUP, + .index = BTP_INDEX, + .expect_len = 0, + .func = broadcast_sink_setup, + }, + { + .opcode = BTP_BAP_BROADCAST_SINK_STOP, + .index = BTP_INDEX, + .expect_len = sizeof(struct btp_bap_broadcast_sink_stop_cmd), + .func = broadcast_sink_stop, + }, +}; + +#define BROADCAST_SINK_PA_SYNC_TIMEOUT_DEFAULT 0x07D0 + +static int +broadcast_sink_pa_sync_params_get(struct ble_gap_periodic_sync_params *params) +{ + params->skip = 0; + params->sync_timeout = BROADCAST_SINK_PA_SYNC_TIMEOUT_DEFAULT; + params->reports_disabled = false; + + return 0; +} + +static int +broadcast_sink_disc_start(const struct ble_gap_ext_disc_params *params) +{ + uint8_t own_addr_type; + int rc; + + /* Figure out address to use while scanning. */ + rc = ble_hs_id_infer_auto(0, &own_addr_type); + if (rc != 0) { + console_printf("%s: determining own address type failed (%d)", __func__, rc); + assert(0); + } + + rc = ble_gap_ext_disc(own_addr_type, 0, 0, 0, 0, 0, params, NULL, NULL, NULL); + if (rc != 0) { + console_printf("%s: ext disc failed (%d)", __func__, rc); + } + + return rc; +} + +static int +broadcast_sink_disc_stop(void) +{ + int rc; + + rc = ble_gap_disc_cancel(); + if (rc != 0) { + console_printf("%s: disc cancel failed (%d)", __func__, rc); + } + + return rc; +} + +static int +broadcast_sink_action_fn(struct ble_audio_broadcast_sink_action *action, void *arg) +{ + switch (action->type) { + case BLE_AUDIO_BROADCAST_SINK_ACTION_PA_SYNC: + return broadcast_sink_pa_sync_params_get(action->pa_sync.out_params); + case BLE_AUDIO_BROADCAST_SINK_ACTION_BIG_SYNC: + break; + case BLE_AUDIO_BROADCAST_SINK_ACTION_BIS_SYNC: + return 0; + case BLE_AUDIO_BROADCAST_SINK_ACTION_DISC_START: + return broadcast_sink_disc_start(action->disc_start.params_preferred); + case BLE_AUDIO_BROADCAST_SINK_ACTION_DISC_STOP: + return broadcast_sink_disc_stop(); + default: + assert(false); + return BLE_HS_ENOTSUP; + } + + return 0; +} + +static int +broadcast_sink_audio_event_handler(struct ble_audio_event *event, void *arg) +{ + switch (event->type) { + case BLE_AUDIO_EVENT_BROADCAST_SINK_PA_SYNC_STATE: + console_printf("%s: source_id=0x%02x PA sync: %s\n", __func__, + event->broadcast_sink_pa_sync_state.source_id, + ble_audio_broadcast_sink_sync_state_str( + event->broadcast_sink_pa_sync_state.state)); + break; + case BLE_AUDIO_EVENT_BROADCAST_SINK_BIS_SYNC_STATE: + console_printf("%s: source_id=0x%02x bis_index=0x%02x BIS sync: %s\n", + __func__, event->broadcast_sink_bis_sync_state.source_id, + event->broadcast_sink_bis_sync_state.bis_index, + ble_audio_broadcast_sink_sync_state_str( + event->broadcast_sink_bis_sync_state.state)); + if (event->broadcast_sink_bis_sync_state.state == + BLE_AUDIO_BROADCAST_SINK_SYNC_STATE_ESTABLISHED) { + console_printf("%s: conn_handle=0x%04x\n", __func__, + event->broadcast_sink_bis_sync_state.conn_handle); + } + break; + default: + break; + } + + return 0; +} + +static int +scan_delegator_pick_source_id_to_swap(uint8_t *out_source_id_to_swap) +{ + /* TODO: Add some logic here */ + *out_source_id_to_swap = 0; + + return 0; +} + +static int +scan_delegator_action_fn(struct ble_audio_scan_delegator_action *action, void *arg) +{ + switch (action->type) { + case BLE_AUDIO_SCAN_DELEGATOR_ACTION_SOURCE_ADD: + console_printf("%s: Source Add:\nsource_id=%u\n", __func__, + action->source_add.source_id); + if (action->source_add.out_source_id_to_swap == NULL) { + return 0; + } + return scan_delegator_pick_source_id_to_swap(action->source_add.out_source_id_to_swap); + case BLE_AUDIO_SCAN_DELEGATOR_ACTION_SOURCE_MODIFY: + console_printf("%s: Source Modify:\nsource_id=%u\n", __func__, + action->source_modify.source_id); + break; + case BLE_AUDIO_SCAN_DELEGATOR_ACTION_SOURCE_REMOVE: + console_printf("%s: Source Remove:\nsource_id=%u\n", __func__, + action->source_remove.source_id); + break; + default: + assert(false); + return BLE_HS_ENOTSUP; + } + + return 0; +} + +static int +scan_delegator_audio_event_handler(struct ble_audio_event *event, void *arg) +{ + switch (event->type) { + case BLE_AUDIO_EVENT_BROADCAST_ANNOUNCEMENT: + break; + default: + break; + } + + return 0; +} + +uint8_t +tester_init_bap(void) +{ + int rc; + + /* Make sure we have proper identity address set (public preferred) */ + rc = ble_hs_util_ensure_addr(0); + assert(rc == 0); + + /* configure global address */ + rc = ble_hs_id_infer_auto(0, &id_addr_type); + assert(rc == 0); + + memset(audio_data, 36, sizeof(char)*155); + + os_callout_init(&audio_broadcast_callout, os_eventq_dflt_get(), + audio_broadcast_event_cb, NULL); + + rc = os_mempool_init(&bis_pool, MYNEWT_VAL(BLE_ISO_MAX_BISES), + sizeof(struct ble_audio_bis), bis_mem, + "bis_pool"); + if (rc) { + return BTP_STATUS_FAILED; + } + + rc = os_mempool_init(&codec_spec_pool, + MYNEWT_VAL(BLE_ISO_MAX_BISES) * 2, 19, + codec_spec_mem, "codec_spec_pool"); + if (rc) { + return BTP_STATUS_FAILED; + } + + static struct ble_audio_event_listener broadcast_sink_listener; + + rc = ble_audio_broadcast_sink_cb_set(broadcast_sink_action_fn, NULL); + assert(rc == 0); + + rc = ble_audio_event_listener_register(&broadcast_sink_listener, + broadcast_sink_audio_event_handler, NULL); + + static struct ble_audio_event_listener scan_delegator_listener; + + rc = ble_audio_scan_delegator_action_fn_set(scan_delegator_action_fn, NULL); + assert(rc == 0); + + rc = ble_audio_event_listener_register(&scan_delegator_listener, + scan_delegator_audio_event_handler, NULL); + assert(rc == 0); + + tester_register_command_handlers(BTP_SERVICE_ID_BAP, handlers, + ARRAY_SIZE(handlers)); + + return BTP_STATUS_SUCCESS; +} + +uint8_t +tester_unregister_bap(void) +{ + return BTP_STATUS_SUCCESS; +} + +#endif /* MYNEWT_VAL(BLE_ISO_BROADCAST_SOURCE) */ + diff --git a/apps/bttester/src/btp_core.c b/apps/bttester/src/btp_core.c new file mode 100644 index 0000000000..65f3491a19 --- /dev/null +++ b/apps/bttester/src/btp_core.c @@ -0,0 +1,218 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* btp_core.c - Bluetooth BTP Core service */ + +/* + * Copyright (C) 2023 Codecoup + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "btp/btp.h" + +static uint8_t registered_services[((BTP_SERVICE_ID_MAX - 1) / 8) + 1]; + +static uint8_t +supported_commands(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + struct btp_core_read_supported_commands_rp *rp = rsp; + + *rsp_len = tester_supported_commands(BTP_SERVICE_ID_CORE, rp->data); + *rsp_len += sizeof(*rp); + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +supported_services(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + struct btp_core_read_supported_services_rp *rp = rsp; + + /* octet 0 */ + tester_set_bit(rp->data, BTP_SERVICE_ID_CORE); + tester_set_bit(rp->data, BTP_SERVICE_ID_GAP); + tester_set_bit(rp->data, BTP_SERVICE_ID_GATT); +#if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) + tester_set_bit(rp->data, BTP_SERVICE_ID_L2CAP); +#endif /* MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) */ +#if MYNEWT_VAL(BLE_MESH) + tester_set_bit(rp->data, BTP_SERVICE_ID_MESH); +#endif /* MYNEWT_VAL(BLE_MESH) */ + tester_set_bit(rp->data, BTP_SERVICE_ID_GATTC); + + *rsp_len = sizeof(*rp) + 2; + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +register_service(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_core_register_service_cmd *cp = cmd; + uint8_t status; + + /* invalid service */ + if ((cp->id == BTP_SERVICE_ID_CORE) || (cp->id > BTP_SERVICE_ID_MAX)) { + return BTP_STATUS_FAILED; + } + + /* already registered */ + if (tester_test_bit(registered_services, cp->id)) { + return BTP_STATUS_FAILED; + } + + switch (cp->id) { + case BTP_SERVICE_ID_GAP: + status = tester_init_gap(); + break; + case BTP_SERVICE_ID_GATT: + status = tester_init_gatt(); + break; +#if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) + case BTP_SERVICE_ID_L2CAP: + status = tester_init_l2cap(); + break; +#endif /* MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) */ +#if MYNEWT_VAL(BLE_MESH) + case BTP_SERVICE_ID_MESH: + status = tester_init_mesh(); + break; +#endif /* MYNEWT_VAL(BLE_MESH) */ +#if MYNEWT_VAL(BLE_ISO_BROADCAST_SOURCE) + case BTP_SERVICE_ID_BAP: + status = tester_init_bap(); + break; +#endif /* MYNEWT_VAL(BLE_ISO_BROADCASTER) */ +#if MYNEWT_VAL(BLE_AUDIO) + case BTP_SERVICE_ID_PACS: + status = tester_init_pacs(); + break; +#endif /* MYNEWT(BLE_AUDIO) */ + case BTP_SERVICE_ID_GATTC: + status = tester_init_gatt_cl(); + break; + default: + status = BTP_STATUS_FAILED; + break; + } + + if (status == BTP_STATUS_SUCCESS) { + tester_set_bit(registered_services, cp->id); + } + + return status; +} + +static uint8_t +unregister_service(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_core_unregister_service_cmd *cp = cmd; + uint8_t status; + + /* invalid service ID */ + if ((cp->id == BTP_SERVICE_ID_CORE) || (cp->id > BTP_SERVICE_ID_MAX)) { + return BTP_STATUS_FAILED; + } + + /* not registered */ + if (!tester_test_bit(registered_services, cp->id)) { + return BTP_STATUS_FAILED; + } + + switch (cp->id) { + case BTP_SERVICE_ID_GAP: + status = tester_unregister_gap(); + break; + case BTP_SERVICE_ID_GATT: + status = tester_unregister_gatt(); + break; +#if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) + case BTP_SERVICE_ID_L2CAP: + status = tester_unregister_l2cap(); + break; +#endif /* MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) */ +#if MYNEWT_VAL(BLE_MESH) + case BTP_SERVICE_ID_MESH: + status = tester_unregister_mesh(); + break; +#endif /* MYNEWT_VAL(BLE_MESH) */ + case BTP_SERVICE_ID_GATTC: + status = tester_unregister_gatt_cl(); + break; +#if MYNEWT_VAL(BLE_ISO_BROADCAST_SOURCE) + case BTP_SERVICE_ID_BAP: + status = tester_unregister_bap(); + break; +#endif /* MYNEWT_VAL(BLE_ISO_BROADCAST_SOURCE) */ +#if MYNEWT_VAL(BLE_AUDIO) + case BTP_SERVICE_ID_PACS: + status = tester_unregister_pacs(); + break; +#endif /* MYNEWT_VAL (BLE_AUDIO) */ + default: + status = BTP_STATUS_FAILED; + break; + } + + if (status == BTP_STATUS_SUCCESS) { + tester_clear_bit(registered_services, cp->id); + } + + return status; +} + +static const struct btp_handler handlers[] = { + { + .opcode = BTP_CORE_READ_SUPPORTED_COMMANDS, + .index = BTP_INDEX_NONE, + .expect_len = 0, + .func = supported_commands, + }, + { + .opcode = BTP_CORE_READ_SUPPORTED_SERVICES, + .index = BTP_INDEX_NONE, + .expect_len = 0, + .func = supported_services, + }, + { + .opcode = BTP_CORE_REGISTER_SERVICE, + .index = BTP_INDEX_NONE, + .expect_len = sizeof(struct btp_core_register_service_cmd), + .func = register_service, + }, + { + .opcode = BTP_CORE_UNREGISTER_SERVICE, + .index = BTP_INDEX_NONE, + .expect_len = sizeof(struct btp_core_unregister_service_cmd), + .func = unregister_service, + }, +}; + +void +tester_init_core(void) +{ + tester_register_command_handlers(BTP_SERVICE_ID_CORE, handlers, + ARRAY_SIZE(handlers)); + tester_set_bit(registered_services, BTP_SERVICE_ID_CORE); +} diff --git a/apps/bttester/src/btp_gap.c b/apps/bttester/src/btp_gap.c new file mode 100644 index 0000000000..29fb50a103 --- /dev/null +++ b/apps/bttester/src/btp_gap.c @@ -0,0 +1,2497 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* gap.c - Bluetooth GAP Tester */ + +/* + * Copyright (c) 2015-2016 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "host/ble_gap.h" +#include "host/util/util.h" +#include "console/console.h" + +#include "../../../nimble/host/src/ble_hs_pvcy_priv.h" +#include "../../../nimble/host/src/ble_hs_hci_priv.h" +#include "../../../nimble/host/src/ble_sm_priv.h" + +#include "btp/btp.h" + +#include + +#define CONTROLLER_INDEX 0 +#define CONTROLLER_NAME "btp_tester" + +#define BLE_AD_DISCOV_MASK (BLE_HS_ADV_F_DISC_LTD | BLE_HS_ADV_F_DISC_GEN) +#define ADV_BUF_LEN (sizeof(struct btp_gap_device_found_ev) + 2 * 31) + +/* parameter values to reject in CPUP if all match the pattern */ +#define REJECT_INTERVAL_MIN 0x0C80 +#define REJECT_INTERVAL_MAX 0x0C80 +#define REJECT_LATENCY 0x0000 +#define REJECT_SUPERVISION_TIMEOUT 0x0C80 + +const uint8_t irk[16] = { + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, +}; + +static uint8_t oob[16]; +static struct ble_sm_sc_oob_data oob_data_local; +static struct ble_sm_sc_oob_data oob_data_remote; + +static uint16_t current_settings; +uint8_t own_addr_type; +static ble_addr_t peer_id_addr; +static ble_addr_t peer_ota_addr; +static bool encrypted = false; + +static bool use_filter_policy = false; + +static struct os_callout update_params_co; +static struct btp_gap_conn_param_update_cmd update_params; + +static struct os_callout connected_ev_co; +static struct btp_gap_device_connected_ev connected_ev; +#define CONNECTED_EV_DELAY_MS(itvl) 8 * BLE_HCI_CONN_ITVL * itvl / 1000 +static int connection_attempts; +#if MYNEWT_VAL(BTTESTER_PRIVACY_MODE) && MYNEWT_VAL(BTTESTER_USE_NRPA) +static int64_t advertising_start; +static struct os_callout bttester_nrpa_rotate_timer; +#endif + +static const struct ble_gap_conn_params dflt_conn_params = { + .scan_itvl = 0x0010, + .scan_window = 0x0010, + .itvl_min = BLE_GAP_INITIAL_CONN_ITVL_MIN, + .itvl_max = BLE_GAP_INITIAL_CONN_ITVL_MAX, + .latency = 0, + .supervision_timeout = 0x0100, + .min_ce_len = 0x0010, + .max_ce_len = 0x0300, +}; + +static int +gap_conn_find_by_addr(const ble_addr_t *dev_addr, + struct ble_gap_conn_desc *out_desc) +{ + ble_addr_t addr = *dev_addr; + + if (memcmp(BLE_ADDR_ANY, &peer_id_addr, 6) == 0) { + return ble_gap_conn_find_by_addr(&addr, out_desc); + } + + if (BLE_ADDR_IS_RPA(&addr)) { + if (ble_addr_cmp(&peer_ota_addr, &addr) != 0) { + return -1; + } + + return ble_gap_conn_find_by_addr(&addr, out_desc); + } else { + if (ble_addr_cmp(&peer_id_addr, &addr) != 0) { + return -1; + } + + if (BLE_ADDR_IS_RPA(&peer_ota_addr)) { + /* Change addr type to ID addr */ + addr.type |= 2; + } + + return ble_gap_conn_find_by_addr(&addr, out_desc); + } +} + +static int +gap_event_cb(struct ble_gap_event *event, void *arg); + +static uint8_t +supported_commands(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + struct btp_gap_read_supported_commands_rp *rp = rsp; + + *rsp_len = tester_supported_commands(BTP_SERVICE_ID_GAP, rp->data); + *rsp_len += sizeof(*rp); + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +controller_index_list(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + struct btp_gap_read_controller_index_list_rp *rp = rsp; + + SYS_LOG_DBG(""); + + rp->num = 1; + rp->index[0] = CONTROLLER_INDEX; + + *rsp_len = sizeof(*rp) + 1; + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +controller_info(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + struct btp_gap_read_controller_info_rp *rp = rsp; + uint32_t supported_settings = 0; + ble_addr_t addr; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_hs_pvcy_set_our_irk(irk); + assert(rc == 0); + + /* Make sure we have proper identity address set (public preferred) */ + rc = ble_hs_util_ensure_addr(1); + assert(rc == 0); + rc = ble_hs_id_copy_addr(BLE_ADDR_RANDOM, addr.val, NULL); + assert(rc == 0); + + if (MYNEWT_VAL(BTTESTER_PRIVACY_MODE)) { + if (MYNEWT_VAL(BTTESTER_USE_NRPA)) { + own_addr_type = BLE_OWN_ADDR_RANDOM; + rc = ble_hs_id_gen_rnd(1, &addr); + assert(rc == 0); + rc = ble_hs_id_set_rnd(addr.val); + assert(rc == 0); + } else { + own_addr_type = BLE_OWN_ADDR_RPA_RANDOM_DEFAULT; + } + current_settings |= BIT(BTP_GAP_SETTINGS_PRIVACY); + supported_settings |= BIT(BTP_GAP_SETTINGS_PRIVACY); + memcpy(&rp->address, &addr, sizeof(rp->address)); + } else { + rc = ble_hs_id_copy_addr(BLE_ADDR_PUBLIC, rp->address, NULL); + if (rc) { + own_addr_type = BLE_OWN_ADDR_RANDOM; + memcpy(rp->address, addr.val, sizeof(rp->address)); + supported_settings |= BIT(BTP_GAP_SETTINGS_STATIC_ADDRESS); + current_settings |= BIT(BTP_GAP_SETTINGS_STATIC_ADDRESS); + } else { + own_addr_type = BLE_OWN_ADDR_PUBLIC; + } + } + + supported_settings |= BIT(BTP_GAP_SETTINGS_POWERED); + supported_settings |= BIT(BTP_GAP_SETTINGS_CONNECTABLE); + supported_settings |= BIT(BTP_GAP_SETTINGS_BONDABLE); + supported_settings |= BIT(BTP_GAP_SETTINGS_LE); + supported_settings |= BIT(BTP_GAP_SETTINGS_ADVERTISING); + supported_settings |= BIT(BTP_GAP_SETTINGS_SC); + + if (ble_hs_cfg.sm_bonding) { + current_settings |= BIT(BTP_GAP_SETTINGS_BONDABLE); + } + if (ble_hs_cfg.sm_sc) { + current_settings |= BIT(BTP_GAP_SETTINGS_SC); + } + + rp->supported_settings = htole32(supported_settings); + rp->current_settings = htole32(current_settings); + + memcpy(rp->name, CONTROLLER_NAME, sizeof(CONTROLLER_NAME)); + + *rsp_len = sizeof(*rp); + + return BTP_STATUS_SUCCESS; +} + +#if MYNEWT_VAL(BLE_EXT_ADV) +static struct ble_gap_ext_adv_params adv_params = { + .primary_phy = BLE_HCI_LE_PHY_1M, + .secondary_phy = BLE_HCI_LE_PHY_1M, + .sid = 1, + .legacy_pdu = 1, +}; +#else +static struct ble_gap_adv_params adv_params = { + .conn_mode = BLE_GAP_CONN_MODE_NON, + .disc_mode = BLE_GAP_DISC_MODE_NON, +}; +#endif + +static uint8_t ad_flags = BLE_HS_ADV_F_BREDR_UNSUP; + +#if MYNEWT_VAL(BTTESTER_PRIVACY_MODE) && MYNEWT_VAL(BTTESTER_USE_NRPA) +static void rotate_nrpa_cb(struct os_event *ev) +{ + int rc; + ble_addr_t addr; + int32_t duration_ms = BLE_HS_FOREVER; + int32_t remaining_time; + os_time_t remaining_ticks; + + if (current_settings & BIT(BTP_GAP_SETTINGS_DISCOVERABLE)) { + if (ad_flags & BLE_HS_ADV_F_DISC_LTD) { + duration_ms = MYNEWT_VAL(BTTESTER_LTD_ADV_TIMEOUT); + } + } + +#if MYNEWT_VAL(BLE_EXT_ADV) + ble_gap_ext_adv_stop(0); +#else + ble_gap_adv_stop(); +#endif + + rc = ble_hs_id_gen_rnd(1, &addr); + assert(rc == 0); + rc = ble_hs_id_set_rnd(addr.val); + assert(rc == 0); + +#if MYNEWT_VAL(BLE_EXT_ADV) + ble_gap_ext_adv_start(0, duration_ms / 10, 0); +#else + ble_gap_adv_start(own_addr_type, NULL, duration_ms, + &adv_params, gap_event_cb, NULL); +#endif + + remaining_time = os_get_uptime_usec() - advertising_start; + if (remaining_time > 0) { + advertising_start = os_get_uptime_usec(); + os_time_ms_to_ticks(remaining_time, &remaining_ticks); + os_callout_reset(&bttester_nrpa_rotate_timer, + remaining_ticks); + } +} +#endif + +static uint8_t +set_connectable(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gap_set_connectable_cmd *cp = cmd; + struct btp_gap_set_connectable_rp *rp = rsp; + + SYS_LOG_DBG(""); + + if (cp->connectable) { + current_settings |= BIT(BTP_GAP_SETTINGS_CONNECTABLE); +#if MYNEWT_VAL(BLE_EXT_ADV) + adv_params.connectable = 1; + adv_params.scannable = 1; +#else + adv_params.conn_mode = BLE_GAP_CONN_MODE_UND; +#endif + } else { + current_settings &= ~BIT(BTP_GAP_SETTINGS_CONNECTABLE); +#if MYNEWT_VAL(BLE_EXT_ADV) + adv_params.connectable = 0; + adv_params.scannable = 0; +#else + adv_params.conn_mode = BLE_GAP_CONN_MODE_NON; +#endif + } + + rp->current_settings = htole32(current_settings); + + *rsp_len = sizeof(*rp); + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +set_discoverable(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gap_set_discoverable_cmd *cp = cmd; + struct btp_gap_set_discoverable_rp *rp = rsp; + + SYS_LOG_DBG(""); + + switch (cp->discoverable) { + case BTP_GAP_NON_DISCOVERABLE: + ad_flags &= ~(BLE_HS_ADV_F_DISC_GEN | BLE_HS_ADV_F_DISC_LTD); +#if !MYNEWT_VAL(BLE_EXT_ADV) + adv_params.disc_mode = BLE_GAP_DISC_MODE_NON; +#endif + current_settings &= ~BIT(BTP_GAP_SETTINGS_DISCOVERABLE); + break; + case BTP_GAP_GENERAL_DISCOVERABLE: + ad_flags &= ~BLE_HS_ADV_F_DISC_LTD; + ad_flags |= BLE_HS_ADV_F_DISC_GEN; +#if !MYNEWT_VAL(BLE_EXT_ADV) + adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN; +#endif + current_settings |= BIT(BTP_GAP_SETTINGS_DISCOVERABLE); + break; + case BTP_GAP_LIMITED_DISCOVERABLE: + ad_flags &= ~BLE_HS_ADV_F_DISC_GEN; + ad_flags |= BLE_HS_ADV_F_DISC_LTD; +#if !MYNEWT_VAL(BLE_EXT_ADV) + adv_params.disc_mode = BLE_GAP_DISC_MODE_LTD; +#endif + current_settings |= BIT(BTP_GAP_SETTINGS_DISCOVERABLE); + break; + default: + return BTP_STATUS_FAILED; + } + + rp->current_settings = htole32(current_settings); + + *rsp_len = sizeof(*rp); + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +set_bondable(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gap_set_bondable_cmd *cp = cmd; + struct btp_gap_set_bondable_rp *rp = rsp; + + SYS_LOG_DBG("bondable: %d", cp->bondable); + + ble_hs_cfg.sm_bonding = cp->bondable; + if (ble_hs_cfg.sm_bonding) { + current_settings |= BIT(BTP_GAP_SETTINGS_BONDABLE); + } else { + current_settings &= ~BIT(BTP_GAP_SETTINGS_BONDABLE); + } + + rp->current_settings = htole32(current_settings); + *rsp_len = sizeof(*rp); + return BTP_STATUS_SUCCESS; +} + +static struct adv_data ad[10] = { + ADV_DATA(BLE_HS_ADV_TYPE_FLAGS, &ad_flags, sizeof(ad_flags)), +}; +static struct adv_data sd[10]; + +static int +set_ad(const struct adv_data *ad_data, size_t ad_len, + uint8_t *buf, uint8_t *buf_len) +{ + int i; + + for (i = 0; i < ad_len; i++) { + buf[(*buf_len)++] = ad_data[i].data_len + 1; + buf[(*buf_len)++] = ad_data[i].type; + + memcpy(&buf[*buf_len], ad_data[i].data, + ad_data[i].data_len); + *buf_len += ad_data[i].data_len; + } + + return 0; +} + +static uint8_t +start_advertising(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gap_start_advertising_cmd *cp = cmd; + struct btp_gap_start_advertising_rp *rp = rsp; + uint8_t buf[BLE_HS_ADV_MAX_SZ]; + uint8_t buf_len = 0; + uint8_t adv_len, sd_len = 0; + uint8_t addr_type; + uint32_t duration; + int err; + int i; +#if MYNEWT_VAL(BLE_EXT_ADV) + struct os_mbuf *ad_buf; + int duration_ms = 0; +#else + int32_t duration_ms = BLE_HS_FOREVER; +#endif + + SYS_LOG_DBG(""); + + /* This command is very unfortunate since after variable data there is + * additional 5 bytes (4 bytes for duration, 1 byte for own address + * type. + */ + if ((cmd_len < sizeof(*cp)) || + (cmd_len != sizeof(*cp) + cp->adv_data_len + cp->scan_rsp_len + + sizeof(duration) + sizeof(own_addr_type))) { + return BTP_STATUS_FAILED; + } + + /* currently ignored */ + duration = get_le32(cp->adv_sr_data + cp->adv_data_len + cp->scan_rsp_len); + (void)duration; + addr_type = cp->adv_sr_data[cp->adv_data_len + + cp->scan_rsp_len + + sizeof(duration)]; + + for (i = 0, adv_len = 1U; i < cp->adv_data_len; adv_len++) { + if (adv_len >= ARRAY_SIZE(ad)) { + SYS_LOG_ERR("ad[] Out of memory"); + return BTP_STATUS_FAILED; + } + + ad[adv_len].type = cp->adv_sr_data[i++]; + ad[adv_len].data_len = cp->adv_sr_data[i++]; + ad[adv_len].data = &cp->adv_sr_data[i]; + i += ad[adv_len].data_len; + } + + for (sd_len = 0U; i < (cp->adv_data_len + cp->scan_rsp_len); sd_len++) { + if (sd_len >= ARRAY_SIZE(sd)) { + SYS_LOG_ERR("sd[] Out of memory"); + return BTP_STATUS_FAILED; + } + + sd[sd_len].type = cp->adv_sr_data[i++]; + sd[sd_len].data_len = cp->adv_sr_data[i++]; + sd[sd_len].data = &cp->adv_sr_data[i]; + i += sd[sd_len].data_len; + } + + err = set_ad(ad, adv_len, buf, &buf_len); + if (err) { + return BTP_STATUS_FAILED; + } + +#if MYNEWT_VAL(BLE_EXT_ADV) + adv_params.own_addr_type = own_addr_type; + + if (sd_len != 0 && adv_params.legacy_pdu) { + adv_params.scannable = 1; + } + + if (use_filter_policy) { + adv_params.filter_policy = BLE_HCI_ADV_FILT_BOTH; + } + + err = ble_gap_ext_adv_configure(0, &adv_params, NULL, gap_event_cb, NULL); + if (err) { + SYS_LOG_ERR("Failed to configure extended advertiser; rc=%d", err); + return BTP_STATUS_FAILED; + } + + ad_buf = os_msys_get_pkthdr(BLE_HS_ADV_MAX_SZ, 0); + + if (os_mbuf_append(ad_buf, buf, buf_len)) { + os_mbuf_free_chain(ad_buf); + return BTP_STATUS_FAILED; + } + err = ble_gap_ext_adv_set_data(0, ad_buf); +#else + err = ble_gap_adv_set_data(buf, buf_len); +#endif + if (err) { + SYS_LOG_ERR("Failed to set advertising data; rc=%d", err); + return BTP_STATUS_FAILED; + } + + if (sd_len) { + buf_len = 0; + + err = set_ad(sd, sd_len, buf, &buf_len); + if (err) { + SYS_LOG_ERR("Advertising failed: err %d", err); + return BTP_STATUS_FAILED; + } + +#if MYNEWT_VAL(BLE_EXT_ADV) + ad_buf = os_msys_get_pkthdr(BLE_HS_ADV_MAX_SZ, 0); + + if (os_mbuf_append(ad_buf, buf, buf_len)) { + os_mbuf_free_chain(ad_buf); + return BTP_STATUS_FAILED; + } + err = ble_gap_ext_adv_rsp_set_data(0, ad_buf); +#else + err = ble_gap_adv_rsp_set_data(buf, buf_len); +#endif + if (err != 0) { + SYS_LOG_ERR("Advertising failed: err %d", err); + return BTP_STATUS_FAILED; + } + } + + if (current_settings & BIT(BTP_GAP_SETTINGS_DISCOVERABLE)) { + if (ad_flags & BLE_HS_ADV_F_DISC_LTD) { + duration_ms = MYNEWT_VAL(BTTESTER_LTD_ADV_TIMEOUT); + } + } + + /* In NimBLE, own_addr_type is configured in `controller_info` function. + * Let's just verify restrictions for Privacy options. + */ + switch (addr_type) { + case 0x00: + break; +#if MYNEWT_VAL(BTTESTER_PRIVACY_MODE) + case 0x01: + /* RPA usage is is controlled via privacy settings */ + if (!(current_settings & BIT(BTP_GAP_SETTINGS_PRIVACY))) { + return BTP_STATUS_FAILED; + } + break; + case 0x02: + /* NRPA is used only for non-connectable advertising */ + if (!(current_settings & BIT(BTP_GAP_SETTINGS_CONNECTABLE))) { + return BTP_STATUS_FAILED; + } + break; +#endif + default: + return BTP_STATUS_FAILED; + } + +#if MYNEWT_VAL(BTTESTER_PRIVACY_MODE) && MYNEWT_VAL(BTTESTER_USE_NRPA) + if (MYNEWT_VAL(BTTESTER_NRPA_TIMEOUT) < duration_ms / 1000) { + advertising_start = os_get_uptime_usec(); + os_callout_reset(&bttester_nrpa_rotate_timer, + OS_TICKS_PER_SEC * MYNEWT_VAL(BTTESTER_NRPA_TIMEOUT)); + } +#endif + +#if MYNEWT_VAL(BLE_EXT_ADV) + err = ble_gap_ext_adv_start(0, duration_ms / 10, 0); +#else + err = ble_gap_adv_start(own_addr_type, NULL, duration_ms, + &adv_params, gap_event_cb, NULL); +#endif + if (err) { + SYS_LOG_ERR("Advertising failed: err %d", err); + return BTP_STATUS_FAILED; + } + + current_settings |= BIT(BTP_GAP_SETTINGS_ADVERTISING); + rp->current_settings = htole32(current_settings); + + *rsp_len = sizeof(*rp); + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +stop_advertising(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + struct btp_gap_stop_advertising_rp *rp = rsp; + + SYS_LOG_DBG(""); + +#if MYNEWT_VAL(BLE_EXT_ADV) + if (ble_gap_ext_adv_stop(0) != 0) { + return BTP_STATUS_FAILED; + } +#else + if (ble_gap_adv_stop() != 0) { + return BTP_STATUS_FAILED; + } +#endif + + current_settings &= ~BIT(BTP_GAP_SETTINGS_ADVERTISING); + rp->current_settings = htole32(current_settings); + + *rsp_len = sizeof(*rp); + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +get_ad_flags(const uint8_t *data, uint8_t data_len) +{ + uint8_t len, i; + + /* Parse advertisement to get flags */ + for (i = 0; i < data_len; i += len - 1) { + len = data[i++]; + if (!len) { + break; + } + + /* Check if field length is correct */ + if (len > (data_len - i) || (data_len - i) < 1) { + break; + } + + switch (data[i++]) { + case BLE_HS_ADV_TYPE_FLAGS: + return data[i]; + default: + break; + } + } + + return 0; +} + +static uint8_t discovery_flags; +static struct os_mbuf *adv_buf; + +static void +store_adv(const ble_addr_t *addr, int8_t rssi, + const uint8_t *data, uint8_t len) +{ + struct btp_gap_device_found_ev *ev; + void *adv_data; + /* cleanup */ + tester_mbuf_reset(adv_buf); + + ev = os_mbuf_extend(adv_buf, sizeof(*ev)); + if (!ev) { + return; + } + + memcpy(&ev->address, addr, sizeof(ev->address)); + ev->rssi = rssi; + ev->flags = BTP_GAP_DEVICE_FOUND_FLAG_AD | BTP_GAP_DEVICE_FOUND_FLAG_RSSI; + ev->eir_data_len = len; + + adv_data = os_mbuf_extend(adv_buf, len); + if (!adv_data) { + return; + } + + memcpy(adv_data, data, len); +} + +static void +device_found(ble_addr_t *addr, int8_t rssi, uint8_t evtype, + const uint8_t *data, uint8_t len) +{ + struct btp_gap_device_found_ev *ev; + void *adv_data; + ble_addr_t a; + + /* if General/Limited Discovery - parse Advertising data to get flags */ + if (!(discovery_flags & BTP_GAP_DISCOVERY_FLAG_LE_OBSERVE) && + (evtype != BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP)) { + uint8_t flags = get_ad_flags(data, len); + + /* ignore non-discoverable devices */ + if (!(flags & BLE_AD_DISCOV_MASK)) { + SYS_LOG_DBG("Non discoverable, skipping"); + return; + } + + /* if Limited Discovery - ignore general discoverable devices */ + if ((discovery_flags & BTP_GAP_DISCOVERY_FLAG_LIMITED) && + !(flags & BLE_HS_ADV_F_DISC_LTD)) { + SYS_LOG_DBG("General discoverable, skipping"); + return; + } + } + + /* attach Scan Response data */ + if (evtype == BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP) { + /* skip if there is no pending advertisement */ + if (!adv_buf->om_len) { + SYS_LOG_INF("No pending advertisement, skipping"); + return; + } + + ev = (void *) adv_buf->om_data; + memcpy(&a, &ev->address, sizeof(a)); + + /* + * in general, the Scan Response comes right after the + * Advertisement, but if not if send stored event and ignore + * this one + */ + if (ble_addr_cmp(addr, &a)) { + SYS_LOG_INF("Address does not match, skipping"); + goto done; + } + + ev->eir_data_len += len; + ev->flags |= BTP_GAP_DEVICE_FOUND_FLAG_SD; + + adv_data = os_mbuf_extend(adv_buf, len); + if (!adv_data) { + return; + } + + memcpy(adv_data, data, len); + + goto done; + } + + /* + * if there is another pending advertisement, send it and store the + * current one + */ + if (adv_buf->om_len) { + tester_event(BTP_SERVICE_ID_GAP, BTP_GAP_EV_DEVICE_FOUND, + adv_buf->om_data, adv_buf->om_len); + } + + store_adv(addr, rssi, data, len); + + /* if Active Scan and scannable event - wait for Scan Response */ + if ((discovery_flags & BTP_GAP_DISCOVERY_FLAG_LE_ACTIVE_SCAN) && + (evtype == BLE_HCI_ADV_RPT_EVTYPE_ADV_IND || + evtype == BLE_HCI_ADV_RPT_EVTYPE_SCAN_IND)) { + SYS_LOG_DBG("Waiting for scan response"); + return; + } +done: + tester_event(BTP_SERVICE_ID_GAP, BTP_GAP_EV_DEVICE_FOUND, + adv_buf->om_data, adv_buf->om_len); +} + +static int +discovery_cb(struct ble_gap_event *event, void *arg) +{ + if (event->type == BLE_GAP_EVENT_DISC) { + device_found(&event->disc.addr, event->disc.rssi, + event->disc.event_type, event->disc.data, + event->disc.length_data); + } + + return 0; +} + +static uint8_t +start_discovery(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gap_start_discovery_cmd *cp = cmd; + struct ble_gap_disc_params params = {0}; + + SYS_LOG_DBG(""); + + /* only LE scan is supported */ + if (cp->flags & BTP_GAP_DISCOVERY_FLAG_BREDR) { + return BTP_STATUS_FAILED; + } + + params.passive = (cp->flags & BTP_GAP_DISCOVERY_FLAG_LE_ACTIVE_SCAN) == 0; + params.limited = (cp->flags & BTP_GAP_DISCOVERY_FLAG_LIMITED) > 0; + params.filter_duplicates = 1; + + if (ble_gap_disc(own_addr_type, BLE_HS_FOREVER, + ¶ms, discovery_cb, NULL) != 0) { + return BTP_STATUS_FAILED; + } + + tester_mbuf_reset(adv_buf); + discovery_flags = cp->flags; + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +stop_discovery(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + SYS_LOG_DBG(""); + + if (ble_gap_disc_cancel() != 0) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +/* Bluetooth Core Spec v5.1 | Section 10.7.1 + * If a privacy-enabled Peripheral, that has a stored bond, + * receives a resolvable private address, the Host may resolve + * the resolvable private address [...] + * If the resolution is successful, the Host may accept the connection. + * If the resolution procedure fails, then the Host shall disconnect + * with the error code "Authentication failure" [...] + */ +static void +periph_privacy(struct ble_gap_conn_desc desc) +{ +#if !MYNEWT_VAL(BTTESTER_PRIVACY_MODE) + return; +#endif + int count; + + SYS_LOG_DBG(""); + + ble_store_util_count(BLE_STORE_OBJ_TYPE_PEER_SEC, &count); + if (count > 0 && BLE_ADDR_IS_RPA(&desc.peer_id_addr)) { + SYS_LOG_DBG("Authentication failure, disconnecting"); + ble_gap_terminate(desc.conn_handle, BLE_ERR_AUTH_FAIL); + } +} + +static void +device_connected_ev_send(struct os_event *ev) +{ + struct ble_gap_conn_desc desc; + int rc; + + SYS_LOG_DBG(""); + + rc = gap_conn_find_by_addr((ble_addr_t *) &connected_ev, &desc); + if (rc) { + tester_rsp(BTP_SERVICE_ID_GAP, BTP_GAP_EV_DEVICE_CONNECTED, + BTP_STATUS_FAILED); + return; + } + + tester_event(BTP_SERVICE_ID_GAP, BTP_GAP_EV_DEVICE_CONNECTED, + (uint8_t *) &connected_ev, sizeof(connected_ev)); + + periph_privacy(desc); +} + +static void +le_connected(uint16_t conn_handle, int status) +{ + struct ble_gap_conn_desc desc; + ble_addr_t *addr; + int rc; + + SYS_LOG_DBG(""); + + if (status != 0) { + return; + } + + rc = ble_gap_conn_find(conn_handle, &desc); + if (rc) { + return; + } + + peer_id_addr = desc.peer_id_addr; + peer_ota_addr = desc.peer_ota_addr; + + addr = &desc.peer_id_addr; + + memcpy(&connected_ev.address, addr, sizeof(connected_ev.address)); + connected_ev.conn_itvl = desc.conn_itvl; + connected_ev.conn_latency = desc.conn_latency; + connected_ev.supervision_timeout = desc.supervision_timeout; + +#if MYNEWT_VAL(BTTESTER_CONN_RETRY) + os_callout_reset(&connected_ev_co, + os_time_ms_to_ticks32( + CONNECTED_EV_DELAY_MS(desc.conn_itvl))); +#else + tester_event(BTP_SERVICE_ID_GAP, BTP_GAP_EV_DEVICE_CONNECTED, + (uint8_t *) &connected_ev, + sizeof(connected_ev)); +#endif +} + +static void +le_disconnected(struct ble_gap_conn_desc *conn, int reason) +{ + struct btp_gap_device_disconnected_ev ev; + ble_addr_t *addr = &conn->peer_ota_addr; + + SYS_LOG_DBG(""); + +#if MYNEWT_VAL(BTTESTER_CONN_RETRY) + int rc; + + if ((reason == BLE_HS_HCI_ERR(BLE_ERR_CONN_ESTABLISHMENT)) && + os_callout_queued(&connected_ev_co)) { + if (connection_attempts < MYNEWT_VAL(BTTESTER_CONN_RETRY)) { + os_callout_stop(&connected_ev_co); + + /* try connecting again */ + rc = ble_gap_connect(own_addr_type, addr, 0, + &dflt_conn_params, gap_event_cb, + NULL); + + if (rc == 0) { + connection_attempts++; + return; + } + } + } else if (os_callout_queued(&connected_ev_co)) { + os_callout_stop(&connected_ev_co); + return; + } +#endif + + connection_attempts = 0; + memset(&connected_ev, 0, sizeof(connected_ev)); + + memcpy(&ev.address, addr, sizeof(ev.address)); + + tester_event(BTP_SERVICE_ID_GAP, BTP_GAP_EV_DEVICE_DISCONNECTED, + (uint8_t *) &ev, sizeof(ev)); +} + +static void +auth_passkey_oob(uint16_t conn_handle) +{ + struct ble_gap_conn_desc desc; + struct ble_sm_io pk; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find(conn_handle, &desc); + if (rc) { + return; + } + + memcpy(pk.oob, oob, sizeof(oob)); + pk.action = BLE_SM_IOACT_OOB; + + rc = ble_sm_inject_io(conn_handle, &pk); + assert(rc == 0); +} + +static void +auth_passkey_display(uint16_t conn_handle, unsigned int passkey) +{ + struct ble_gap_conn_desc desc; + struct btp_gap_passkey_display_ev ev; + ble_addr_t *addr; + struct ble_sm_io pk; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find(conn_handle, &desc); + if (rc) { + return; + } + + rc = ble_hs_hci_rand(&pk.passkey, sizeof(pk.passkey)); + assert(rc == 0); + /* Max value is 999999 */ + pk.passkey %= 1000000; + pk.action = BLE_SM_IOACT_DISP; + + rc = ble_sm_inject_io(conn_handle, &pk); + assert(rc == 0); + + addr = &desc.peer_ota_addr; + + memcpy(&ev.address, addr, sizeof(ev.address)); + ev.passkey = htole32(pk.passkey); + + tester_event(BTP_SERVICE_ID_GAP, BTP_GAP_EV_PASSKEY_DISPLAY, + (uint8_t *) &ev, sizeof(ev)); +} + +static void +auth_passkey_entry(uint16_t conn_handle) +{ + struct ble_gap_conn_desc desc; + struct btp_gap_passkey_entry_req_ev ev; + ble_addr_t *addr; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find(conn_handle, &desc); + if (rc) { + return; + } + + addr = &desc.peer_ota_addr; + + memcpy(&ev.address, addr, sizeof(ev.address)); + + tester_event(BTP_SERVICE_ID_GAP, BTP_GAP_EV_PASSKEY_ENTRY_REQ, + (uint8_t *) &ev, sizeof(ev)); +} + +static void +auth_passkey_numcmp(uint16_t conn_handle, unsigned int passkey) +{ + struct ble_gap_conn_desc desc; + struct btp_gap_passkey_confirm_req_ev ev; + ble_addr_t *addr; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find(conn_handle, &desc); + if (rc) { + return; + } + + addr = &desc.peer_ota_addr; + + memcpy(&ev.address, addr, sizeof(ev.address)); + ev.passkey = htole32(passkey); + + tester_event(BTP_SERVICE_ID_GAP, BTP_GAP_EV_PASSKEY_CONFIRM_REQ, + (uint8_t *) &ev, sizeof(ev)); +} + +static void +auth_passkey_oob_sc(uint16_t conn_handle) +{ + int rc; + struct ble_sm_io pk; + + SYS_LOG_DBG(""); + + memset(&pk, 0, sizeof(pk)); + + pk.oob_sc_data.local = &oob_data_local; + + if (ble_hs_cfg.sm_oob_data_flag) { + pk.oob_sc_data.remote = &oob_data_remote; + } + + pk.action = BLE_SM_IOACT_OOB_SC; + rc = ble_sm_inject_io(conn_handle, &pk); + if (rc != 0) { + console_printf("error providing oob; rc=%d\n", rc); + } +} + +static void +le_passkey_action(uint16_t conn_handle, + struct ble_gap_passkey_params *params) +{ + SYS_LOG_DBG(""); + + switch (params->action) { + case BLE_SM_IOACT_NONE: + break; + case BLE_SM_IOACT_OOB: + auth_passkey_oob(conn_handle); + break; + case BLE_SM_IOACT_INPUT: + auth_passkey_entry(conn_handle); + break; + case BLE_SM_IOACT_DISP: + auth_passkey_display(conn_handle, + params->numcmp); + break; + case BLE_SM_IOACT_NUMCMP: + auth_passkey_numcmp(conn_handle, + params->numcmp); + break; + case BLE_SM_IOACT_OOB_SC: + auth_passkey_oob_sc(conn_handle); + break; + default: + assert(0); + } +} + +static void +le_identity_resolved(uint16_t conn_handle) +{ + struct ble_gap_conn_desc desc; + struct btp_gap_identity_resolved_ev ev; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find(conn_handle, &desc); + if (rc) { + return; + } + + peer_id_addr = desc.peer_id_addr; + peer_ota_addr = desc.peer_ota_addr; + + memcpy(&ev.address, &desc.peer_ota_addr, sizeof(ev.address)); + + memcpy(&ev.identity_address, &desc.peer_id_addr, + sizeof(ev.identity_address)); + + tester_event(BTP_SERVICE_ID_GAP, BTP_GAP_EV_IDENTITY_RESOLVED, + (uint8_t *) &ev, sizeof(ev)); +} + +static void +le_pairing_failed(uint16_t conn_handle, int reason) +{ + struct ble_gap_conn_desc desc; + struct btp_gap_sec_pairing_failed_ev ev; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find(conn_handle, &desc); + if (rc) { + return; + } + + peer_id_addr = desc.peer_id_addr; + peer_ota_addr = desc.peer_ota_addr; + + memcpy(&ev.address, &desc.peer_ota_addr, sizeof(ev.address)); + + ev.reason = reason; + + tester_event(BTP_SERVICE_ID_GAP, BTP_GAP_EV_SEC_PAIRING_FAILED, + (uint8_t *) &ev, sizeof(ev)); +} + +static void +le_conn_param_update(struct ble_gap_conn_desc *desc) +{ + struct btp_gap_conn_param_update_ev ev; + + SYS_LOG_DBG(""); + + memcpy(&ev.address, &desc->peer_ota_addr, sizeof(ev.address)); + + ev.conn_itvl = desc->conn_itvl; + ev.conn_latency = desc->conn_latency; + ev.supervision_timeout = desc->supervision_timeout; + + tester_event(BTP_SERVICE_ID_GAP, BTP_GAP_EV_CONN_PARAM_UPDATE, + (uint8_t *) &ev, sizeof(ev)); +} + +static void +le_encryption_changed(struct ble_gap_conn_desc *desc) +{ + struct btp_gap_sec_level_changed_ev ev; + + SYS_LOG_DBG(""); + + encrypted = (bool) desc->sec_state.encrypted; + + memcpy(&ev.address, &desc->peer_ota_addr, sizeof(ev.address)); + ev.level = 0; + + if (desc->sec_state.encrypted) { + if (desc->sec_state.authenticated) { + if (desc->sec_state.key_size == 16) { + ev.level = 3; + } else { + ev.level = 2; + } + } else { + ev.level = 1; + } + } + + tester_event(BTP_SERVICE_ID_GAP, BTP_GAP_EV_SEC_LEVEL_CHANGED, + (uint8_t *) &ev, sizeof(ev)); +} + +static void +bond_lost(uint16_t conn_handle) +{ + struct btp_gap_bond_lost_ev ev; + struct ble_gap_conn_desc desc; + int rc; + + rc = ble_gap_conn_find(conn_handle, &desc); + assert(rc == 0); + + memcpy(&ev.address, &desc.peer_id_addr, sizeof(ev.address)); + tester_event(BTP_SERVICE_ID_GAP, BTP_GAP_EV_BOND_LOST, + (uint8_t *) &ev, sizeof(ev)); +} + +#if MYNEWT_VAL(BLE_PERIODIC_ADV) +static void +sync_established(struct ble_gap_event *event) +{ + struct gap_periodic_sync_est_ev ev; + + ev.status = event->periodic_sync.status; + ev.sync_handle = event->periodic_sync.sync_handle; + ev.peer_addr = event->periodic_sync.adv_addr; + + tester_event(BTP_SERVICE_ID_GAP, GAP_EV_PERIODIC_SYNC_ESTABLISHED, + (uint8_t *) &ev, sizeof(ev)); +} + +static void +sync_lost(struct ble_gap_event *event) +{ + struct gap_periodic_sync_lost_ev ev; + + ev.reason = event->periodic_sync_lost.reason; + ev.sync_handle = event->periodic_sync_lost.sync_handle; + + tester_event(BTP_SERVICE_ID_GAP, GAP_EV_PERIODIC_SYNC_LOST, + (uint8_t *) &ev, sizeof(ev)); +} + +static void +periodic_report(struct ble_gap_event *event) +{ + struct gap_periodic_report_ev ev; + + ev.sync_handle = event->periodic_report.sync_handle; + ev.tx_power = event->periodic_report.tx_power; + ev.rssi = event->periodic_report.rssi; + ev.cte_type = 0xFF; + ev.data_status = event->periodic_report.data_status; + ev.data_length = event->periodic_report.data_length; + memcpy(ev.data, event->periodic_report.data, + event->periodic_report.data_length); + + tester_event(BTP_SERVICE_ID_GAP, GAP_EV_PERIODIC_REPORT, + (uint8_t *) &ev, sizeof(ev)); +} +#endif + +#if MYNEWT_VAL(BLE_PERIODIC_ADV_SYNC_TRANSFER) +static void +periodic_transfer_received(struct ble_gap_event *event) +{ + int rc; + struct ble_gap_conn_desc desc; + struct gap_periodic_transfer_recieved_ev ev; + + ev.adv_addr = event->periodic_transfer.adv_addr; + ev.sync_handle = event->periodic_transfer.sync_handle; + ev.status = event->periodic_transfer.status; + + rc = ble_gap_conn_find(event->periodic_transfer.conn_handle, &desc); + assert(rc == 0); + + ev.peer_addr = desc.peer_id_addr; + + tester_event(BTP_SERVICE_ID_GAP, GAP_EV_PERIODIC_TRANSFER_RECEIVED, + (uint8_t *) &ev, sizeof(ev)); +} +#endif + +#if MYNEWT_VAL(BLE_CONN_SUBRATING) +static void +subrate_change_received(struct ble_gap_event *event) +{ + int rc; + struct ble_gap_conn_desc desc; + struct gap_subrate_change_ev ev; + + rc = ble_gap_conn_find(event->subrate_change.conn_handle, &desc); + assert(rc == 0); + + ev.addr = desc.peer_ota_addr; + ev.status = event->subrate_change.status; + ev.conn_handle = event->subrate_change.conn_handle; + ev.subrate_factor = event->subrate_change.subrate_factor; + ev.periph_latency = event->subrate_change.periph_latency; + ev.cont_num = event->subrate_change.cont_num; + ev.supervision_tmo = event->subrate_change.supervision_tmo; + + tester_event(BTP_SERVICE_ID_GAP, GAP_EV_SUBRATE_CHANGE, (uint8_t *)&ev, + sizeof(ev)); +} +#endif + +static void +print_bytes(const uint8_t *bytes, int len) +{ + int i; + + for (i = 0; i < len; i++) { + console_printf("%s0x%02x", i != 0 ? ":" : "", bytes[i]); + } +} + +static void +print_mbuf(const struct os_mbuf *om) +{ + int colon; + + colon = 0; + while (om != NULL) { + if (colon) { + console_printf(":"); + } else { + colon = 1; + } + print_bytes(om->om_data, om->om_len); + om = SLIST_NEXT(om, om_next); + } +} + +static void +print_addr(const void *addr) +{ + const uint8_t *u8p; + + u8p = addr; + console_printf("%02x:%02x:%02x:%02x:%02x:%02x", + u8p[5], u8p[4], u8p[3], u8p[2], u8p[1], u8p[0]); +} + +static void +print_conn_desc(const struct ble_gap_conn_desc *desc) +{ + console_printf("handle=%d our_ota_addr_type=%d our_ota_addr=", + desc->conn_handle, desc->our_ota_addr.type); + print_addr(desc->our_ota_addr.val); + console_printf(" our_id_addr_type=%d our_id_addr=", + desc->our_id_addr.type); + print_addr(desc->our_id_addr.val); + console_printf(" peer_ota_addr_type=%d peer_ota_addr=", + desc->peer_ota_addr.type); + print_addr(desc->peer_ota_addr.val); + console_printf(" peer_id_addr_type=%d peer_id_addr=", + desc->peer_id_addr.type); + print_addr(desc->peer_id_addr.val); + console_printf(" conn_itvl=%d conn_latency=%d supervision_timeout=%d " + "key_sz=%d encrypted=%d authenticated=%d bonded=%d\n", + desc->conn_itvl, desc->conn_latency, + desc->supervision_timeout, + desc->sec_state.key_size, + desc->sec_state.encrypted, + desc->sec_state.authenticated, + desc->sec_state.bonded); +} + +static void +adv_complete(void) +{ + struct btp_gap_new_settings_ev ev; + + current_settings &= ~BIT(BTP_GAP_SETTINGS_ADVERTISING); + ev.current_settings = htole32(current_settings); + + tester_event(BTP_SERVICE_ID_GAP, BTP_GAP_EV_NEW_SETTINGS, + (uint8_t *) &ev, sizeof(ev)); +} + +static int +gap_event_cb(struct ble_gap_event *event, void *arg) +{ + struct ble_gap_conn_desc desc; + int rc; + + switch (event->type) { + case BLE_GAP_EVENT_ADV_COMPLETE: + console_printf("advertising complete; reason=%d\n", + event->adv_complete.reason); + break; + case BLE_GAP_EVENT_CONNECT: + console_printf("connection %s; status=%d ", + event->connect.status == 0 ? "established" + : "failed", + event->connect.status); + if (event->connect.status == 0) { + rc = ble_gap_conn_find(event->connect.conn_handle, &desc); + assert(rc == 0); + print_conn_desc(&desc); + } + + if (desc.role == BLE_GAP_ROLE_SLAVE) { + adv_complete(); + } + + le_connected(event->connect.conn_handle, + event->connect.status); + break; + case BLE_GAP_EVENT_DISCONNECT: + console_printf("disconnect; reason=%d ", + event->disconnect.reason); + print_conn_desc(&event->disconnect.conn); + le_disconnected(&event->disconnect.conn, + event->disconnect.reason); + break; + case BLE_GAP_EVENT_ENC_CHANGE: + console_printf("encryption change event; status=%d ", + event->enc_change.status); + rc = ble_gap_conn_find(event->enc_change.conn_handle, &desc); + assert(rc == 0); + print_conn_desc(&desc); + le_encryption_changed(&desc); + if (event->enc_change.status + == BLE_HS_HCI_ERR(BLE_ERR_PINKEY_MISSING)) { + bond_lost(event->enc_change.conn_handle); + } + break; + case BLE_GAP_EVENT_PASSKEY_ACTION: + console_printf("passkey action event; action=%d", + event->passkey.params.action); + if (event->passkey.params.action == BLE_SM_IOACT_NUMCMP) { + console_printf(" numcmp=%lu", + (unsigned long) event->passkey.params.numcmp); + } + console_printf("\n"); + le_passkey_action(event->passkey.conn_handle, + &event->passkey.params); + break; + case BLE_GAP_EVENT_IDENTITY_RESOLVED: + console_printf("identity resolved "); + rc = ble_gap_conn_find(event->identity_resolved.conn_handle, &desc); + assert(rc == 0); + print_conn_desc(&desc); + le_identity_resolved(event->identity_resolved.conn_handle); + break; + case BLE_GAP_EVENT_NOTIFY_RX: + console_printf( + "notification rx event; attr_handle=%d indication=%d " + "len=%d data=", + event->notify_rx.attr_handle, + event->notify_rx.indication, + OS_MBUF_PKTLEN(event->notify_rx.om)); + + print_mbuf(event->notify_rx.om); + console_printf("\n"); + tester_gattc_notify_rx_ev(event->notify_rx.conn_handle, + event->notify_rx.attr_handle, + event->notify_rx.indication, + event->notify_rx.om); + break; + case BLE_GAP_EVENT_SUBSCRIBE: + console_printf("subscribe event; conn_handle=%d attr_handle=%d " + "reason=%d prevn=%d curn=%d previ=%d curi=%d\n", + event->subscribe.conn_handle, + event->subscribe.attr_handle, + event->subscribe.reason, + event->subscribe.prev_notify, + event->subscribe.cur_notify, + event->subscribe.prev_indicate, + event->subscribe.cur_indicate); + tester_gatt_subscribe_ev(event->subscribe.conn_handle, + event->subscribe.attr_handle, + event->subscribe.reason, + event->subscribe.prev_notify, + event->subscribe.cur_notify, + event->subscribe.prev_indicate, + event->subscribe.cur_indicate); + break; + case BLE_GAP_EVENT_REPEAT_PAIRING: + console_printf("repeat pairing event; conn_handle=%d " + "cur_key_sz=%d cur_auth=%d cur_sc=%d " + "new_key_sz=%d new_auth=%d new_sc=%d " + "new_bonding=%d\n", + event->repeat_pairing.conn_handle, + event->repeat_pairing.cur_key_size, + event->repeat_pairing.cur_authenticated, + event->repeat_pairing.cur_sc, + event->repeat_pairing.new_key_size, + event->repeat_pairing.new_authenticated, + event->repeat_pairing.new_sc, + event->repeat_pairing.new_bonding); + rc = ble_gap_conn_find(event->repeat_pairing.conn_handle, &desc); + assert(rc == 0); + rc = ble_store_util_delete_peer(&desc.peer_id_addr); + assert(rc == 0); + bond_lost(event->repeat_pairing.conn_handle); + return BLE_GAP_REPEAT_PAIRING_RETRY; + case BLE_GAP_EVENT_CONN_UPDATE: + console_printf("connection update event; status=%d ", + event->conn_update.status); + rc = ble_gap_conn_find(event->conn_update.conn_handle, &desc); + assert(rc == 0); + print_conn_desc(&desc); + le_conn_param_update(&desc); + break; + case BLE_GAP_EVENT_CONN_UPDATE_REQ: + console_printf("connection update request event; " + "conn_handle=%d itvl_min=%d itvl_max=%d " + "latency=%d supervision_timoeut=%d " + "min_ce_len=%d max_ce_len=%d\n", + event->conn_update_req.conn_handle, + event->conn_update_req.peer_params->itvl_min, + event->conn_update_req.peer_params->itvl_max, + event->conn_update_req.peer_params->latency, + event->conn_update_req.peer_params->supervision_timeout, + event->conn_update_req.peer_params->min_ce_len, + event->conn_update_req.peer_params->max_ce_len); + + *event->conn_update_req.self_params = *event->conn_update_req.peer_params; + break; + case BLE_GAP_EVENT_L2CAP_UPDATE_REQ: + console_printf("connection update request event; " + "conn_handle=%d itvl_min=%d itvl_max=%d " + "latency=%d supervision_timoeut=%d " + "min_ce_len=%d max_ce_len=%d\n", + event->conn_update_req.conn_handle, + event->conn_update_req.peer_params->itvl_min, + event->conn_update_req.peer_params->itvl_max, + event->conn_update_req.peer_params->latency, + event->conn_update_req.peer_params->supervision_timeout, + event->conn_update_req.peer_params->min_ce_len, + event->conn_update_req.peer_params->max_ce_len); + if (event->conn_update_req.peer_params->itvl_min + == REJECT_INTERVAL_MIN && + event->conn_update_req.peer_params->itvl_max + == REJECT_INTERVAL_MAX && + event->conn_update_req.peer_params->latency == REJECT_LATENCY + && + event->conn_update_req.peer_params->supervision_timeout + == REJECT_SUPERVISION_TIMEOUT) { + return EINVAL; + } + case BLE_GAP_EVENT_PAIRING_COMPLETE: + console_printf("received pairing complete: " + "conn_handle=%d status=%d\n", + event->pairing_complete.conn_handle, + event->pairing_complete.status); + if (event->pairing_complete.status != BLE_SM_ERR_SUCCESS) { + le_pairing_failed(event->pairing_complete.conn_handle, + event->pairing_complete.status); + } + break; +#if MYNEWT_VAL(BLE_PERIODIC_ADV) + case BLE_GAP_EVENT_PERIODIC_SYNC: + console_printf("Periodic Sync established: " + "sync_handle=%d, status=%d sid=%d adv_addr=", + event->periodic_sync.sync_handle, + event->periodic_sync.status, event->periodic_sync.sid); + print_addr(event->periodic_sync.adv_addr.val); + console_printf("adv_phy=%d per_adv_ival=%d adv_clk_accuracy=%d\n", + event->periodic_sync.adv_phy, + event->periodic_sync.per_adv_ival, + event->periodic_sync.adv_clk_accuracy); + sync_established(event); + break; + case BLE_GAP_EVENT_PERIODIC_REPORT: + console_printf("Periodic Sync Report: " + "sync_handle=%d, tx_power=%d rssi=%d data_status=%d" + "data_length=%d data=", + event->periodic_report.sync_handle, + event->periodic_report.tx_power, + event->periodic_report.rssi, + event->periodic_report.data_status, + event->periodic_report.data_length); + print_bytes(event->periodic_report.data, + event->periodic_report.data_length); + console_printf("\n"); + periodic_report(event); + break; + case BLE_GAP_EVENT_PERIODIC_SYNC_LOST: + console_printf("Periodic Sync lost: " + "sync_handle=%d, reason=%d\n", + event->periodic_sync_lost.sync_handle, + event->periodic_sync_lost.reason); + sync_lost(event); + break; +#endif +#if MYNEWT_VAL(BLE_PERIODIC_ADV_SYNC_TRANSFER) + case BLE_GAP_EVENT_PERIODIC_TRANSFER: + console_printf("Periodic transfer received:" + "status=%d, sync_handle=%d, conn_handle=%d, service_data=%d, sid=%d addr=", + event->periodic_transfer.status, + event->periodic_transfer.sync_handle, + event->periodic_transfer.conn_handle, + event->periodic_transfer.service_data, + event->periodic_transfer.sid); + print_addr(event->periodic_sync.adv_addr.val); + console_printf(" adv_phy=%d, per_adv_itvl=%d, adv_clk_accuracy=%d\n", + event->periodic_transfer.adv_phy, + event->periodic_transfer.per_adv_itvl, + event->periodic_transfer.adv_clk_accuracy); + periodic_transfer_received(event); + break; +#endif +#if MYNEWT_VAL(BLE_CONN_SUBRATING) + case BLE_GAP_EVENT_SUBRATE_CHANGE: + console_printf( + "Subrate change received:" + "status=%d, conn_handle=%d, subrate_factor=%d, perpih_latency=%d," + "cont_num=%d supervision_tmo=%d", + event->subrate_change.status, event->subrate_change.conn_handle, + event->subrate_change.subrate_factor, + event->subrate_change.periph_latency, event->subrate_change.cont_num, + event->subrate_change.supervision_tmo); + subrate_change_received(event); + break; +#endif + default: + break; + } + + return 0; +} + +static uint8_t +connect(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gap_connect_cmd *cp = cmd; + + ble_addr_t *addr = (ble_addr_t *)&cp->address; + + SYS_LOG_DBG(""); + + if (ble_addr_cmp(BLE_ADDR_ANY, addr) == 0) { + addr = NULL; + } + + if (ble_gap_connect(own_addr_type, addr, 0, + &dflt_conn_params, gap_event_cb, NULL)) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +disconnect(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gap_disconnect_cmd *cp = cmd; + struct ble_gap_conn_desc desc; + int rc; + + SYS_LOG_DBG(""); + + rc = gap_conn_find_by_addr(&cp->address, &desc); + if (rc) { + return BTP_STATUS_FAILED; + } + + if (ble_gap_terminate(desc.conn_handle, BLE_ERR_REM_USER_CONN_TERM)) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +set_io_cap(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gap_set_io_cap_cmd *cp = cmd; + + SYS_LOG_DBG(""); + + switch (cp->io_cap) { + case BTP_GAP_IO_CAP_DISPLAY_ONLY: + ble_hs_cfg.sm_io_cap = BLE_SM_IO_CAP_DISP_ONLY; + ble_hs_cfg.sm_mitm = 1; + break; + case BTP_GAP_IO_CAP_KEYBOARD_DISPLAY: + ble_hs_cfg.sm_io_cap = BLE_SM_IO_CAP_KEYBOARD_DISP; + ble_hs_cfg.sm_mitm = 1; + break; + case BTP_GAP_IO_CAP_NO_INPUT_OUTPUT: + ble_hs_cfg.sm_io_cap = BLE_SM_IO_CAP_NO_IO; + ble_hs_cfg.sm_mitm = 0; + break; + case BTP_GAP_IO_CAP_KEYBOARD_ONLY: + ble_hs_cfg.sm_io_cap = BLE_SM_IO_CAP_KEYBOARD_ONLY; + ble_hs_cfg.sm_mitm = 1; + break; + case BTP_GAP_IO_CAP_DISPLAY_YESNO: + ble_hs_cfg.sm_io_cap = BLE_SM_IO_CAP_DISP_YES_NO; + ble_hs_cfg.sm_mitm = 1; + break; + default: + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +pair(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gap_pair_cmd *cp = cmd; + struct ble_gap_conn_desc desc; + int rc; + + SYS_LOG_DBG(""); + + rc = gap_conn_find_by_addr(&cp->address, &desc); + if (rc) { + return BTP_STATUS_FAILED; + } + + rc = ble_gap_security_initiate(desc.conn_handle); + if (rc != 0 && rc != BLE_HS_EALREADY) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +unpair(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gap_unpair_cmd *cp = cmd; + int err; + + SYS_LOG_DBG(""); + + err = ble_gap_unpair(&cp->address); + return err != 0 ? BTP_STATUS_FAILED : BTP_STATUS_SUCCESS; +} + +static uint8_t +passkey_entry(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gap_passkey_entry_cmd *cp = cmd; + struct ble_gap_conn_desc desc; + struct ble_sm_io pk; + int rc; + + SYS_LOG_DBG(""); + + rc = gap_conn_find_by_addr(&cp->address, &desc); + if (rc) { + return BTP_STATUS_FAILED; + } + + pk.action = BLE_SM_IOACT_INPUT; + pk.passkey = le32toh(cp->passkey); + + rc = ble_sm_inject_io(desc.conn_handle, &pk); + if (rc) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +passkey_confirm(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gap_passkey_confirm_cmd *cp = cmd; + struct ble_gap_conn_desc desc; + struct ble_sm_io pk; + int rc; + + SYS_LOG_DBG(""); + + rc = gap_conn_find_by_addr(&cp->address, &desc); + if (rc) { + return BTP_STATUS_FAILED; + } + + pk.action = BLE_SM_IOACT_NUMCMP; + pk.numcmp_accept = cp->match; + + rc = ble_sm_inject_io(desc.conn_handle, &pk); + if (rc) { + console_printf("sm inject io failed"); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +#if MYNEWT_VAL(BLE_EXT_ADV) +static struct ble_gap_ext_adv_params dir_adv_params = { + .primary_phy = BLE_HCI_LE_PHY_1M, + .secondary_phy = BLE_HCI_LE_PHY_1M, + .sid = 1, + .legacy_pdu = 1, + .directed = 1, + .connectable = 1, +}; +#else +static struct ble_gap_adv_params dir_adv_params = { + .conn_mode = BLE_GAP_CONN_MODE_DIR, +}; +#endif + +static uint8_t +start_direct_adv(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gap_start_direct_adv_cmd *cp = cmd; + struct btp_gap_start_advertising_rp *rp = rsp; + int err; + + SYS_LOG_DBG(""); + +#if MYNEWT_VAL(BLE_EXT_ADV) + dir_adv_params.high_duty_directed = cp->options & BIT(1); + dir_adv_params.own_addr_type = own_addr_type; + memcpy(&dir_adv_params.peer, &cp->address, sizeof(dir_adv_params.peer)); + + err = ble_gap_ext_adv_configure(0, &dir_adv_params, NULL, gap_event_cb, NULL); + if (err) { + SYS_LOG_ERR("Failed to configure extended advertiser; rc=%d", err); + return BTP_STATUS_FAILED; + } + + err = ble_gap_ext_adv_start(0, 128, 0); +#else + dir_adv_params.high_duty_cycle = cp->options & BIT(1); + + err = ble_gap_adv_start(own_addr_type, &cp->address, + BLE_HS_FOREVER, &dir_adv_params, + gap_event_cb, NULL); +#endif + + if (err) { + SYS_LOG_ERR("Advertising failed: err %d", err); + return BTP_STATUS_FAILED; + } + + current_settings |= BIT(BTP_GAP_SETTINGS_ADVERTISING); + rp->current_settings = htole32(current_settings); + + *rsp_len = sizeof(*rp); + + return BTP_STATUS_SUCCESS; +} + +static void +conn_param_update_cb(uint16_t conn_handle, int status, void *arg) +{ + console_printf("conn param update complete; conn_handle=%d status=%d\n", + conn_handle, status); +} + +static int +conn_param_update_slave(uint16_t conn_handle, + const struct btp_gap_conn_param_update_cmd *cmd) +{ + int rc; + struct ble_l2cap_sig_update_params params; + + params.itvl_min = cmd->conn_itvl_min; + params.itvl_max = cmd->conn_itvl_max; + params.slave_latency = cmd->conn_latency; + params.timeout_multiplier = cmd->supervision_timeout; + + rc = ble_l2cap_sig_update(conn_handle, ¶ms, + conn_param_update_cb, NULL); + if (rc) { + SYS_LOG_ERR("Failed to send update params: rc=%d", rc); + } + + return 0; +} + +static int +conn_param_update_master(uint16_t conn_handle, + const struct btp_gap_conn_param_update_cmd *cmd) +{ + int rc; + struct ble_gap_upd_params params; + + params.itvl_min = cmd->conn_itvl_min; + params.itvl_max = cmd->conn_itvl_max; + params.latency = cmd->conn_latency; + params.supervision_timeout = cmd->supervision_timeout; + params.min_ce_len = 0; + params.max_ce_len = 0; + rc = ble_gap_update_params(conn_handle, ¶ms); + if (rc) { + SYS_LOG_ERR("Failed to send update params: rc=%d", rc); + } + + return rc; +} + +static void +conn_param_update(struct os_event *ev) +{ + struct ble_gap_conn_desc desc; + int rc; + + SYS_LOG_DBG(""); + + rc = gap_conn_find_by_addr((ble_addr_t *) &update_params, &desc); + if (rc) { + goto rsp; + } + + if ((desc.conn_itvl >= update_params.conn_itvl_min) && + (desc.conn_itvl <= update_params.conn_itvl_max) && + (desc.conn_latency == update_params.conn_latency) && + (desc.supervision_timeout == update_params.supervision_timeout)) { + goto rsp; + } + + if (desc.role == BLE_GAP_ROLE_MASTER) { + rc = conn_param_update_master(desc.conn_handle, &update_params); + } else { + rc = conn_param_update_slave(desc.conn_handle, &update_params); + } + + if (rc == 0) { + return; + } + +rsp: + SYS_LOG_ERR("Conn param update fail; rc=%d", rc); +} + +static uint8_t +conn_param_update_async(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gap_conn_param_update_cmd *cp = cmd; + update_params = *cp; + + os_callout_reset(&update_params_co, 0); + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +set_oob_legacy_data(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gap_oob_legacy_set_data_cmd *cp = cmd; + + ble_hs_cfg.sm_oob_data_flag = 1; + memcpy(oob, cp->oob_data, sizeof(oob)); + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +get_oob_sc_local_data(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + struct btp_gap_oob_sc_get_local_data_rp *rp = rsp; + + memcpy(rp->r, oob_data_local.r, 16); + memcpy(rp->c, oob_data_local.c, 16); + + *rsp_len = sizeof(*rp); + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +set_oob_sc_remote_data(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gap_oob_sc_set_remote_data_cmd *cp = cmd; + + ble_hs_cfg.sm_oob_data_flag = 1; + memcpy(oob_data_remote.r, cp->r, 16); + memcpy(oob_data_remote.c, cp->c, 16); + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +set_mitm(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gap_set_mitm_cmd *cp = cmd; + + ble_hs_cfg.sm_mitm = cp->mitm; + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +set_filter_accept_list(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gap_set_filter_accept_list_cmd *cp = cmd; + int err; + + SYS_LOG_DBG(""); + + use_filter_policy = cp->list_len != 0; + + /* + * Check if the nb of bytes received matches the len of addrs list. + * Then set the filter accept list. + */ + if ((cmd_len < sizeof(*cp)) || + (cmd_len != sizeof(*cp) + (cp->list_len * sizeof(cp->addrs[0])))) { + return BTP_STATUS_FAILED; + } + + err = ble_gap_wl_set(cp->addrs, cp->list_len); + if (err != 0) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +#if MYNEWT_VAL(BLE_EXT_ADV) +static uint8_t +set_ext_advertising(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + struct btp_gap_set_ext_advertising_rp *rp = rsp; + const struct btp_gap_set_ext_advertising_cmd *cp = cmd; + + if (current_settings & BIT(BTP_GAP_SETTINGS_ADVERTISING)) { + return BTP_STATUS_FAILED; + } + + if (cp->setting) { + current_settings |= BIT(BTP_GAP_SETTINGS_EXTENDED_ADVERTISING); + adv_params.legacy_pdu = 0; + /* TODO: This is temporary until auto-pts nonscannable implementation */ + adv_params.scannable = 0; + } else { + current_settings &= ~BIT(BTP_GAP_SETTINGS_EXTENDED_ADVERTISING); + adv_params.legacy_pdu = 1; + } + + rp->current_settings = htole32(current_settings); + *rsp_len = sizeof(*rp); + + return BTP_STATUS_SUCCESS; +} + +#endif + +#if MYNEWT_VAL(BLE_PERIODIC_ADV) +static uint8_t +periodic_adv_configure(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + struct ble_gap_ext_adv_params ext_params = {0}; + struct ble_gap_periodic_adv_params params = {0}; + const struct gap_periodic_adv_configure_cmd *cp = cmd; + struct btp_gap_periodic_adv_configure_rp *rp = rsp; + + int rc; + + memset(¶ms, 0, sizeof(params)); + params.include_tx_power = cp->flags & 0x01; + params.itvl_min = cp->itvl_min; + params.itvl_max = cp->itvl_max; + + ext_params.connectable = 0; + ext_params.scannable = 0; + ext_params.legacy_pdu = 0; + ext_params.anonymous = 0; + ext_params.own_addr_type = own_addr_type; + ext_params.primary_phy = BLE_HCI_LE_PHY_1M; + ext_params.secondary_phy = BLE_HCI_LE_PHY_1M; + ext_params.sid = 1; + + rc = ble_gap_ext_adv_configure(1, &ext_params, NULL, gap_event_cb, NULL); + if (rc) { + SYS_LOG_ERR("Failed to configure extended advertiser; rc=%d", rc); + return BTP_STATUS_FAILED; + } + + rc = ble_gap_periodic_adv_configure(1, ¶ms); + if (rc) { + SYS_LOG_ERR("Failed to configure periodic advertiser; rc=%d\n" + "params.itvl_min %d\n" + "params.itvl_max %d\n", rc, params.itvl_min, + params.itvl_max); + return BTP_STATUS_FAILED; + } + + current_settings |= BIT(BTP_GAP_SETTINGS_PERIODIC_ADVERTISING); + + rp->current_settings = htole32(current_settings); + *rsp_len = sizeof(*rp); + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +periodic_adv_start(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + int rc; + struct btp_gap_periodic_adv_start_rp *rp = rsp; + + rc = ble_gap_ext_adv_start(1, 0, 0); + if (rc) { + SYS_LOG_ERR("Failed to start extended advertiser; rc=%d", rc); + return BTP_STATUS_FAILED; + } + + rc = ble_gap_periodic_adv_start(1, NULL); + if (rc) { + SYS_LOG_ERR("Failed to start periodic advertiser; rc=%d", rc); + return BTP_STATUS_FAILED; + } + + rp->current_settings = htole32(current_settings); + *rsp_len = sizeof(*rp); + return BTP_STATUS_SUCCESS; +} + +static uint8_t +periodic_adv_set_data(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + struct os_mbuf *adv_data; + const struct gap_periodic_adv_set_data_cmd *cp = cmd; + int rc; + uint16_t data_len = le16toh(cp->adv_data_len); + + adv_data = os_msys_get_pkthdr(data_len, 0); + if (!adv_data) { + return BTP_STATUS_FAILED; + } + + if (os_mbuf_append(adv_data, cp->adv_data, data_len)) { + return BTP_STATUS_FAILED; + } + + rc = ble_gap_periodic_adv_set_data(1, adv_data, NULL); + if (rc) { + SYS_LOG_ERR("Failed to set periodic advertiser data; rc=%d", rc); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +periodic_adv_create_sync(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct gap_periodic_adv_create_sync_cmd *cp = cmd; + struct ble_gap_periodic_sync_params params; + struct ble_gap_disc_params scan_params = {0}; + int rc; + + params.reports_disabled = BIT(0) & cp->flags; + params.skip = cp->skip; + params.sync_timeout = cp->sync_timeout; + SYS_LOG_DBG("\nreports_disabled %d\nskip %d\nsync_timeout %d\n", + params.reports_disabled, params.skip, params.sync_timeout); + + scan_params.passive = 0; + scan_params.limited = 0; + scan_params.filter_duplicates = 0; + + ble_gap_disc(own_addr_type, BLE_HS_FOREVER, &scan_params, NULL, NULL); + rc = ble_gap_periodic_adv_sync_create(&cp->addr, cp->adv_sid, ¶ms, + gap_event_cb, NULL); + if (rc) { + SYS_LOG_ERR("Failed to create sync; rc=%d", rc); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +#endif +#if MYNEWT_VAL(BLE_PERIODIC_ADV_SYNC_TRANSFER) +static uint8_t +periodic_adv_sync_transfer_start(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct gap_periodic_adv_sync_transfer_start_cmd *cp = cmd; + struct ble_gap_conn_desc desc; + int rc; + + rc = gap_conn_find_by_addr(&cp->addr, &desc); + if (rc) { + return BTP_STATUS_FAILED; + } + + rc = ble_gap_periodic_adv_sync_transfer(cp->sync_handle, desc.conn_handle, + cp->svc_data); + if (rc) { + SYS_LOG_ERR("Failed to initiate sync transfer; rc=%d", rc); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +periodic_adv_sync_transfer_recv(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct gap_periodic_adv_sync_transfer_recv_cmd *cp = cmd; + struct ble_gap_conn_desc desc; + struct ble_gap_periodic_sync_params params; + int rc; + + rc = gap_conn_find_by_addr(&cp->addr, &desc); + if (rc) { + return BTP_STATUS_FAILED; + } + + params.reports_disabled = BIT(0) & cp->flags; + params.skip = cp->skip; + params.sync_timeout = cp->sync_timeout; + + rc = ble_gap_periodic_adv_sync_receive(desc.conn_handle, ¶ms, + gap_event_cb, NULL); + if (rc) { + SYS_LOG_ERR("Failed to receive periodic sync; rc=%d", rc); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +periodic_adv_sync_transfer_set_info(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct gap_periodic_adv_sync_transfer_set_info_cmd *cp = cmd; + struct ble_gap_conn_desc desc; + int rc; + + rc = gap_conn_find_by_addr(&cp->addr, &desc); + if (rc) { + return BTP_STATUS_FAILED; + } + + rc = ble_gap_periodic_adv_sync_set_info(1, desc.conn_handle, + cp->svc_data); + if (rc) { + SYS_LOG_ERR("Failed to set info; rc=%d", rc); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} +#endif + +#if MYNEWT_VAL(BLE_CONN_SUBRATING) +static uint8_t +subrate_request(const void *cmd, uint16_t cmd_len, void *rsp, uint16_t *rsp_len) +{ + const struct gap_subrate_request_cmd *cp = cmd; + struct ble_gap_conn_desc desc; + int rc; + + rc = gap_conn_find_by_addr(&cp->address, &desc); + if (rc) { + return BTP_STATUS_FAILED; + } + + rc = ble_gap_subrate_req(desc.conn_handle, cp->subrate_min, cp->subrate_max, + cp->max_latency, cp->cont_num, cp->supervision_timeout); + if (rc) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} +#endif + +static const struct btp_handler handlers[] = { + { + .opcode = BTP_GAP_READ_SUPPORTED_COMMANDS, + .index = BTP_INDEX_NONE, + .expect_len = 0, + .func = supported_commands, + }, + { + .opcode = BTP_GAP_READ_CONTROLLER_INDEX_LIST, + .index = BTP_INDEX_NONE, + .expect_len = 0, + .func = controller_index_list, + }, + { + .opcode = BTP_GAP_READ_CONTROLLER_INFO, + .expect_len = 0, + .func = controller_info, + }, + { + .opcode = BTP_GAP_SET_CONNECTABLE, + .expect_len = sizeof(struct btp_gap_set_connectable_cmd), + .func = set_connectable, + }, + { + .opcode = BTP_GAP_SET_DISCOVERABLE, + .expect_len = sizeof(struct btp_gap_set_discoverable_cmd), + .func = set_discoverable, + }, + { + .opcode = BTP_GAP_SET_BONDABLE, + .expect_len = sizeof(struct btp_gap_set_bondable_cmd), + .func = set_bondable, + }, + { + .opcode = BTP_GAP_START_ADVERTISING, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = start_advertising, + }, + { + .opcode = BTP_GAP_START_DIRECT_ADV, + .expect_len = sizeof(struct btp_gap_start_direct_adv_cmd), + .func = start_direct_adv, + }, + { + .opcode = BTP_GAP_STOP_ADVERTISING, + .expect_len = 0, + .func = stop_advertising, + }, + { + .opcode = BTP_GAP_START_DISCOVERY, + .expect_len = sizeof(struct btp_gap_start_discovery_cmd), + .func = start_discovery, + }, + { + .opcode = BTP_GAP_STOP_DISCOVERY, + .expect_len = 0, + .func = stop_discovery, + }, + { + .opcode = BTP_GAP_CONNECT, + .expect_len = sizeof(struct btp_gap_connect_cmd), + .func = connect, + }, + { + .opcode = BTP_GAP_DISCONNECT, + .expect_len = sizeof(struct btp_gap_disconnect_cmd), + .func = disconnect, + }, + { + .opcode = BTP_GAP_SET_IO_CAP, + .expect_len = sizeof(struct btp_gap_set_io_cap_cmd), + .func = set_io_cap, + }, + { + .opcode = BTP_GAP_PAIR, + .expect_len = sizeof(struct btp_gap_pair_cmd), + .func = pair, + }, + { + .opcode = BTP_GAP_UNPAIR, + .expect_len = sizeof(struct btp_gap_unpair_cmd), + .func = unpair, + }, + { + .opcode = BTP_GAP_PASSKEY_ENTRY, + .expect_len = sizeof(struct btp_gap_passkey_entry_cmd), + .func = passkey_entry, + }, + { + .opcode = BTP_GAP_PASSKEY_CONFIRM, + .expect_len = sizeof(struct btp_gap_passkey_confirm_cmd), + .func = passkey_confirm, + }, + { + .opcode = BTP_GAP_CONN_PARAM_UPDATE, + .expect_len = sizeof(struct btp_gap_conn_param_update_cmd), + .func = conn_param_update_async, + }, + { + .opcode = BTP_GAP_OOB_LEGACY_SET_DATA, + .expect_len = sizeof(struct btp_gap_oob_legacy_set_data_cmd), + .func = set_oob_legacy_data, + }, + { + .opcode = BTP_GAP_OOB_SC_GET_LOCAL_DATA, + .expect_len = 0, + .func = get_oob_sc_local_data, + }, + { + .opcode = BTP_GAP_OOB_SC_SET_REMOTE_DATA, + .expect_len = sizeof(struct btp_gap_oob_sc_set_remote_data_cmd), + .func = set_oob_sc_remote_data, + }, + { + .opcode = BTP_GAP_SET_MITM, + .expect_len = sizeof(struct btp_gap_set_mitm_cmd), + .func = set_mitm, + }, + { + .opcode = BTP_GAP_SET_FILTER_ACCEPT_LIST, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = set_filter_accept_list, + }, +#if MYNEWT_VAL(BLE_EXT_ADV) + { + .opcode = GAP_SET_EXT_ADV, + .expect_len = sizeof(struct btp_gap_set_ext_advertising_cmd), + .func = set_ext_advertising, + }, +#endif /* BLE_EXT_ADV*/ +#if MYNEWT_VAL(BLE_PERIODIC_ADV) + { + .opcode = GAP_PADV_CONFIGURE, + .expect_len = sizeof(struct gap_periodic_adv_configure_cmd), + .func = periodic_adv_configure, + }, + { + .opcode = GAP_PADV_START, + .expect_len = sizeof(struct gap_periodic_adv_start_cmd), + .func = periodic_adv_start, + }, + { + .opcode = GAP_PADV_SET_DATA, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = periodic_adv_set_data, + }, + { + .opcode = GAP_PADV_CREATE_SYNC, + .expect_len = sizeof(struct gap_periodic_adv_create_sync_cmd), + .func = periodic_adv_create_sync, + }, +#endif +#if MYNEWT_VAL(BLE_PERIODIC_ADV_SYNC_TRANSFER) + { + .opcode = GAP_PADV_SYNC_TRANSFER_SET_INFO, + .expect_len = + sizeof(struct gap_periodic_adv_sync_transfer_set_info_cmd), + .func = periodic_adv_sync_transfer_set_info, + }, + { + .opcode = GAP_PADV_SYNC_TRANSFER_START, + .expect_len = sizeof(struct gap_periodic_adv_sync_transfer_start_cmd), + .func = periodic_adv_sync_transfer_start, + }, + { + .opcode = GAP_PADV_SYNC_TRANSFER_RECV, + .expect_len = sizeof(struct gap_periodic_adv_sync_transfer_recv_cmd), + .func = periodic_adv_sync_transfer_recv, + }, +#endif +#if MYNEWT_VAL(BLE_CONN_SUBRATING) + { + .opcode = GAP_SUBRATE_REQUEST, + .expect_len = sizeof(struct gap_subrate_request_cmd), + .func = subrate_request, + }, +#endif +}; + +static void +tester_init_gap_cb() +{ + current_settings = 0; + current_settings |= BIT(BTP_GAP_SETTINGS_POWERED); + current_settings |= BIT(BTP_GAP_SETTINGS_LE); + + os_callout_init(&update_params_co, os_eventq_dflt_get(), + conn_param_update, NULL); + + os_callout_init(&connected_ev_co, os_eventq_dflt_get(), + device_connected_ev_send, NULL); +} + +uint8_t +tester_init_gap(void) +{ +#if MYNEWT_VAL(BLE_SM_SC) + int rc; + + rc = ble_sm_sc_oob_generate_data(&oob_data_local); + if (rc) { + console_printf("Error: generating oob data; reason=%d\n", rc); + return BTP_STATUS_FAILED; + } +#endif +#if MYNEWT_VAL(BTTESTER_PRIVACY_MODE) && MYNEWT_VAL(BTTESTER_USE_NRPA) + os_callout_init(&bttester_nrpa_rotate_timer, os_eventq_dflt_get(), + rotate_nrpa_cb, NULL); +#endif + adv_buf = os_msys_get(ADV_BUF_LEN, 0); + assert(adv_buf); + + tester_init_gap_cb(); + + tester_register_command_handlers(BTP_SERVICE_ID_GAP, handlers, + ARRAY_SIZE(handlers)); + + return BTP_STATUS_SUCCESS; +} + +uint8_t +tester_unregister_gap(void) +{ + return BTP_STATUS_SUCCESS; +} diff --git a/apps/bttester/src/btp_gatt.c b/apps/bttester/src/btp_gatt.c new file mode 100644 index 0000000000..17c083bf3a --- /dev/null +++ b/apps/bttester/src/btp_gatt.c @@ -0,0 +1,2307 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* gatt.c - Bluetooth GATT Server Tester */ + +/* + * Copyright (c) 2015-2016 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include "host/ble_gap.h" +#include "host/ble_gatt.h" +#include "console/console.h" +#include "services/gatt/ble_svc_gatt.h" +#include "../../../nimble/host/src/ble_att_priv.h" +#include "../../../nimble/host/src/ble_gatt_priv.h" + +#include "btp/btp.h" + +#define CONTROLLER_INDEX 0 +#define MAX_BUFFER_SIZE 2048 + +/* 0000xxxx-8c26-476f-89a7-a108033a69c7 */ +#define PTS_UUID_DECLARE(uuid16) \ + ((const ble_uuid_t *) (&(ble_uuid128_t) BLE_UUID128_INIT( \ + 0xc7, 0x69, 0x3a, 0x03, 0x08, 0xa1, 0xa7, 0x89, \ + 0x6f, 0x47, 0x26, 0x8c, uuid16, uuid16 >> 8, 0x00, 0x00 \ + ))) + +/* 0000xxxx-8c26-476f-89a7-a108033a69c6 */ +#define PTS_UUID_DECLARE_ALT(uuid16) \ + ((const ble_uuid_t *) (&(ble_uuid128_t) BLE_UUID128_INIT( \ + 0xc6, 0x69, 0x3a, 0x03, 0x08, 0xa1, 0xa7, 0x89, \ + 0x6f, 0x47, 0x26, 0x8c, uuid16, uuid16 >> 8, 0x00, 0x00 \ + ))) + +#define PTS_SVC 0x0001 +#define PTS_CHR_READ 0x0002 +#define PTS_CHR_WRITE 0x0003 +#define PTS_CHR_RELIABLE_WRITE 0x0004 +#define PTS_CHR_WRITE_NO_RSP 0x0005 +#define PTS_CHR_READ_WRITE 0x0006 +#define PTS_CHR_READ_WRITE_ENC 0x0007 +#define PTS_CHR_READ_WRITE_AUTHEN 0x0008 +#define PTS_DSC_READ 0x0009 +#define PTS_DSC_WRITE 0x000a +#define PTS_DSC_READ_WRITE 0x000b +#define PTS_CHR_NOTIFY 0x0025 +#define PTS_CHR_NOTIFY_ALT 0x0026 +#define PTS_CHR_READ_WRITE_AUTHOR 0x0027 +#define PTS_LONG_CHR_READ_WRITE 0x0015 +#define PTS_LONG_CHR_READ_WRITE_ALT 0x0016 +#define PTS_LONG_DSC_READ_WRITE 0x001b +#define PTS_INC_SVC 0x001e +#define PTS_CHR_READ_WRITE_ALT 0x001f + +static uint8_t gatt_svr_pts_static_long_val[300]; +static uint8_t gatt_svr_pts_static_val[30]; +static uint8_t gatt_svr_pts_static_short_val; +static uint8_t notify_state; +static uint8_t indicate_state; +static uint16_t myconn_handle; +static struct os_callout notify_tx_timer; +uint16_t notify_handle; +uint16_t notify_handle_alt; +uint8_t notify_value = 90; + +struct find_attr_data { + ble_uuid_any_t *uuid; + int attr_type; + void *ptr; + uint16_t handle; +}; + +struct notify_mult_cb_data { + size_t tuple_cnt; + uint16_t handles[8]; +}; + +static int +gatt_svr_read_write_test(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, + void *arg); + +static int +gatt_svr_read_write_auth_test(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, + void *arg); + +static int +gatt_svr_read_write_author_test(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, + void *arg); + +static int +gatt_svr_read_write_enc_test(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, + void *arg); + +static int +gatt_svr_dsc_read_write_test(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, + void *arg); + +static int +gatt_svr_write_no_rsp_test(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, + void *arg); + +static int +gatt_svr_rel_write_test(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, + void *arg); + +static int +gatt_svr_read_write_long_test(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, + void *arg); + +static int +gatt_svr_dsc_read_test(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, + void *arg); + +static int +gatt_svr_dsc_read_write_long_test(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, + void *arg); + +static const struct ble_gatt_svc_def gatt_svr_inc_svcs[] = { + { + .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid = BLE_UUID16_DECLARE(PTS_INC_SVC), + .characteristics = (struct ble_gatt_chr_def[]) {{ + .uuid = PTS_UUID_DECLARE(PTS_CHR_READ_WRITE_ALT), + .access_cb = gatt_svr_read_write_test, + .flags = BLE_GATT_CHR_F_WRITE | + BLE_GATT_CHR_F_READ, + }, { + 0, + }}, + + }, + + { + 0, /* No more services. */ + }, +}; + +static const struct ble_gatt_svc_def *inc_svcs[] = { + &gatt_svr_inc_svcs[0], + NULL, +}; + +static const struct ble_gatt_svc_def gatt_svr_svcs[] = { + { + /*** Service: PTS test. */ + .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid = PTS_UUID_DECLARE(PTS_SVC), + .includes = inc_svcs, + .characteristics = (struct ble_gatt_chr_def[]) { + { + .uuid = PTS_UUID_DECLARE(PTS_CHR_READ_WRITE), + .access_cb = gatt_svr_read_write_test, + .flags = BLE_GATT_CHR_F_READ | + BLE_GATT_CHR_F_WRITE, + .descriptors = (struct ble_gatt_dsc_def[]) {{ + .uuid = PTS_UUID_DECLARE(PTS_DSC_READ_WRITE), + .access_cb = gatt_svr_dsc_read_write_test, + .att_flags = BLE_ATT_F_READ | + BLE_ATT_F_WRITE, + }, { + .uuid = PTS_UUID_DECLARE(PTS_LONG_DSC_READ_WRITE), + .access_cb = gatt_svr_dsc_read_write_long_test, + .att_flags = BLE_ATT_F_READ | + BLE_ATT_F_WRITE, + }, { + .uuid = PTS_UUID_DECLARE(PTS_DSC_READ), + .access_cb = gatt_svr_dsc_read_test, + .att_flags = BLE_ATT_F_READ, + }, { + 0, /* No more descriptors in this characteristic */ + }} + }, { + .uuid = PTS_UUID_DECLARE(PTS_CHR_WRITE_NO_RSP), + .access_cb = gatt_svr_write_no_rsp_test, + .flags = BLE_GATT_CHR_F_READ | + BLE_GATT_CHR_F_WRITE | + BLE_GATT_CHR_F_WRITE_NO_RSP, + }, { + .uuid = PTS_UUID_DECLARE(PTS_CHR_READ_WRITE_AUTHEN), + .access_cb = gatt_svr_read_write_auth_test, + .flags = BLE_GATT_CHR_F_READ_AUTHEN | + BLE_GATT_CHR_F_READ | + BLE_GATT_CHR_F_WRITE_AUTHEN | + BLE_GATT_CHR_F_WRITE | + BLE_GATT_CHR_F_WRITE_AUTHEN, + }, { + .uuid = PTS_UUID_DECLARE(PTS_CHR_READ_WRITE_AUTHOR), + .access_cb = gatt_svr_read_write_author_test, + .flags = BLE_GATT_CHR_F_READ_AUTHOR | + BLE_GATT_CHR_F_READ | + BLE_GATT_CHR_F_WRITE_AUTHOR | + BLE_GATT_CHR_F_WRITE + }, { + .uuid = PTS_UUID_DECLARE(PTS_CHR_RELIABLE_WRITE), + .access_cb = gatt_svr_rel_write_test, + .flags = BLE_GATT_CHR_F_WRITE | + BLE_GATT_CHR_F_RELIABLE_WRITE, + }, { + .uuid = PTS_UUID_DECLARE(PTS_CHR_READ_WRITE_ENC), + .access_cb = gatt_svr_read_write_enc_test, + .flags = BLE_GATT_CHR_F_READ_ENC | + BLE_GATT_CHR_F_READ | + BLE_GATT_CHR_F_WRITE | + BLE_GATT_CHR_F_WRITE_ENC, + .min_key_size = 16, + }, { + .uuid = PTS_UUID_DECLARE(PTS_LONG_CHR_READ_WRITE), + .access_cb = gatt_svr_read_write_long_test, + .flags = BLE_GATT_CHR_F_WRITE | + BLE_GATT_CHR_F_READ, + }, { + .uuid = PTS_UUID_DECLARE(PTS_LONG_CHR_READ_WRITE_ALT), + .access_cb = gatt_svr_read_write_long_test, + .flags = BLE_GATT_CHR_F_WRITE | + BLE_GATT_CHR_F_READ, + }, { + .uuid = PTS_UUID_DECLARE(PTS_CHR_NOTIFY), + .access_cb = gatt_svr_read_write_test, + .val_handle = ¬ify_handle, + .flags = BLE_GATT_CHR_F_READ | + BLE_GATT_CHR_F_WRITE | + BLE_GATT_CHR_F_NOTIFY | + BLE_GATT_CHR_F_INDICATE, + }, { + .uuid = PTS_UUID_DECLARE(PTS_CHR_NOTIFY_ALT), + .access_cb = gatt_svr_read_write_test, + .val_handle = ¬ify_handle_alt, + .flags = BLE_GATT_CHR_F_READ | + BLE_GATT_CHR_F_WRITE | + BLE_GATT_CHR_F_NOTIFY | + BLE_GATT_CHR_F_INDICATE, + }, { + 0, /* No more characteristics in this service. */ + } + }, + }, { + .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid = PTS_UUID_DECLARE_ALT(PTS_SVC), + .characteristics = (struct ble_gatt_chr_def[]) {{ + .uuid = PTS_UUID_DECLARE_ALT(PTS_CHR_READ_WRITE), + .access_cb = gatt_svr_read_write_test, + .flags = BLE_GATT_CHR_F_WRITE | + BLE_GATT_CHR_F_READ, + }, { + 0, /* No more characteristics in this service */ + }}, + }, { + 0, /* No more services. */ + }, +}; + +static void +attr_value_changed_ev(uint16_t handle, struct os_mbuf *data) +{ + struct btp_gatt_attr_value_changed_ev *ev; + struct os_mbuf *buf = os_msys_get(0, 0); + + SYS_LOG_DBG(""); + + ev = os_mbuf_extend(buf, sizeof(*ev)); + if (!ev) { + return; + } + + ev->handle = htole16(handle); + ev->data_length = htole16(os_mbuf_len(data)); + os_mbuf_appendfrom(buf, data, 0, os_mbuf_len(data)); + + tester_event(BTP_SERVICE_ID_GATT, BTP_GATT_EV_ATTR_VALUE_CHANGED, + buf->om_data, buf->om_len); +} + +static int +gatt_svr_chr_write(uint16_t conn_handle, uint16_t attr_handle, + struct os_mbuf *om, uint16_t min_len, uint16_t max_len, + void *dst, uint16_t *len) +{ + uint16_t om_len; + int rc; + + om_len = OS_MBUF_PKTLEN(om); + if (om_len < min_len || om_len > max_len) { + return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; + } + + rc = ble_hs_mbuf_to_flat(om, dst, max_len, len); + if (rc != 0) { + return BLE_ATT_ERR_UNLIKELY; + } + + attr_value_changed_ev(attr_handle, om); + + return 0; +} + +static uint16_t +extract_uuid16_from_pts_uuid128(const ble_uuid_t *uuid) +{ + const uint8_t *u8ptr; + uint16_t uuid16; + + u8ptr = BLE_UUID128(uuid)->value; + uuid16 = u8ptr[12]; + uuid16 |= (uint16_t) u8ptr[13] << 8; + return uuid16; +} + +static int +gatt_svr_read_write_test(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, + void *arg) +{ + uint16_t uuid16; + int rc; + + uuid16 = extract_uuid16_from_pts_uuid128(ctxt->chr->uuid); + assert(uuid16 != 0); + + switch (uuid16) { + case PTS_CHR_READ_WRITE: + case PTS_CHR_READ_WRITE_ALT: + case PTS_CHR_NOTIFY: + case PTS_CHR_NOTIFY_ALT: + if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) { + rc = gatt_svr_chr_write(conn_handle, attr_handle, ctxt->om, 0, + sizeof(gatt_svr_pts_static_short_val), + &gatt_svr_pts_static_short_val, NULL); + return rc; + } else if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) { + rc = os_mbuf_append(ctxt->om, &gatt_svr_pts_static_short_val, + sizeof(gatt_svr_pts_static_short_val)); + return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; + } + default: + assert(0); + return BLE_ATT_ERR_UNLIKELY; + } +} + +static int +gatt_svr_read_write_long_test(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, + void *arg) +{ + uint16_t uuid16; + int rc; + + uuid16 = extract_uuid16_from_pts_uuid128(ctxt->chr->uuid); + assert(uuid16 != 0); + + switch (uuid16) { + case PTS_LONG_CHR_READ_WRITE: + case PTS_LONG_CHR_READ_WRITE_ALT: + if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) { + rc = gatt_svr_chr_write(conn_handle, attr_handle, ctxt->om, 0, + sizeof(gatt_svr_pts_static_long_val), + &gatt_svr_pts_static_long_val, NULL); + return rc; + } else if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) { + rc = os_mbuf_append(ctxt->om, &gatt_svr_pts_static_long_val, + sizeof(gatt_svr_pts_static_long_val)); + return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; + } + default: + assert(0); + return BLE_ATT_ERR_UNLIKELY; + } +} + +static int +gatt_svr_read_write_auth_test(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, + void *arg) +{ + uint16_t uuid16; + int rc; + + uuid16 = extract_uuid16_from_pts_uuid128(ctxt->chr->uuid); + assert(uuid16 != 0); + + switch (uuid16) { + case PTS_CHR_READ_WRITE_AUTHEN: + if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) { + rc = gatt_svr_chr_write(conn_handle, attr_handle, ctxt->om, 0, + sizeof(gatt_svr_pts_static_val), + &gatt_svr_pts_static_val, NULL); + return rc; + } else if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) { + rc = os_mbuf_append(ctxt->om, &gatt_svr_pts_static_val, + sizeof(gatt_svr_pts_static_val)); + return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; + } + default: + assert(0); + return BLE_ATT_ERR_UNLIKELY; + } +} + +static int +gatt_svr_read_write_author_test(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, + void *arg) +{ + uint16_t uuid16; + + uuid16 = extract_uuid16_from_pts_uuid128(ctxt->chr->uuid); + assert(uuid16 != 0); + + switch (uuid16) { + case PTS_CHR_READ_WRITE_AUTHOR: + if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) { + return BLE_ATT_ERR_INSUFFICIENT_AUTHOR; + } else if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) { + return BLE_ATT_ERR_INSUFFICIENT_AUTHOR; + } + default: + assert(0); + return BLE_ATT_ERR_UNLIKELY; + } +} + +static int +gatt_svr_read_write_enc_test(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, + void *arg) +{ + uint16_t uuid16; + int rc; + + uuid16 = extract_uuid16_from_pts_uuid128(ctxt->chr->uuid); + assert(uuid16 != 0); + + switch (uuid16) { + case PTS_CHR_READ_WRITE_ENC: + if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) { + rc = os_mbuf_append(ctxt->om, &gatt_svr_pts_static_val, + sizeof(gatt_svr_pts_static_val)); + return rc; + } else if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) { + rc = gatt_svr_chr_write(conn_handle, attr_handle, ctxt->om, 0, + sizeof(gatt_svr_pts_static_val), + &gatt_svr_pts_static_val, NULL); + return rc; + } + default: + assert(0); + return BLE_ATT_ERR_UNLIKELY; + } +} + +static int +gatt_svr_dsc_read_write_test(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, + void *arg) +{ + uint16_t uuid16; + int rc; + + uuid16 = extract_uuid16_from_pts_uuid128(ctxt->chr->uuid); + assert(uuid16 != 0); + + switch (uuid16) { + case PTS_DSC_READ_WRITE: + if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_DSC) { + rc = gatt_svr_chr_write(conn_handle, attr_handle, ctxt->om, 0, + sizeof(gatt_svr_pts_static_short_val), + &gatt_svr_pts_static_short_val, NULL); + return rc; + } else if (ctxt->op == BLE_GATT_ACCESS_OP_READ_DSC) { + rc = os_mbuf_append(ctxt->om, &gatt_svr_pts_static_short_val, + sizeof(gatt_svr_pts_static_short_val)); + return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; + } + default: + assert(0); + return BLE_ATT_ERR_UNLIKELY; + } +} + +static int +gatt_svr_dsc_read_write_long_test(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, + void *arg) +{ + uint16_t uuid16; + int rc; + + uuid16 = extract_uuid16_from_pts_uuid128(ctxt->chr->uuid); + assert(uuid16 != 0); + + switch (uuid16) { + case PTS_LONG_DSC_READ_WRITE: + if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_DSC) { + rc = gatt_svr_chr_write(conn_handle, attr_handle, ctxt->om, 0, + sizeof(gatt_svr_pts_static_long_val), + &gatt_svr_pts_static_long_val, NULL); + return rc; + } else if (ctxt->op == BLE_GATT_ACCESS_OP_READ_DSC) { + rc = os_mbuf_append(ctxt->om, &gatt_svr_pts_static_long_val, + sizeof(gatt_svr_pts_static_long_val)); + return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; + } + default: + assert(0); + return BLE_ATT_ERR_UNLIKELY; + } +} + +static int +gatt_svr_dsc_read_test(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, + void *arg) +{ + uint16_t uuid16; + int rc; + + uuid16 = extract_uuid16_from_pts_uuid128(ctxt->chr->uuid); + assert(uuid16 != 0); + + switch (uuid16) { + case PTS_DSC_READ: + if (ctxt->op == BLE_GATT_ACCESS_OP_READ_DSC) { + rc = os_mbuf_append(ctxt->om, &gatt_svr_pts_static_long_val, + sizeof(gatt_svr_pts_static_long_val)); + return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; + } + default: + assert(0); + return BLE_ATT_ERR_UNLIKELY; + } +} + +static int +gatt_svr_write_no_rsp_test(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, + void *arg) +{ + uint16_t uuid16; + int rc; + + uuid16 = extract_uuid16_from_pts_uuid128(ctxt->chr->uuid); + assert(uuid16 != 0); + + switch (uuid16) { + case PTS_CHR_WRITE_NO_RSP: + if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) { + rc = gatt_svr_chr_write(conn_handle, attr_handle, ctxt->om, 0, + sizeof(gatt_svr_pts_static_short_val), + &gatt_svr_pts_static_short_val, NULL); + return rc; + } else if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) { + rc = os_mbuf_append(ctxt->om, &gatt_svr_pts_static_short_val, + sizeof(gatt_svr_pts_static_short_val)); + return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; + } + default: + assert(0); + return BLE_ATT_ERR_UNLIKELY; + } +} + +static int +gatt_svr_rel_write_test(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, + void *arg) +{ + uint16_t uuid16; + int rc; + + uuid16 = extract_uuid16_from_pts_uuid128(ctxt->chr->uuid); + assert(uuid16 != 0); + + switch (uuid16) { + case PTS_CHR_RELIABLE_WRITE: + if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) { + rc = gatt_svr_chr_write(conn_handle, attr_handle, ctxt->om, 0, + sizeof(gatt_svr_pts_static_val), + &gatt_svr_pts_static_val, NULL); + return rc; + } + + default: + assert(0); + return BLE_ATT_ERR_UNLIKELY; + } +} + +static uint8_t +start_server(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + struct btp_gatt_start_server_rp *rp = rsp; + + SYS_LOG_DBG(""); + + ble_gatts_show_local(); + + ble_svc_gatt_changed(0x0001, 0xffff); + + rp->db_attr_off = 0; + rp->db_attr_cnt = 0; + + *rsp_len = sizeof(*rp); + + return BTP_STATUS_SUCCESS; +} + +/* Convert UUID from BTP command to bt_uuid */ +static uint8_t +btp2bt_uuid(const uint8_t *uuid, uint8_t len, + ble_uuid_any_t *bt_uuid) +{ + uint16_t le16; + + switch (len) { + case 0x02: /* UUID 16 */ + bt_uuid->u.type = BLE_UUID_TYPE_16; + memcpy(&le16, uuid, sizeof(le16)); + BLE_UUID16(bt_uuid)->value = le16toh(le16); + break; + case 0x10: /* UUID 128*/ + bt_uuid->u.type = BLE_UUID_TYPE_128; + memcpy(BLE_UUID128(bt_uuid)->value, uuid, 16); + break; + default: + return BTP_STATUS_FAILED; + } + return BTP_STATUS_SUCCESS; +} + +/* + * gatt_buf - cache used by a gatt client (to cache data read/discovered) + * and gatt server (to store attribute user_data). + * It is not intended to be used by client and server at the same time. + */ +static struct { + uint16_t len; + uint8_t buf[MAX_BUFFER_SIZE]; +} gatt_buf; + +static void * +gatt_buf_add(const void *data, size_t len) +{ + void *ptr = gatt_buf.buf + gatt_buf.len; + + if ((len + gatt_buf.len) > MAX_BUFFER_SIZE) { + return NULL; + } + + if (data) { + memcpy(ptr, data, len); + } else { + (void) memset(ptr, 0, len); + } + + gatt_buf.len += len; + + SYS_LOG_DBG("%d/%d used", gatt_buf.len, MAX_BUFFER_SIZE); + + return ptr; +} + +static void * +gatt_buf_reserve(size_t len) +{ + return gatt_buf_add(NULL, len); +} + +static void +gatt_buf_clear(void) +{ + (void) memset(&gatt_buf, 0, sizeof(gatt_buf)); +} + +static void +discover_destroy(void) +{ + gatt_buf_clear(); +} + +static void +read_destroy() +{ + gatt_buf_clear(); +} + +static int +read_cb(uint16_t conn_handle, + const struct ble_gatt_error *error, + struct ble_gatt_attr *attr, + void *arg) +{ + struct btp_gatt_read_rp *rp = (void *) gatt_buf.buf; + uint8_t btp_opcode = (uint8_t) (int) arg; + + SYS_LOG_DBG("status=%d", error->status); + + if (error->status != 0 && error->status != BLE_HS_EDONE) { + rp->att_response = (uint8_t) BLE_HS_ATT_ERR(error->status); + tester_rsp_full(BTP_SERVICE_ID_GATT, btp_opcode, + gatt_buf.buf, gatt_buf.len); + read_destroy(); + return 0; + } + + if (!gatt_buf_add(attr->om->om_data, attr->om->om_len)) { + tester_rsp(BTP_SERVICE_ID_GATT, btp_opcode, + BTP_STATUS_FAILED); + read_destroy(); + return 0; + } + + rp->data_length += attr->om->om_len; + tester_rsp_full(BTP_SERVICE_ID_GATT, btp_opcode, + gatt_buf.buf, gatt_buf.len); + read_destroy(); + + return 0; +} + +static uint8_t +read_data(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gatt_read_cmd *cp = cmd; + struct ble_gap_conn_desc conn; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find_by_addr(&cp->address, &conn); + if (rc) { + return BTP_STATUS_FAILED; + } + + /* Clear buffer */ + read_destroy(); + + if (!gatt_buf_reserve(sizeof(struct btp_gatt_read_rp))) { + return BTP_STATUS_FAILED; + } + + if (ble_gattc_read(conn.conn_handle, le16toh(cp->handle), + read_cb, (void *) BTP_GATT_READ)) { + read_destroy(); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static int +read_long_cb(uint16_t conn_handle, + const struct ble_gatt_error *error, + struct ble_gatt_attr *attr, + void *arg) +{ + struct btp_gatt_read_rp *rp = (void *) gatt_buf.buf; + uint8_t btp_opcode = (uint8_t) (int) arg; + + SYS_LOG_DBG("status=%d", error->status); + + if (error->status != 0 && error->status != BLE_HS_EDONE) { + rp->att_response = (uint8_t) BLE_HS_ATT_ERR(error->status); + tester_rsp_full(BTP_SERVICE_ID_GATT, btp_opcode, + gatt_buf.buf, gatt_buf.len); + read_destroy(); + return 0; + } + + if (error->status == BLE_HS_EDONE) { + tester_rsp_full(BTP_SERVICE_ID_GATT, btp_opcode, + gatt_buf.buf, gatt_buf.len); + read_destroy(); + return 0; + } + + if (gatt_buf_add(attr->om->om_data, attr->om->om_len) == NULL) { + tester_rsp(BTP_SERVICE_ID_GATT, btp_opcode, + BTP_STATUS_FAILED); + read_destroy(); + return BLE_HS_ENOMEM; + } + + rp->data_length += attr->om->om_len; + + return 0; +} + +static uint8_t +read_long(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gatt_read_long_cmd *cp = cmd; + struct ble_gap_conn_desc conn; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find_by_addr(&cp->address, &conn); + if (rc) { + return BTP_STATUS_FAILED; + } + + /* Clear buffer */ + read_destroy(); + + if (!gatt_buf_reserve(sizeof(struct btp_gatt_read_rp))) { + return BTP_STATUS_FAILED; + } + + if (ble_gattc_read_long(conn.conn_handle, + le16toh(cp->handle), + le16toh(cp->offset), + read_long_cb, (void *) BTP_GATT_READ_LONG)) { + read_destroy(); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +read_multiple(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gatt_read_multiple_cmd *cp = cmd; + uint16_t handles[cp->handles_count]; + struct ble_gap_conn_desc conn; + int rc, i; + + SYS_LOG_DBG(""); + + for (i = 0; i < ARRAY_SIZE(handles); i++) { + handles[i] = le16toh(cp->handles[i]); + } + + rc = ble_gap_conn_find_by_addr(&cp->address, &conn); + if (rc) { + return BTP_STATUS_FAILED; + } + + /* Clear buffer */ + read_destroy(); + + if (!gatt_buf_reserve(sizeof(struct btp_gatt_read_rp))) { + return BTP_STATUS_FAILED; + } + + if (ble_gattc_read_mult(conn.conn_handle, handles, + cp->handles_count, read_cb, + (void *) BTP_GATT_READ_MULTIPLE)) { + read_destroy(); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +write_without_rsp(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gatt_write_without_rsp_cmd *cp = cmd; + struct ble_gap_conn_desc conn; + int rc; + + SYS_LOG_DBG(""); + + if (cmd_len < sizeof(*cp) || + cmd_len != sizeof(*cp) + le16toh(cp->data_length)) { + return BTP_STATUS_FAILED; + } + + rc = ble_gap_conn_find_by_addr(&cp->address, &conn); + if (rc) { + return BTP_STATUS_FAILED; + } + + if (ble_gattc_write_no_rsp_flat(conn.conn_handle, + le16toh(cp->handle), cp->data, + le16toh(cp->data_length))) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static int +write_rsp(uint16_t conn_handle, const struct ble_gatt_error *error, + struct ble_gatt_attr *attr, + void *arg) +{ + uint8_t err = (uint8_t) error->status; + uint8_t btp_opcode = (uint8_t) (int) arg; + + SYS_LOG_DBG(""); + + tester_rsp_full(BTP_SERVICE_ID_GATT, btp_opcode, + &err, sizeof(err)); + return 0; +} + +static uint8_t +write_data(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gatt_write_cmd *cp = cmd; + struct ble_gap_conn_desc conn; + int rc; + + SYS_LOG_DBG(""); + + if (cmd_len < sizeof(*cp) || + cmd_len != sizeof(*cp) + le16toh(cp->data_length)) { + return BTP_STATUS_FAILED; + } + + rc = ble_gap_conn_find_by_addr(&cp->address, &conn); + if (rc) { + return BTP_STATUS_FAILED; + } + + if (ble_gattc_write_flat(conn.conn_handle, le16toh(cp->handle), + cp->data, le16toh(cp->data_length), + write_rsp, (void *) BTP_GATT_WRITE)) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_DELAY_REPLY; +} + +static uint8_t +write_long(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gatt_write_long_cmd *cp = cmd; + struct ble_gap_conn_desc conn; + struct os_mbuf *om = NULL; + int rc = 0; + + SYS_LOG_DBG(""); + + if (cmd_len < sizeof(*cp) || + cmd_len != sizeof(*cp) + le16toh(cp->data_length)) { + goto fail; + } + + rc = ble_gap_conn_find_by_addr(&cp->address, &conn); + if (rc) { + goto fail; + } + + om = ble_hs_mbuf_from_flat(cp->data, le16toh(cp->data_length)); + if (!om) { + SYS_LOG_ERR("Insufficient resources"); + goto fail; + } + + rc = ble_gattc_write_long(conn.conn_handle, + le16toh(cp->handle), + le16toh(cp->offset), + om, write_rsp, + (void *) BTP_GATT_WRITE_LONG); + if (!rc) { + return BTP_STATUS_DELAY_REPLY; + } + +fail: + SYS_LOG_ERR("Failed to send Write Long request, rc=%d", rc); + os_mbuf_free_chain(om); + return BTP_STATUS_FAILED; +} + +static int +reliable_write_rsp(uint16_t conn_handle, + const struct ble_gatt_error *error, + struct ble_gatt_attr *attrs, + uint8_t num_attrs, + void *arg) +{ + uint8_t err = (uint8_t) error->status; + + SYS_LOG_DBG("Reliable write status %d", err); + + tester_rsp_full(BTP_SERVICE_ID_GATT, BTP_GATT_RELIABLE_WRITE, + &err, sizeof(err)); + return 0; +} + +static uint8_t +reliable_write(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gatt_reliable_write_cmd *cp = cmd; + struct ble_gap_conn_desc conn; + struct ble_gatt_attr attr; + struct os_mbuf *om = NULL; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find_by_addr(&cp->address, &conn); + if (rc) { + goto fail; + } + + om = ble_hs_mbuf_from_flat(cp->data, le16toh(cp->data_length)); + /* This is required, because Nimble checks if + * the data is longer than offset + */ + if (os_mbuf_extend(om, le16toh(cp->offset) + 1) == NULL) { + goto fail; + } + + attr.handle = le16toh(cp->handle); + attr.offset = le16toh(cp->offset); + attr.om = om; + + if (ble_gattc_write_reliable(conn.conn_handle, &attr, 1, + reliable_write_rsp, NULL)) { + goto fail; + } + + return BTP_STATUS_SUCCESS; + +fail: + os_mbuf_free_chain(om); + + return BTP_STATUS_FAILED; +} + +static struct bt_gatt_subscribe_params { + uint16_t ccc_handle; + uint16_t value; + uint16_t value_handle; +} subscribe_params; + +static uint8_t +read_uuid(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gatt_read_uuid_cmd *cp = cmd; + struct ble_gap_conn_desc conn; + ble_uuid_any_t uuid; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find_by_addr(&cp->address, &conn); + if (rc) { + return BTP_STATUS_FAILED; + } + + if (btp2bt_uuid(cp->uuid, cp->uuid_length, &uuid)) { + return BTP_STATUS_FAILED; + } + + /* Clear buffer */ + read_destroy(); + + if (!gatt_buf_reserve(sizeof(struct btp_gatt_read_rp))) { + return BTP_STATUS_FAILED; + } + + if (ble_gattc_read_by_uuid(conn.conn_handle, + le16toh(cp->start_handle), + le16toh(cp->end_handle), &uuid.u, + read_long_cb, (void *) BTP_GATT_READ_UUID)) { + read_destroy(); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static int +disc_prim_uuid_cb(uint16_t conn_handle, + const struct ble_gatt_error *error, + const struct ble_gatt_svc *gatt_svc, void *arg) +{ + struct btp_gatt_disc_prim_uuid_rp *rp = (void *) gatt_buf.buf; + struct btp_gatt_service *service; + const ble_uuid_any_t *uuid; + uint8_t uuid_length; + uint8_t opcode = (uint8_t) (int) arg; + + SYS_LOG_DBG(""); + + if (error->status != 0 && error->status != BLE_HS_EDONE) { + tester_rsp(BTP_SERVICE_ID_GATT, opcode, + BTP_STATUS_FAILED); + discover_destroy(); + return 0; + } + + if (error->status == BLE_HS_EDONE) { + tester_rsp_full(BTP_SERVICE_ID_GATT, opcode, + gatt_buf.buf, gatt_buf.len); + discover_destroy(); + return 0; + } + + uuid = &gatt_svc->uuid; + uuid_length = (uint8_t) (uuid->u.type == BLE_UUID_TYPE_16 ? 2 : 16); + + service = gatt_buf_reserve(sizeof(*service) + uuid_length); + if (!service) { + tester_rsp(BTP_SERVICE_ID_GATT, opcode, + BTP_STATUS_FAILED); + discover_destroy(); + return BLE_HS_ENOMEM; + } + + service->start_handle = htole16(gatt_svc->start_handle); + service->end_handle = htole16(gatt_svc->end_handle); + service->uuid_length = uuid_length; + + if (uuid->u.type == BLE_UUID_TYPE_16) { + uint16_t u16 = htole16(BLE_UUID16(uuid)->value); + memcpy(service->uuid, &u16, uuid_length); + } else { + memcpy(service->uuid, BLE_UUID128(uuid)->value, + uuid_length); + } + + rp->services_count++; + + return 0; +} + +static int +disc_all_desc_cb(uint16_t conn_handle, + const struct ble_gatt_error *error, + uint16_t chr_val_handle, + const struct ble_gatt_dsc *gatt_dsc, + void *arg) +{ + struct btp_gatt_disc_all_desc_rp *rp = (void *) gatt_buf.buf; + struct btp_gatt_descriptor *dsc; + const ble_uuid_any_t *uuid; + uint8_t uuid_length; + + SYS_LOG_DBG(""); + + if (error->status != 0 && error->status != BLE_HS_EDONE) { + tester_rsp(BTP_SERVICE_ID_GATT, BTP_GATT_DISC_ALL_DESC, + BTP_STATUS_FAILED); + discover_destroy(); + return 0; + } + + if (error->status == BLE_HS_EDONE) { + tester_rsp_full(BTP_SERVICE_ID_GATT, BTP_GATT_DISC_ALL_DESC, + gatt_buf.buf, gatt_buf.len); + discover_destroy(); + return 0; + } + + uuid = &gatt_dsc->uuid; + uuid_length = (uint8_t) (uuid->u.type == BLE_UUID_TYPE_16 ? 2 : 16); + + dsc = gatt_buf_reserve(sizeof(*dsc) + uuid_length); + if (!dsc) { + tester_rsp(BTP_SERVICE_ID_GATT, BTP_GATT_DISC_ALL_DESC, + BTP_STATUS_FAILED); + discover_destroy(); + return BLE_HS_ENOMEM; + } + + dsc->descriptor_handle = htole16(gatt_dsc->handle); + dsc->uuid_length = uuid_length; + + if (uuid->u.type == BLE_UUID_TYPE_16) { + uint16_t u16 = htole16(BLE_UUID16(uuid)->value); + memcpy(dsc->uuid, &u16, uuid_length); + } else { + memcpy(dsc->uuid, BLE_UUID128(uuid)->value, uuid_length); + } + + rp->descriptors_count++; + + return 0; +} + +static uint8_t +disc_all_prim_svcs(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gatt_disc_all_prim_svcs_cmd *cp = cmd; + struct ble_gap_conn_desc conn; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find_by_addr(&cp->address, &conn); + if (rc) { + return BTP_STATUS_FAILED; + } + + if (!gatt_buf_reserve(sizeof(struct btp_gatt_disc_all_prim_svcs_rp))) { + return BTP_STATUS_FAILED; + } + + if (ble_gattc_disc_all_svcs(conn.conn_handle, disc_prim_uuid_cb, + (void *) BTP_GATT_DISC_ALL_PRIM_SVCS)) { + discover_destroy(); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_DELAY_REPLY; +} + +static uint8_t +disc_all_desc(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gatt_disc_all_desc_cmd *cp = cmd; + struct ble_gap_conn_desc conn; + uint16_t start_handle, end_handle; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find_by_addr(&cp->address, &conn); + if (rc) { + return BTP_STATUS_FAILED; + } + + if (!gatt_buf_reserve(sizeof(struct btp_gatt_disc_all_desc_rp))) { + return BTP_STATUS_FAILED; + } + + start_handle = le16toh(cp->start_handle) - 1; + end_handle = le16toh(cp->end_handle); + + rc = ble_gattc_disc_all_dscs(conn.conn_handle, start_handle, end_handle, + disc_all_desc_cb, NULL); + + SYS_LOG_DBG("rc=%d", rc); + + if (rc) { + discover_destroy(); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_DELAY_REPLY; +} + +static int +find_included_cb(uint16_t conn_handle, + const struct ble_gatt_error *error, + const struct ble_gatt_svc *gatt_svc, void *arg) +{ + struct btp_gatt_find_included_rp *rp = (void *) gatt_buf.buf; + struct btp_gatt_included *included; + const ble_uuid_any_t *uuid; + int service_handle = (int) arg; + uint8_t uuid_length; + + SYS_LOG_DBG(""); + + if (error->status != 0 && error->status != BLE_HS_EDONE) { + tester_rsp(BTP_SERVICE_ID_GATT, BTP_GATT_FIND_INCLUDED, + BTP_STATUS_FAILED); + discover_destroy(); + return 0; + } + + if (error->status == BLE_HS_EDONE) { + tester_rsp_full(BTP_SERVICE_ID_GATT, BTP_GATT_FIND_INCLUDED, + gatt_buf.buf, gatt_buf.len); + discover_destroy(); + return 0; + } + + uuid = &gatt_svc->uuid; + uuid_length = (uint8_t) (uuid->u.type == BLE_UUID_TYPE_16 ? 2 : 16); + + included = gatt_buf_reserve(sizeof(*included) + uuid_length); + if (!included) { + tester_rsp(BTP_SERVICE_ID_GATT, BTP_GATT_FIND_INCLUDED, + BTP_STATUS_FAILED); + discover_destroy(); + return BLE_HS_ENOMEM; + } + + included->included_handle = htole16(service_handle + 1 + + rp->services_count); + included->service.start_handle = htole16(gatt_svc->start_handle); + included->service.end_handle = htole16(gatt_svc->end_handle); + included->service.uuid_length = uuid_length; + + if (uuid->u.type == BLE_UUID_TYPE_16) { + uint16_t u16 = htole16(BLE_UUID16(uuid)->value); + memcpy(included->service.uuid, &u16, uuid_length); + } else { + memcpy(included->service.uuid, BLE_UUID128(uuid)->value, + uuid_length); + } + + rp->services_count++; + + return 0; +} + +static int +disc_chrc_cb(uint16_t conn_handle, + const struct ble_gatt_error *error, + const struct ble_gatt_chr *gatt_chr, void *arg) +{ + struct btp_gatt_disc_chrc_rp *rp = (void *) gatt_buf.buf; + struct btp_gatt_characteristic *chrc; + const ble_uuid_any_t *uuid; + uint8_t btp_opcode = (uint8_t) (int) arg; + uint8_t uuid_length; + + SYS_LOG_DBG(""); + + if (error->status != 0 && error->status != BLE_HS_EDONE) { + tester_rsp(BTP_SERVICE_ID_GATT, btp_opcode, + BTP_STATUS_FAILED); + discover_destroy(); + return 0; + } + + if (error->status == BLE_HS_EDONE) { + tester_rsp_full(BTP_SERVICE_ID_GATT, btp_opcode, + gatt_buf.buf, gatt_buf.len); + discover_destroy(); + return 0; + } + + uuid = &gatt_chr->uuid; + uuid_length = (uint8_t) (uuid->u.type == BLE_UUID_TYPE_16 ? 2 : 16); + + chrc = gatt_buf_reserve(sizeof(*chrc) + uuid_length); + if (!chrc) { + tester_rsp(BTP_SERVICE_ID_GATT, btp_opcode, + BTP_STATUS_FAILED); + discover_destroy(); + return BLE_HS_ENOMEM; + } + + chrc->characteristic_handle = htole16(gatt_chr->def_handle); + chrc->properties = gatt_chr->properties; + chrc->value_handle = htole16(gatt_chr->val_handle); + chrc->uuid_length = uuid_length; + + if (uuid->u.type == BLE_UUID_TYPE_16) { + uint16_t u16 = htole16(BLE_UUID16(uuid)->value); + memcpy(chrc->uuid, &u16, uuid_length); + } else { + memcpy(chrc->uuid, BLE_UUID128(uuid)->value, + uuid_length); + } + + rp->characteristics_count++; + + return 0; +} + +static uint8_t +disc_chrc_uuid(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gatt_disc_chrc_uuid_cmd *cp = cmd; + struct ble_gap_conn_desc conn; + uint16_t start_handle, end_handle; + ble_uuid_any_t uuid; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find_by_addr(&cp->address, &conn); + if (rc) { + return BTP_STATUS_FAILED; + } + + if (btp2bt_uuid(cp->uuid, cp->uuid_length, &uuid)) { + return BTP_STATUS_FAILED; + } + + if (!gatt_buf_reserve(sizeof(struct btp_gatt_disc_chrc_rp))) { + return BTP_STATUS_FAILED; + } + + start_handle = le16toh(cp->start_handle); + end_handle = le16toh(cp->end_handle); + + if (ble_gattc_disc_chrs_by_uuid(conn.conn_handle, start_handle, + end_handle, &uuid.u, disc_chrc_cb, + (void *) BTP_GATT_DISC_CHRC_UUID)) { + discover_destroy(); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_DELAY_REPLY; +} + +static uint8_t +disc_prim_uuid(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gatt_disc_prim_uuid_cmd *cp = cmd; + struct ble_gap_conn_desc conn; + ble_uuid_any_t uuid; + int rc; + + SYS_LOG_DBG(""); + + if ((cmd_len < sizeof(*cp)) || + (cmd_len != sizeof(*cp) + cp->uuid_length)) { + return BTP_STATUS_FAILED; + } + + rc = ble_gap_conn_find_by_addr(&cp->address, &conn); + if (rc) { + return BTP_STATUS_FAILED; + } + + if (btp2bt_uuid(cp->uuid, cp->uuid_length, &uuid)) { + return BTP_STATUS_FAILED; + } + + if (!gatt_buf_reserve(sizeof(struct btp_gatt_disc_prim_uuid_rp))) { + return BTP_STATUS_FAILED; + } + + if (ble_gattc_disc_svc_by_uuid(conn.conn_handle, + &uuid.u, disc_prim_uuid_cb, + (void *) BTP_GATT_DISC_PRIM_UUID)) { + discover_destroy(); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_DELAY_REPLY; +} + +static uint8_t +disc_all_chrc(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gatt_disc_all_chrc_cmd *cp = cmd; + struct ble_gap_conn_desc conn; + uint16_t start_handle, end_handle; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find_by_addr(&cp->address, &conn); + if (rc) { + SYS_LOG_DBG("Conn find failed"); + return BTP_STATUS_FAILED; + } + + if (!gatt_buf_reserve(sizeof(struct btp_gatt_disc_chrc_rp))) { + SYS_LOG_DBG("Buf reserve failed"); + return BTP_STATUS_FAILED; + } + + start_handle = le16toh(cp->start_handle); + end_handle = le16toh(cp->end_handle); + + rc = ble_gattc_disc_all_chrs(conn.conn_handle, start_handle, end_handle, + disc_chrc_cb, (void *) BTP_GATT_DISC_ALL_CHRC); + if (rc) { + discover_destroy(); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_DELAY_REPLY; +} + +static uint8_t +find_included(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gatt_find_included_cmd *cp = cmd; + struct ble_gap_conn_desc conn; + uint16_t start_handle, end_handle; + int service_handle_arg; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find_by_addr(&cp->address, &conn); + if (rc) { + return BTP_STATUS_FAILED; + } + + if (!gatt_buf_reserve(sizeof(struct btp_gatt_find_included_rp))) { + return BTP_STATUS_FAILED; + } + + start_handle = le16toh(cp->start_handle); + end_handle = le16toh(cp->end_handle); + service_handle_arg = start_handle; + + if (ble_gattc_find_inc_svcs(conn.conn_handle, start_handle, end_handle, + find_included_cb, + (void *) service_handle_arg)) { + discover_destroy(); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_DELAY_REPLY; +} + +static int +exchange_func(uint16_t conn_handle, + const struct ble_gatt_error *error, + uint16_t mtu, void *arg) +{ + SYS_LOG_DBG(""); + + if (error->status) { + SYS_LOG_DBG("MTU exchange failed"); + + return 0; + } + + SYS_LOG_DBG("MTU exchange succeed"); + + return 0; +} + +static uint8_t +exchange_mtu(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gatt_exchange_mtu_cmd *cp = cmd; + struct ble_gap_conn_desc conn; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find_by_addr(&cp->address, &conn); + if (rc) { + return BTP_STATUS_FAILED; + } + + if (ble_gattc_exchange_mtu(conn.conn_handle, exchange_func, NULL)) { + return BTP_STATUS_FAILED; + } + + /* this BTP command is about initiating MTU exchange, no need to wait + * for procedure to complete. + */ + return BTP_STATUS_SUCCESS; +} + +static int +enable_subscription(uint16_t conn_handle, uint16_t ccc_handle, + uint16_t value) +{ + uint8_t op; + + SYS_LOG_DBG(""); + + op = (uint8_t) (value == 0x0001 ? BTP_GATT_CFG_NOTIFY : BTP_GATT_CFG_INDICATE); + + if (ble_gattc_write_flat(conn_handle, ccc_handle, + &value, sizeof(value), NULL, NULL)) { + return -EINVAL; + } + + subscribe_params.ccc_handle = value; + + tester_rsp(BTP_SERVICE_ID_GATT, op, BTP_STATUS_SUCCESS); + return 0; +} + +static int +disable_subscription(uint16_t conn_handle, uint16_t ccc_handle) +{ + uint16_t value = 0x00; + + SYS_LOG_DBG(""); + + /* Fail if CCC handle doesn't match */ + if (ccc_handle != subscribe_params.ccc_handle) { + SYS_LOG_ERR("CCC handle doesn't match"); + return -EINVAL; + } + + if (ble_gattc_write_no_rsp_flat(conn_handle, ccc_handle, + &value, sizeof(value))) { + return -EINVAL; + } + + subscribe_params.ccc_handle = 0; + return 0; +} + +static uint8_t +config_subscription_notif(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gatt_cfg_notify_cmd *cp = cmd; + struct ble_gap_conn_desc conn; + uint16_t ccc_handle = le16toh(cp->ccc_handle); + uint8_t status; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find_by_addr(&cp->address, &conn); + if (rc) { + return BTP_STATUS_FAILED; + } + + if (cp->enable) { + /* on success response will be sent from callback */ + if (enable_subscription(conn.conn_handle, + ccc_handle, 0x0001) == 0) { + return BTP_STATUS_DELAY_REPLY; + } + + status = BTP_STATUS_FAILED; + } else { + if (disable_subscription(conn.conn_handle, ccc_handle) < 0) { + status = BTP_STATUS_FAILED; + } else { + status = BTP_STATUS_SUCCESS; + } + } + + return status; +} + +static uint8_t +config_subscription_ind(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gatt_cfg_notify_cmd *cp = cmd; + struct ble_gap_conn_desc conn; + uint16_t ccc_handle = le16toh(cp->ccc_handle); + uint8_t status; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find_by_addr(&cp->address, &conn); + if (rc) { + return BTP_STATUS_FAILED; + } + + if (cp->enable) { + /* on success response will be sent from callback */ + if (enable_subscription(conn.conn_handle, + ccc_handle, 0x0002) == 0) { + return BTP_STATUS_DELAY_REPLY; + } + + status = BTP_STATUS_FAILED; + } else { + if (disable_subscription(conn.conn_handle, ccc_handle) < 0) { + status = BTP_STATUS_FAILED; + } else { + status = BTP_STATUS_SUCCESS; + } + } + + return status; +} + +#define BTP_PERM_F_READ 0x01 +#define BTP_PERM_F_WRITE 0x02 +#define BTP_PERM_F_READ_ENC 0x04 +#define BTP_PERM_F_WRITE_ENC 0x08 +#define BTP_PERM_F_READ_AUTHEN 0x10 +#define BTP_PERM_F_WRITE_AUTHEN 0x20 +#define BTP_PERM_F_READ_AUTHOR 0x40 +#define BTP_PERM_F_WRITE_AUTHOR 0x80 + +static int flags_hs2btp_map[] = { + BTP_PERM_F_READ, + BTP_PERM_F_WRITE, + BTP_PERM_F_READ_ENC, + BTP_PERM_F_READ_AUTHEN, + BTP_PERM_F_READ_AUTHOR, + BTP_PERM_F_WRITE_ENC, + BTP_PERM_F_WRITE_AUTHEN, + BTP_PERM_F_WRITE_AUTHOR, +}; + +static uint8_t +flags_hs2btp(uint8_t flags) +{ + int i; + uint8_t ret = 0; + + for (i = 0; i < 8; ++i) { + if (flags & BIT(i)) { + ret |= flags_hs2btp_map[i]; + } + } + + return ret; +} + +static uint8_t +get_attrs(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gatt_get_attributes_cmd *cp = cmd; + struct btp_gatt_get_attributes_rp *rp = rsp; + struct btp_gatt_attr *gatt_attr; + struct os_mbuf *buf = os_msys_get(0, 0); + uint16_t start_handle, end_handle; + struct ble_att_svr_entry *entry = NULL; + ble_uuid_any_t uuid; + ble_uuid_t *uuid_ptr = NULL; + uint8_t count = 0; + char str[BLE_UUID_STR_LEN]; + uint8_t status = BTP_STATUS_SUCCESS; + + SYS_LOG_DBG(""); + + if (!buf) { + return BTP_STATUS_FAILED; + } + + memset(str, 0, sizeof(str)); + memset(&uuid, 0, sizeof(uuid)); + start_handle = le16toh(cp->start_handle); + end_handle = le16toh(cp->end_handle); + + if (cp->type_length) { + if (btp2bt_uuid(cp->type, cp->type_length, &uuid)) { + status = BTP_STATUS_FAILED; + goto done; + } + + ble_uuid_to_str(&uuid.u, str); + SYS_LOG_DBG("start 0x%04x end 0x%04x, uuid %s", start_handle, + end_handle, str); + + uuid_ptr = &uuid.u; + } else { + SYS_LOG_DBG("start 0x%04x end 0x%04x", start_handle, end_handle); + } + + entry = ble_att_svr_find_by_uuid(entry, uuid_ptr, end_handle); + while (entry) { + + if (entry->ha_handle_id < start_handle) { + entry = ble_att_svr_find_by_uuid(entry, + uuid_ptr, end_handle); + continue; + } + + gatt_attr = os_mbuf_extend(buf, sizeof(*gatt_attr)); + if (!gatt_attr) { + status = BTP_STATUS_FAILED; + goto done; + } + gatt_attr->handle = htole16(entry->ha_handle_id); + gatt_attr->permission = flags_hs2btp(entry->ha_flags); + + if (entry->ha_uuid->type == BLE_UUID_TYPE_16) { + uint16_t uuid_val; + + gatt_attr->type_length = 2; + uuid_val = htole16(BLE_UUID16(entry->ha_uuid)->value); + if (os_mbuf_append(buf, &uuid_val, sizeof(uuid_val))) { + status = BTP_STATUS_FAILED; + goto done; + } + } else { + gatt_attr->type_length = 16; + if (os_mbuf_append(buf, BLE_UUID128(entry->ha_uuid)->value, + gatt_attr->type_length)) { + status = BTP_STATUS_FAILED; + goto done; + } + } + + count++; + + entry = ble_att_svr_find_by_uuid(entry, uuid_ptr, end_handle); + } + + rp->attrs_count = count; + os_mbuf_copydata(buf, 0, os_mbuf_len(buf), rp->attrs); + + *rsp_len = sizeof(*rp) + os_mbuf_len(buf); + +done: + os_mbuf_free_chain(buf); + return status; +} + +static uint8_t +get_attr_val(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gatt_get_attribute_value_cmd *cp = cmd; + struct btp_gatt_get_attribute_value_rp *rp; + struct ble_gap_conn_desc conn; + struct os_mbuf *buf = os_msys_get(0, 0); + uint16_t handle = le16toh(cp->handle); + uint8_t out_att_err = 0; + int conn_status; + uint8_t status = BTP_STATUS_SUCCESS; + + conn_status = ble_gap_conn_find_by_addr(&cp->address, &conn); + + if (conn_status) { + rp = os_mbuf_extend(buf, sizeof(*rp)); + if (!rp) { + status = BTP_STATUS_FAILED; + goto free; + } + + ble_att_svr_read_handle(BLE_HS_CONN_HANDLE_NONE, + handle, 0, buf, + &out_att_err); + + rp->att_response = out_att_err; + rp->value_length = os_mbuf_len(buf) - sizeof(*rp); + + os_mbuf_copydata(buf, 0, os_mbuf_len(buf), rsp); + *rsp_len = os_mbuf_len(buf); + + goto free; + } else { + rp = os_mbuf_extend(buf, sizeof(*rp)); + if (!rp) { + status = BTP_STATUS_FAILED; + goto free; + } + + ble_att_svr_read_handle(conn.conn_handle, + handle, 0, buf, + &out_att_err); + + rp->att_response = out_att_err; + rp->value_length = os_mbuf_len(buf) - sizeof(*rp); + + os_mbuf_copydata(buf, 0, os_mbuf_len(buf), rsp); + *rsp_len = os_mbuf_len(buf); + + goto free; + } + +free: + os_mbuf_free_chain(buf); + return status; +} + +int +notify_multiple(uint16_t conn_handle, void *arg) +{ + struct notify_mult_cb_data *notify_data = + (struct notify_mult_cb_data *) arg; + int rc; + + SYS_LOG_DBG("") + + rc = ble_gatts_notify_multiple(conn_handle, + notify_data->tuple_cnt, + notify_data->handles); + + return rc; +} + +static uint8_t +notify_mult(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gatt_notify_mult_val_cmd *cp = cmd; + struct notify_mult_cb_data cb_data; + int i; + + + if (cmd_len < sizeof(*cp) || + (cmd_len != (sizeof(*cp) + + (le16toh(cp->count) * sizeof(cp->handles[0]))))) { + + return BTP_STATUS_FAILED; + } + + if (le16toh(cp->count) > sizeof(cb_data.handles)) { + SYS_LOG_ERR("Too many handles to notify"); + return BTP_STATUS_FAILED; + } + + for (i = 0; i < cp->count; i++) { + cb_data.handles[i] = le16toh(cp->handles[i]); + } + + cb_data.tuple_cnt = cp->count; + + ble_gap_conn_foreach_handle(notify_multiple, (void *)&cb_data); + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +change_database(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gatt_change_database_cmd *cp = cmd; + + SYS_LOG_DBG("") + + ble_gatts_show_local(); + + ble_svc_gatt_changed(cp->start_handle, cp->end_handle); + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +supported_commands(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + struct btp_gatt_read_supported_commands_rp *rp = rsp; + + *rsp_len = tester_supported_commands(BTP_SERVICE_ID_GATT, rp->data); + *rsp_len += sizeof(*rp); + + return BTP_STATUS_SUCCESS; +} + +enum attr_type { + BLE_GATT_ATTR_SVC = 0, + BLE_GATT_ATTR_CHR, + BLE_GATT_ATTR_DSC, +}; + +static const struct btp_handler handlers[] = { + { + .opcode = BTP_GATT_READ_SUPPORTED_COMMANDS, + .index = BTP_INDEX_NONE, + .expect_len = 0, + .func = supported_commands, + }, + { + .opcode = BTP_GATT_START_SERVER, + .expect_len = 0, + .func = start_server, + }, + { + .opcode = BTP_GATT_EXCHANGE_MTU, + .expect_len = sizeof(struct btp_gatt_exchange_mtu_cmd), + .func = exchange_mtu, + }, + { + .opcode = BTP_GATT_DISC_ALL_PRIM_SVCS, + .expect_len = sizeof(struct btp_gatt_disc_all_prim_svcs_cmd), + .func = disc_all_prim_svcs, + }, + { + .opcode = BTP_GATT_DISC_PRIM_UUID, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = disc_prim_uuid, + }, + { + .opcode = BTP_GATT_FIND_INCLUDED, + .expect_len = sizeof(struct btp_gatt_find_included_cmd), + .func = find_included, + }, + { + .opcode = BTP_GATT_DISC_ALL_CHRC, + .expect_len = sizeof(struct btp_gatt_disc_all_chrc_cmd), + .func = disc_all_chrc, + }, + { + .opcode = BTP_GATT_DISC_CHRC_UUID, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = disc_chrc_uuid, + }, + { + .opcode = BTP_GATT_DISC_ALL_DESC, + .expect_len = sizeof(struct btp_gatt_disc_all_desc_cmd), + .func = disc_all_desc, + }, + { + .opcode = BTP_GATT_CHANGE_DATABASE, + .expect_len = sizeof(struct btp_gatt_change_database_cmd), + .func = change_database, + }, + { + .opcode = BTP_GATT_READ, + .expect_len = sizeof(struct btp_gatt_read_cmd), + .func = read_data, + }, + { + .opcode = BTP_GATT_READ_UUID, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = read_uuid, + }, + { + .opcode = BTP_GATT_READ_LONG, + .expect_len = sizeof(struct btp_gatt_read_long_cmd), + .func = read_long, + }, + { + .opcode = BTP_GATT_READ_MULTIPLE, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = read_multiple, + }, + { + .opcode = BTP_GATT_WRITE_WITHOUT_RSP, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = write_without_rsp, + }, +#if 0 + { + .opcode = BTP_GATT_SIGNED_WRITE_WITHOUT_RSP, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = write_signed_without_rsp, + }, +#endif + { + .opcode = BTP_GATT_WRITE, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = write_data, + }, + { + .opcode = BTP_GATT_WRITE_LONG, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = write_long, + }, + { + .opcode = BTP_GATT_RELIABLE_WRITE, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = reliable_write, + }, + { + .opcode = BTP_GATT_CFG_NOTIFY, + .expect_len = sizeof(struct btp_gatt_cfg_notify_cmd), + .func = config_subscription_notif, + }, + { + .opcode = BTP_GATT_CFG_INDICATE, + .expect_len = sizeof(struct btp_gatt_cfg_notify_cmd), + .func = config_subscription_ind, + }, + { + .opcode = BTP_GATT_GET_ATTRIBUTES, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = get_attrs, + }, + { + .opcode = BTP_GATT_GET_ATTRIBUTE_VALUE, + .expect_len = sizeof(struct btp_gatt_get_attribute_value_cmd), + .func = get_attr_val, + }, + { + .opcode = BTP_GATT_NOTIFY_MULTIPLE, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = notify_mult, + }, +}; + +int +tester_gatt_notify_rx_ev(uint16_t conn_handle, uint16_t attr_handle, + uint8_t indication, struct os_mbuf *om) +{ + struct btp_gatt_notification_ev *ev; + struct ble_gap_conn_desc conn; + struct os_mbuf *buf = os_msys_get(0, 0); + const ble_addr_t *addr; + + SYS_LOG_DBG(""); + + if (!subscribe_params.ccc_handle) { + goto fail; + } + + if (ble_gap_conn_find(conn_handle, &conn)) { + goto fail; + } + + ev = os_mbuf_extend(buf, sizeof(*ev)); + if (!ev) { + goto fail; + } + + addr = &conn.peer_ota_addr; + + memcpy(&ev->address, addr, sizeof(ev->address)); + ev->type = (uint8_t) (indication ? 0x02 : 0x01); + ev->handle = htole16(attr_handle); + ev->data_length = htole16(os_mbuf_len(om)); + os_mbuf_appendfrom(buf, om, 0, os_mbuf_len(om)); + + tester_event(BTP_SERVICE_ID_GATT, BTP_GATT_EV_NOTIFICATION, + buf->om_data, buf->om_len); + +fail: + os_mbuf_free_chain(buf); + return 0; +} + +void +notify_test_stop(void) +{ + os_callout_stop(¬ify_tx_timer); +} + +void +notify_test_reset(void) +{ + int rc; + + rc = os_callout_reset(¬ify_tx_timer, OS_TICKS_PER_SEC); + assert(rc == 0); +} + +void +notify_test(struct os_event *ev) +{ + static uint8_t ntf[1]; + struct os_mbuf *om; + int rc; + + if (!notify_state && !indicate_state) { + notify_test_stop(); + notify_value = 90; + return; + } + + ntf[0] = notify_value; + + notify_value++; + if (notify_value == 160) { + notify_value = 90; + } + + om = ble_hs_mbuf_from_flat(ntf, sizeof(ntf)); + + if (notify_state) { + rc = ble_gatts_notify_custom(myconn_handle, notify_handle, om); + assert(rc == 0); + } + + if (indicate_state) { + rc = ble_gatts_indicate_custom(myconn_handle, notify_handle, om); + assert(rc == 0); + } +} + +int +tester_gatt_subscribe_ev(uint16_t conn_handle, + uint16_t attr_handle, + uint8_t reason, + uint8_t prev_notify, + uint8_t cur_notify, + uint8_t prev_indicate, + uint8_t cur_indicate) +{ + SYS_LOG_DBG(""); + myconn_handle = conn_handle; + + if (cur_notify == 0 && cur_indicate == 0) { + SYS_LOG_INF("Unsubscribed"); + memset(&subscribe_params, 0, sizeof(subscribe_params)); + return 0; + } + + if (cur_notify) { + SYS_LOG_INF("Subscribed to notifications"); + if (attr_handle == notify_handle) { + notify_state = cur_notify; + } + } + + if (cur_indicate) { + SYS_LOG_INF("Subscribed to indications"); + if (attr_handle == notify_handle) { + indicate_state = cur_indicate; + } + } + + if (notify_state || indicate_state) { + notify_test_reset(); + } else { + notify_test_stop(); + } + + return 0; +} + +void +gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg) +{ + char buf[BLE_UUID_STR_LEN]; + + switch (ctxt->op) { + case BLE_GATT_REGISTER_OP_SVC: + MODLOG_DFLT(DEBUG, + "registered service %s with handle=%d\n", + ble_uuid_to_str( + ctxt->svc.svc_def->uuid, + buf), + ctxt->svc.handle); + break; + + case BLE_GATT_REGISTER_OP_CHR: + MODLOG_DFLT(DEBUG, + "registering characteristic %s with " + "def_handle=%d val_handle=%d\n", + ble_uuid_to_str( + ctxt->chr.chr_def->uuid, + buf), + ctxt->chr.def_handle, + ctxt->chr.val_handle); + break; + + case BLE_GATT_REGISTER_OP_DSC: + MODLOG_DFLT(DEBUG, + "registering descriptor %s with handle=%d\n", + ble_uuid_to_str( + ctxt->dsc.dsc_def->uuid, + buf), + ctxt->dsc.handle); + break; + + default: + assert(0); + break; + } +} + +int +gatt_svr_init(void) +{ + int rc; + + rc = ble_gatts_count_cfg(gatt_svr_inc_svcs); + if (rc != 0) { + return rc; + } + + rc = ble_gatts_add_svcs(gatt_svr_inc_svcs); + if (rc != 0) { + return rc; + } + + rc = ble_gatts_count_cfg(gatt_svr_svcs); + if (rc != 0) { + return rc; + } + + rc = ble_gatts_add_svcs(gatt_svr_svcs); + if (rc != 0) { + return rc; + } + + return 0; +} + +uint8_t +tester_init_gatt(void) +{ + os_callout_init(¬ify_tx_timer, os_eventq_dflt_get(), + notify_test, NULL); + + tester_register_command_handlers(BTP_SERVICE_ID_GATT, handlers, + ARRAY_SIZE(handlers)); + + return BTP_STATUS_SUCCESS; +} + +uint8_t +tester_unregister_gatt(void) +{ + return BTP_STATUS_SUCCESS; +} diff --git a/apps/bttester/src/btp_gatt_cl.c b/apps/bttester/src/btp_gatt_cl.c new file mode 100644 index 0000000000..8771c395b8 --- /dev/null +++ b/apps/bttester/src/btp_gatt_cl.c @@ -0,0 +1,1620 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include + +#include "host/ble_gap.h" +#include "host/ble_gatt.h" +#include "console/console.h" +#include "services/gatt/ble_svc_gatt.h" +#include "../../../nimble/host/src/ble_att_priv.h" +#include "../../../nimble/host/src/ble_gatt_priv.h" + +#include "btp/btp.h" + +#define CONTROLLER_INDEX 0 +#define MAX_BUFFER_SIZE 2048 + +/* Convert UUID from BTP command to bt_uuid */ +static uint8_t +btp2bt_uuid(const uint8_t *uuid, uint8_t len, + ble_uuid_any_t *bt_uuid) +{ + uint16_t le16; + + switch (len) { + case 0x02: /* UUID 16 */ + bt_uuid->u.type = BLE_UUID_TYPE_16; + memcpy(&le16, uuid, sizeof(le16)); + BLE_UUID16(bt_uuid)->value = le16toh(le16); + break; + case 0x10: /* UUID 128*/ + bt_uuid->u.type = BLE_UUID_TYPE_128; + memcpy(BLE_UUID128(bt_uuid)->value, uuid, 16); + break; + default: + return BTP_STATUS_FAILED; + } + return BTP_STATUS_SUCCESS; +} + +/* + * gatt_buf - cache used by a gatt client (to cache data read/discovered) + * and gatt server (to store attribute user_data). + * It is not intended to be used by client and server at the same time. + */ +static struct { + uint16_t len; + uint8_t buf[MAX_BUFFER_SIZE]; + uint16_t cnt; +} gatt_buf; +static struct bt_gatt_subscribe_params { + uint16_t ccc_handle; + uint16_t value; + uint16_t value_handle; +} subscribe_params; + +static void * +gatt_buf_add(const void *data, size_t len) +{ + void *ptr = gatt_buf.buf + gatt_buf.len; + + if ((len + gatt_buf.len) > MAX_BUFFER_SIZE) { + return NULL; + } + + if (data) { + memcpy(ptr, data, len); + } else { + (void) memset(ptr, 0, len); + } + + gatt_buf.len += len; + + SYS_LOG_DBG("%d/%d used", gatt_buf.len, MAX_BUFFER_SIZE); + + return ptr; +} + +static void * +gatt_buf_reserve(size_t len) +{ + return gatt_buf_add(NULL, len); +} + +static void +gatt_buf_clear(void) +{ + (void) memset(&gatt_buf, 0, sizeof(gatt_buf)); +} + +static void +discover_destroy(void) +{ + gatt_buf_clear(); +} + +static void +read_destroy() +{ + gatt_buf_clear(); +} + +static int +tester_mtu_exchanged_ev(uint16_t conn_handle, + const struct ble_gatt_error *error, + uint16_t mtu, void *arg) +{ + struct btp_gattc_exchange_mtu_ev *ev; + struct ble_gap_conn_desc conn; + struct os_mbuf *buf = os_msys_get(0, 0); + + SYS_LOG_DBG(""); + + if (ble_gap_conn_find(conn_handle, &conn)) { + goto fail; + } + + ev = os_mbuf_extend(buf, sizeof(*ev)); + if (!ev) { + return 0; + } + + memcpy(&ev->address, &conn.peer_ota_addr, sizeof(ev->address)); + + ev->mtu = mtu; + + tester_event(BTP_SERVICE_ID_GATTC, BTP_GATTC_EV_MTU_EXCHANGED, + buf->om_data, buf->om_len); +fail: + os_mbuf_free_chain(buf); + return 0; +} + +static uint8_t +exchange_mtu(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gattc_exchange_mtu_cmd *cp = cmd; + struct ble_gap_conn_desc conn; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find_by_addr(&cp->address, &conn); + if (rc) { + return BTP_STATUS_FAILED; + } + + if (ble_gattc_exchange_mtu(conn.conn_handle, + tester_mtu_exchanged_ev, + NULL)) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static int +disc_prim_svcs_cb(uint16_t conn_handle, + const struct ble_gatt_error *error, + const struct ble_gatt_svc *gatt_svc, void *arg) +{ + struct btp_gattc_disc_prim_svcs_rp *rp; + struct ble_gap_conn_desc conn; + struct btp_gatt_service *service; + const ble_uuid_any_t *uuid; + uint8_t uuid_length; + struct os_mbuf *buf = os_msys_get(0, 0); + uint8_t opcode = (uint8_t) (int) arg; + uint8_t err = (uint8_t) error->status; + int rc = 0; + + SYS_LOG_DBG(""); + + if (ble_gap_conn_find(conn_handle, &conn)) { + goto free; + } + + rp = os_mbuf_extend(buf, sizeof(*rp)); + if (!rp) { + rc = BLE_HS_ENOMEM; + goto free; + } + + memcpy(&rp->address, &conn.peer_ota_addr, sizeof(rp->address)); + + rp->status = err; + if (error->status != 0 && error->status != BLE_HS_EDONE) { + rp->services_count = 0; + tester_event(BTP_SERVICE_ID_GATTC, opcode, + buf->om_data, buf->om_len); + discover_destroy(); + goto free; + } + + if (error->status == BLE_HS_EDONE) { + rp->status = 0; + rp->services_count = gatt_buf.cnt; + os_mbuf_append(buf, gatt_buf.buf, gatt_buf.len); + tester_event(BTP_SERVICE_ID_GATTC, opcode, + buf->om_data, buf->om_len); + discover_destroy(); + goto free; + } + + uuid = &gatt_svc->uuid; + uuid_length = (uint8_t) (uuid->u.type == BLE_UUID_TYPE_16 ? 2 : 16); + + service = gatt_buf_reserve(sizeof(*service) + uuid_length); + if (!service) { + discover_destroy(); + rc = BLE_HS_ENOMEM; + goto free; + } + + service->start_handle = htole16(gatt_svc->start_handle); + service->end_handle = htole16(gatt_svc->end_handle); + service->uuid_length = uuid_length; + + if (uuid->u.type == BLE_UUID_TYPE_16) { + uint16_t u16 = htole16(BLE_UUID16(uuid)->value); + memcpy(service->uuid, &u16, uuid_length); + } else { + memcpy(service->uuid, BLE_UUID128(uuid)->value, + uuid_length); + } + + gatt_buf.cnt++; + +free: + os_mbuf_free_chain(buf); + return rc; +} + +static uint8_t +disc_all_prim_svcs(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gattc_disc_all_prim_svcs_cmd *cp = cmd; + struct ble_gap_conn_desc conn; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find_by_addr(&cp->address, &conn); + if (rc) { + return BTP_STATUS_FAILED; + } + + if (ble_gattc_disc_all_svcs(conn.conn_handle, disc_prim_svcs_cb, + (void *) BTP_GATTC_DISC_ALL_PRIM_RP)) { + discover_destroy(); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +disc_prim_uuid(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gattc_disc_prim_uuid_cmd *cp = cmd; + struct ble_gap_conn_desc conn; + ble_uuid_any_t uuid; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find_by_addr(&cp->address, &conn); + if (rc) { + return BTP_STATUS_FAILED; + } + + if (btp2bt_uuid(cp->uuid, cp->uuid_length, &uuid)) { + return BTP_STATUS_FAILED; + } + + if (ble_gattc_disc_svc_by_uuid(conn.conn_handle, + &uuid.u, disc_prim_svcs_cb, + (void *) BTP_GATTC_DISC_PRIM_UUID_RP)) { + discover_destroy(); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static int +find_included_cb(uint16_t conn_handle, + const struct ble_gatt_error *error, + const struct ble_gatt_svc *gatt_svc, void *arg) +{ + struct btp_gattc_find_included_rp *rp; + struct btp_gatt_included *included; + const ble_uuid_any_t *uuid; + int service_handle = (int) arg; + uint8_t uuid_length; + uint8_t err = (uint8_t) error->status; + struct os_mbuf *buf = os_msys_get(0, 0); + struct ble_gap_conn_desc conn; + int rc = 0; + + SYS_LOG_DBG(""); + + if (ble_gap_conn_find(conn_handle, &conn)) { + rc = BLE_HS_EINVAL; + goto free; + } + + rp = os_mbuf_extend(buf, sizeof(*rp)); + if (!rp) { + rc = BLE_HS_ENOMEM; + goto free; + } + + memcpy(&rp->address, &conn.peer_ota_addr, sizeof(rp->address)); + + rp->status = err; + + SYS_LOG_DBG(""); + if (error->status != 0 && error->status != BLE_HS_EDONE) { + rp->services_count = 0; + tester_event(BTP_SERVICE_ID_GATTC, BTP_GATTC_FIND_INCLUDED_RP, + buf->om_data, buf->om_len); + discover_destroy(); + goto free; + } + + if (error->status == BLE_HS_EDONE) { + rp->status = 0; + rp->services_count = gatt_buf.cnt; + os_mbuf_append(buf, gatt_buf.buf, gatt_buf.len); + tester_event(BTP_SERVICE_ID_GATTC, BTP_GATTC_FIND_INCLUDED_RP, + buf->om_data, buf->om_len); + discover_destroy(); + goto free; + } + + uuid = &gatt_svc->uuid; + uuid_length = (uint8_t) (uuid->u.type == BLE_UUID_TYPE_16 ? 2 : 16); + + included = gatt_buf_reserve(sizeof(*included) + uuid_length); + if (!included) { + discover_destroy(); + rc = BLE_HS_ENOMEM; + goto free; + } + + included->included_handle = htole16(service_handle + 1 + + rp->services_count); + included->service.start_handle = htole16(gatt_svc->start_handle); + included->service.end_handle = htole16(gatt_svc->end_handle); + included->service.uuid_length = uuid_length; + + if (uuid->u.type == BLE_UUID_TYPE_16) { + uint16_t u16 = htole16(BLE_UUID16(uuid)->value); + memcpy(included->service.uuid, &u16, uuid_length); + } else { + memcpy(included->service.uuid, BLE_UUID128(uuid)->value, + uuid_length); + } + + gatt_buf.cnt++; + +free: + os_mbuf_free_chain(buf); + return rc; +} + +static uint8_t +find_included(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gattc_find_included_cmd *cp = cmd; + struct ble_gap_conn_desc conn; + uint16_t start_handle, end_handle; + int service_handle_arg; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find_by_addr(&cp->address, &conn); + if (rc) { + return BTP_STATUS_FAILED; + } + + start_handle = le16toh(cp->start_handle); + end_handle = le16toh(cp->end_handle); + service_handle_arg = start_handle; + + if (ble_gattc_find_inc_svcs(conn.conn_handle, start_handle, end_handle, + find_included_cb, + (void *) service_handle_arg)) { + discover_destroy(); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static int +disc_chrc_cb(uint16_t conn_handle, + const struct ble_gatt_error *error, + const struct ble_gatt_chr *gatt_chr, void *arg) +{ + struct btp_gattc_disc_chrc_rp *rp; + struct btp_gatt_characteristic *chrc; + const ble_uuid_any_t *uuid; + uint8_t uuid_length; + uint8_t opcode = (uint8_t) (int) arg; + uint8_t err = (uint8_t) error->status; + struct os_mbuf *buf = os_msys_get(0, 0); + struct ble_gap_conn_desc conn; + int rc = 0; + + SYS_LOG_DBG(""); + if (ble_gap_conn_find(conn_handle, &conn)) { + goto free; + } + + rp = os_mbuf_extend(buf, sizeof(*rp)); + if (!rp) { + rc = BLE_HS_ENOMEM; + goto free; + } + + memcpy(&rp->address, &conn.peer_ota_addr, sizeof(rp->address)); + + rp->status = err; + + if (ble_gap_conn_find(conn_handle, &conn)) { + rc = BLE_HS_EINVAL; + goto free; + } + + if (error->status != 0 && error->status != BLE_HS_EDONE) { + rp->characteristics_count = 0; + tester_event(BTP_SERVICE_ID_GATTC, opcode, + buf->om_data, buf->om_len); + discover_destroy(); + goto free; + } + + if (error->status == BLE_HS_EDONE) { + rp->status = 0; + rp->characteristics_count = gatt_buf.cnt; + os_mbuf_append(buf, gatt_buf.buf, gatt_buf.len); + tester_event(BTP_SERVICE_ID_GATTC, opcode, + buf->om_data, buf->om_len); + discover_destroy(); + goto free; + } + + uuid = &gatt_chr->uuid; + uuid_length = (uint8_t) (uuid->u.type == BLE_UUID_TYPE_16 ? 2 : 16); + + chrc = gatt_buf_reserve(sizeof(*chrc) + uuid_length); + if (!chrc) { + discover_destroy(); + rc = BLE_HS_ENOMEM; + goto free; + } + + chrc->characteristic_handle = htole16(gatt_chr->def_handle); + chrc->properties = gatt_chr->properties; + chrc->value_handle = htole16(gatt_chr->val_handle); + chrc->uuid_length = uuid_length; + + if (uuid->u.type == BLE_UUID_TYPE_16) { + uint16_t u16 = htole16(BLE_UUID16(uuid)->value); + memcpy(chrc->uuid, &u16, uuid_length); + } else { + memcpy(chrc->uuid, BLE_UUID128(uuid)->value, + uuid_length); + } + + gatt_buf.cnt++; +free: + os_mbuf_free_chain(buf); + return rc; +} + +static uint8_t +disc_all_chrc(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gattc_disc_all_chrc_cmd *cp = cmd; + struct ble_gap_conn_desc conn; + uint16_t start_handle, end_handle; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find_by_addr(&cp->address, &conn); + if (rc) { + SYS_LOG_DBG("Conn find rsped"); + return BTP_STATUS_FAILED; + } + + start_handle = le16toh(cp->start_handle); + end_handle = le16toh(cp->end_handle); + + rc = ble_gattc_disc_all_chrs(conn.conn_handle, + start_handle, + end_handle, + disc_chrc_cb, + (void *) BTP_GATTC_DISC_ALL_CHRC_RP); + if (rc) { + discover_destroy(); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +disc_chrc_uuid(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gattc_disc_chrc_uuid_cmd *cp = cmd; + struct ble_gap_conn_desc conn; + uint16_t start_handle, end_handle; + ble_uuid_any_t uuid; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find_by_addr(&cp->address, &conn); + if (rc) { + return BTP_STATUS_FAILED; + } + + if (btp2bt_uuid(cp->uuid, cp->uuid_length, &uuid)) { + return BTP_STATUS_FAILED; + } + + start_handle = le16toh(cp->start_handle); + end_handle = le16toh(cp->end_handle); + + rc = ble_gattc_disc_chrs_by_uuid(conn.conn_handle, start_handle, + end_handle, &uuid.u, disc_chrc_cb, + (void *) BTP_GATTC_DISC_CHRC_UUID_RP); + if (rc) { + discover_destroy(); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static int +disc_all_desc_cb(uint16_t conn_handle, + const struct ble_gatt_error *error, + uint16_t chr_val_handle, + const struct ble_gatt_dsc *gatt_dsc, + void *arg) +{ + struct btp_gattc_disc_all_desc_rp *rp; + struct btp_gatt_descriptor *dsc; + const ble_uuid_any_t *uuid; + uint8_t uuid_length; + uint8_t err = (uint8_t) error->status; + struct os_mbuf *buf = os_msys_get(0, 0); + struct ble_gap_conn_desc conn; + int rc = 0; + + SYS_LOG_DBG(""); + + if (ble_gap_conn_find(conn_handle, &conn)) { + rc = BLE_HS_EINVAL; + goto free; + } + + rp = os_mbuf_extend(buf, sizeof(*rp)); + if (!rp) { + rc = BLE_HS_ENOMEM; + goto free; + } + + memcpy(&rp->address, &conn.peer_ota_addr, sizeof(rp->address)); + + rp->status = err; + + if (error->status != 0 && error->status != BLE_HS_EDONE) { + rp->descriptors_count = 0; + tester_event(BTP_SERVICE_ID_GATTC, BTP_GATTC_DISC_ALL_DESC_RP, + buf->om_data, buf->om_len); + discover_destroy(); + goto free; + } + + if (error->status == BLE_HS_EDONE) { + rp->status = 0; + rp->descriptors_count = gatt_buf.cnt; + os_mbuf_append(buf, gatt_buf.buf, gatt_buf.len); + tester_event(BTP_SERVICE_ID_GATTC, BTP_GATTC_DISC_ALL_DESC_RP, + buf->om_data, buf->om_len); + discover_destroy(); + goto free; + } + + uuid = &gatt_dsc->uuid; + uuid_length = (uint8_t) (uuid->u.type == BLE_UUID_TYPE_16 ? 2 : 16); + + dsc = gatt_buf_reserve(sizeof(*dsc) + uuid_length); + if (!dsc) { + discover_destroy(); + rc = BLE_HS_ENOMEM; + goto free; + } + + dsc->descriptor_handle = htole16(gatt_dsc->handle); + dsc->uuid_length = uuid_length; + + if (uuid->u.type == BLE_UUID_TYPE_16) { + uint16_t u16 = htole16(BLE_UUID16(uuid)->value); + memcpy(dsc->uuid, &u16, uuid_length); + } else { + memcpy(dsc->uuid, BLE_UUID128(uuid)->value, uuid_length); + } + + gatt_buf.cnt++; + +free: + os_mbuf_free_chain(buf); + return rc; +} + +static uint8_t +disc_all_desc(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gattc_disc_all_desc_cmd *cp = cmd; + struct ble_gap_conn_desc conn; + uint16_t start_handle, end_handle; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find_by_addr(&cp->address, &conn); + if (rc) { + return BTP_STATUS_FAILED; + } + + start_handle = le16toh(cp->start_handle) - 1; + end_handle = le16toh(cp->end_handle); + + rc = ble_gattc_disc_all_dscs(conn.conn_handle, + start_handle, + end_handle, + disc_all_desc_cb, + (void *) BTP_GATTC_DISC_ALL_DESC); + + SYS_LOG_DBG("rc=%d", rc); + + if (rc) { + discover_destroy(); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static int +read_cb(uint16_t conn_handle, + const struct ble_gatt_error *error, + struct ble_gatt_attr *attr, + void *arg) +{ + struct btp_gattc_read_rp *rp; + uint8_t opcode = (uint8_t) (int) arg; + struct os_mbuf *buf = os_msys_get(0, 0); + struct ble_gap_conn_desc conn; + int rc = 0; + + if (ble_gap_conn_find(conn_handle, &conn)) { + rc = BLE_HS_EINVAL; + goto free; + } + + rp = os_mbuf_extend(buf, sizeof(*rp)); + if (!rp) { + rc = BLE_HS_ENOMEM; + goto free; + } + + memcpy(&rp->address, &conn.peer_ota_addr, sizeof(rp->address)); + + SYS_LOG_DBG("status=%d", error->status); + + if (error->status != 0 && error->status != BLE_HS_EDONE) { + rp->status = (uint8_t) BLE_HS_ATT_ERR(error->status); + rp->data_length = 0; + tester_event(BTP_SERVICE_ID_GATTC, opcode, + buf->om_data, buf->om_len); + read_destroy(); + goto free; + } + + if (!gatt_buf_add(attr->om->om_data, attr->om->om_len)) { + read_destroy(); + rc = BLE_HS_ENOMEM; + goto free; + } + + rp->status = 0; + rp->data_length = attr->om->om_len; + os_mbuf_appendfrom(buf, attr->om, 0, os_mbuf_len(attr->om)); + tester_event(BTP_SERVICE_ID_GATTC, opcode, + buf->om_data, buf->om_len); + read_destroy(); +free: + os_mbuf_free_chain(buf); + return rc; +} + +static uint8_t +read(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gattc_read_cmd *cp = cmd; + struct ble_gap_conn_desc conn; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find_by_addr(&cp->address, &conn); + if (rc) { + return BTP_STATUS_FAILED; + } + + /* Clear buffer */ + read_destroy(); + + if (ble_gattc_read(conn.conn_handle, le16toh(cp->handle), + read_cb, (void *) BTP_GATTC_READ_RP)) { + read_destroy(); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static int +read_uuid_cb(uint16_t conn_handle, + const struct ble_gatt_error *error, + struct ble_gatt_attr *attr, + void *arg) +{ + struct btp_gattc_read_uuid_rp *rp; + struct btp_gatt_read_uuid_chr *chr; + uint8_t opcode = (uint8_t) (int) arg; + uint8_t err = (uint8_t) error->status; + struct os_mbuf *buf = os_msys_get(0, 0); + struct ble_gap_conn_desc conn; + int rc = 0; + static uint16_t attr_len; + + SYS_LOG_DBG("status=%d", error->status); + + if (ble_gap_conn_find(conn_handle, &conn)) { + rc = BLE_HS_EINVAL; + goto free; + } + + rp = os_mbuf_extend(buf, sizeof(*rp)); + if (!rp) { + rc = BLE_HS_ENOMEM; + goto free; + } + + memcpy(&rp->address, &conn.peer_ota_addr, sizeof(rp->address)); + + rp->status = err; + + if (error->status != 0 && error->status != BLE_HS_EDONE) { + rp->data_length = 0; + tester_event(BTP_SERVICE_ID_GATTC, opcode, + buf->om_data, buf->om_len); + read_destroy(); + goto free; + } + + if (error->status == BLE_HS_EDONE) { + rp->data_length = gatt_buf.len; + rp->value_length = attr_len; + rp->status = 0; + os_mbuf_append(buf, gatt_buf.buf, gatt_buf.len); + + tester_event(BTP_SERVICE_ID_GATTC, opcode, + buf->om_data, buf->om_len); + read_destroy(); + goto free; + } + + if (error->status == 0) { + attr_len = attr->om->om_len; + } + + chr = gatt_buf_reserve(sizeof(*chr) + attr->om->om_len); + if (!chr) { + read_destroy(); + rc = BLE_HS_ENOMEM; + goto free; + } + + chr->handle = htobe16(attr->handle); + memcpy(chr->data, attr->om->om_data, attr->om->om_len); + +free: + os_mbuf_free_chain(buf); + return rc; +} + +static uint8_t +read_uuid(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gattc_read_uuid_cmd *cp = cmd; + struct ble_gap_conn_desc conn; + ble_uuid_any_t uuid; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find_by_addr(&cp->address, &conn); + if (rc) { + return BTP_STATUS_FAILED; + } + + if (btp2bt_uuid(cp->uuid, cp->uuid_length, &uuid)) { + return BTP_STATUS_FAILED; + } + + /* Clear buffer */ + read_destroy(); + + if (ble_gattc_read_by_uuid(conn.conn_handle, + le16toh(cp->start_handle), + le16toh(cp->end_handle), &uuid.u, + read_uuid_cb, (void *) BTP_GATTC_READ_UUID_RP)) { + read_destroy(); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static int +read_long_cb(uint16_t conn_handle, + const struct ble_gatt_error *error, + struct ble_gatt_attr *attr, + void *arg) +{ + struct btp_gattc_read_rp *rp;; + uint8_t opcode = (uint8_t) (int) arg; + uint8_t err = (uint8_t) error->status; + struct os_mbuf *buf = os_msys_get(0, 0); + struct ble_gap_conn_desc conn; + int rc = 0; + + SYS_LOG_DBG("status=%d", error->status); + + if (ble_gap_conn_find(conn_handle, &conn)) { + rc = BLE_HS_EINVAL; + goto free; + } + + rp = os_mbuf_extend(buf, sizeof(*rp)); + if (!rp) { + rc = BLE_HS_ENOMEM; + goto free; + } + + memcpy(&rp->address, &conn.peer_ota_addr, sizeof(rp->address)); + + rp->status = err; + + if (error->status != 0 && error->status != BLE_HS_EDONE) { + rp->data_length = 0; + tester_event(BTP_SERVICE_ID_GATTC, opcode, + buf->om_data, buf->om_len); + read_destroy(); + goto free; + } + + if (error->status == BLE_HS_EDONE) { + rp->status = 0; + rp->data_length = gatt_buf.len; + os_mbuf_append(buf, gatt_buf.buf, gatt_buf.len); + tester_event(BTP_SERVICE_ID_GATTC, opcode, + buf->om_data, buf->om_len); + read_destroy(); + goto free; + } + + if (gatt_buf_add(attr->om->om_data, attr->om->om_len) == NULL) { + read_destroy(); + rc = BLE_HS_ENOMEM; + goto free; + } + + rp->data_length += attr->om->om_len; + +free: + os_mbuf_free_chain(buf); + return rc; +} + +static uint8_t +read_long(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gattc_read_long_cmd *cp = cmd; + struct ble_gap_conn_desc conn; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find_by_addr(&cp->address, &conn); + if (rc) { + return BTP_STATUS_FAILED; + } + + /* Clear buffer */ + read_destroy(); + + if (ble_gattc_read_long(conn.conn_handle, + le16toh(cp->handle), + le16toh(cp->offset), + read_long_cb, (void *) BTP_GATTC_READ_LONG_RP)) { + read_destroy(); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +read_multiple(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gattc_read_multiple_cmd *cp = cmd; + uint16_t handles[cp->handles_count]; + struct ble_gap_conn_desc conn; + int rc, i; + + SYS_LOG_DBG(""); + + for (i = 0; i < ARRAY_SIZE(handles); i++) { + handles[i] = le16toh(cp->handles[i]); + } + + rc = ble_gap_conn_find_by_addr(&cp->address, &conn); + if (rc) { + return BTP_STATUS_FAILED; + } + + /* Clear buffer */ + read_destroy(); + + if (ble_gattc_read_mult(conn.conn_handle, + handles, + cp->handles_count, + read_cb, + (void *) BTP_GATTC_READ_MULTIPLE_RP)) { + read_destroy(); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +write_without_rsp(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gattc_write_without_rsp_cmd *cp = cmd; + struct ble_gap_conn_desc conn; + int rc; + + SYS_LOG_DBG(""); + + if (cmd_len < sizeof(*cp) || + cmd_len != sizeof(*cp) + le16toh(cp->data_length)) { + return BTP_STATUS_FAILED; + } + + rc = ble_gap_conn_find_by_addr(&cp->address, &conn); + if (rc) { + return BTP_STATUS_FAILED; + } + + if (ble_gattc_write_no_rsp_flat(conn.conn_handle, + le16toh(cp->handle), cp->data, + le16toh(cp->data_length))) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static int +write_cb(uint16_t conn_handle, const struct ble_gatt_error *error, + struct ble_gatt_attr *attr, + void *arg) +{ + struct btp_gattc_write_rp *rp; + uint8_t err = (uint8_t) error->status; + uint8_t opcode = (uint8_t) (int) arg; + struct os_mbuf *buf = os_msys_get(0, 0); + struct ble_gap_conn_desc conn; + int rc = 0; + + SYS_LOG_DBG(""); + + if (ble_gap_conn_find(conn_handle, &conn)) { + rc = BLE_HS_EINVAL; + goto free; + } + + rp = os_mbuf_extend(buf, sizeof(*rp)); + if (!rp) { + rc = BLE_HS_ENOMEM; + goto free; + } + + memcpy(&rp->address, &conn.peer_ota_addr, sizeof(rp->address)); + + rp->status = err; + tester_event(BTP_SERVICE_ID_GATTC, opcode, + buf->om_data, buf->om_len); +free: + os_mbuf_free_chain(buf); + return rc; +} + +static uint8_t +write(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gattc_write_cmd *cp = cmd; + struct ble_gap_conn_desc conn; + int rc; + + SYS_LOG_DBG(""); + + if (cmd_len < sizeof(*cp) || + cmd_len != sizeof(*cp) + le16toh(cp->data_length)) { + return BTP_STATUS_FAILED; + } + + rc = ble_gap_conn_find_by_addr(&cp->address, &conn); + if (rc) { + return BTP_STATUS_FAILED; + } + + if (ble_gattc_write_flat(conn.conn_handle, le16toh(cp->handle), + cp->data, le16toh(cp->data_length), + write_cb, (void *) BTP_GATTC_WRITE_RP)) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +write_long(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gattc_write_long_cmd *cp = cmd; + struct ble_gap_conn_desc conn; + struct os_mbuf *om = NULL; + int rc = 0; + + SYS_LOG_DBG(""); + + if (cmd_len < sizeof(*cp) || + cmd_len != sizeof(*cp) + le16toh(cp->data_length)) { + goto fail; + } + + rc = ble_gap_conn_find_by_addr(&cp->address, &conn); + if (rc) { + goto fail; + } + + om = ble_hs_mbuf_from_flat(cp->data, le16toh(cp->data_length)); + if (!om) { + SYS_LOG_ERR("Insufficient resources"); + goto fail; + } + + rc = ble_gattc_write_long(conn.conn_handle, + le16toh(cp->handle), + le16toh(cp->offset), + om, write_cb, + (void *) BTP_GATTC_WRITE_LONG_RP); + if (!rc) { + return BTP_STATUS_SUCCESS; + } + +fail: + SYS_LOG_ERR("Failed to send Write Long request, rc=%d", rc); + os_mbuf_free_chain(om); + return BTP_STATUS_FAILED; +} + +static int +reliable_write_cb(uint16_t conn_handle, + const struct ble_gatt_error *error, + struct ble_gatt_attr *attrs, + uint8_t num_attrs, + void *arg) +{ + struct btp_gattc_write_rp *rp; + uint8_t err = (uint8_t) error->status; + struct os_mbuf *buf = os_msys_get(0, 0); + struct ble_gap_conn_desc conn; + int rc = 0; + + SYS_LOG_DBG(""); + + if (ble_gap_conn_find(conn_handle, &conn)) { + rc = BLE_HS_EINVAL; + goto free; + } + + rp = os_mbuf_extend(buf, sizeof(*rp)); + if (!rp) { + rc = BLE_HS_ENOMEM; + goto free; + } + + memcpy(&rp->address, &conn.peer_ota_addr, sizeof(rp->address)); + + rp->status = err; + tester_event(BTP_SERVICE_ID_GATTC, BTP_GATTC_RELIABLE_WRITE_RP, + buf->om_data, buf->om_len); +free: + os_mbuf_free_chain(buf); + return rc; +} + +static uint8_t +reliable_write(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gattc_reliable_write_cmd *cp = cmd; + struct ble_gap_conn_desc conn; + struct ble_gatt_attr attr; + struct os_mbuf *om = NULL; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find_by_addr(&cp->address, &conn); + if (rc) { + return BTP_STATUS_SUCCESS; + } + + om = ble_hs_mbuf_from_flat(cp->data, le16toh(cp->data_length)); + /* This is required, because Nimble checks if + * the data is longer than offset + */ + if (os_mbuf_extend(om, le16toh(cp->offset) + 1) == NULL) { + return BTP_STATUS_SUCCESS; + } + + attr.handle = le16toh(cp->handle); + attr.offset = le16toh(cp->offset); + attr.om = om; + + if (ble_gattc_write_reliable(conn.conn_handle, &attr, 1, + reliable_write_cb, NULL)) { + goto fail; + } + + return BTP_STATUS_SUCCESS; + +fail: + os_mbuf_free_chain(om); + + return BTP_STATUS_FAILED; +} + +static int +subscribe_cb(uint16_t conn_handle, + const struct ble_gatt_error *error, + struct ble_gatt_attr *attrs, + void *arg) +{ + struct btp_subscribe_rp *rp; + uint8_t err = (uint8_t) error->status; + uint8_t opcode = (uint8_t) (int) arg; + struct os_mbuf *buf = os_msys_get(0, 0); + struct ble_gap_conn_desc conn; + int rc = 0; + + SYS_LOG_DBG(""); + + if (ble_gap_conn_find(conn_handle, &conn)) { + rc = BLE_HS_EINVAL; + goto free; + } + + rp = os_mbuf_extend(buf, sizeof(*rp)); + if (!rp) { + rc = BLE_HS_ENOMEM; + goto free; + } + + memcpy(&rp->address, &conn.peer_ota_addr, sizeof(rp->address)); + + rp->status = err; + tester_event(BTP_SERVICE_ID_GATTC, opcode, + buf->om_data, buf->om_len); +free: + os_mbuf_free_chain(buf); + return rc; +} + +static int +enable_subscription(uint16_t conn_handle, uint16_t ccc_handle, + uint16_t value) +{ + uint32_t opcode; + + SYS_LOG_DBG(""); + + opcode = (uint32_t) (value == 0x0001 ? BTP_GATTC_CFG_NOTIFY_RP + : BTP_GATTC_CFG_INDICATE_RP); + + if (ble_gattc_write_flat(conn_handle, + ccc_handle, + &value, + sizeof(value), + subscribe_cb, + (void *) opcode)) { + return -EINVAL; + } + + subscribe_params.ccc_handle = value; + + return 0; +} + +static int +disable_subscription(uint16_t conn_handle, uint16_t ccc_handle) +{ + uint16_t value = 0x00; + uint32_t opcode; + + SYS_LOG_DBG(""); + + opcode = (uint32_t) (value == 0x0001 ? BTP_GATTC_CFG_NOTIFY_RP + : BTP_GATTC_CFG_INDICATE_RP); + + /* Fail if CCC handle doesn't match */ + if (ccc_handle != subscribe_params.ccc_handle) { + SYS_LOG_ERR("CCC handle doesn't match"); + return -EINVAL; + } + + if (ble_gattc_write_flat(conn_handle, + ccc_handle, + &value, + sizeof(value), + subscribe_cb, + (void *) opcode)) { + return -EINVAL; + } + + subscribe_params.ccc_handle = 0; + return 0; +} + +static uint8_t +config_subscription_notif(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gattc_cfg_notify_cmd *cp = cmd; + struct ble_gap_conn_desc conn; + uint16_t ccc_handle = le16toh(cp->ccc_handle); + uint8_t status; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find_by_addr(&cp->address, &conn); + if (rc) { + return BTP_STATUS_FAILED; + } + + if (cp->enable) { + if (enable_subscription(conn.conn_handle, + ccc_handle, 0x0001) == 0) { + return BTP_STATUS_SUCCESS; + } + + status = BTP_STATUS_FAILED; + } else { + if (disable_subscription(conn.conn_handle, ccc_handle) < 0) { + status = BTP_STATUS_FAILED; + } else { + status = BTP_STATUS_SUCCESS; + } + } + + return status; +} + +static uint8_t +config_subscription_ind(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gattc_cfg_notify_cmd *cp = cmd; + struct ble_gap_conn_desc conn; + uint16_t ccc_handle = le16toh(cp->ccc_handle); + uint8_t status; + int rc; + + SYS_LOG_DBG(""); + + rc = ble_gap_conn_find_by_addr(&cp->address, &conn); + if (rc) { + return BTP_STATUS_FAILED; + } + + if (cp->enable) { + if (enable_subscription(conn.conn_handle, + ccc_handle, 0x0002) == 0) { + return BTP_STATUS_SUCCESS; + } + + status = BTP_STATUS_FAILED; + } else { + if (disable_subscription(conn.conn_handle, ccc_handle) < 0) { + status = BTP_STATUS_FAILED; + } else { + status = BTP_STATUS_SUCCESS; + } + } + + return status; +} + +static int +read_var_cb(uint16_t conn_handle, + const struct ble_gatt_error *error, + struct ble_gatt_attr *attr, + uint8_t num_attrs, + void *arg) +{ + struct btp_gattc_read_rp *rp = (void *) gatt_buf.buf; + struct ble_gap_conn_desc conn; + uint8_t rp_data_off = 0; + struct ble_gatt_attr attrs[num_attrs]; + + SYS_LOG_DBG("status=%d", error->status); + + if (ble_gap_conn_find(conn_handle, &conn)) { + return BTP_STATUS_FAILED; + } + + memcpy(attrs, attr, sizeof(struct ble_gatt_attr) * num_attrs); + + memcpy(&rp->address, &conn.peer_ota_addr, sizeof(rp->address)); + + rp->status = (uint8_t) BLE_HS_ATT_ERR(error->status); + + if (error->status != 0) { + rp->data_length = 0; + tester_event(BTP_SERVICE_ID_GATTC, BTP_GATTC_READ_MULTIPLE_VAR_RP, + rp, sizeof(*rp)); + return 0; + } + + for (int i = 0; i < num_attrs; i++) { + memcpy(rp->data + rp_data_off, &attrs[i].om->om_len, 2); + rp_data_off += 2; + memcpy(rp->data + rp_data_off, attrs[i].om->om_data, + attrs[i].om->om_len); + rp_data_off += attrs[i].om->om_len; + } + + rp->data_length = rp_data_off; + + if (error->status == 0) { + tester_event(BTP_SERVICE_ID_GATTC, BTP_GATTC_READ_MULTIPLE_VAR_RP, + rp, sizeof(*rp) + rp->data_length); + read_destroy(); + return 0; + } + + return 0; +} + +static uint8_t +read_multiple_var(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_gattc_read_multiple_var_cmd *cp = cmd; + uint16_t handles[cp->handles_count]; + struct ble_gap_conn_desc conn; + int rc, i; + + SYS_LOG_DBG(""); + + for (i = 0; i < ARRAY_SIZE(handles); i++) { + handles[i] = le16toh(cp->handles[i]); + } + + rc = ble_gap_conn_find_by_addr(&cp->address, &conn); + if (rc) { + return BTP_STATUS_FAILED; + } + + if (!gatt_buf_reserve(sizeof(struct btp_gatt_read_rp))) { + return BTP_STATUS_FAILED; + } + + if (ble_gattc_read_mult_var(conn.conn_handle, handles, + cp->handles_count, read_var_cb, + NULL)) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +int +tester_gattc_notify_rx_ev(uint16_t conn_handle, uint16_t attr_handle, + uint8_t indication, struct os_mbuf *om) +{ + struct btp_gattc_notification_ev *ev; + struct ble_gap_conn_desc conn; + struct os_mbuf *buf = os_msys_get(0, 0); + + SYS_LOG_DBG(""); + + if (!subscribe_params.ccc_handle) { + goto fail; + } + + if (ble_gap_conn_find(conn_handle, &conn)) { + goto fail; + } + + ev = os_mbuf_extend(buf, sizeof(*ev)); + if (!ev) { + return 0; + } + + memcpy(&ev->address, &conn.peer_ota_addr, sizeof(ev->address)); + ev->type = (uint8_t) (indication ? 0x02 : 0x01); + ev->handle = htole16(attr_handle); + ev->data_length = htole16(os_mbuf_len(om)); + os_mbuf_appendfrom(buf, om, 0, os_mbuf_len(om)); + + tester_event(BTP_SERVICE_ID_GATTC, BTP_GATTC_EV_NOTIFICATION_RXED, + buf->om_data, buf->om_len); + +fail: + os_mbuf_free_chain(buf); + return 0; +} + +static uint8_t +supported_commands(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + struct btp_gattc_read_supported_commands_rp *rp = rsp; + + *rsp_len = tester_supported_commands(BTP_SERVICE_ID_GATTC, rp->data); + *rsp_len += sizeof(*rp); + + return BTP_STATUS_SUCCESS; +} + + +static const struct btp_handler handlers[] = { + { + .opcode = BTP_GATTC_READ_SUPPORTED_COMMANDS, + .index = BTP_INDEX_NONE, + .expect_len = 0, + .func = supported_commands, + }, + { + .opcode = BTP_GATTC_EXCHANGE_MTU, + .expect_len = sizeof(struct btp_gattc_exchange_mtu_cmd), + .func = exchange_mtu, + }, + { + .opcode = BTP_GATTC_DISC_ALL_PRIM_SVCS, + .expect_len = sizeof(struct btp_gattc_disc_all_prim_svcs_cmd), + .func = disc_all_prim_svcs, + }, + { + .opcode = BTP_GATTC_DISC_PRIM_UUID, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = disc_prim_uuid, + }, + { + .opcode = BTP_GATTC_FIND_INCLUDED, + .expect_len = sizeof(struct btp_gattc_find_included_cmd), + .func = find_included, + }, + { + .opcode = BTP_GATTC_DISC_ALL_CHRC, + .expect_len = sizeof(struct btp_gattc_disc_all_chrc_cmd), + .func = disc_all_chrc, + }, + { + .opcode = BTP_GATTC_DISC_CHRC_UUID, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = disc_chrc_uuid, + }, + { + .opcode = BTP_GATTC_DISC_ALL_DESC, + .expect_len = sizeof(struct btp_gattc_disc_all_desc_cmd), + .func = disc_all_desc, + }, + { + .opcode = BTP_GATTC_READ, + .expect_len = sizeof(struct btp_gattc_read_cmd), + .func = read, + }, + { + .opcode = BTP_GATTC_READ_UUID, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = read_uuid, + }, + { + .opcode = BTP_GATTC_READ_LONG, + .expect_len = sizeof(struct btp_gattc_read_long_cmd), + .func = read_long, + }, + { + .opcode = BTP_GATTC_READ_MULTIPLE, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = read_multiple, + }, + { + .opcode = BTP_GATTC_WRITE_WITHOUT_RSP, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = write_without_rsp, + }, +#if 0 + { + .opcode = BTP_GATTC_SIGNED_WRITE_WITHOUT_RSP, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = write_signed_without_rsp, + }, +#endif + { + .opcode = BTP_GATTC_WRITE, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = write, + }, + { + .opcode = BTP_GATTC_WRITE_LONG, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = write_long, + }, + { + .opcode = BTP_GATTC_RELIABLE_WRITE, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = reliable_write, + }, + { + .opcode = BTP_GATTC_CFG_NOTIFY, + .expect_len = sizeof(struct btp_gattc_cfg_notify_cmd), + .func = config_subscription_notif, + }, + { + .opcode = BTP_GATTC_CFG_INDICATE, + .expect_len = sizeof(struct btp_gattc_cfg_notify_cmd), + .func = config_subscription_ind, + }, + { + .opcode = BTP_GATTC_READ_MULTIPLE_VAR, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = read_multiple_var, + }, +}; + +uint8_t +tester_init_gatt_cl(void) +{ + tester_register_command_handlers(BTP_SERVICE_ID_GATTC, handlers, + ARRAY_SIZE(handlers)); + + return BTP_STATUS_SUCCESS; +} + +uint8_t +tester_unregister_gatt_cl(void) +{ + return BTP_STATUS_SUCCESS; +} diff --git a/apps/bttester/src/btp_l2cap.c b/apps/bttester/src/btp_l2cap.c new file mode 100644 index 0000000000..e11c54de3c --- /dev/null +++ b/apps/bttester/src/btp_l2cap.c @@ -0,0 +1,786 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* l2cap.c - Bluetooth L2CAP Tester */ + +/* + * Copyright (c) 2016 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "syscfg/syscfg.h" + +#if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) + +#include "console/console.h" +#include "host/ble_gap.h" +#include "host/ble_l2cap.h" + +#include "../../../nimble/host/src/ble_l2cap_priv.h" + +#include "btp/btp.h" + +#define CONTROLLER_INDEX 0 +#define CHANNELS MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) +#define TESTER_COC_MTU MYNEWT_VAL(BTTESTER_L2CAP_COC_MTU) +#define TESTER_COC_BUF_COUNT (3 * MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM)) + +static os_membuf_t tester_sdu_coc_mem[ + OS_MEMPOOL_SIZE(TESTER_COC_BUF_COUNT, TESTER_COC_MTU) +]; + +struct os_mbuf_pool sdu_os_mbuf_pool; +static struct os_mempool sdu_coc_mbuf_mempool; +static bool hold_credit = false; + +static struct channel { + uint8_t chan_id; /* Internal number that identifies L2CAP channel. */ + uint8_t state; + struct ble_l2cap_chan *chan; + struct os_mbuf *queued_sdu_tx; +} channels[CHANNELS]; + +static uint8_t + recv_cb_buf[TESTER_COC_MTU + sizeof(struct btp_l2cap_data_received_ev)]; + +static struct channel * +get_free_channel(void) +{ + uint8_t i; + struct channel *chan; + + for (i = 0; i < CHANNELS; i++) { + if (channels[i].state) { + continue; + } + + chan = &channels[i]; + chan->chan_id = i; + return chan; + } + + return NULL; +} + +struct channel * +find_channel(struct ble_l2cap_chan *chan) +{ + int i; + + for (i = 0; i < CHANNELS; ++i) { + if (channels[i].chan == chan) { + return &channels[i]; + } + } + + return NULL; +} + +struct channel * +get_channel(uint8_t chan_id) +{ + if (chan_id >= CHANNELS) { + return NULL; + } + + return &channels[chan_id]; +} + +static void +free_channel(struct channel *chan) +{ + if (chan->queued_sdu_tx) { + os_mbuf_free_chain(chan->queued_sdu_tx); + } + + memset(chan, 0, sizeof(*chan)); +} + +static void +tester_l2cap_coc_recv(struct ble_l2cap_chan *chan, struct os_mbuf *sdu) +{ + SYS_LOG_DBG("LE CoC SDU received, chan: 0x%08lx, data len %d", + (uint32_t) chan, OS_MBUF_PKTLEN(sdu)); + + os_mbuf_free_chain(sdu); + if (!hold_credit) { + sdu = os_mbuf_get_pkthdr(&sdu_os_mbuf_pool, 0); + assert(sdu != NULL); + + ble_l2cap_recv_ready(chan, sdu); + } +} + +static void +recv_cb(uint16_t conn_handle, struct ble_l2cap_chan *chan, + struct os_mbuf *buf, void *arg) +{ + struct btp_l2cap_data_received_ev *ev = (void *) recv_cb_buf; + struct channel *channel = find_channel(chan); + assert(channel != NULL); + + ev->chan_id = channel->chan_id; + ev->data_length = OS_MBUF_PKTLEN(buf); + + if (ev->data_length > TESTER_COC_MTU) { + SYS_LOG_ERR("Too large sdu received, truncating data"); + ev->data_length = TESTER_COC_MTU; + } + os_mbuf_copydata(buf, 0, ev->data_length, ev->data); + + tester_event(BTP_SERVICE_ID_L2CAP, BTP_L2CAP_EV_DATA_RECEIVED, + recv_cb_buf, sizeof(*ev) + ev->data_length); + + tester_l2cap_coc_recv(chan, buf); +} + +static void +reconfigured_ev(uint16_t conn_handle, struct ble_l2cap_chan *chan, + struct ble_l2cap_chan_info *chan_info, + int status) +{ + struct btp_l2cap_reconfigured_ev ev; + struct channel *channel; + + if (status != 0) { + return; + } + + channel = find_channel(chan); + assert(channel != NULL); + + ev.chan_id = channel->chan_id; + ev.peer_mtu = chan_info->peer_coc_mtu; + ev.peer_mps = chan_info->peer_l2cap_mtu; + ev.our_mtu = chan_info->our_coc_mtu; + ev.our_mps = chan_info->our_l2cap_mtu; + + tester_event(BTP_SERVICE_ID_L2CAP, BTP_L2CAP_EV_RECONFIGURED, + (uint8_t *) &ev, sizeof(ev)); +} + +static void +connected_cb(uint16_t conn_handle, struct ble_l2cap_chan *chan, + struct ble_l2cap_chan_info *chan_info, void *arg) +{ + struct btp_l2cap_connected_ev ev; + struct ble_gap_conn_desc desc; + struct channel *channel = find_channel(chan); + + if (channel == NULL) { + channel = get_free_channel(); + } + + ev.chan_id = channel->chan_id; + ev.psm = chan_info->psm; + ev.peer_mtu = chan_info->peer_coc_mtu; + ev.peer_mps = chan_info->peer_l2cap_mtu; + ev.our_mtu = chan_info->our_coc_mtu; + ev.our_mps = chan_info->our_l2cap_mtu; + channel->state = 1; + channel->chan = chan; + + if (!ble_gap_conn_find(conn_handle, &desc)) { + memcpy(&ev.address, &desc.peer_ota_addr, sizeof(ev.address)); + } + + tester_event(BTP_SERVICE_ID_L2CAP, BTP_L2CAP_EV_CONNECTED, + (uint8_t *) &ev, sizeof(ev)); +} + +static void +disconnected_cb(uint16_t conn_handle, struct ble_l2cap_chan *chan, + struct ble_l2cap_chan_info *chan_info, void *arg) +{ + struct btp_l2cap_disconnected_ev ev; + struct ble_gap_conn_desc desc; + struct channel *channel; + + memset(&ev, 0, sizeof(struct btp_l2cap_disconnected_ev)); + + channel = find_channel(chan); + assert(channel != NULL); + + ev.chan_id = channel->chan_id; + ev.psm = chan_info->psm; + + free_channel(channel); + + if (!ble_gap_conn_find(conn_handle, &desc)) { + memcpy(&ev.address, &desc.peer_ota_addr, sizeof(ev.address)); + } + + tester_event(BTP_SERVICE_ID_L2CAP, BTP_L2CAP_EV_DISCONNECTED, + (uint8_t *) &ev, sizeof(ev)); +} + +static int +accept_cb(uint16_t conn_handle, uint16_t peer_mtu, + struct ble_l2cap_chan *chan) +{ + struct os_mbuf *sdu_rx; + + SYS_LOG_DBG("LE CoC accepting, chan: 0x%08lx, peer_mtu %d", + (uint32_t) chan, peer_mtu); + + sdu_rx = os_mbuf_get_pkthdr(&sdu_os_mbuf_pool, 0); + if (!sdu_rx) { + return BLE_HS_ENOMEM; + } + + ble_l2cap_recv_ready(chan, sdu_rx); + + return 0; +} + +static int +tester_l2cap_event(struct ble_l2cap_event *event, void *arg) +{ + struct ble_l2cap_chan_info chan_info; + struct ble_gap_conn_desc conn; + struct channel *chan; + int rc; + + switch (event->type) { + case BLE_L2CAP_EVENT_COC_CONNECTED: + if (ble_l2cap_get_chan_info(event->connect.chan, &chan_info)) { + assert(0); + } + + if (event->connect.status) { + console_printf("LE COC error: %d\n", event->connect.status); + return 0; + } + + console_printf("LE COC connected, conn: %d, chan: 0x%08lx, " + "psm: 0x%02x, scid: 0x%04x, dcid: 0x%04x, " + "our_mps: %d, our_mtu: %d, peer_mps: %d, " + "peer_mtu: %d\n", event->connect.conn_handle, + (uint32_t) event->connect.chan, chan_info.psm, + chan_info.scid, chan_info.dcid, + chan_info.our_l2cap_mtu, chan_info.our_coc_mtu, + chan_info.peer_l2cap_mtu, chan_info.peer_coc_mtu); + + connected_cb(event->connect.conn_handle, + event->connect.chan, &chan_info, arg); + + return 0; + case BLE_L2CAP_EVENT_COC_DISCONNECTED: + if (ble_l2cap_get_chan_info(event->disconnect.chan, + &chan_info)) { + assert(0); + } + console_printf("LE CoC disconnected, chan: 0x%08lx\n", + (uint32_t) event->disconnect.chan); + + disconnected_cb(event->disconnect.conn_handle, + event->disconnect.chan, &chan_info, arg); + return 0; + case BLE_L2CAP_EVENT_COC_ACCEPT: + ble_l2cap_get_chan_info(event->accept.chan, + &chan_info); + if (chan_info.psm == 0x00F2) { + /* TSPX_psm_authentication_required */ + ble_gap_conn_find(event->accept.conn_handle, &conn); + if (!conn.sec_state.authenticated) { + return BLE_HS_EAUTHEN; + } + } else if (chan_info.psm == 0x00F3) { + /* TSPX_psm_authorization_required */ + ble_gap_conn_find(event->accept.conn_handle, &conn); + if (!conn.sec_state.encrypted) { + return BLE_HS_EAUTHOR; + } + return BLE_HS_EAUTHOR; + } else if (chan_info.psm == 0x00F4) { + /* TSPX_psm_encryption_key_size_required */ + ble_gap_conn_find(event->accept.conn_handle, &conn); + if (conn.sec_state.key_size < 16) { + return BLE_HS_EENCRYPT_KEY_SZ; + } + } else if (chan_info.psm == 0x00F5) { + /* TSPX_psm_encryption_required */ + ble_gap_conn_find(event->accept.conn_handle, &conn); + if (conn.sec_state.key_size == 0) { + return BLE_HS_EENCRYPT; + } + } + + console_printf( + "LE CoC accept, chan: 0x%08lx, handle: %u, sdu_size: %u\n", + (uint32_t) event->accept.chan, + event->accept.conn_handle, + event->accept.peer_sdu_size); + + return accept_cb(event->accept.conn_handle, + event->accept.peer_sdu_size, + event->accept.chan); + + case BLE_L2CAP_EVENT_COC_DATA_RECEIVED: + console_printf( + "LE CoC data received, chan: 0x%08lx, handle: %u, sdu_len: %u\n", + (uint32_t) event->receive.chan, + event->receive.conn_handle, + OS_MBUF_PKTLEN(event->receive.sdu_rx)); + + recv_cb(event->receive.conn_handle, event->receive.chan, + event->receive.sdu_rx, arg); + return 0; + case BLE_L2CAP_EVENT_COC_TX_UNSTALLED: + console_printf( + "LE CoC tx unstalled, chan: 0x%08lx, handle: %u, status: %d\n", + (uint32_t) event->tx_unstalled.chan, + event->tx_unstalled.conn_handle, + event->tx_unstalled.status); + + chan = find_channel(event->tx_unstalled.chan); + assert(chan != NULL); + + if (chan->queued_sdu_tx) { + rc = ble_l2cap_send(event->tx_unstalled.chan, chan->queued_sdu_tx); + if (rc != 0 && rc != BLE_HS_ESTALLED) { + os_mbuf_free_chain(chan->queued_sdu_tx); + } + + chan->queued_sdu_tx = NULL; + } + + return 0; + case BLE_L2CAP_EVENT_COC_RECONFIG_COMPLETED: + if (ble_l2cap_get_chan_info(event->reconfigured.chan, + &chan_info)) { + assert(0); + } + console_printf("LE CoC reconfigure completed status 0x%02x, " + "chan: 0x%08lx\n", event->reconfigured.status, + (uint32_t) event->reconfigured.chan); + + if (event->reconfigured.status == 0) { + console_printf("\t our_mps: %d our_mtu %d\n", + chan_info.our_l2cap_mtu, chan_info.our_coc_mtu); + } + + reconfigured_ev(event->reconfigured.conn_handle, + event->reconfigured.chan, + &chan_info, + event->reconfigured.status); + return 0; + case BLE_L2CAP_EVENT_COC_PEER_RECONFIGURED: + if (ble_l2cap_get_chan_info(event->reconfigured.chan, + &chan_info)) { + assert(0); + } + console_printf("LE CoC peer reconfigured status 0x%02x, " + "chan: 0x%08lx\n", event->reconfigured.status, + (uint32_t) event->reconfigured.chan); + + if (event->reconfigured.status == 0) { + console_printf("\t peer_mps: %d peer_mtu %d\n", + chan_info.peer_l2cap_mtu, + chan_info.peer_coc_mtu); + } + + reconfigured_ev(event->reconfigured.conn_handle, + event->reconfigured.chan, + &chan_info, + event->reconfigured.status); + return 0; + default: + return 0; + } +} + +static uint8_t +connect(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_l2cap_connect_cmd *cp = cmd; + struct btp_l2cap_connect_rp *rp = rsp; + struct ble_gap_conn_desc desc; + struct channel *chan; + struct os_mbuf *sdu_rx[cp->num]; + ble_addr_t *addr = (void *)&cp->address; + uint16_t mtu = le16toh(cp->mtu); + uint16_t psm = le16toh(cp->psm); + int rc; + int i, j; + uint8_t status = BTP_STATUS_SUCCESS; + bool ecfc = cp->options & BTP_L2CAP_CONNECT_OPT_ECFC; + hold_credit = cp->options & BTP_L2CAP_CONNECT_OPT_HOLD_CREDIT; + + SYS_LOG_DBG("connect: type: %d addr: %s", + addr->type, + string_from_bytes(addr->val, 6)); + + rc = ble_gap_conn_find_by_addr(addr, &desc); + if (cp->num == 0 || cp->num > CHANNELS || + mtu > TESTER_COC_MTU || mtu == 0) { + return BTP_STATUS_FAILED; + } + + if (rc) { + SYS_LOG_ERR("GAP conn find failed"); + return BTP_STATUS_FAILED; + } + + for (i = 0; i < cp->num; i++) { + chan = get_free_channel(); + if (!chan) { + SYS_LOG_ERR("No free channels"); + status = BTP_STATUS_FAILED; + goto done; + } + /* temporarily mark channel as used to select next one */ + chan->state = 1; + + rp->chan_ids[i] = chan->chan_id; + + sdu_rx[i] = os_mbuf_get_pkthdr(&sdu_os_mbuf_pool, 0); + if (sdu_rx[i] == NULL) { + SYS_LOG_ERR("Failed to alloc buf"); + status = BTP_STATUS_FAILED; + goto done; + } + } + + if (cp->num == 1 && !ecfc) { + rc = ble_l2cap_connect(desc.conn_handle, psm, + mtu, sdu_rx[0], + tester_l2cap_event, NULL); + } else if (ecfc) { + rc = ble_l2cap_enhanced_connect(desc.conn_handle, + psm, mtu, + cp->num, sdu_rx, + tester_l2cap_event, NULL); + } else { + SYS_LOG_ERR("Invalid 'num' parameter value"); + status = BTP_STATUS_FAILED; + goto done; + } + + if (rc) { + SYS_LOG_ERR("L2CAP connect failed\n"); + status = BTP_STATUS_FAILED; + goto done; + } + + rp->num = cp->num; + + *rsp_len = sizeof(*rp) + (rp->num * sizeof(rp->chan_ids[0])); +done: + /* mark selected channels as unused again */ + for (i = 0; i < cp->num; i++) { + for (j = 0; j < CHANNELS; j++) { + if (rp->chan_ids[i] == channels[j].chan_id) { + channels[j].state = 0; + } + } + } + + return status; +} + +static uint8_t +disconnect(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_l2cap_disconnect_cmd *cp = cmd; + struct channel *chan; + int err; + + SYS_LOG_DBG(""); + + if (cp->chan_id >= CHANNELS) { + return BTP_STATUS_FAILED; + } + + chan = get_channel(cp->chan_id); + assert(chan != NULL); + + err = ble_l2cap_disconnect(chan->chan); + if (err) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +send_data(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_l2cap_send_data_cmd *cp = cmd; + struct channel *chan; + struct os_mbuf *sdu_tx = NULL; + int rc; + uint16_t data_len; + + SYS_LOG_DBG("cmd->chan_id=%d", cp->chan_id); + + if (cmd_len < sizeof(*cp) || + cmd_len != sizeof(*cp) + le16toh(cp->data_len)) { + return BTP_STATUS_FAILED; + } + + if (cp->chan_id >= CHANNELS) { + return BTP_STATUS_FAILED; + } + + chan = get_channel(cp->chan_id); + data_len = le16toh(cp->data_len); + + if (!chan) { + SYS_LOG_ERR("Invalid channel\n"); + return BTP_STATUS_FAILED; + } + + /* FIXME: For now, fail if data length exceeds buffer length */ + if (data_len > TESTER_COC_MTU) { + SYS_LOG_ERR("Data length exceeds buffer length (%u > %u)", data_len, + TESTER_COC_MTU); + return BTP_STATUS_FAILED; + } + + sdu_tx = os_mbuf_get_pkthdr(&sdu_os_mbuf_pool, 0); + if (sdu_tx == NULL) { + SYS_LOG_ERR("No memory in the test sdu pool\n"); + rc = BLE_HS_ENOMEM; + goto fail; + } + + os_mbuf_append(sdu_tx, cp->data, data_len); + + /* ble_l2cap_send takes ownership of the sdu */ + rc = ble_l2cap_send(chan->chan, sdu_tx); + if (rc == 0 || rc == BLE_HS_ESTALLED) { + return BTP_STATUS_SUCCESS; + } + + /* autopts may queue more SDUs, for now support at least one queued*/ + if (rc == BLE_HS_EBUSY && chan->queued_sdu_tx == NULL) { + chan->queued_sdu_tx = sdu_tx; + return BTP_STATUS_SUCCESS; + } + +fail: + SYS_LOG_ERR("Unable to send data: %d", rc); + os_mbuf_free_chain(sdu_tx); + + return BTP_STATUS_FAILED; +} + +static uint8_t +listen(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_l2cap_listen_cmd *cp = cmd; + uint16_t mtu = htole16(cp->mtu); + uint16_t psm = htole16(cp->psm); + int rc; + + SYS_LOG_DBG(""); + + if (psm == 0) { + return BTP_STATUS_FAILED; + } + + if (mtu == 0 || mtu > TESTER_COC_MTU) { + mtu = TESTER_COC_MTU; + } + + /* We do not support BR/EDR transport */ + if (cp->transport == 0) { + return BTP_STATUS_FAILED; + } + + rc = ble_l2cap_create_server(psm, mtu, tester_l2cap_event, NULL); + if (rc) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +credits(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_l2cap_credits_cmd *cp = cmd; + struct channel *chan; + struct os_mbuf *sdu; + int rc; + + if (cp->chan_id >= CHANNELS) { + return BTP_STATUS_FAILED; + } + + chan = get_channel(cp->chan_id); + if (chan == NULL) { + return BTP_STATUS_FAILED; + } + + sdu = os_mbuf_get_pkthdr(&sdu_os_mbuf_pool, 0); + if (sdu == NULL) { + os_mbuf_free_chain(sdu); + return BTP_STATUS_FAILED; + } + + rc = ble_l2cap_recv_ready(chan->chan, sdu); + if (rc != 0) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +reconfigure(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_l2cap_reconfigure_cmd *cp = cmd; + uint16_t mtu = le16toh(cp->mtu); + struct ble_gap_conn_desc desc; + ble_addr_t *addr = (ble_addr_t *)&cp->address; + struct ble_l2cap_chan *chans[cp->num]; + struct channel *channel; + int rc; + int i; + + SYS_LOG_DBG(""); + + if (mtu == 0 || mtu > TESTER_COC_MTU) { + mtu = TESTER_COC_MTU; + } + + rc = ble_gap_conn_find_by_addr(addr, &desc); + if (rc) { + SYS_LOG_ERR("GAP conn find failed"); + return BTP_STATUS_FAILED; + } + + if (cmd_len < sizeof(*cp) || + cmd_len != sizeof(*cp) + cp->num) { + return BTP_STATUS_FAILED; + } + + if (cp->num > CHANNELS) { + return BTP_STATUS_FAILED; + } + + mtu = le16toh(cp->mtu); + if (mtu > TESTER_COC_MTU) { + return BTP_STATUS_FAILED; + } + + for (i = 0; i < cp->num; ++i) { + channel = get_channel(cp->idxs[i]); + if (channel == NULL) { + return BTP_STATUS_FAILED; + } + chans[i] = channel->chan; + } + + rc = ble_l2cap_reconfig(chans, cp->num, mtu); + if (rc) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +supported_commands(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + struct btp_l2cap_read_supported_commands_rp *rp = rsp; + + *rsp_len = tester_supported_commands(BTP_SERVICE_ID_L2CAP, rp->data); + *rsp_len += sizeof(*rp); + + return BTP_STATUS_SUCCESS; +} + +static const struct btp_handler handlers[] = { + { + .opcode = BTP_L2CAP_READ_SUPPORTED_COMMANDS, + .index = BTP_INDEX_NONE, + .expect_len = 0, + .func = supported_commands, + }, + { + .opcode = BTP_L2CAP_CONNECT, + .expect_len = sizeof(struct btp_l2cap_connect_cmd), + .func = connect, + }, + { + .opcode = BTP_L2CAP_DISCONNECT, + .expect_len = sizeof(struct btp_l2cap_disconnect_cmd), + .func = disconnect, + }, + { + .opcode = BTP_L2CAP_SEND_DATA, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = send_data, + }, + { + .opcode = BTP_L2CAP_LISTEN, + .expect_len = sizeof(struct btp_l2cap_listen_cmd), + .func = listen, + }, + { + .opcode = BTP_L2CAP_RECONFIGURE, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = reconfigure, + }, + { + .opcode = BTP_L2CAP_CREDITS, + .expect_len = sizeof(struct btp_l2cap_credits_cmd), + .func = credits, + }, +}; + +uint8_t +tester_init_l2cap(void) +{ + int rc; + + /* For testing we want to support all the available channels */ + rc = os_mempool_init(&sdu_coc_mbuf_mempool, TESTER_COC_BUF_COUNT, + TESTER_COC_MTU, tester_sdu_coc_mem, + "tester_coc_sdu_pool"); + assert(rc == 0); + + rc = os_mbuf_pool_init(&sdu_os_mbuf_pool, &sdu_coc_mbuf_mempool, + TESTER_COC_MTU, TESTER_COC_BUF_COUNT); + assert(rc == 0); + + tester_register_command_handlers(BTP_SERVICE_ID_L2CAP, handlers, + ARRAY_SIZE(handlers)); + + return BTP_STATUS_SUCCESS; +} + +uint8_t +tester_unregister_l2cap(void) +{ + return BTP_STATUS_SUCCESS; +} + +#endif diff --git a/apps/bttester/src/btp_mesh.c b/apps/bttester/src/btp_mesh.c new file mode 100644 index 0000000000..4815dbe5b8 --- /dev/null +++ b/apps/bttester/src/btp_mesh.c @@ -0,0 +1,1099 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* mesh.c - Bluetooth Mesh Tester */ + +/* + * Copyright (c) 2017 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "syscfg/syscfg.h" + +#if MYNEWT_VAL(BLE_MESH) + +#include + +#include "mesh/mesh.h" +#include "mesh/glue.h" +#include "mesh/testing.h" +#include "console/console.h" + +#include "btp/btp.h" + +#ifndef min +#define min(a, b) ((a) < (b) ? (a) : (b)) +#endif + +extern uint8_t own_addr_type; + +#define CONTROLLER_INDEX 0 +#define CID_LOCAL 0x0002 + +/* Health server data */ +#define CUR_FAULTS_MAX 4 +#define HEALTH_TEST_ID 0x00 + +static uint8_t cur_faults[CUR_FAULTS_MAX]; +static uint8_t reg_faults[CUR_FAULTS_MAX * 2]; + +/* Provision node data */ +static uint8_t net_key[16]; +static uint16_t net_key_idx; +static uint8_t flags; +static uint32_t iv_index; +static uint16_t addr; +static uint8_t dev_key[16]; +static uint8_t input_size; + +/* Configured provisioning data */ +static uint8_t dev_uuid[16]; +static uint8_t static_auth[16]; + +/* Vendor Model data */ +#define VND_MODEL_ID_1 0x1234 + +/* Model send data */ +#define MODEL_BOUNDS_MAX 2 + +static struct model_data { + struct bt_mesh_model *model; + uint16_t addr; + uint16_t appkey_idx; +} model_bound[MODEL_BOUNDS_MAX]; + +static struct { + uint16_t local; + uint16_t dst; + uint16_t net_idx; +} net = { + .local = BT_MESH_ADDR_UNASSIGNED, + .dst = BT_MESH_ADDR_UNASSIGNED, +}; + +static uint8_t +supported_commands(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + struct btp_mesh_read_supported_commands_rp *rp = rsp; + + *rsp_len = tester_supported_commands(BTP_SERVICE_ID_GAP, rp->data); + *rsp_len += sizeof(*rp); + + return BTP_STATUS_SUCCESS; +} + +static void +get_faults(uint8_t *faults, uint8_t faults_size, uint8_t *dst, uint8_t *count) +{ + uint8_t i, limit = *count; + + for (i = 0, *count = 0; i < faults_size && *count < limit; i++) { + if (faults[i]) { + *dst++ = faults[i]; + (*count)++; + } + } +} + +static int +fault_get_cur(struct bt_mesh_model *model, uint8_t *test_id, + uint16_t *company_id, uint8_t *faults, uint8_t *fault_count) +{ + SYS_LOG_DBG(""); + + *test_id = HEALTH_TEST_ID; + *company_id = CID_LOCAL; + + get_faults(cur_faults, sizeof(cur_faults), faults, fault_count); + + return 0; +} + +static int +fault_get_reg(struct bt_mesh_model *model, uint16_t company_id, + uint8_t *test_id, uint8_t *faults, uint8_t *fault_count) +{ + SYS_LOG_DBG("company_id 0x%04x", company_id); + + if (company_id != CID_LOCAL) { + return -EINVAL; + } + + *test_id = HEALTH_TEST_ID; + + get_faults(reg_faults, sizeof(reg_faults), faults, fault_count); + + return 0; +} + +static int +fault_clear(struct bt_mesh_model *model, uint16_t company_id) +{ + SYS_LOG_DBG("company_id 0x%04x", company_id); + + if (company_id != CID_LOCAL) { + return -EINVAL; + } + + memset(reg_faults, 0, sizeof(reg_faults)); + + return 0; +} + +static int +fault_test(struct bt_mesh_model *model, uint8_t test_id, + uint16_t company_id) +{ + SYS_LOG_DBG("test_id 0x%02x company_id 0x%04x", test_id, company_id); + + if (company_id != CID_LOCAL || test_id != HEALTH_TEST_ID) { + return -EINVAL; + } + + return 0; +} + +static const struct bt_mesh_health_srv_cb health_srv_cb = { + .fault_get_cur = fault_get_cur, + .fault_get_reg = fault_get_reg, + .fault_clear = fault_clear, + .fault_test = fault_test, +}; + +static struct bt_mesh_health_srv health_srv = { + .cb = &health_srv_cb, +}; + +static struct bt_mesh_model_pub health_pub; + +static void +health_pub_init(void) +{ + health_pub.msg = BT_MESH_HEALTH_FAULT_MSG(CUR_FAULTS_MAX); +} + +static struct bt_mesh_cfg_cli cfg_cli = { +}; + +void +show_faults(uint8_t test_id, uint16_t cid, uint8_t *faults, size_t fault_count) +{ + size_t i; + + if (!fault_count) { + SYS_LOG_DBG("Health Test ID 0x%02x Company ID 0x%04x: " + "no faults", test_id, cid); + return; + } + + SYS_LOG_DBG("Health Test ID 0x%02x Company ID 0x%04x Fault Count %zu: ", + test_id, cid, fault_count); + + for (i = 0; i < fault_count; i++) { + SYS_LOG_DBG("0x%02x", faults[i]); + } +} + +static void +health_current_status(struct bt_mesh_health_cli *cli, uint16_t addr, + uint8_t test_id, uint16_t cid, uint8_t *faults, + size_t fault_count) +{ + SYS_LOG_DBG("Health Current Status from 0x%04x", addr); + show_faults(test_id, cid, faults, fault_count); +} + +static struct bt_mesh_health_cli health_cli = { + .current_status = health_current_status, +}; + +static struct bt_mesh_model root_models[] = { + BT_MESH_MODEL_CFG_SRV, + BT_MESH_MODEL_CFG_CLI(&cfg_cli), + BT_MESH_MODEL_HEALTH_SRV(&health_srv, &health_pub), + BT_MESH_MODEL_HEALTH_CLI(&health_cli), +}; + +static struct bt_mesh_model vnd_models[] = { + BT_MESH_MODEL_VND(CID_LOCAL, VND_MODEL_ID_1, BT_MESH_MODEL_NO_OPS, NULL, + NULL), +}; + +static struct bt_mesh_elem elements[] = { + BT_MESH_ELEM(0, root_models, vnd_models), +}; + +static void +link_open(bt_mesh_prov_bearer_t bearer) +{ + struct btp_mesh_prov_link_open_ev ev; + + SYS_LOG_DBG("bearer 0x%02x", bearer); + + switch (bearer) { + case BT_MESH_PROV_ADV: + ev.bearer = BTP_MESH_PROV_BEARER_PB_ADV; + break; + case BT_MESH_PROV_GATT: + ev.bearer = BTP_MESH_PROV_BEARER_PB_GATT; + break; + default: + SYS_LOG_ERR("Invalid bearer"); + + return; + } + + tester_event(BTP_SERVICE_ID_MESH, BTP_MESH_EV_PROV_LINK_OPEN, + (uint8_t *) &ev, sizeof(ev)); +} + +static void +link_close(bt_mesh_prov_bearer_t bearer) +{ + struct btp_mesh_prov_link_closed_ev ev; + + SYS_LOG_DBG("bearer 0x%02x", bearer); + + switch (bearer) { + case BT_MESH_PROV_ADV: + ev.bearer = BTP_MESH_PROV_BEARER_PB_ADV; + break; + case BT_MESH_PROV_GATT: + ev.bearer = BTP_MESH_PROV_BEARER_PB_GATT; + break; + default: + SYS_LOG_ERR("Invalid bearer"); + + return; + } + + tester_event(BTP_SERVICE_ID_MESH, BTP_MESH_EV_PROV_LINK_CLOSED, + (uint8_t *) &ev, sizeof(ev)); +} + +static int +output_number(bt_mesh_output_action_t action, uint32_t number) +{ + struct btp_mesh_out_number_action_ev ev; + + SYS_LOG_DBG("action 0x%04x number 0x%08lx", action, number); + + ev.action = htole16(action); + ev.number = htole32(number); + + tester_event(BTP_SERVICE_ID_MESH, BTP_MESH_EV_OUT_NUMBER_ACTION, + (uint8_t *) &ev, sizeof(ev)); + + return 0; +} + +static int +output_string(const char *str) +{ + struct btp_mesh_out_string_action_ev *ev; + struct os_mbuf *buf = NET_BUF_SIMPLE(BTP_DATA_MAX_SIZE); + + SYS_LOG_DBG("str %s", str); + + net_buf_simple_init(buf, 0); + + ev = net_buf_simple_add(buf, sizeof(*ev)); + ev->string_len = strlen(str); + + net_buf_simple_add_mem(buf, str, ev->string_len); + + tester_send_buf(BTP_SERVICE_ID_MESH, BTP_MESH_EV_OUT_STRING_ACTION, + CONTROLLER_INDEX, buf); + + os_mbuf_free_chain(buf); + return 0; +} + +static int +input(bt_mesh_input_action_t action, uint8_t size) +{ + struct btp_mesh_in_action_ev ev; + + SYS_LOG_DBG("action 0x%04x number 0x%02x", action, size); + + input_size = size; + + ev.action = htole16(action); + ev.size = size; + + tester_event(BTP_SERVICE_ID_MESH, BTP_MESH_EV_IN_ACTION, + (uint8_t *) &ev, sizeof(ev)); + + return 0; +} + +static uint8_t vnd_app_key[16]; +static uint16_t vnd_app_key_idx = 0x000f; + +static void +prov_complete(uint16_t net_idx, uint16_t addr) +{ + SYS_LOG_DBG("net_idx 0x%04x addr 0x%04x", net_idx, addr); + + net.net_idx = net_idx, + net.local = addr; + net.dst = addr; + + tester_event(BTP_SERVICE_ID_MESH, BTP_MESH_EV_PROVISIONED, + NULL, 0); +} + +static void +prov_reset(void) +{ + SYS_LOG_DBG(""); + + bt_mesh_prov_enable(BT_MESH_PROV_ADV | BT_MESH_PROV_GATT); +} + +static const struct bt_mesh_comp comp = { + .cid = CID_LOCAL, + .elem = elements, + .elem_count = ARRAY_SIZE(elements), +}; + +static struct bt_mesh_prov prov = { + .uuid = dev_uuid, + .static_val = static_auth, + .static_val_len = sizeof(static_auth), + .output_number = output_number, + .output_string = output_string, + .input = input, + .link_open = link_open, + .link_close = link_close, + .complete = prov_complete, + .reset = prov_reset, +}; + +static uint8_t +config_prov(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_mesh_config_provisioning_cmd *cp = cmd; + + SYS_LOG_DBG(""); + + if (cmd_len < sizeof(*cp)) { + return BTP_STATUS_FAILED; + } + + memcpy(dev_uuid, cp->uuid, sizeof(dev_uuid)); + memcpy(static_auth, cp->static_auth, sizeof(static_auth)); + + prov.output_size = cp->out_size; + prov.output_actions = sys_le16_to_cpu(cp->out_actions); + prov.input_size = cp->in_size; + prov.input_actions = sys_le16_to_cpu(cp->in_actions); + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +provision_node(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_mesh_provision_node_cmd *cp = cmd; + + SYS_LOG_DBG(""); + + if (cmd_len != sizeof(*cp)) { + return BTP_STATUS_FAILED; + } + + memcpy(dev_key, cp->dev_key, sizeof(dev_key)); + memcpy(net_key, cp->net_key, sizeof(net_key)); + + addr = sys_le16_to_cpu(cp->addr); + flags = cp->flags; + iv_index = le32toh(cp->iv_index); + net_key_idx = sys_le16_to_cpu(cp->net_key_idx); + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +init(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_mesh_init_cmd *cp = cmd; + int err; + + SYS_LOG_DBG(""); + + if (cmd_len != sizeof(*cp)) { + return BTP_STATUS_FAILED; + } + + err = bt_mesh_init(own_addr_type, &prov, &comp); + if (err) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +reset(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + SYS_LOG_DBG(""); + + bt_mesh_reset(); + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +input_number(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_mesh_input_number_cmd *cp = cmd; + uint32_t number; + int err; + + number = le32toh(cp->number); + + SYS_LOG_DBG("number 0x%04lx", number); + + err = bt_mesh_input_number(number); + if (err) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +input_string(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_mesh_input_string_cmd *cp = cmd; + int err; + + SYS_LOG_DBG(""); + + if (cmd_len < sizeof(*cp) && + cmd_len != (sizeof(*cp) + cp->string_len)) { + return BTP_STATUS_FAILED; + } + + /* for historical reasons this commands must send NULL terminated + * string + */ + if (cp->string[cp->string_len] != '\0') { + return BTP_STATUS_FAILED; + } + + if (strlen((char *)cp->string) < input_size) { + SYS_LOG_ERR("Too short input (%u chars required)", input_size); + return BTP_STATUS_FAILED; + } + err = bt_mesh_input_string((char *)cp->string); + if (err) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +ivu_test_mode(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_mesh_ivu_test_mode_cmd *cp = cmd; + + SYS_LOG_DBG("enable 0x%02x", cp->enable); + + bt_mesh_iv_update_test(cp->enable ? true : false); + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +ivu_toggle_state(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + bool result; + + SYS_LOG_DBG(""); + + result = bt_mesh_iv_update(); + if (!result) { + SYS_LOG_ERR("Failed to toggle the IV Update state"); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +lpn(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_mesh_lpn_set_cmd *cp = cmd; + bool enable; + int err; + + SYS_LOG_DBG("enable 0x%02x", cp->enable); + + enable = cp->enable ? true : false; + err = bt_mesh_lpn_set(enable); + if (err) { + SYS_LOG_ERR("Failed to toggle LPN (err %d)", err); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +lpn_poll(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + int err; + + SYS_LOG_DBG(""); + + err = bt_mesh_lpn_poll(); + if (err) { + SYS_LOG_ERR("Failed to send poll msg (err %d)", err); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +net_send(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_mesh_net_send_cmd *cp = cmd; + struct os_mbuf *msg = NET_BUF_SIMPLE(UINT8_MAX); + struct bt_mesh_msg_ctx ctx = { + .net_idx = net.net_idx, + .app_idx = vnd_app_key_idx, + .addr = sys_le16_to_cpu(cp->dst), + .send_ttl = cp->ttl, + }; + int err; + int status = BTP_STATUS_SUCCESS; + + if (cmd_len < sizeof(*cp) && + cmd_len != (sizeof(*cp) + cp->payload_len)) { + return BTP_STATUS_FAILED; + } + + SYS_LOG_DBG("ttl 0x%02x dst 0x%04x payload_len %d", ctx.send_ttl, + ctx.addr, cp->payload_len); + + if (!bt_mesh_app_key_exists(vnd_app_key_idx)) { + (void) bt_mesh_app_key_add(vnd_app_key_idx, net.net_idx, + vnd_app_key); + vnd_models[0].keys[0] = vnd_app_key_idx; + } + + net_buf_simple_add_mem(msg, cp->payload, cp->payload_len); + + err = bt_mesh_model_send(&vnd_models[0], &ctx, msg, NULL, NULL); + if (err) { + SYS_LOG_ERR("Failed to send (err %d)", err); + status = BTP_STATUS_FAILED; + } + + os_mbuf_free_chain(msg); + + return status; +} + +static uint8_t +health_generate_faults(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + struct btp_mesh_health_generate_faults_rp *rp = rsp; + uint8_t some_faults[] = {0x01, 0x02, 0x03, 0xff, 0x06}; + uint8_t cur_faults_count, reg_faults_count; + + cur_faults_count = min(sizeof(cur_faults), sizeof(some_faults)); + memcpy(cur_faults, some_faults, cur_faults_count); + memcpy(rp->current_faults, cur_faults, cur_faults_count); + rp->cur_faults_count = cur_faults_count; + + reg_faults_count = min(sizeof(reg_faults), sizeof(some_faults)); + memcpy(reg_faults, some_faults, reg_faults_count); + memcpy(rp->registered_faults + cur_faults_count, reg_faults, reg_faults_count); + rp->reg_faults_count = reg_faults_count; + + bt_mesh_fault_update(&elements[0]); + + *rsp_len = sizeof(*rp) + cur_faults_count + reg_faults_count; + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +health_clear_faults(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + SYS_LOG_DBG(""); + + memset(cur_faults, 0, sizeof(cur_faults)); + memset(reg_faults, 0, sizeof(reg_faults)); + + bt_mesh_fault_update(&elements[0]); + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +model_send(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_mesh_model_send_cmd *cp = cmd; + struct os_mbuf *msg = NET_BUF_SIMPLE(UINT8_MAX); + struct bt_mesh_model *model = NULL; + int err, i; + uint16_t src; + int status = BTP_STATUS_SUCCESS; + + if (cmd_len < sizeof(*cp) && + cmd_len != (sizeof(*cp) + cp->payload_len)) { + return BTP_STATUS_FAILED; + } + + struct bt_mesh_msg_ctx ctx = { + .net_idx = net.net_idx, + .app_idx = BT_MESH_KEY_DEV, + .addr = sys_le16_to_cpu(cp->dst), + .send_ttl = cp->ttl, + }; + + src = sys_le16_to_cpu(cp->src); + + /* Lookup source address */ + for (i = 0; i < ARRAY_SIZE(model_bound); i++) { + if (bt_mesh_model_elem(model_bound[i].model)->addr == src) { + model = model_bound[i].model; + ctx.app_idx = model_bound[i].appkey_idx; + + break; + } + } + + if (!model) { + SYS_LOG_ERR("Model not found"); + status = BTP_STATUS_FAILED; + + goto rsp; + } + + SYS_LOG_DBG("src 0x%04x dst 0x%04x model %p payload_len %d", src, + ctx.addr, model, cp->payload_len); + + net_buf_simple_add_mem(msg, cp->payload, cp->payload_len); + + err = bt_mesh_model_send(model, &ctx, msg, NULL, NULL); + if (err) { + SYS_LOG_ERR("Failed to send (err %d)", err); + status = BTP_STATUS_FAILED; + } + +rsp: + os_mbuf_free_chain(msg); + return status; +} + +#if MYNEWT_VAL(BLE_MESH_TESTING) + +static uint8_t +lpn_subscribe(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_mesh_lpn_subscribe_cmd *cp = cmd; + uint16_t address = sys_le16_to_cpu(cp->address); + int err; + + SYS_LOG_DBG("address 0x%04x", address); + + err = bt_test_mesh_lpn_group_add(address); + if (err) { + SYS_LOG_ERR("Failed to subscribe (err %d)", err); + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +lpn_unsubscribe(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_mesh_lpn_unsubscribe_cmd *cp = cmd; + uint16_t address = sys_le16_to_cpu(cp->address); + int err; + + SYS_LOG_DBG("address 0x%04x", address); + + err = bt_test_mesh_lpn_group_remove(&address, 1); + if (err) { + SYS_LOG_ERR("Failed to unsubscribe (err %d)", err); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +rpl_clear(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + int err; + + SYS_LOG_DBG(""); + + err = bt_test_mesh_rpl_clear(); + if (err) { + SYS_LOG_ERR("Failed to clear RPL (err %d)", err); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +#endif /* MYNEWT_VAL(BLE_MESH_TESTING) */ + +static uint8_t +proxy_identity_enable(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + int err; + + SYS_LOG_DBG(""); + + err = bt_mesh_proxy_identity_enable(); + if (err) { + SYS_LOG_ERR("Failed to enable proxy identity (err %d)", err); + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +start(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + int err; + + SYS_LOG_DBG(""); + + if (addr) { + err = bt_mesh_provision(net_key, net_key_idx, flags, iv_index, + addr, dev_key); + if (err) { + return BTP_STATUS_FAILED; + } + } else { + err = bt_mesh_prov_enable(BT_MESH_PROV_ADV | BT_MESH_PROV_GATT); + if (err) { + return BTP_STATUS_FAILED; + } + } + + return BTP_STATUS_SUCCESS; +} + +static const struct btp_handler handlers[] = { + { + .opcode = BTP_MESH_READ_SUPPORTED_COMMANDS, + .index = BTP_INDEX_NONE, + .expect_len = 0, + .func = supported_commands, + }, + { + .opcode = BTP_MESH_CONFIG_PROVISIONING, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = config_prov, + }, + { + .opcode = BTP_MESH_PROVISION_NODE, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = provision_node, + }, + { + .opcode = BTP_MESH_INIT, + .expect_len = 1, + .func = init, + }, + { + .opcode = BTP_MESH_RESET, + .expect_len = 0, + .func = reset, + }, + { + .opcode = BTP_MESH_INPUT_NUMBER, + .expect_len = sizeof(struct btp_mesh_input_number_cmd), + .func = input_number, + }, + { + .opcode = BTP_MESH_INPUT_STRING, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = input_string, + }, + { + .opcode = BTP_MESH_IVU_TEST_MODE, + .expect_len = sizeof(struct btp_mesh_ivu_test_mode_cmd), + .func = ivu_test_mode, + }, + { + .opcode = BTP_MESH_IVU_TOGGLE_STATE, + .expect_len = 0, + .func = ivu_toggle_state, + }, + { + .opcode = BTP_MESH_LPN, + .expect_len = sizeof(struct btp_mesh_lpn_set_cmd), + .func = lpn, + }, + { + .opcode = BTP_MESH_LPN_POLL, + .expect_len = 0, + .func = lpn_poll, + }, + { + .opcode = BTP_MESH_NET_SEND, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = net_send, + }, + { + .opcode = BTP_MESH_HEALTH_GENERATE_FAULTS, + .expect_len = 0, + .func = health_generate_faults, + }, + { + .opcode = BTP_MESH_HEALTH_CLEAR_FAULTS, + .expect_len = 0, + .func = health_clear_faults, + }, + { + .opcode = BTP_MESH_MODEL_SEND, + .expect_len = BTP_HANDLER_LENGTH_VARIABLE, + .func = model_send, + }, + { + .opcode = BTP_MESH_LPN_SUBSCRIBE, + .expect_len = sizeof(struct btp_mesh_lpn_subscribe_cmd), + .func = lpn_subscribe, + }, + { + .opcode = BTP_MESH_LPN_UNSUBSCRIBE, + .expect_len = sizeof(struct btp_mesh_lpn_unsubscribe_cmd), + .func = lpn_unsubscribe, + }, + { + .opcode = BTP_MESH_RPL_CLEAR, + .expect_len = 0, + .func = rpl_clear, + }, + { + .opcode = BTP_MESH_PROXY_IDENTITY, + .expect_len = 0, + .func = proxy_identity_enable, + }, + { + .opcode = BTP_MESH_START, + .expect_len = 0, + .func = start, + }, +}; + +void +net_recv_ev(uint8_t ttl, + uint8_t ctl, + uint16_t src, + uint16_t dst, + const void *payload, + size_t payload_len) +{ + struct os_mbuf *buf = NET_BUF_SIMPLE(UINT8_MAX); + struct btp_mesh_net_recv_ev *ev; + + SYS_LOG_DBG("ttl 0x%02x ctl 0x%02x src 0x%04x dst 0x%04x " + "payload_len %d", ttl, ctl, src, dst, payload_len); + + if (payload_len > net_buf_simple_tailroom(buf)) { + SYS_LOG_ERR("Payload size exceeds buffer size"); + + goto done; + } + + ev = net_buf_simple_add(buf, sizeof(*ev)); + ev->ttl = ttl; + ev->ctl = ctl; + ev->src = htole16(src); + ev->dst = htole16(dst); + ev->payload_len = payload_len; + net_buf_simple_add_mem(buf, payload, payload_len); + + tester_send_buf(BTP_SERVICE_ID_MESH, BTP_MESH_EV_NET_RECV, CONTROLLER_INDEX, + buf); +done: + os_mbuf_free_chain(buf); +} + +static void +model_bound_cb(uint16_t addr, struct bt_mesh_model *model, + uint16_t key_idx) +{ + int i; + + SYS_LOG_DBG("remote addr 0x%04x key_idx 0x%04x model %p", + addr, key_idx, model); + + for (i = 0; i < ARRAY_SIZE(model_bound); i++) { + if (!model_bound[i].model) { + model_bound[i].model = model; + model_bound[i].addr = addr; + model_bound[i].appkey_idx = key_idx; + + return; + } + } + + SYS_LOG_ERR("model_bound is full"); +} + +static void +model_unbound_cb(uint16_t addr, struct bt_mesh_model *model, + uint16_t key_idx) +{ + int i; + + SYS_LOG_DBG("remote addr 0x%04x key_idx 0x%04x model %p", + addr, key_idx, model); + + for (i = 0; i < ARRAY_SIZE(model_bound); i++) { + if (model_bound[i].model == model) { + model_bound[i].model = NULL; + model_bound[i].addr = 0x0000; + model_bound[i].appkey_idx = BT_MESH_KEY_UNUSED; + + return; + } + } + + SYS_LOG_INF("model not found"); +} + +static void +invalid_bearer_cb(uint8_t opcode) +{ + struct btp_mesh_invalid_bearer_ev ev = { + .opcode = opcode, + }; + + SYS_LOG_DBG("opcode 0x%02x", opcode); + + tester_event(BTP_SERVICE_ID_MESH, BTP_MESH_EV_INVALID_BEARER, + (uint8_t *) &ev, sizeof(ev)); +} + +static void +incomp_timer_exp_cb(void) +{ + tester_event(BTP_SERVICE_ID_MESH, BTP_MESH_EV_INCOMP_TIMER_EXP, + NULL, 0); +} + +static struct bt_test_cb bt_test_cb = { + .mesh_net_recv = net_recv_ev, + .mesh_model_bound = model_bound_cb, + .mesh_model_unbound = model_unbound_cb, + .mesh_prov_invalid_bearer = invalid_bearer_cb, + .mesh_trans_incomp_timer_exp = incomp_timer_exp_cb, +}; + +static void +lpn_established(uint16_t friend_addr) +{ + + struct bt_mesh_lpn *lpn = &bt_mesh.lpn; + struct btp_mesh_lpn_established_ev + ev = {lpn->sub->net_idx, friend_addr, lpn->queue_size, + lpn->recv_win}; + + SYS_LOG_DBG("Friendship (as LPN) established with " + "Friend 0x%04x Queue Size %d Receive Window %d", + friend_addr, lpn->queue_size, lpn->recv_win); + + tester_event(BTP_SERVICE_ID_MESH, BTP_MESH_EV_LPN_ESTABLISHED, + (uint8_t *) &ev, sizeof(ev)); +} + +static void +lpn_terminated(uint16_t friend_addr) +{ + struct bt_mesh_lpn *lpn = &bt_mesh.lpn; + struct btp_mesh_lpn_terminated_ev ev = {lpn->sub->net_idx, friend_addr}; + + SYS_LOG_DBG("Friendship (as LPN) lost with Friend " + "0x%04x", friend_addr); + + tester_event(BTP_SERVICE_ID_MESH, BTP_MESH_EV_LPN_TERMINATED, + (uint8_t *) &ev, sizeof(ev)); +} + +void +lpn_cb(uint16_t friend_addr, bool established) +{ + if (established) { + lpn_established(friend_addr); + } else { + lpn_terminated(friend_addr); + } +} + +uint8_t +tester_init_mesh(void) +{ + health_pub_init(); + + if (IS_ENABLED(CONFIG_BT_TESTING)) { + bt_mesh_lpn_set_cb(lpn_cb); + bt_test_cb_register(&bt_test_cb); + } + + tester_register_command_handlers(BTP_SERVICE_ID_MESH, handlers, + ARRAY_SIZE(handlers)); + + return BTP_STATUS_SUCCESS; +} + +uint8_t +tester_unregister_mesh(void) +{ + return BTP_STATUS_SUCCESS; +} + +#endif /* MYNEWT_VAL(BLE_MESH) */ diff --git a/apps/bttester/src/btp_pacs.c b/apps/bttester/src/btp_pacs.c new file mode 100644 index 0000000000..2ccc6f1b9a --- /dev/null +++ b/apps/bttester/src/btp_pacs.c @@ -0,0 +1,329 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* btp_pacs.c - Bluetooth Published Audio Capacity Service Tester */ + +#include "syscfg/syscfg.h" + +#if MYNEWT_VAL(BLE_AUDIO) + +#include "audio/ble_audio.h" +#include "audio/ble_audio_codec.h" +#include "btp/bttester.h" +#include "host/ble_gap.h" +#include "os/util.h" +#include + +#include "btp/btp.h" +#include "btp/btp_pacs.h" +#include "services/pacs/ble_audio_svc_pacs.h" +#include "services/pacs/ble_audio_svc_pacs_lc3.h" + +#define BLE_SVC_AUDIO_PACS_LC3_CODEC_ID 0x06 +#define BTTESTER_SUPPORTED_CTXTS 0x07 + +struct set_avail_cb_data { + uint16_t src_ctxts; + uint16_t snk_ctxts; +}; + +#ifdef MYNEWT_VAL_BLE_SVC_AUDIO_PACS_LC3_SNK_METADATA +static uint8_t ble_svc_audio_pacs_lc3_snk_metadata[] = +{ UNMANGLE_MYNEWT_VAL(MYNEWT_VAL(BLE_SVC_AUDIO_PACS_LC3_SNK_METADATA)) }; +#endif + +static uint8_t ble_svc_audio_pacs_lc3_snk_codec_spec_caps[] = BLE_AUDIO_BUILD_CODEC_CAPS( + MYNEWT_VAL(BLE_SVC_AUDIO_PACS_LC3_SNK_SAMPLING_FREQUENCIES), + MYNEWT_VAL(BLE_SVC_AUDIO_PACS_LC3_SNK_FRAME_DURATIONS), + #ifdef MYNEWT_VAL_BLE_SVC_AUDIO_PACS_LC3_SRC_AUDIO_CHANNEL_COUNTS + MYNEWT_VAL(BLE_SVC_AUDIO_PACS_LC3_SNK_AUDIO_CHANNEL_COUNTS), + #else + , + #endif + MYNEWT_VAL(BLE_SVC_AUDIO_PACS_LC3_SNK_MIN_OCTETS_PER_CODEC_FRAME), + MYNEWT_VAL(BLE_SVC_AUDIO_PACS_LC3_SRC_MAX_OCTETS_PER_CODEC_FRAME), + #ifdef MYNEWT_VAL_BLE_SVC_AUDIO_PACS_LC3_SRC_MAX_CODEC_FRAMES_PER_SDU + MYNEWT_VAL(BLE_SVC_AUDIO_PACS_LC3_SNK_MAX_CODEC_FRAMES_PER_SDU), + #endif +); + +static uint8_t ble_svc_audio_pacs_lc3_src_codec_spec_caps[] = BLE_AUDIO_BUILD_CODEC_CAPS( + MYNEWT_VAL(BLE_SVC_AUDIO_PACS_LC3_SRC_SAMPLING_FREQUENCIES), + MYNEWT_VAL(BLE_SVC_AUDIO_PACS_LC3_SRC_FRAME_DURATIONS), +#ifdef MYNEWT_VAL_BLE_SVC_AUDIO_PACS_LC3_SRC_AUDIO_CHANNEL_COUNTS + MYNEWT_VAL(BLE_SVC_AUDIO_PACS_LC3_SRC_AUDIO_CHANNEL_COUNTS), +#else + , +#endif + MYNEWT_VAL(BLE_SVC_AUDIO_PACS_LC3_SRC_MIN_OCTETS_PER_CODEC_FRAME), + MYNEWT_VAL(BLE_SVC_AUDIO_PACS_LC3_SRC_MAX_OCTETS_PER_CODEC_FRAME), +#ifdef MYNEWT_VAL_BLE_SVC_AUDIO_PACS_LC3_SRC_MAX_CODEC_FRAMES_PER_SDU + MYNEWT_VAL(BLE_SVC_AUDIO_PACS_LC3_SRC_MAX_CODEC_FRAMES_PER_SDU), +#endif +); + +static struct ble_audio_codec_register_params snk_codec_params = { + .codec_id = { + .format = BLE_SVC_AUDIO_PACS_LC3_CODEC_ID, + .company_id = 0x00, + .vendor_specific = 0x00 + }, + .codec_spec_caps_len = sizeof(ble_svc_audio_pacs_lc3_snk_codec_spec_caps), + .codec_spec_caps = ble_svc_audio_pacs_lc3_snk_codec_spec_caps, +#ifdef MYNEWT_VAL_BLE_SVC_AUDIO_PACS_LC3_SNK_METADATA + .metadata_len = sizeof(ble_svc_audio_pacs_lc3_snk_metadata), + .metadata = ble_svc_audio_pacs_lc3_snk_metadata, +#else + .metadata_len = 0, +#endif + + .direction = BLE_AUDIO_CODEC_DIR_SINK_BIT +}; + +static struct ble_audio_codec_register_params src_codec_params = { + .codec_id = { + .format = BLE_SVC_AUDIO_PACS_LC3_CODEC_ID, + .company_id = 0x00, + .vendor_specific = 0x00 + }, + .codec_spec_caps_len = sizeof(ble_svc_audio_pacs_lc3_src_codec_spec_caps), + .codec_spec_caps = ble_svc_audio_pacs_lc3_src_codec_spec_caps, +#ifdef MYNEWT_VAL_BLE_SVC_AUDIO_PACS_LC3_SRC_METADATA + .metadata_len = sizeof(ble_svc_audio_pacs_lc3_src_metadata), + .metadata = ble_svc_audio_pacs_lc3_src_metadata, +#else + .metadata_len = 0, +#endif + .direction = BLE_AUDIO_CODEC_DIR_SOURCE_BIT +}; + +int +set_available(uint16_t conn_handle, void *arg) +{ + int rc; + struct set_avail_cb_data *avail_data = arg; + + rc = ble_svc_audio_pacs_avail_contexts_set(conn_handle, + avail_data->snk_ctxts, + avail_data->src_ctxts); + if (rc) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +pacs_set_available_contexts(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + const struct btp_pacs_set_available_contexts_cmd *cp = cmd; + uint16_t source_contexts = le16toh(cp->source_contexts); + uint16_t sink_conexts = le16toh(cp->sink_contexts); + struct set_avail_cb_data cb_data; + + /* If this originated from pacs_update_characteristic - we update with unspecified */ + if (sink_conexts == BTP_PACS_CHARACTERISTIC_AVAILABLE_AUDIO_CONTEXTS) { + cb_data.snk_ctxts = BLE_AUDIO_CONTEXT_TYPE_UNSPECIFIED; + cb_data.src_ctxts = BLE_AUDIO_CONTEXT_TYPE_UNSPECIFIED; + } else { + cb_data.snk_ctxts = sink_conexts; + cb_data.src_ctxts = source_contexts; + } + + ble_gap_conn_foreach_handle(set_available, &cb_data); + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +pacs_set_snk_location(void) +{ + int rc; + struct ble_svc_audio_pacs_set_param snk_params = { + .audio_locations = 0, + .supported_contexts = MYNEWT_VAL(BLE_SVC_AUDIO_PACS_LC3_SNK_SUP_CONTEXTS) + }; + + rc = ble_svc_audio_pacs_set(BLE_AUDIO_CODEC_DIR_SINK_BIT, &snk_params); + if (rc) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +pacs_set_src_location(void) +{ + int rc; + struct ble_svc_audio_pacs_set_param src_params = { + .audio_locations = 0, + .supported_contexts = MYNEWT_VAL(BLE_SVC_AUDIO_PACS_LC3_SRC_SUP_CONTEXTS) + }; + + rc = ble_svc_audio_pacs_set(BLE_AUDIO_CODEC_DIR_SOURCE_BIT, &src_params); + if (rc) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +pacs_update_characteristic(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + int rc; + const struct btp_pacs_update_characteristic_cmd *cp = cmd; + + switch (cp->char_id) { + case BTP_PACS_CHARACTERISTIC_SINK_PAC: + rc = ble_audio_codec_register(&snk_codec_params, NULL); + if (rc) { + return BTP_STATUS_FAILED; + } + break; + case BTP_PACS_CHARACTERISTIC_SOURCE_PAC: + rc = ble_audio_codec_register(&src_codec_params, NULL); + if (rc) { + return BTP_STATUS_FAILED; + } + break; + case BTP_PACS_CHARACTERISTIC_SINK_AUDIO_LOCATIONS: + rc = pacs_set_snk_location(); + if (rc) { + return BTP_STATUS_FAILED; + } + break; + case BTP_PACS_CHARACTERISTIC_SOURCE_AUDIO_LOCATIONS: + rc = pacs_set_src_location(); + if (rc) { + return BTP_STATUS_FAILED; + } + break; + case BTP_PACS_CHARACTERISTIC_AVAILABLE_AUDIO_CONTEXTS: + rc = pacs_set_available_contexts(cmd, cmd_len, rsp, rsp_len); + if (rc) { + return BTP_STATUS_FAILED; + } + break; + default: + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +pacs_set_supported_contexts(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + int rc; + const struct btp_pacs_set_supported_contexts_cmd *sup_ctxts = cmd; + + struct ble_svc_audio_pacs_set_param src_params = { + .audio_locations = 0, + .supported_contexts = sup_ctxts->source_contexts, + }; + struct ble_svc_audio_pacs_set_param snk_params = { + .audio_locations = 0, + .supported_contexts = sup_ctxts->sink_contexts, + }; + + rc = ble_svc_audio_pacs_set(BLE_AUDIO_CODEC_DIR_SOURCE_BIT, &src_params); + if (rc) { + return BTP_STATUS_FAILED; + } + + rc = ble_svc_audio_pacs_set(BLE_AUDIO_CODEC_DIR_SINK_BIT, &snk_params); + if (rc) { + return BTP_STATUS_FAILED; + } + + return BTP_STATUS_SUCCESS; +} + +static uint8_t +supported_commands(const void *cmd, uint16_t cmd_len, + void *rsp, uint16_t *rsp_len) +{ + struct btp_pacs_read_supported_commands_rp *rp = rsp; + + *rsp_len = tester_supported_commands(BTP_SERVICE_ID_PACS, rp->data); + *rsp_len += sizeof(*rp); + + return BTP_STATUS_SUCCESS; +} + +static const struct btp_handler handlers[] = { + { + .opcode = BTP_PACS_READ_SUPPORTED_COMMANDS, + .expect_len = 0, + .func = supported_commands, + }, + { + .opcode = BTP_PACS_UPDATE_CHARACTERISTIC, + .expect_len = sizeof(struct btp_pacs_update_characteristic_cmd), + .func = pacs_update_characteristic, + }, + { + .opcode = BTP_PACS_SET_AVAILABLE_CONTEXTS, + .expect_len = sizeof(struct btp_pacs_set_available_contexts_cmd), + .func = pacs_set_available_contexts, + }, + { + .opcode = BTP_PACS_SET_SUPPORTED_CONTEXTS, + .expect_len = sizeof(struct btp_pacs_set_supported_contexts_cmd), + .func = pacs_set_supported_contexts, + }, +}; + +uint8_t +tester_init_pacs(void) +{ + int rc; + struct ble_svc_audio_pacs_set_param src_params = { + .audio_locations = MYNEWT_VAL(BLE_SVC_AUDIO_PACS_LC3_SRC_AUDIO_LOCATIONS), + .supported_contexts = BTTESTER_SUPPORTED_CTXTS + }; + struct ble_svc_audio_pacs_set_param snk_params = { + .audio_locations = MYNEWT_VAL(BLE_SVC_AUDIO_PACS_LC3_SRC_AUDIO_LOCATIONS), + .supported_contexts = BTTESTER_SUPPORTED_CTXTS + }; + + rc = ble_svc_audio_pacs_set(BLE_AUDIO_CODEC_DIR_SOURCE_BIT, &src_params); + SYSINIT_PANIC_ASSERT(rc == 0); + + rc = ble_svc_audio_pacs_set(BLE_AUDIO_CODEC_DIR_SINK_BIT, &snk_params); + SYSINIT_PANIC_ASSERT(rc == 0); + + tester_register_command_handlers(BTP_SERVICE_ID_PACS, handlers, + ARRAY_SIZE(handlers)); + + return BTP_STATUS_SUCCESS; +} + +uint8_t +tester_unregister_pacs(void) +{ + return BTP_STATUS_SUCCESS; +} + +#endif /* MYNEWT_VAL(BLE_AUDIO)*/ diff --git a/apps/bttester/src/bttester.c b/apps/bttester/src/bttester.c index 5ddc295482..ad8a827d30 100644 --- a/apps/bttester/src/bttester.c +++ b/apps/bttester/src/bttester.c @@ -33,342 +33,364 @@ #include "console/console.h" #include "bttester_pipe.h" -#include "bttester.h" +#include "btp/btp.h" + +#ifndef min +#define min(a, b) ((a) < (b) ? (a) : (b)) +#endif #define CMD_QUEUED 2 static struct os_eventq avail_queue; static struct os_eventq *cmds_queue; static struct os_event bttester_ev[CMD_QUEUED]; +static struct btp_buf *delayed_cmd; struct btp_buf { - struct os_event *ev; - union { - uint8_t data[BTP_MTU]; - struct btp_hdr hdr; - }; + struct os_event *ev; + union { + uint8_t data[BTP_MTU]; + struct btp_hdr hdr; + }; + uint8_t rsp[BTP_MTU]; }; static struct btp_buf cmd_buf[CMD_QUEUED]; -static void supported_commands(uint8_t *data, uint16_t len) -{ - uint8_t buf[1]; - struct core_read_supported_commands_rp *rp = (void *) buf; +static struct { + const struct btp_handler *handlers; + uint8_t num; +} service_handler[BTP_SERVICE_ID_MAX + 1]; - memset(buf, 0, sizeof(buf)); - tester_set_bit(buf, CORE_READ_SUPPORTED_COMMANDS); - tester_set_bit(buf, CORE_READ_SUPPORTED_SERVICES); - tester_set_bit(buf, CORE_REGISTER_SERVICE); - tester_set_bit(buf, CORE_UNREGISTER_SERVICE); +void +tester_mbuf_reset(struct os_mbuf *buf) +{ + buf->om_data = &buf->om_databuf[buf->om_pkthdr_len]; + buf->om_len = 0; +} + +static void +tester_send_with_index(uint8_t service, uint8_t opcode, uint8_t index, + const uint8_t *data, size_t len); +static void +tester_rsp_with_index(uint8_t service, uint8_t opcode, uint8_t index, + uint8_t status); + +void +tester_register_command_handlers(uint8_t service, + const struct btp_handler *handlers, + size_t num) +{ + assert(service <= BTP_SERVICE_ID_MAX); + assert(service_handler[service].handlers == NULL); - tester_send(BTP_SERVICE_ID_CORE, CORE_READ_SUPPORTED_COMMANDS, - BTP_INDEX_NONE, (uint8_t *) rp, sizeof(buf)); + service_handler[service].handlers = handlers; + service_handler[service].num = num; } -static void supported_services(uint8_t *data, uint16_t len) +const char * +string_from_bytes(const void *buf, size_t len) { - uint8_t buf[1]; - struct core_read_supported_services_rp *rp = (void *) buf; - - memset(buf, 0, sizeof(buf)); - - tester_set_bit(buf, BTP_SERVICE_ID_CORE); - tester_set_bit(buf, BTP_SERVICE_ID_GAP); - tester_set_bit(buf, BTP_SERVICE_ID_GATT); -#if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) - tester_set_bit(buf, BTP_SERVICE_ID_L2CAP); -#endif /* MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) */ -#if MYNEWT_VAL(BLE_MESH) - tester_set_bit(buf, BTP_SERVICE_ID_MESH); -#endif /* MYNEWT_VAL(BLE_MESH) */ - - tester_send(BTP_SERVICE_ID_CORE, CORE_READ_SUPPORTED_SERVICES, - BTP_INDEX_NONE, (uint8_t *) rp, sizeof(buf)); + static const char hex[] = "0123456789abcdef"; + static char hexbufs[4][137]; + static uint8_t curbuf; + const uint8_t *b = buf; + char *str; + int i; + + str = hexbufs[curbuf++]; + curbuf %= ARRAY_SIZE(hexbufs); + + len = min(len, (sizeof(hexbufs[0]) - 1) / 2); + + for (i = 0; i < len; i++) { + str[i * 2] = hex[b[i] >> 4]; + str[i * 2 + 1] = hex[b[i] & 0xf]; + } + + str[i * 2] = '\0'; + + return str; } -static void register_service(uint8_t *data, uint16_t len) +static const struct btp_handler * +find_btp_handler(uint8_t service, uint8_t opcode) { - struct core_register_service_cmd *cmd = (void *) data; - uint8_t status; - - switch (cmd->id) { - case BTP_SERVICE_ID_GAP: - status = tester_init_gap(); - /* Rsp with success status will be handled by bt enable cb */ - if (status == BTP_STATUS_FAILED) { - goto rsp; - } - return; - case BTP_SERVICE_ID_GATT: - status = tester_init_gatt(); - break; -#if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) - case BTP_SERVICE_ID_L2CAP: - status = tester_init_l2cap(); - break; -#endif /* MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) */ -#if MYNEWT_VAL(BLE_MESH) - case BTP_SERVICE_ID_MESH: - status = tester_init_mesh(); - break; -#endif /* MYNEWT_VAL(BLE_MESH) */ - default: - status = BTP_STATUS_FAILED; - break; - } - -rsp: - tester_rsp(BTP_SERVICE_ID_CORE, CORE_REGISTER_SERVICE, BTP_INDEX_NONE, - status); + if ((service > BTP_SERVICE_ID_MAX) || + (service_handler[service].handlers == NULL)) { + return NULL; + } + + for (uint8_t i = 0; i < service_handler[service].num; i++) { + if (service_handler[service].handlers[i].opcode == opcode) { + return &service_handler[service].handlers[i]; + } + } + + return NULL; } -static void unregister_service(uint8_t *data, uint16_t len) +static void +cmd_handler(struct os_event *ev) { - struct core_unregister_service_cmd *cmd = (void *) data; - uint8_t status; - - switch (cmd->id) { - case BTP_SERVICE_ID_GAP: - status = tester_unregister_gap(); - break; - case BTP_SERVICE_ID_GATT: - status = tester_unregister_gatt(); - break; -#if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) - case BTP_SERVICE_ID_L2CAP: - status = tester_unregister_l2cap(); - break; -#endif /* MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) */ -#if MYNEWT_VAL(BLE_MESH) - case BTP_SERVICE_ID_MESH: - status = tester_unregister_mesh(); - break; -#endif /* MYNEWT_VAL(BLE_MESH) */ - default: - status = BTP_STATUS_FAILED; - break; - } - - tester_rsp(BTP_SERVICE_ID_CORE, CORE_UNREGISTER_SERVICE, BTP_INDEX_NONE, - status); + const struct btp_handler *btp; + uint16_t len; + struct btp_buf *cmd; + uint8_t status; + uint16_t rsp_len = 0; + + if (!ev || !ev->ev_arg) { + return; + } + + cmd = ev->ev_arg; + + len = le16toh(cmd->hdr.len); + if (MYNEWT_VAL(BTTESTER_BTP_LOG)) { + console_printf("[DBG] BTP received %d bytes: %s\n", sizeof(cmd->hdr) + len, + string_from_bytes(cmd->data, sizeof(cmd->hdr) + len)); + } + + btp = find_btp_handler(cmd->hdr.service, cmd->hdr.opcode); + if (btp) { + if (btp->index != cmd->hdr.index) { + status = BTP_STATUS_FAILED; + } else if ((btp->expect_len >= 0) && (btp->expect_len != len)) { + status = BTP_STATUS_FAILED; + } else { + status = btp->func(cmd->hdr.data, len, + cmd->rsp, &rsp_len); + } + + assert((rsp_len + sizeof(struct btp_hdr)) <= BTP_MTU); + } else { + status = BTP_STATUS_UNKNOWN_CMD; + } + + /* Allow to delay only 1 command. This is for convenience only + * of using cmd data without need of copying those in async + * functions. Should be not needed eventually. + */ + if (status == BTP_STATUS_DELAY_REPLY) { + assert(delayed_cmd == NULL); + delayed_cmd = cmd; + return; + } + + if ((status == BTP_STATUS_SUCCESS) && rsp_len > 0) { + tester_send_with_index(cmd->hdr.service, cmd->hdr.opcode, + cmd->hdr.index, cmd->rsp, rsp_len); + } else { + tester_rsp_with_index(cmd->hdr.service, cmd->hdr.opcode, + cmd->hdr.index, status); + } + + os_eventq_put(&avail_queue, ev); } -static void handle_core(uint8_t opcode, uint8_t index, uint8_t *data, - uint16_t len) +static uint8_t * +recv_cb(uint8_t *buf, size_t *off) { - if (index != BTP_INDEX_NONE) { - tester_rsp(BTP_SERVICE_ID_CORE, opcode, index, - BTP_STATUS_FAILED); - return; - } - - switch (opcode) { - case CORE_READ_SUPPORTED_COMMANDS: - supported_commands(data, len); - return; - case CORE_READ_SUPPORTED_SERVICES: - supported_services(data, len); - return; - case CORE_REGISTER_SERVICE: - register_service(data, len); - return; - case CORE_UNREGISTER_SERVICE: - unregister_service(data, len); - return; - default: - tester_rsp(BTP_SERVICE_ID_CORE, opcode, BTP_INDEX_NONE, - BTP_STATUS_UNKNOWN_CMD); - return; - } + struct btp_hdr *cmd = (void *) buf; + struct os_event *new_ev; + struct btp_buf *new_buf, *old_buf; + uint16_t len; + + if (*off < sizeof(*cmd)) { + return buf; + } + + len = le16toh(cmd->len); + if (len > BTP_MTU - sizeof(*cmd)) { + *off = 0; + return buf; + } + + if (*off < sizeof(*cmd) + len) { + return buf; + } + + new_ev = os_eventq_get_no_wait(&avail_queue); + if (!new_ev) { + SYS_LOG_ERR("BT tester: RX overflow"); + *off = 0; + return buf; + } + + old_buf = CONTAINER_OF(buf, struct btp_buf, data); + os_eventq_put(cmds_queue, old_buf->ev); + + new_buf = new_ev->ev_arg; + *off = 0; + return new_buf->data; } -static void cmd_handler(struct os_event *ev) +static void +avail_queue_init(void) { - uint16_t len; - struct btp_buf *cmd; - - if (!ev || !ev->ev_arg) { - return; - } - - cmd = ev->ev_arg; - - len = sys_le16_to_cpu(cmd->hdr.len); - if (MYNEWT_VAL(BTTESTER_BTP_LOG)) { - console_printf("[DBG] received %d bytes: %s\n", - sizeof(cmd->hdr) + len, - bt_hex(cmd->data, - sizeof(cmd->hdr) + len)); - } - - /* TODO - * verify if service is registered before calling handler - */ - - switch (cmd->hdr.service) { - case BTP_SERVICE_ID_CORE: - handle_core(cmd->hdr.opcode, cmd->hdr.index, - cmd->hdr.data, len); - break; - case BTP_SERVICE_ID_GAP: - tester_handle_gap(cmd->hdr.opcode, cmd->hdr.index, - cmd->hdr.data, len); - break; - case BTP_SERVICE_ID_GATT: - tester_handle_gatt(cmd->hdr.opcode, cmd->hdr.index, - cmd->hdr.data, len); - break; -#if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) - case BTP_SERVICE_ID_L2CAP: - tester_handle_l2cap(cmd->hdr.opcode, cmd->hdr.index, - cmd->hdr.data, len); - break; -#endif /* MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) */ -#if MYNEWT_VAL(BLE_MESH) - case BTP_SERVICE_ID_MESH: - tester_handle_mesh(cmd->hdr.opcode, cmd->hdr.index, - cmd->hdr.data, len); - break; -#endif /* MYNEWT_VAL(BLE_MESH) */ - default: - tester_rsp(cmd->hdr.service, cmd->hdr.opcode, - cmd->hdr.index, BTP_STATUS_FAILED); - break; - } - - os_eventq_put(&avail_queue, ev); + int i; + + os_eventq_init(&avail_queue); + + for (i = 0; i < CMD_QUEUED; i++) { + cmd_buf[i].ev = &bttester_ev[i]; + bttester_ev[i].ev_cb = cmd_handler; + bttester_ev[i].ev_arg = &cmd_buf[i]; + + os_eventq_put(&avail_queue, &bttester_ev[i]); + } } -static uint8_t *recv_cb(uint8_t *buf, size_t *off) +void +bttester_evq_set(struct os_eventq *evq) { - struct btp_hdr *cmd = (void *) buf; - struct os_event *new_ev; - struct btp_buf *new_buf, *old_buf; - uint16_t len; - - if (*off < sizeof(*cmd)) { - return buf; - } - - len = sys_le16_to_cpu(cmd->len); - if (len > BTP_MTU - sizeof(*cmd)) { - *off = 0; - return buf; - } - - if (*off < sizeof(*cmd) + len) { - return buf; - } - - new_ev = os_eventq_get_no_wait(&avail_queue); - if (!new_ev) { - SYS_LOG_ERR("BT tester: RX overflow"); - *off = 0; - return buf; - } - - old_buf = CONTAINER_OF(buf, struct btp_buf, data); - os_eventq_put(cmds_queue, old_buf->ev); - - new_buf = new_ev->ev_arg; - *off = 0; - return new_buf->data; + cmds_queue = evq; } -static void avail_queue_init(void) +void +tester_init(void) { - int i; + struct os_event *ev; + struct btp_buf *buf; + + avail_queue_init(); + bttester_evq_set(os_eventq_dflt_get()); + + ev = os_eventq_get(&avail_queue); + buf = ev->ev_arg; - os_eventq_init(&avail_queue); + if (bttester_pipe_init()) { + SYS_LOG_ERR("Failed to initialize pipe"); + return; + } - for (i = 0; i < CMD_QUEUED; i++) { - cmd_buf[i].ev = &bttester_ev[i]; - bttester_ev[i].ev_cb = cmd_handler; - bttester_ev[i].ev_arg = &cmd_buf[i]; + bttester_pipe_register(buf->data, BTP_MTU, recv_cb); - os_eventq_put(&avail_queue, &bttester_ev[i]); - } + /* core service is always available */ + tester_init_core(); + + tester_send_with_index(BTP_SERVICE_ID_CORE, BTP_CORE_EV_IUT_READY, + BTP_INDEX_NONE, NULL, 0); } -void bttester_evq_set(struct os_eventq *evq) +static void +tester_send_with_index(uint8_t service, uint8_t opcode, uint8_t index, + const uint8_t *data, size_t len) { - cmds_queue = evq; + struct btp_hdr msg; + + msg.service = service; + msg.opcode = opcode; + msg.index = index; + msg.len = htole16(len); + + bttester_pipe_send((uint8_t *) &msg, sizeof(msg)); + if (data && len) { + bttester_pipe_send(data, len); + } + + if (MYNEWT_VAL(BTTESTER_BTP_LOG)) { + console_printf("[DBG] BTP send %d bytes hdr: %s\n", sizeof(msg), + string_from_bytes((char *)&msg, sizeof(msg))); + if (data && len) { + console_printf("[DBG] BTP send %d bytes data: %s\n", len, + string_from_bytes((char *)data, len)); + } + } } -void tester_init(void) +void +tester_send_buf(uint8_t service, uint8_t opcode, uint8_t index, + struct os_mbuf *data) { - struct os_event *ev; - struct btp_buf *buf; + struct btp_hdr msg; - avail_queue_init(); - bttester_evq_set(os_eventq_dflt_get()); + msg.service = service; + msg.opcode = opcode; + msg.index = index; + msg.len = os_mbuf_len(data); - ev = os_eventq_get(&avail_queue); - buf = ev->ev_arg; + bttester_pipe_send((uint8_t *) &msg, sizeof(msg)); + if (data && msg.len) { + bttester_pipe_send_buf(data); + } +} - if (bttester_pipe_init()) { - SYS_LOG_ERR("Failed to initialize pipe"); - return; - } +static void +tester_rsp_with_index(uint8_t service, uint8_t opcode, uint8_t index, + uint8_t status) +{ + struct btp_status s; - bttester_pipe_register(buf->data, BTP_MTU, recv_cb); + if (status == BTP_STATUS_SUCCESS) { + tester_send_with_index(service, opcode, index, NULL, 0); + return; + } - tester_send(BTP_SERVICE_ID_CORE, CORE_EV_IUT_READY, BTP_INDEX_NONE, - NULL, 0); + s.code = status; + tester_send_with_index(service, BTP_STATUS, index, (uint8_t *) &s, sizeof(s)); } -void tester_send(uint8_t service, uint8_t opcode, uint8_t index, uint8_t *data, - size_t len) +void +tester_event(uint8_t service, uint8_t opcode, const void *data, size_t len) { - struct btp_hdr msg; - - msg.service = service; - msg.opcode = opcode; - msg.index = index; - msg.len = len; - - bttester_pipe_send((uint8_t *)&msg, sizeof(msg)); - if (data && len) { - bttester_pipe_send(data, len); - } - - if (MYNEWT_VAL(BTTESTER_BTP_LOG)) { - console_printf("[DBG] send %d bytes hdr: %s\n", sizeof(msg), - bt_hex((char *) &msg, sizeof(msg))); - if (data && len) { - console_printf("[DBG] send %d bytes data: %s\n", len, - bt_hex((char *) data, len)); - } - } + assert(opcode >= 0x80); + tester_send_with_index(service, opcode, BTP_INDEX, data, len); } -void tester_send_buf(uint8_t service, uint8_t opcode, uint8_t index, - struct os_mbuf *data) +void +tester_rsp_full(uint8_t service, uint8_t opcode, const void *rsp, size_t len) { - struct btp_hdr msg; + struct btp_buf *cmd; + + assert(opcode < 0x80); + assert(delayed_cmd != NULL); - msg.service = service; - msg.opcode = opcode; - msg.index = index; - msg.len = os_mbuf_len(data); + tester_send_with_index(service, opcode, BTP_INDEX, rsp, len); - bttester_pipe_send((uint8_t *)&msg, sizeof(msg)); - if (data && msg.len) { - bttester_pipe_send_buf(data); - } + cmd = delayed_cmd; + delayed_cmd = NULL; + + (void)memset(cmd, 0, sizeof(*cmd)); + + os_eventq_put(&avail_queue, + CONTAINER_OF(cmd, struct btp_buf, data)->ev); } -void tester_rsp(uint8_t service, uint8_t opcode, uint8_t index, uint8_t status) +void +tester_rsp(uint8_t service, uint8_t opcode, uint8_t status) { - struct btp_status s; + struct btp_buf *cmd; + + assert(opcode < 0x80); + assert(delayed_cmd != NULL); + + tester_rsp_with_index(service, opcode, BTP_INDEX, status); + + cmd = delayed_cmd; + delayed_cmd = NULL; + + (void)memset(cmd, 0, sizeof(*cmd)); + os_eventq_put(&avail_queue, + CONTAINER_OF(cmd, struct btp_buf, data)->ev); +} + +uint16_t +tester_supported_commands(uint8_t service, uint8_t *cmds) +{ + uint8_t opcode_max = 0; + + assert(service <= BTP_SERVICE_ID_MAX); + + for (size_t i = 0; i < service_handler[service].num; i++) { + const struct btp_handler *handler = &service_handler[service].handlers[i]; + tester_set_bit(cmds, handler->opcode); - if (status == BTP_STATUS_SUCCESS) { - tester_send(service, opcode, index, NULL, 0); - return; - } + if (handler->opcode > opcode_max) { + opcode_max = handler->opcode; + } + } - s.code = status; - tester_send(service, BTP_STATUS, index, (uint8_t *) &s, sizeof(s)); + return (opcode_max / 8) + 1; } diff --git a/apps/bttester/src/bttester.h b/apps/bttester/src/bttester.h deleted file mode 100644 index 4a8fc47142..0000000000 --- a/apps/bttester/src/bttester.h +++ /dev/null @@ -1,1058 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -/* bttester.h - Bluetooth tester headers */ - -/* - * Copyright (c) 2015-2016 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#ifndef __BTTESTER_H__ -#define __BTTESTER_H__ - -#include "syscfg/syscfg.h" -#include "host/ble_gatt.h" - -#if MYNEWT_VAL(BLE_MESH) -#include "mesh/glue.h" -#else -#include "glue.h" -#endif - -#define BTP_MTU MYNEWT_VAL(BTTESTER_BTP_DATA_SIZE_MAX) -#define BTP_DATA_MAX_SIZE (BTP_MTU - sizeof(struct btp_hdr)) - -#define BTP_INDEX_NONE 0xff - -#define BTP_SERVICE_ID_CORE 0 -#define BTP_SERVICE_ID_GAP 1 -#define BTP_SERVICE_ID_GATT 2 -#define BTP_SERVICE_ID_L2CAP 3 -#define BTP_SERVICE_ID_MESH 4 - -#define BTP_STATUS_SUCCESS 0x00 -#define BTP_STATUS_FAILED 0x01 -#define BTP_STATUS_UNKNOWN_CMD 0x02 -#define BTP_STATUS_NOT_READY 0x03 - -#define SYS_LOG_DBG(fmt, ...) \ - if (MYNEWT_VAL(BTTESTER_DEBUG)) { \ - console_printf("[DBG] %s: " fmt "\n", \ - __func__, ## __VA_ARGS__); \ - } -#define SYS_LOG_INF(fmt, ...) console_printf("[INF] %s: " fmt "\n", \ - __func__, ## __VA_ARGS__); -#define SYS_LOG_ERR(fmt, ...) console_printf("[WRN] %s: " fmt "\n", \ - __func__, ## __VA_ARGS__); - -#define SYS_LOG_LEVEL SYS_LOG_LEVEL_DEBUG -#define SYS_LOG_DOMAIN "bttester" - -#define sys_cpu_to_le32 htole32 -#define sys_le32_to_cpu le32toh -#define sys_cpu_to_le16 htole16 - -struct btp_hdr { - uint8_t service; - uint8_t opcode; - uint8_t index; - uint16_t len; - uint8_t data[0]; -} __packed; - -#define BTP_STATUS 0x00 -struct btp_status { - uint8_t code; -} __packed; - -/* Core Service */ -#define CORE_READ_SUPPORTED_COMMANDS 0x01 -struct core_read_supported_commands_rp { - uint8_t data[0]; -} __packed; - -#define CORE_READ_SUPPORTED_SERVICES 0x02 -struct core_read_supported_services_rp { - uint8_t data[0]; -} __packed; - -#define CORE_REGISTER_SERVICE 0x03 -struct core_register_service_cmd { - uint8_t id; -} __packed; - -#define CORE_UNREGISTER_SERVICE 0x04 -struct core_unregister_service_cmd { - uint8_t id; -} __packed; - -/* events */ -#define CORE_EV_IUT_READY 0x80 - -/* GAP Service */ -/* commands */ -#define GAP_READ_SUPPORTED_COMMANDS 0x01 -struct gap_read_supported_commands_rp { - uint8_t data[0]; -} __packed; - -#define GAP_READ_CONTROLLER_INDEX_LIST 0x02 -struct gap_read_controller_index_list_rp { - uint8_t num; - uint8_t index[0]; -} __packed; - -#define GAP_SETTINGS_POWERED 0 -#define GAP_SETTINGS_CONNECTABLE 1 -#define GAP_SETTINGS_FAST_CONNECTABLE 2 -#define GAP_SETTINGS_DISCOVERABLE 3 -#define GAP_SETTINGS_BONDABLE 4 -#define GAP_SETTINGS_LINK_SEC_3 5 -#define GAP_SETTINGS_SSP 6 -#define GAP_SETTINGS_BREDR 7 -#define GAP_SETTINGS_HS 8 -#define GAP_SETTINGS_LE 9 -#define GAP_SETTINGS_ADVERTISING 10 -#define GAP_SETTINGS_SC 11 -#define GAP_SETTINGS_DEBUG_KEYS 12 -#define GAP_SETTINGS_PRIVACY 13 -#define GAP_SETTINGS_CONTROLLER_CONFIG 14 -#define GAP_SETTINGS_STATIC_ADDRESS 15 - -#define GAP_READ_CONTROLLER_INFO 0x03 -struct gap_read_controller_info_rp { - uint8_t address[6]; - uint32_t supported_settings; - uint32_t current_settings; - uint8_t cod[3]; - uint8_t name[249]; - uint8_t short_name[11]; -} __packed; - -#define GAP_RESET 0x04 -struct gap_reset_rp { - uint32_t current_settings; -} __packed; - -#define GAP_SET_POWERED 0x05 -struct gap_set_powered_cmd { - uint8_t powered; -} __packed; -struct gap_set_powered_rp { - uint32_t current_settings; -} __packed; - -#define GAP_SET_CONNECTABLE 0x06 -struct gap_set_connectable_cmd { - uint8_t connectable; -} __packed; -struct gap_set_connectable_rp { - uint32_t current_settings; -} __packed; - -#define GAP_SET_FAST_CONNECTABLE 0x07 -struct gap_set_fast_connectable_cmd { - uint8_t fast_connectable; -} __packed; -struct gap_set_fast_connectable_rp { - uint32_t current_settings; -} __packed; - -#define GAP_NON_DISCOVERABLE 0x00 -#define GAP_GENERAL_DISCOVERABLE 0x01 -#define GAP_LIMITED_DISCOVERABLE 0x02 - -#define GAP_SET_DISCOVERABLE 0x08 -struct gap_set_discoverable_cmd { - uint8_t discoverable; -} __packed; -struct gap_set_discoverable_rp { - uint32_t current_settings; -} __packed; - -#define GAP_SET_BONDABLE 0x09 -struct gap_set_bondable_cmd { - uint8_t bondable; -} __packed; -struct gap_set_bondable_rp { - uint32_t current_settings; -} __packed; - -#define GAP_START_ADVERTISING 0x0a -struct gap_start_advertising_cmd { - uint8_t adv_data_len; - uint8_t scan_rsp_len; - uint8_t adv_data[0]; - uint8_t scan_rsp[0]; -} __packed; -struct gap_start_advertising_rp { - uint32_t current_settings; -} __packed; - -#define GAP_STOP_ADVERTISING 0x0b -struct gap_stop_advertising_rp { - uint32_t current_settings; -} __packed; - -#define GAP_DISCOVERY_FLAG_LE 0x01 -#define GAP_DISCOVERY_FLAG_BREDR 0x02 -#define GAP_DISCOVERY_FLAG_LIMITED 0x04 -#define GAP_DISCOVERY_FLAG_LE_ACTIVE_SCAN 0x08 -#define GAP_DISCOVERY_FLAG_LE_OBSERVE 0x10 - -#define GAP_START_DISCOVERY 0x0c -struct gap_start_discovery_cmd { - uint8_t flags; -} __packed; - -#define GAP_STOP_DISCOVERY 0x0d - -#define GAP_CONNECT 0x0e -struct gap_connect_cmd { - uint8_t address_type; - uint8_t address[6]; -} __packed; - -#define GAP_DISCONNECT 0x0f -struct gap_disconnect_cmd { - uint8_t address_type; - uint8_t address[6]; -} __packed; - -#define GAP_IO_CAP_DISPLAY_ONLY 0 -#define GAP_IO_CAP_DISPLAY_YESNO 1 -#define GAP_IO_CAP_KEYBOARD_ONLY 2 -#define GAP_IO_CAP_NO_INPUT_OUTPUT 3 -#define GAP_IO_CAP_KEYBOARD_DISPLAY 4 - -#define GAP_SET_IO_CAP 0x10 -struct gap_set_io_cap_cmd { - uint8_t io_cap; -} __packed; - -#define GAP_PAIR 0x11 -struct gap_pair_cmd { - uint8_t address_type; - uint8_t address[6]; -} __packed; - -#define GAP_UNPAIR 0x12 -struct gap_unpair_cmd { - uint8_t address_type; - uint8_t address[6]; -} __packed; - -#define GAP_PASSKEY_ENTRY 0x13 -struct gap_passkey_entry_cmd { - uint8_t address_type; - uint8_t address[6]; - uint32_t passkey; -} __packed; - -#define GAP_PASSKEY_CONFIRM 0x14 -struct gap_passkey_confirm_cmd { - uint8_t address_type; - uint8_t address[6]; - uint8_t match; -} __packed; - -#define GAP_START_DIRECT_ADV 0x15 -struct gap_start_direct_adv_cmd { - uint8_t address_type; - uint8_t address[6]; - uint8_t high_duty; -} __packed; - -#define GAP_CONN_PARAM_UPDATE 0x16 -struct gap_conn_param_update_cmd { - uint8_t address_type; - uint8_t address[6]; - uint16_t conn_itvl_min; - uint16_t conn_itvl_max; - uint16_t conn_latency; - uint16_t supervision_timeout; -} __packed; - -#define GAP_PAIRING_CONSENT_RSP 0x17 -struct gap_pairing_consent_rsp_cmd { - uint8_t address_type; - uint8_t address[6]; - uint8_t consent; -} __packed; - -#define GAP_OOB_LEGACY_SET_DATA 0x18 -struct gap_oob_legacy_set_data_cmd { - uint8_t oob_data[16]; -} __packed; - -#define GAP_OOB_SC_GET_LOCAL_DATA 0x19 -struct gap_oob_sc_get_local_data_rp { - uint8_t r[16]; - uint8_t c[16]; -} __packed; - -#define GAP_OOB_SC_SET_REMOTE_DATA 0x1a -struct gap_oob_sc_set_remote_data_cmd { - uint8_t r[16]; - uint8_t c[16]; -} __packed; - -#define GAP_SET_MITM 0x1b -struct gap_set_mitm_cmd { - uint8_t mitm; -} __packed; - -/* events */ -#define GAP_EV_NEW_SETTINGS 0x80 -struct gap_new_settings_ev { - uint32_t current_settings; -} __packed; - -#define GAP_DEVICE_FOUND_FLAG_RSSI 0x01 -#define GAP_DEVICE_FOUND_FLAG_AD 0x02 -#define GAP_DEVICE_FOUND_FLAG_SD 0x04 - -#define GAP_EV_DEVICE_FOUND 0x81 -struct gap_device_found_ev { - uint8_t address_type; - uint8_t address[6]; - int8_t rssi; - uint8_t flags; - uint16_t eir_data_len; - uint8_t eir_data[0]; -} __packed; - -#define GAP_EV_DEVICE_CONNECTED 0x82 -struct gap_device_connected_ev { - uint8_t address_type; - uint8_t address[6]; - uint16_t conn_itvl; - uint16_t conn_latency; - uint16_t supervision_timeout; -} __packed; - -#define GAP_EV_DEVICE_DISCONNECTED 0x83 -struct gap_device_disconnected_ev { - uint8_t address_type; - uint8_t address[6]; -} __packed; - -#define GAP_EV_PASSKEY_DISPLAY 0x84 -struct gap_passkey_display_ev { - uint8_t address_type; - uint8_t address[6]; - uint32_t passkey; -} __packed; - -#define GAP_EV_PASSKEY_ENTRY_REQ 0x85 -struct gap_passkey_entry_req_ev { - uint8_t address_type; - uint8_t address[6]; -} __packed; - -#define GAP_EV_PASSKEY_CONFIRM_REQ 0x86 -struct gap_passkey_confirm_req_ev { - uint8_t address_type; - uint8_t address[6]; - uint32_t passkey; -} __packed; - -#define GAP_EV_IDENTITY_RESOLVED 0x87 -struct gap_identity_resolved_ev { - uint8_t address_type; - uint8_t address[6]; - uint8_t identity_address_type; - uint8_t identity_address[6]; -} __packed; - -#define GAP_EV_CONN_PARAM_UPDATE 0x88 -struct gap_conn_param_update_ev { - uint8_t address_type; - uint8_t address[6]; - uint16_t conn_itvl; - uint16_t conn_latency; - uint16_t supervision_timeout; -} __packed; - -#define GAP_EV_SEC_LEVEL_CHANGED 0x89 -struct gap_sec_level_changed_ev { - uint8_t address_type; - uint8_t address[6]; - uint8_t level; -} __packed; - -#define GAP_EV_PAIRING_CONSENT_REQ 0x8a -struct gap_pairing_consent_req_ev { - uint8_t address_type; - uint8_t address[6]; -} __packed; - -/* GATT Service */ -/* commands */ -#define GATT_READ_SUPPORTED_COMMANDS 0x01 -struct gatt_read_supported_commands_rp { - uint8_t data[0]; -} __packed; - -#define GATT_SERVICE_PRIMARY 0x00 -#define GATT_SERVICE_SECONDARY 0x01 - -#define GATT_ADD_SERVICE 0x02 -struct gatt_add_service_cmd { - uint8_t type; - uint8_t uuid_length; - uint8_t uuid[0]; -} __packed; -struct gatt_add_service_rp { - uint16_t svc_id; -} __packed; - -#define GATT_ADD_CHARACTERISTIC 0x03 -struct gatt_add_characteristic_cmd { - uint16_t svc_id; - uint8_t properties; - uint8_t permissions; - uint8_t uuid_length; - uint8_t uuid[0]; -} __packed; -struct gatt_add_characteristic_rp { - uint16_t char_id; -} __packed; - -#define GATT_ADD_DESCRIPTOR 0x04 -struct gatt_add_descriptor_cmd { - uint16_t char_id; - uint8_t permissions; - uint8_t uuid_length; - uint8_t uuid[0]; -} __packed; -struct gatt_add_descriptor_rp { - uint16_t desc_id; -} __packed; - -#define GATT_ADD_INCLUDED_SERVICE 0x05 -struct gatt_add_included_service_cmd { - uint16_t svc_id; -} __packed; -struct gatt_add_included_service_rp { - uint16_t included_service_id; -} __packed; - -#define GATT_SET_VALUE 0x06 - struct gatt_set_value_cmd { - uint16_t attr_id; - uint16_t len; - uint8_t value[0]; -} __packed; - -#define GATT_START_SERVER 0x07 -struct gatt_start_server_rp { - uint16_t db_attr_off; - uint8_t db_attr_cnt; -} __packed; - -#define GATT_SET_ENC_KEY_SIZE 0x09 -struct gatt_set_enc_key_size_cmd { - uint16_t attr_id; - uint8_t key_size; -} __packed; - -/* Gatt Client */ -struct gatt_service { - uint16_t start_handle; - uint16_t end_handle; - uint8_t uuid_length; - uint8_t uuid[0]; -} __packed; - -struct gatt_included { - uint16_t included_handle; - struct gatt_service service; -} __packed; - -struct gatt_characteristic { - uint16_t characteristic_handle; - uint16_t value_handle; - uint8_t properties; - uint8_t uuid_length; - uint8_t uuid[0]; -} __packed; - -struct gatt_descriptor { - uint16_t descriptor_handle; - uint8_t uuid_length; - uint8_t uuid[0]; -} __packed; - -#define GATT_EXCHANGE_MTU 0x0a - -#define GATT_DISC_ALL_PRIM_SVCS 0x0b -struct gatt_disc_all_prim_svcs_cmd { - uint8_t address_type; - uint8_t address[6]; -} __packed; -struct gatt_disc_all_prim_svcs_rp { - uint8_t services_count; - struct gatt_service services[0]; -} __packed; - -#define GATT_DISC_PRIM_UUID 0x0c -struct gatt_disc_prim_uuid_cmd { - uint8_t address_type; - uint8_t address[6]; - uint8_t uuid_length; - uint8_t uuid[0]; -} __packed; -struct gatt_disc_prim_uuid_rp { - uint8_t services_count; - struct gatt_service services[0]; -} __packed; - -#define GATT_FIND_INCLUDED 0x0d -struct gatt_find_included_cmd { - uint8_t address_type; - uint8_t address[6]; - uint16_t start_handle; - uint16_t end_handle; -} __packed; -struct gatt_find_included_rp { - uint8_t services_count; - struct gatt_included included[0]; -} __packed; - -#define GATT_DISC_ALL_CHRC 0x0e -struct gatt_disc_all_chrc_cmd { - uint8_t address_type; - uint8_t address[6]; - uint16_t start_handle; - uint16_t end_handle; -} __packed; -struct gatt_disc_chrc_rp { - uint8_t characteristics_count; - struct gatt_characteristic characteristics[0]; -} __packed; - -#define GATT_DISC_CHRC_UUID 0x0f -struct gatt_disc_chrc_uuid_cmd { - uint8_t address_type; - uint8_t address[6]; - uint16_t start_handle; - uint16_t end_handle; - uint8_t uuid_length; - uint8_t uuid[0]; -} __packed; - -#define GATT_DISC_ALL_DESC 0x10 -struct gatt_disc_all_desc_cmd { - uint8_t address_type; - uint8_t address[6]; - uint16_t start_handle; - uint16_t end_handle; -} __packed; -struct gatt_disc_all_desc_rp { - uint8_t descriptors_count; - struct gatt_descriptor descriptors[0]; -} __packed; - -#define GATT_READ 0x11 -struct gatt_read_cmd { - uint8_t address_type; - uint8_t address[6]; - uint16_t handle; -} __packed; -struct gatt_read_rp { - uint8_t att_response; - uint16_t data_length; - uint8_t data[0]; -} __packed; - -#define GATT_READ_UUID 0x12 -struct gatt_read_uuid_cmd { - uint8_t address_type; - uint8_t address[6]; - uint16_t start_handle; - uint16_t end_handle; - uint8_t uuid_length; - uint8_t uuid[0]; -} __packed; - -#define GATT_READ_LONG 0x13 -struct gatt_read_long_cmd { - uint8_t address_type; - uint8_t address[6]; - uint16_t handle; - uint16_t offset; -} __packed; - -#define GATT_READ_MULTIPLE 0x14 -struct gatt_read_multiple_cmd { - uint8_t address_type; - uint8_t address[6]; - uint8_t handles_count; - uint16_t handles[0]; -} __packed; - -#define GATT_WRITE_WITHOUT_RSP 0x15 -struct gatt_write_without_rsp_cmd { - uint8_t address_type; - uint8_t address[6]; - uint16_t handle; - uint16_t data_length; - uint8_t data[0]; -} __packed; - -#define GATT_SIGNED_WRITE_WITHOUT_RSP 0x16 -struct gatt_signed_write_without_rsp_cmd { - uint8_t address_type; - uint8_t address[6]; - uint16_t handle; - uint16_t data_length; - uint8_t data[0]; -} __packed; - -#define GATT_WRITE 0x17 -struct gatt_write_cmd { - uint8_t address_type; - uint8_t address[6]; - uint16_t handle; - uint16_t data_length; - uint8_t data[0]; -} __packed; - -#define GATT_WRITE_LONG 0x18 -struct gatt_write_long_cmd { - uint8_t address_type; - uint8_t address[6]; - uint16_t handle; - uint16_t offset; - uint16_t data_length; - uint8_t data[0]; -} __packed; - -#define GATT_RELIABLE_WRITE 0x19 -struct gatt_reliable_write_cmd { - uint8_t address_type; - uint8_t address[6]; - uint16_t handle; - uint16_t offset; - uint16_t data_length; - uint8_t data[0]; -} __packed; - -#define GATT_CFG_NOTIFY 0x1a -#define GATT_CFG_INDICATE 0x1b -struct gatt_cfg_notify_cmd { - uint8_t address_type; - uint8_t address[6]; - uint8_t enable; - uint16_t ccc_handle; -} __packed; - -#define GATT_GET_ATTRIBUTES 0x1c -struct gatt_get_attributes_cmd { - uint16_t start_handle; - uint16_t end_handle; - uint8_t type_length; - uint8_t type[0]; -} __packed; -struct gatt_get_attributes_rp { - uint8_t attrs_count; - uint8_t attrs[0]; -} __packed; -struct gatt_attr { - uint16_t handle; - uint8_t permission; - uint8_t type_length; - uint8_t type[0]; -} __packed; - -#define GATT_GET_ATTRIBUTE_VALUE 0x1d -struct gatt_get_attribute_value_cmd { - uint8_t address_type; - uint8_t address[6]; - uint16_t handle; -} __packed; -struct gatt_get_attribute_value_rp { - uint8_t att_response; - uint16_t value_length; - uint8_t value[0]; -} __packed; - -#define GATT_CHANGE_DATABASE 0x1e -struct gatt_change_database { - uint16_t start_handle; - uint16_t end_handle; - uint8_t visibility; -} __packed; - -/* GATT events */ -#define GATT_EV_NOTIFICATION 0x80 -struct gatt_notification_ev { - uint8_t address_type; - uint8_t address[6]; - uint8_t type; - uint16_t handle; - uint16_t data_length; - uint8_t data[0]; -} __packed; - -#define GATT_EV_ATTR_VALUE_CHANGED 0x81 -struct gatt_attr_value_changed_ev { - uint16_t handle; - uint16_t data_length; - uint8_t data[0]; -} __packed; - -static inline void tester_set_bit(uint8_t *addr, unsigned int bit) -{ - uint8_t *p = addr + (bit / 8); - - *p |= BIT(bit % 8); -} - -static inline uint8_t tester_test_bit(const uint8_t *addr, unsigned int bit) -{ - const uint8_t *p = addr + (bit / 8); - - return *p & BIT(bit % 8); -} - -/* L2CAP Service */ -/* commands */ -#define L2CAP_READ_SUPPORTED_COMMANDS 0x01 -struct l2cap_read_supported_commands_rp { - uint8_t data[0]; -} __packed; - -#define L2CAP_CONNECT 0x02 -struct l2cap_connect_cmd { - uint8_t address_type; - uint8_t address[6]; - uint16_t psm; - uint16_t mtu; - uint8_t num; -} __packed; - -struct l2cap_connect_rp { - uint8_t num; - uint8_t chan_ids[0]; -} __packed; - -#define L2CAP_DISCONNECT 0x03 -struct l2cap_disconnect_cmd { - uint8_t chan_id; -} __packed; - -#define L2CAP_SEND_DATA 0x04 -struct l2cap_send_data_cmd { - uint8_t chan_id; - uint16_t data_len; - uint8_t data[]; -} __packed; - -#define L2CAP_TRANSPORT_BREDR 0x00 -#define L2CAP_TRANSPORT_LE 0x01 - -#define L2CAP_LISTEN 0x05 -struct l2cap_listen_cmd { - uint16_t psm; - uint8_t transport; - uint16_t mtu; - uint16_t response; -} __packed; - -#define L2CAP_ACCEPT_CONNECTION 0x06 -struct l2cap_accept_connection_cmd { - uint8_t chan_id; - uint16_t result; -} __packed; - -#define L2CAP_RECONFIGURE 0x07 -struct l2cap_reconfigure_cmd { - uint8_t address_type; - uint8_t address[6]; - uint16_t mtu; - uint8_t num; - uint8_t idxs[]; -} __packed; - -/* events */ -#define L2CAP_EV_CONNECTION_REQ 0x80 -struct l2cap_connection_req_ev { - uint8_t chan_id; - uint16_t psm; - uint8_t address_type; - uint8_t address[6]; -} __packed; - -#define L2CAP_EV_CONNECTED 0x81 -struct l2cap_connected_ev { - uint8_t chan_id; - uint16_t psm; - uint16_t peer_mtu; - uint16_t peer_mps; - uint16_t our_mtu; - uint16_t our_mps; - uint8_t address_type; - uint8_t address[6]; -} __packed; - -#define L2CAP_EV_DISCONNECTED 0x82 -struct l2cap_disconnected_ev { - uint16_t result; - uint8_t chan_id; - uint16_t psm; - uint8_t address_type; - uint8_t address[6]; -} __packed; - -#define L2CAP_EV_DATA_RECEIVED 0x83 -struct l2cap_data_received_ev { - uint8_t chan_id; - uint16_t data_length; - uint8_t data[0]; -} __packed; - -#define L2CAP_EV_RECONFIGURED 0x84 -struct l2cap_reconfigured_ev { - uint8_t chan_id; - uint16_t peer_mtu; - uint16_t peer_mps; - uint16_t our_mtu; - uint16_t our_mps; -} __packed; - -/* MESH Service */ -/* commands */ -#define MESH_READ_SUPPORTED_COMMANDS 0x01 -struct mesh_read_supported_commands_rp { - uint8_t data[0]; -} __packed; - -#define MESH_OUT_BLINK BIT(0) -#define MESH_OUT_BEEP BIT(1) -#define MESH_OUT_VIBRATE BIT(2) -#define MESH_OUT_DISPLAY_NUMBER BIT(3) -#define MESH_OUT_DISPLAY_STRING BIT(4) - -#define MESH_IN_PUSH BIT(0) -#define MESH_IN_TWIST BIT(1) -#define MESH_IN_ENTER_NUMBER BIT(2) -#define MESH_IN_ENTER_STRING BIT(3) - -#define MESH_CONFIG_PROVISIONING 0x02 -struct mesh_config_provisioning_cmd { - uint8_t uuid[16]; - uint8_t static_auth[16]; - uint8_t out_size; - uint16_t out_actions; - uint8_t in_size; - uint16_t in_actions; -} __packed; - -#define MESH_PROVISION_NODE 0x03 -struct mesh_provision_node_cmd { - uint8_t net_key[16]; - uint16_t net_key_idx; - uint8_t flags; - uint32_t iv_index; - uint32_t seq_num; - uint16_t addr; - uint8_t dev_key[16]; -} __packed; - -#define MESH_INIT 0x04 -#define MESH_RESET 0x05 -#define MESH_INPUT_NUMBER 0x06 -struct mesh_input_number_cmd { - uint32_t number; -} __packed; - -#define MESH_INPUT_STRING 0x07 -struct mesh_input_string_cmd { - uint8_t string_len; - uint8_t string[0]; -} __packed; - -#define MESH_IVU_TEST_MODE 0x08 -struct mesh_ivu_test_mode_cmd { - uint8_t enable; -} __packed; - -#define MESH_IVU_TOGGLE_STATE 0x09 - -#define MESH_NET_SEND 0x0a -struct mesh_net_send_cmd { - uint8_t ttl; - uint16_t src; - uint16_t dst; - uint8_t payload_len; - uint8_t payload[0]; -} __packed; - -#define MESH_HEALTH_GENERATE_FAULTS 0x0b -struct mesh_health_generate_faults_rp { - uint8_t test_id; - uint8_t cur_faults_count; - uint8_t reg_faults_count; - uint8_t current_faults[0]; - uint8_t registered_faults[0]; -} __packed; - -#define MESH_HEALTH_CLEAR_FAULTS 0x0c - -#define MESH_LPN 0x0d -struct mesh_lpn_set_cmd { - uint8_t enable; -} __packed; - -#define MESH_LPN_POLL 0x0e - -#define MESH_MODEL_SEND 0x0f -struct mesh_model_send_cmd { - uint16_t src; - uint16_t dst; - uint8_t payload_len; - uint8_t payload[0]; -} __packed; - -#define MESH_LPN_SUBSCRIBE 0x10 -struct mesh_lpn_subscribe_cmd { - uint16_t address; -} __packed; - -#define MESH_LPN_UNSUBSCRIBE 0x11 -struct mesh_lpn_unsubscribe_cmd { - uint16_t address; -} __packed; - -#define MESH_RPL_CLEAR 0x12 -#define MESH_PROXY_IDENTITY 0x13 - -/* events */ -#define MESH_EV_OUT_NUMBER_ACTION 0x80 -struct mesh_out_number_action_ev { - uint16_t action; - uint32_t number; -} __packed; - -#define MESH_EV_OUT_STRING_ACTION 0x81 -struct mesh_out_string_action_ev { - uint8_t string_len; - uint8_t string[0]; -} __packed; - -#define MESH_EV_IN_ACTION 0x82 -struct mesh_in_action_ev { - uint16_t action; - uint8_t size; -} __packed; - -#define MESH_EV_PROVISIONED 0x83 - -#define MESH_PROV_BEARER_PB_ADV 0x00 -#define MESH_PROV_BEARER_PB_GATT 0x01 -#define MESH_EV_PROV_LINK_OPEN 0x84 -struct mesh_prov_link_open_ev { - uint8_t bearer; -} __packed; - -#define MESH_EV_PROV_LINK_CLOSED 0x85 -struct mesh_prov_link_closed_ev { - uint8_t bearer; -} __packed; - -#define MESH_EV_NET_RECV 0x86 -struct mesh_net_recv_ev { - uint8_t ttl; - uint8_t ctl; - uint16_t src; - uint16_t dst; - uint8_t payload_len; - uint8_t payload[0]; -} __packed; - -#define MESH_EV_INVALID_BEARER 0x87 -struct mesh_invalid_bearer_ev { - uint8_t opcode; -} __packed; - -#define MESH_EV_INCOMP_TIMER_EXP 0x88 - -#define MESH_EV_LPN_ESTABLISHED 0x8b -struct mesh_lpn_established_ev { - uint16_t net_idx; - uint16_t friend_addr; - uint8_t queue_size; - uint8_t recv_win; -} __packed; - -#define MESH_EV_LPN_TERMINATED 0x8c -struct mesh_lpn_terminated_ev { - uint16_t net_idx; - uint16_t friend_addr; -} __packed; - -#define MESH_EV_LPN_POLLED 0x8d -struct mesh_lpn_polled_ev { - uint16_t net_idx; - uint16_t friend_addr; - uint8_t retry; -} __packed; - -void tester_init(void); -void tester_rsp(uint8_t service, uint8_t opcode, uint8_t index, uint8_t status); -void tester_send(uint8_t service, uint8_t opcode, uint8_t index, uint8_t *data, - size_t len); -void tester_send_buf(uint8_t service, uint8_t opcode, uint8_t index, - struct os_mbuf *buf); - -uint8_t tester_init_gap(void); -uint8_t tester_unregister_gap(void); -void tester_handle_gap(uint8_t opcode, uint8_t index, uint8_t *data, - uint16_t len); -uint8_t tester_init_gatt(void); -uint8_t tester_unregister_gatt(void); -void tester_handle_gatt(uint8_t opcode, uint8_t index, uint8_t *data, - uint16_t len); -int tester_gatt_notify_rx_ev(uint16_t conn_handle, uint16_t attr_handle, - uint8_t indication, struct os_mbuf *om); -int tester_gatt_subscribe_ev(uint16_t conn_handle, uint16_t attr_handle, uint8_t reason, - uint8_t prev_notify, uint8_t cur_notify, - uint8_t prev_indicate, uint8_t cur_indicate); - -#if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) -uint8_t tester_init_l2cap(void); -uint8_t tester_unregister_l2cap(void); -void tester_handle_l2cap(uint8_t opcode, uint8_t index, uint8_t *data, - uint16_t len); -#endif - -#if MYNEWT_VAL(BLE_MESH) -uint8_t tester_init_mesh(void); -uint8_t tester_unregister_mesh(void); -void tester_handle_mesh(uint8_t opcode, uint8_t index, uint8_t *data, uint16_t len); -#endif /* MYNEWT_VAL(BLE_MESH) */ - -void gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg); -int gatt_svr_init(void); - -#endif /* __BTTESTER_H__ */ diff --git a/apps/bttester/src/bttester_pipe.h b/apps/bttester/src/bttester_pipe.h index 64b63cd6a1..ac56c575ac 100644 --- a/apps/bttester/src/bttester_pipe.h +++ b/apps/bttester/src/bttester_pipe.h @@ -21,17 +21,21 @@ #define __BTTESTER_PIPE_H__ #include -#include "bttester.h" +#include "btp/bttester.h" #ifdef __cplusplus extern "C" { #endif typedef uint8_t *(*bttester_pipe_recv_cb)(uint8_t *buf, size_t *off); -void bttester_pipe_register(uint8_t *buf, size_t len, bttester_pipe_recv_cb cb); -int bttester_pipe_send(const uint8_t *data, int len); -int bttester_pipe_send_buf(struct os_mbuf *buf); -int bttester_pipe_init(void); +void +bttester_pipe_register(uint8_t *buf, size_t len, bttester_pipe_recv_cb cb); +int +bttester_pipe_send(const uint8_t *data, int len); +int +bttester_pipe_send_buf(struct os_mbuf *buf); +int +bttester_pipe_init(void); #ifdef __cplusplus } diff --git a/apps/bttester/src/gap.c b/apps/bttester/src/gap.c deleted file mode 100644 index acac9989f0..0000000000 --- a/apps/bttester/src/gap.c +++ /dev/null @@ -1,1688 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -/* gap.c - Bluetooth GAP Tester */ - -/* - * Copyright (c) 2015-2016 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "host/ble_gap.h" -#include "host/util/util.h" -#include "console/console.h" - -#include "../../../nimble/host/src/ble_hs_pvcy_priv.h" -#include "../../../nimble/host/src/ble_hs_hci_priv.h" -#include "../../../nimble/host/src/ble_sm_priv.h" - -#include "bttester.h" - -#define CONTROLLER_INDEX 0 -#define CONTROLLER_NAME "btp_tester" - -#define BLE_AD_DISCOV_MASK (BLE_HS_ADV_F_DISC_LTD | BLE_HS_ADV_F_DISC_GEN) -#define ADV_BUF_LEN (sizeof(struct gap_device_found_ev) + 2 * 31) - -const uint8_t irk[16] = { - 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, -}; - -static uint8_t oob[16]; -static struct ble_sm_sc_oob_data oob_data_local; -static struct ble_sm_sc_oob_data oob_data_remote; - -static uint16_t current_settings; -uint8_t own_addr_type; -static ble_addr_t peer_id_addr; -static ble_addr_t peer_ota_addr; -static bool encrypted = false; - -static struct os_callout update_params_co; -static struct gap_conn_param_update_cmd update_params; - -static struct os_callout connected_ev_co; -static struct gap_device_connected_ev connected_ev; -#define CONNECTED_EV_DELAY_MS(itvl) 8 * BLE_HCI_CONN_ITVL * itvl / 1000 -static int connection_attempts; - -static const struct ble_gap_conn_params dflt_conn_params = { - .scan_itvl = 0x0010, - .scan_window = 0x0010, - .itvl_min = BLE_GAP_INITIAL_CONN_ITVL_MIN, - .itvl_max = BLE_GAP_INITIAL_CONN_ITVL_MAX, - .latency = 0, - .supervision_timeout = 0x0100, - .min_ce_len = 0x0010, - .max_ce_len = 0x0300, -}; - -static void conn_param_update(struct os_event *ev); - - -static int gap_conn_find_by_addr(const ble_addr_t *dev_addr, - struct ble_gap_conn_desc *out_desc) -{ - ble_addr_t addr = *dev_addr; - - if (memcmp(BLE_ADDR_ANY, &peer_id_addr, 6) == 0) { - return ble_gap_conn_find_by_addr(&addr, out_desc); - } - - if (BLE_ADDR_IS_RPA(&addr)) { - if(ble_addr_cmp(&peer_ota_addr, &addr) != 0) { - return -1; - } - - return ble_gap_conn_find_by_addr(&addr, out_desc); - } else { - if(ble_addr_cmp(&peer_id_addr, &addr) != 0) { - return -1; - } - - if (BLE_ADDR_IS_RPA(&peer_ota_addr)) { - /* Change addr type to ID addr */ - addr.type |= 2; - } - - return ble_gap_conn_find_by_addr(&addr, out_desc); - } -} - -static int gap_event_cb(struct ble_gap_event *event, void *arg); - -static void supported_commands(uint8_t *data, uint16_t len) -{ - uint8_t cmds[3]; - struct gap_read_supported_commands_rp *rp = (void *) &cmds; - - SYS_LOG_DBG(""); - - memset(cmds, 0, sizeof(cmds)); - - tester_set_bit(cmds, GAP_READ_SUPPORTED_COMMANDS); - tester_set_bit(cmds, GAP_READ_CONTROLLER_INDEX_LIST); - tester_set_bit(cmds, GAP_READ_CONTROLLER_INFO); - tester_set_bit(cmds, GAP_SET_CONNECTABLE); - tester_set_bit(cmds, GAP_SET_DISCOVERABLE); - tester_set_bit(cmds, GAP_SET_BONDABLE); - tester_set_bit(cmds, GAP_START_ADVERTISING); - tester_set_bit(cmds, GAP_STOP_ADVERTISING); - tester_set_bit(cmds, GAP_START_DISCOVERY); - tester_set_bit(cmds, GAP_STOP_DISCOVERY); - tester_set_bit(cmds, GAP_CONNECT); - tester_set_bit(cmds, GAP_DISCONNECT); - tester_set_bit(cmds, GAP_SET_IO_CAP); - tester_set_bit(cmds, GAP_PAIR); - tester_set_bit(cmds, GAP_UNPAIR); - tester_set_bit(cmds, GAP_PASSKEY_ENTRY); - tester_set_bit(cmds, GAP_PASSKEY_CONFIRM); - tester_set_bit(cmds, GAP_START_DIRECT_ADV); - tester_set_bit(cmds, GAP_CONN_PARAM_UPDATE); - tester_set_bit(cmds, GAP_OOB_LEGACY_SET_DATA); - tester_set_bit(cmds, GAP_OOB_SC_GET_LOCAL_DATA); - tester_set_bit(cmds, GAP_OOB_SC_SET_REMOTE_DATA); - tester_set_bit(cmds, GAP_SET_MITM); - - tester_send(BTP_SERVICE_ID_GAP, GAP_READ_SUPPORTED_COMMANDS, - CONTROLLER_INDEX, (uint8_t *) rp, sizeof(cmds)); -} - -static void controller_index_list(uint8_t *data, uint16_t len) -{ - struct gap_read_controller_index_list_rp *rp; - uint8_t buf[sizeof(*rp) + 1]; - - SYS_LOG_DBG(""); - - rp = (void *) buf; - - rp->num = 1; - rp->index[0] = CONTROLLER_INDEX; - - tester_send(BTP_SERVICE_ID_GAP, GAP_READ_CONTROLLER_INDEX_LIST, - BTP_INDEX_NONE, (uint8_t *) rp, sizeof(buf)); -} - -static int check_pub_addr_unassigned(void) -{ -#ifdef ARCH_sim - return 0; -#else - uint8_t zero_addr[BLE_DEV_ADDR_LEN] = { 0 }; - - return memcmp(MYNEWT_VAL(BLE_PUBLIC_DEV_ADDR), - zero_addr, BLE_DEV_ADDR_LEN) == 0; -#endif -} - -static void controller_info(uint8_t *data, uint16_t len) -{ - struct gap_read_controller_info_rp rp; - uint32_t supported_settings = 0; - ble_addr_t addr; - int rc; - - SYS_LOG_DBG(""); - - rc = ble_hs_pvcy_set_our_irk(irk); - assert(rc == 0); - - memset(&rp, 0, sizeof(rp)); - - /* Make sure we have proper identity address set (public preferred) */ - rc = ble_hs_util_ensure_addr(1); - assert(rc == 0); - rc = ble_hs_id_copy_addr(BLE_ADDR_RANDOM, addr.val, NULL); - assert(rc == 0); - - if (MYNEWT_VAL(BTTESTER_PRIVACY_MODE)) { - if (MYNEWT_VAL(BTTESTER_USE_NRPA)) { - own_addr_type = BLE_OWN_ADDR_RANDOM; - rc = ble_hs_id_gen_rnd(1, &addr); - assert(rc == 0); - rc = ble_hs_id_set_rnd(addr.val); - assert(rc == 0); - } else { - own_addr_type = BLE_OWN_ADDR_RPA_RANDOM_DEFAULT; - } - current_settings |= BIT(GAP_SETTINGS_PRIVACY); - supported_settings |= BIT(GAP_SETTINGS_PRIVACY); - memcpy(rp.address, addr.val, sizeof(rp.address)); - } else { - if (check_pub_addr_unassigned()) { - own_addr_type = BLE_OWN_ADDR_RANDOM; - memcpy(rp.address, addr.val, sizeof(rp.address)); - supported_settings |= BIT(GAP_SETTINGS_STATIC_ADDRESS); - current_settings |= BIT(GAP_SETTINGS_STATIC_ADDRESS); - } else { - own_addr_type = BLE_OWN_ADDR_PUBLIC; - memcpy(rp.address, MYNEWT_VAL(BLE_PUBLIC_DEV_ADDR), - sizeof(rp.address)); - } - } - - supported_settings |= BIT(GAP_SETTINGS_POWERED); - supported_settings |= BIT(GAP_SETTINGS_CONNECTABLE); - supported_settings |= BIT(GAP_SETTINGS_BONDABLE); - supported_settings |= BIT(GAP_SETTINGS_LE); - supported_settings |= BIT(GAP_SETTINGS_ADVERTISING); - supported_settings |= BIT(GAP_SETTINGS_SC); - - if (ble_hs_cfg.sm_bonding) { - current_settings |= BIT(GAP_SETTINGS_BONDABLE); - } - if (ble_hs_cfg.sm_sc) { - current_settings |= BIT(GAP_SETTINGS_SC); - } - - rp.supported_settings = sys_cpu_to_le32(supported_settings); - rp.current_settings = sys_cpu_to_le32(current_settings); - - memcpy(rp.name, CONTROLLER_NAME, sizeof(CONTROLLER_NAME)); - - tester_send(BTP_SERVICE_ID_GAP, GAP_READ_CONTROLLER_INFO, - CONTROLLER_INDEX, (uint8_t *) &rp, sizeof(rp)); -} - -static struct ble_gap_adv_params adv_params = { - .conn_mode = BLE_GAP_CONN_MODE_NON, - .disc_mode = BLE_GAP_DISC_MODE_NON, -}; - -static void set_connectable(uint8_t *data, uint16_t len) -{ - const struct gap_set_connectable_cmd *cmd = (void *) data; - struct gap_set_connectable_rp rp; - - SYS_LOG_DBG(""); - - if (cmd->connectable) { - current_settings |= BIT(GAP_SETTINGS_CONNECTABLE); - adv_params.conn_mode = BLE_GAP_CONN_MODE_UND; - } else { - current_settings &= ~BIT(GAP_SETTINGS_CONNECTABLE); - adv_params.conn_mode = BLE_GAP_CONN_MODE_NON; - } - - rp.current_settings = sys_cpu_to_le32(current_settings); - - tester_send(BTP_SERVICE_ID_GAP, GAP_SET_CONNECTABLE, CONTROLLER_INDEX, - (uint8_t *) &rp, sizeof(rp)); -} - -static uint8_t ad_flags = BLE_HS_ADV_F_BREDR_UNSUP; - -static void set_discoverable(uint8_t *data, uint16_t len) -{ - const struct gap_set_discoverable_cmd *cmd = (void *) data; - struct gap_set_discoverable_rp rp; - - SYS_LOG_DBG(""); - - switch (cmd->discoverable) { - case GAP_NON_DISCOVERABLE: - ad_flags &= ~(BLE_HS_ADV_F_DISC_GEN | BLE_HS_ADV_F_DISC_LTD); - adv_params.disc_mode = BLE_GAP_DISC_MODE_NON; - current_settings &= ~BIT(GAP_SETTINGS_DISCOVERABLE); - break; - case GAP_GENERAL_DISCOVERABLE: - ad_flags &= ~BLE_HS_ADV_F_DISC_LTD; - ad_flags |= BLE_HS_ADV_F_DISC_GEN; - adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN; - current_settings |= BIT(GAP_SETTINGS_DISCOVERABLE); - break; - case GAP_LIMITED_DISCOVERABLE: - ad_flags &= ~BLE_HS_ADV_F_DISC_GEN; - ad_flags |= BLE_HS_ADV_F_DISC_LTD; - adv_params.disc_mode = BLE_GAP_DISC_MODE_LTD; - current_settings |= BIT(GAP_SETTINGS_DISCOVERABLE); - break; - default: - tester_rsp(BTP_SERVICE_ID_GAP, GAP_SET_DISCOVERABLE, - CONTROLLER_INDEX, BTP_STATUS_FAILED); - return; - } - - rp.current_settings = sys_cpu_to_le32(current_settings); - - tester_send(BTP_SERVICE_ID_GAP, GAP_SET_DISCOVERABLE, CONTROLLER_INDEX, - (uint8_t *) &rp, sizeof(rp)); -} - -static void set_bondable(const uint8_t *data, uint16_t len) -{ - const struct gap_set_bondable_cmd *cmd = (void *) data; - struct gap_set_bondable_rp rp; - - SYS_LOG_DBG(""); - - ble_hs_cfg.sm_bonding = cmd->bondable; - if (ble_hs_cfg.sm_bonding) { - current_settings |= BIT(GAP_SETTINGS_BONDABLE); - } else { - current_settings &= ~BIT(GAP_SETTINGS_BONDABLE); - } - - rp.current_settings = sys_cpu_to_le32(current_settings); - - tester_send(BTP_SERVICE_ID_GAP, GAP_SET_BONDABLE, CONTROLLER_INDEX, - (uint8_t *) &rp, sizeof(rp)); -} - -static struct bt_data ad[10] = { - BT_DATA(BLE_HS_ADV_TYPE_FLAGS, &ad_flags, sizeof(ad_flags)), -}; -static struct bt_data sd[10]; - -static int set_ad(const struct bt_data *ad, size_t ad_len, - uint8_t *buf, uint8_t *buf_len) -{ - int i; - - for (i = 0; i < ad_len; i++) { - buf[(*buf_len)++] = ad[i].data_len + 1; - buf[(*buf_len)++] = ad[i].type; - - memcpy(&buf[*buf_len], ad[i].data, - ad[i].data_len); - *buf_len += ad[i].data_len; - } - - return 0; -} - -static void start_advertising(const uint8_t *data, uint16_t len) -{ - const struct gap_start_advertising_cmd *cmd = (void *) data; - struct gap_start_advertising_rp rp; - int32_t duration_ms = BLE_HS_FOREVER; - uint8_t buf[BLE_HS_ADV_MAX_SZ]; - uint8_t buf_len = 0; - uint8_t adv_len, sd_len; - int err; - - int i; - - SYS_LOG_DBG(""); - - for (i = 0, adv_len = 1; i < cmd->adv_data_len; adv_len++) { - if (adv_len >= ARRAY_SIZE(ad)) { - SYS_LOG_ERR("ad[] Out of memory"); - goto fail; - } - - ad[adv_len].type = cmd->adv_data[i++]; - ad[adv_len].data_len = cmd->adv_data[i++]; - ad[adv_len].data = &cmd->adv_data[i]; - i += ad[adv_len].data_len; - } - - for (i = 0, sd_len = 0; i < cmd->scan_rsp_len; sd_len++) { - if (sd_len >= ARRAY_SIZE(sd)) { - SYS_LOG_ERR("sd[] Out of memory"); - goto fail; - } - - sd[sd_len].type = cmd->scan_rsp[i++]; - sd[sd_len].data_len = cmd->scan_rsp[i++]; - sd[sd_len].data = &cmd->scan_rsp[i]; - i += sd[sd_len].data_len; - } - - err = set_ad(ad, adv_len, buf, &buf_len); - if (err) { - goto fail; - } - - err = ble_gap_adv_set_data(buf, buf_len); - if (err != 0) { - goto fail; - } - - if (sd_len) { - buf_len = 0; - - err = set_ad(sd, sd_len, buf, &buf_len); - if (err) { - SYS_LOG_ERR("Advertising failed: err %d", err); - goto fail; - } - - err = ble_gap_adv_rsp_set_data(buf, buf_len); - if (err != 0) { - SYS_LOG_ERR("Advertising failed: err %d", err); - goto fail; - } - } - - if (adv_params.disc_mode == BLE_GAP_DISC_MODE_LTD) { - duration_ms = MYNEWT_VAL(BTTESTER_LTD_ADV_TIMEOUT); - } - - err = ble_gap_adv_start(own_addr_type, NULL, duration_ms, - &adv_params, gap_event_cb, NULL); - if (err) { - SYS_LOG_ERR("Advertising failed: err %d", err); - goto fail; - } - - current_settings |= BIT(GAP_SETTINGS_ADVERTISING); - rp.current_settings = sys_cpu_to_le32(current_settings); - - tester_send(BTP_SERVICE_ID_GAP, GAP_START_ADVERTISING, CONTROLLER_INDEX, - (uint8_t *) &rp, sizeof(rp)); - return; -fail: - tester_rsp(BTP_SERVICE_ID_GAP, GAP_START_ADVERTISING, CONTROLLER_INDEX, - BTP_STATUS_FAILED); -} - -static void stop_advertising(const uint8_t *data, uint16_t len) -{ - struct gap_stop_advertising_rp rp; - - SYS_LOG_DBG(""); - - if (ble_gap_adv_stop() != 0) { - tester_rsp(BTP_SERVICE_ID_GAP, GAP_STOP_ADVERTISING, - CONTROLLER_INDEX, BTP_STATUS_FAILED); - return; - } - - current_settings &= ~BIT(GAP_SETTINGS_ADVERTISING); - rp.current_settings = sys_cpu_to_le32(current_settings); - - tester_send(BTP_SERVICE_ID_GAP, GAP_STOP_ADVERTISING, CONTROLLER_INDEX, - (uint8_t *) &rp, sizeof(rp)); -} - -static uint8_t get_ad_flags(const uint8_t *data, uint8_t data_len) -{ - uint8_t len, i; - - /* Parse advertisement to get flags */ - for (i = 0; i < data_len; i += len - 1) { - len = data[i++]; - if (!len) { - break; - } - - /* Check if field length is correct */ - if (len > (data_len - i) || (data_len - i) < 1) { - break; - } - - switch (data[i++]) { - case BLE_HS_ADV_TYPE_FLAGS: - return data[i]; - default: - break; - } - } - - return 0; -} - -static uint8_t discovery_flags; -static struct os_mbuf *adv_buf; - -static void store_adv(const ble_addr_t *addr, int8_t rssi, - const uint8_t *data, uint8_t len) -{ - struct gap_device_found_ev *ev; - - /* cleanup */ - net_buf_simple_init(adv_buf, 0); - - ev = net_buf_simple_add(adv_buf, sizeof(*ev)); - - memcpy(ev->address, addr->val, sizeof(ev->address)); - ev->address_type = addr->type; - ev->rssi = rssi; - ev->flags = GAP_DEVICE_FOUND_FLAG_AD | GAP_DEVICE_FOUND_FLAG_RSSI; - ev->eir_data_len = len; - memcpy(net_buf_simple_add(adv_buf, len), data, len); -} - -static void device_found(ble_addr_t *addr, int8_t rssi, uint8_t evtype, - const uint8_t *data, uint8_t len) -{ - struct gap_device_found_ev *ev; - ble_addr_t a; - - /* if General/Limited Discovery - parse Advertising data to get flags */ - if (!(discovery_flags & GAP_DISCOVERY_FLAG_LE_OBSERVE) && - (evtype != BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP)) { - uint8_t flags = get_ad_flags(data, len); - - /* ignore non-discoverable devices */ - if (!(flags & BLE_AD_DISCOV_MASK)) { - SYS_LOG_DBG("Non discoverable, skipping"); - return; - } - - /* if Limited Discovery - ignore general discoverable devices */ - if ((discovery_flags & GAP_DISCOVERY_FLAG_LIMITED) && - !(flags & BLE_HS_ADV_F_DISC_LTD)) { - SYS_LOG_DBG("General discoverable, skipping"); - return; - } - } - - /* attach Scan Response data */ - if (evtype == BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP) { - /* skip if there is no pending advertisement */ - if (!adv_buf->om_len) { - SYS_LOG_INF("No pending advertisement, skipping"); - return; - } - - ev = (void *) adv_buf->om_data; - a.type = ev->address_type; - memcpy(a.val, ev->address, sizeof(a.val)); - - /* - * in general, the Scan Response comes right after the - * Advertisement, but if not if send stored event and ignore - * this one - */ - if (ble_addr_cmp(addr, &a)) { - SYS_LOG_INF("Address does not match, skipping"); - goto done; - } - - ev->eir_data_len += len; - ev->flags |= GAP_DEVICE_FOUND_FLAG_SD; - - memcpy(net_buf_simple_add(adv_buf, len), data, len); - - goto done; - } - - /* - * if there is another pending advertisement, send it and store the - * current one - */ - if (adv_buf->om_len) { - tester_send(BTP_SERVICE_ID_GAP, GAP_EV_DEVICE_FOUND, - CONTROLLER_INDEX, adv_buf->om_data, - adv_buf->om_len); - } - - store_adv(addr, rssi, data, len); - - /* if Active Scan and scannable event - wait for Scan Response */ - if ((discovery_flags & GAP_DISCOVERY_FLAG_LE_ACTIVE_SCAN) && - (evtype == BLE_HCI_ADV_RPT_EVTYPE_ADV_IND || - evtype == BLE_HCI_ADV_RPT_EVTYPE_SCAN_IND)) { - SYS_LOG_DBG("Waiting for scan response"); - return; - } -done: - tester_send(BTP_SERVICE_ID_GAP, GAP_EV_DEVICE_FOUND, - CONTROLLER_INDEX, adv_buf->om_data, adv_buf->om_len); -} - -static int discovery_cb(struct ble_gap_event *event, void *arg) -{ - if (event->type == BLE_GAP_EVENT_DISC) { - device_found(&event->disc.addr, event->disc.rssi, - event->disc.event_type, event->disc.data, - event->disc.length_data); - } - - return 0; -} - -static void start_discovery(const uint8_t *data, uint16_t len) -{ - const struct gap_start_discovery_cmd *cmd = (void *) data; - struct ble_gap_disc_params params = {0}; - uint8_t status; - - SYS_LOG_DBG(""); - - /* only LE scan is supported */ - if (cmd->flags & GAP_DISCOVERY_FLAG_BREDR) { - status = BTP_STATUS_FAILED; - goto reply; - } - - params.passive = (cmd->flags & GAP_DISCOVERY_FLAG_LE_ACTIVE_SCAN) == 0; - params.limited = (cmd->flags & GAP_DISCOVERY_FLAG_LIMITED) > 0; - params.filter_duplicates = 1; - - if (ble_gap_disc(own_addr_type, BLE_HS_FOREVER, - ¶ms, discovery_cb, NULL) != 0) { - status = BTP_STATUS_FAILED; - goto reply; - } - - net_buf_simple_init(adv_buf, 0); - discovery_flags = cmd->flags; - - status = BTP_STATUS_SUCCESS; -reply: - tester_rsp(BTP_SERVICE_ID_GAP, GAP_START_DISCOVERY, CONTROLLER_INDEX, - status); -} - -static void stop_discovery(const uint8_t *data, uint16_t len) -{ - uint8_t status = BTP_STATUS_SUCCESS; - - SYS_LOG_DBG(""); - - if (ble_gap_disc_cancel() != 0) { - status = BTP_STATUS_FAILED; - } - - tester_rsp(BTP_SERVICE_ID_GAP, GAP_STOP_DISCOVERY, CONTROLLER_INDEX, - status); -} - - -/* Bluetooth Core Spec v5.1 | Section 10.7.1 - * If a privacy-enabled Peripheral, that has a stored bond, - * receives a resolvable private address, the Host may resolve - * the resolvable private address [...] - * If the resolution is successful, the Host may accept the connection. - * If the resolution procedure fails, then the Host shall disconnect - * with the error code "Authentication failure" [...] - */ -static void periph_privacy(struct ble_gap_conn_desc desc) -{ -#if !MYNEWT_VAL(BTTESTER_PRIVACY_MODE) - return; -#endif - int count; - - SYS_LOG_DBG(""); - - ble_store_util_count(BLE_STORE_OBJ_TYPE_PEER_SEC, &count); - if (count > 0 && BLE_ADDR_IS_RPA(&desc.peer_id_addr)) { - SYS_LOG_DBG("Authentication failure, disconnecting"); - ble_gap_terminate(desc.conn_handle, BLE_ERR_AUTH_FAIL); - } -} - -static void device_connected_ev_send(struct os_event *ev) -{ - struct ble_gap_conn_desc desc; - int rc; - - SYS_LOG_DBG(""); - - rc = gap_conn_find_by_addr((ble_addr_t *)&connected_ev, &desc); - if (rc) { - tester_rsp(BTP_SERVICE_ID_GAP, GAP_EV_DEVICE_CONNECTED, - CONTROLLER_INDEX, BTP_STATUS_FAILED); - return; - } - - tester_send(BTP_SERVICE_ID_GAP, GAP_EV_DEVICE_CONNECTED, - CONTROLLER_INDEX, (uint8_t *) &connected_ev, - sizeof(connected_ev)); - - periph_privacy(desc); -} - -static void le_connected(uint16_t conn_handle, int status) -{ - struct ble_gap_conn_desc desc; - ble_addr_t *addr; - int rc; - - SYS_LOG_DBG(""); - - if (status != 0) { - return; - } - - rc = ble_gap_conn_find(conn_handle, &desc); - if (rc) { - return; - } - - peer_id_addr = desc.peer_id_addr; - peer_ota_addr = desc.peer_ota_addr; - - addr = &desc.peer_id_addr; - - memcpy(connected_ev.address, addr->val, sizeof(connected_ev.address)); - connected_ev.address_type = addr->type; - connected_ev.conn_itvl = desc.conn_itvl; - connected_ev.conn_latency = desc.conn_latency; - connected_ev.supervision_timeout = desc.supervision_timeout; - -#if MYNEWT_VAL(BTTESTER_CONN_RETRY) - os_callout_reset(&connected_ev_co, - os_time_ms_to_ticks32( - CONNECTED_EV_DELAY_MS(desc.conn_itvl))); -#else - tester_send(BTP_SERVICE_ID_GAP, GAP_EV_DEVICE_CONNECTED, - CONTROLLER_INDEX, (uint8_t *) &connected_ev, - sizeof(connected_ev)); -#endif -} - -static void le_disconnected(struct ble_gap_conn_desc *conn, int reason) -{ - struct gap_device_disconnected_ev ev; - ble_addr_t *addr = &conn->peer_ota_addr; - - SYS_LOG_DBG(""); - -#if MYNEWT_VAL(BTTESTER_CONN_RETRY) - int rc; - - if ((reason == BLE_HS_HCI_ERR(BLE_ERR_CONN_ESTABLISHMENT)) && - os_callout_queued(&connected_ev_co)) { - if (connection_attempts < MYNEWT_VAL(BTTESTER_CONN_RETRY)) { - os_callout_stop(&connected_ev_co); - - /* try connecting again */ - rc = ble_gap_connect(own_addr_type, addr, 0, - &dflt_conn_params, gap_event_cb, - NULL); - - if (rc == 0) { - connection_attempts++; - return; - } - } - } else if (os_callout_queued(&connected_ev_co)) { - os_callout_stop(&connected_ev_co); - return; - } -#endif - - connection_attempts = 0; - memset(&connected_ev, 0, sizeof(connected_ev)); - - memcpy(ev.address, addr->val, sizeof(ev.address)); - ev.address_type = addr->type; - - tester_send(BTP_SERVICE_ID_GAP, GAP_EV_DEVICE_DISCONNECTED, - CONTROLLER_INDEX, (uint8_t *) &ev, sizeof(ev)); -} - -static void auth_passkey_oob(uint16_t conn_handle) -{ - struct ble_gap_conn_desc desc; - struct ble_sm_io pk; - int rc; - - SYS_LOG_DBG(""); - - rc = ble_gap_conn_find(conn_handle, &desc); - if (rc) { - return; - } - - memcpy(pk.oob, oob, sizeof(oob)); - pk.action = BLE_SM_IOACT_OOB; - - rc = ble_sm_inject_io(conn_handle, &pk); - assert(rc == 0); -} - -static void auth_passkey_display(uint16_t conn_handle, unsigned int passkey) -{ - struct ble_gap_conn_desc desc; - struct gap_passkey_display_ev ev; - ble_addr_t *addr; - struct ble_sm_io pk; - int rc; - - SYS_LOG_DBG(""); - - rc = ble_gap_conn_find(conn_handle, &desc); - if (rc) { - return; - } - - rc = ble_hs_hci_util_rand(&pk.passkey, sizeof(pk.passkey)); - assert(rc == 0); - /* Max value is 999999 */ - pk.passkey %= 1000000; - pk.action = BLE_SM_IOACT_DISP; - - rc = ble_sm_inject_io(conn_handle, &pk); - assert(rc == 0); - - addr = &desc.peer_ota_addr; - - memcpy(ev.address, addr->val, sizeof(ev.address)); - ev.address_type = addr->type; - ev.passkey = sys_cpu_to_le32(pk.passkey); - - tester_send(BTP_SERVICE_ID_GAP, GAP_EV_PASSKEY_DISPLAY, - CONTROLLER_INDEX, (uint8_t *) &ev, sizeof(ev)); -} - -static void auth_passkey_entry(uint16_t conn_handle) -{ - struct ble_gap_conn_desc desc; - struct gap_passkey_entry_req_ev ev; - ble_addr_t *addr; - int rc; - - SYS_LOG_DBG(""); - - rc = ble_gap_conn_find(conn_handle, &desc); - if (rc) { - return; - } - - addr = &desc.peer_ota_addr; - - memcpy(ev.address, addr->val, sizeof(ev.address)); - ev.address_type = addr->type; - - tester_send(BTP_SERVICE_ID_GAP, GAP_EV_PASSKEY_ENTRY_REQ, - CONTROLLER_INDEX, (uint8_t *) &ev, sizeof(ev)); -} - -static void auth_passkey_numcmp(uint16_t conn_handle, unsigned int passkey) -{ - struct ble_gap_conn_desc desc; - struct gap_passkey_confirm_req_ev ev; - ble_addr_t *addr; - int rc; - - SYS_LOG_DBG(""); - - rc = ble_gap_conn_find(conn_handle, &desc); - if (rc) { - return; - } - - addr = &desc.peer_ota_addr; - - memcpy(ev.address, addr->val, sizeof(ev.address)); - ev.address_type = addr->type; - ev.passkey = sys_cpu_to_le32(passkey); - - tester_send(BTP_SERVICE_ID_GAP, GAP_EV_PASSKEY_CONFIRM_REQ, - CONTROLLER_INDEX, (uint8_t *) &ev, sizeof(ev)); -} - -static void auth_passkey_oob_sc(uint16_t conn_handle) -{ - int rc; - struct ble_sm_io pk; - - SYS_LOG_DBG(""); - - memset(&pk, 0, sizeof(pk)); - - pk.oob_sc_data.local = &oob_data_local; - - if (ble_hs_cfg.sm_oob_data_flag) { - pk.oob_sc_data.remote = &oob_data_remote; - } - - pk.action = BLE_SM_IOACT_OOB_SC; - rc = ble_sm_inject_io(conn_handle, &pk); - if (rc != 0) { - console_printf("error providing oob; rc=%d\n", rc); - } -} - -static void le_passkey_action(uint16_t conn_handle, - struct ble_gap_passkey_params *params) -{ - SYS_LOG_DBG(""); - - switch (params->action) { - case BLE_SM_IOACT_NONE: - break; - case BLE_SM_IOACT_OOB: - auth_passkey_oob(conn_handle); - break; - case BLE_SM_IOACT_INPUT: - auth_passkey_entry(conn_handle); - break; - case BLE_SM_IOACT_DISP: - auth_passkey_display(conn_handle, params->numcmp); - break; - case BLE_SM_IOACT_NUMCMP: - auth_passkey_numcmp(conn_handle, params->numcmp); - break; - case BLE_SM_IOACT_OOB_SC: - auth_passkey_oob_sc(conn_handle); - break; - default: - assert(0); - } -} - -static void le_identity_resolved(uint16_t conn_handle) -{ - struct ble_gap_conn_desc desc; - struct gap_identity_resolved_ev ev; - int rc; - - SYS_LOG_DBG(""); - - rc = ble_gap_conn_find(conn_handle, &desc); - if (rc) { - return; - } - - peer_id_addr = desc.peer_id_addr; - peer_ota_addr = desc.peer_ota_addr; - - ev.address_type = desc.peer_ota_addr.type; - memcpy(ev.address, desc.peer_ota_addr.val, sizeof(ev.address)); - - ev.identity_address_type = desc.peer_id_addr.type; - memcpy(ev.identity_address, desc.peer_id_addr.val, - sizeof(ev.identity_address)); - - tester_send(BTP_SERVICE_ID_GAP, GAP_EV_IDENTITY_RESOLVED, - CONTROLLER_INDEX, (uint8_t *) &ev, sizeof(ev)); -} - -static void le_conn_param_update(struct ble_gap_conn_desc *desc) -{ - struct gap_conn_param_update_ev ev; - - SYS_LOG_DBG(""); - - ev.address_type = desc->peer_ota_addr.type; - memcpy(ev.address, desc->peer_ota_addr.val, sizeof(ev.address)); - - ev.conn_itvl = desc->conn_itvl; - ev.conn_latency = desc->conn_latency; - ev.supervision_timeout = desc->supervision_timeout; - - tester_send(BTP_SERVICE_ID_GAP, GAP_EV_CONN_PARAM_UPDATE, - CONTROLLER_INDEX, (uint8_t *) &ev, sizeof(ev)); -} - -static void le_encryption_changed(struct ble_gap_conn_desc *desc) -{ - struct gap_sec_level_changed_ev ev; - - SYS_LOG_DBG(""); - - encrypted = (bool) desc->sec_state.encrypted; - - ev.address_type = desc->peer_ota_addr.type; - memcpy(ev.address, desc->peer_ota_addr.val, sizeof(ev.address)); - ev.level = 0; - - if (desc->sec_state.encrypted) { - if (desc->sec_state.authenticated) { - if (desc->sec_state.key_size == 16) { - ev.level = 3; - } else { - ev.level = 2; - } - } else { - ev.level = 1; - } - } - - tester_send(BTP_SERVICE_ID_GAP, GAP_EV_SEC_LEVEL_CHANGED, - CONTROLLER_INDEX, (uint8_t *) &ev, sizeof(ev)); -} - -static void print_bytes(const uint8_t *bytes, int len) -{ - int i; - - for (i = 0; i < len; i++) { - console_printf("%s0x%02x", i != 0 ? ":" : "", bytes[i]); - } -} - -static void print_mbuf(const struct os_mbuf *om) -{ - int colon; - - colon = 0; - while (om != NULL) { - if (colon) { - console_printf(":"); - } else { - colon = 1; - } - print_bytes(om->om_data, om->om_len); - om = SLIST_NEXT(om, om_next); - } -} - -static void print_addr(const void *addr) -{ - const uint8_t *u8p; - - u8p = addr; - console_printf("%02x:%02x:%02x:%02x:%02x:%02x", - u8p[5], u8p[4], u8p[3], u8p[2], u8p[1], u8p[0]); -} - -static void print_conn_desc(const struct ble_gap_conn_desc *desc) -{ - console_printf("handle=%d our_ota_addr_type=%d our_ota_addr=", - desc->conn_handle, desc->our_ota_addr.type); - print_addr(desc->our_ota_addr.val); - console_printf(" our_id_addr_type=%d our_id_addr=", - desc->our_id_addr.type); - print_addr(desc->our_id_addr.val); - console_printf(" peer_ota_addr_type=%d peer_ota_addr=", - desc->peer_ota_addr.type); - print_addr(desc->peer_ota_addr.val); - console_printf(" peer_id_addr_type=%d peer_id_addr=", - desc->peer_id_addr.type); - print_addr(desc->peer_id_addr.val); - console_printf(" conn_itvl=%d conn_latency=%d supervision_timeout=%d " - "key_sz=%d encrypted=%d authenticated=%d bonded=%d\n", - desc->conn_itvl, desc->conn_latency, - desc->supervision_timeout, - desc->sec_state.key_size, - desc->sec_state.encrypted, - desc->sec_state.authenticated, - desc->sec_state.bonded); -} - -static void adv_complete(void) -{ - struct gap_new_settings_ev ev; - - current_settings &= ~BIT(GAP_SETTINGS_ADVERTISING); - ev.current_settings = sys_cpu_to_le32(current_settings); - - tester_send(BTP_SERVICE_ID_GAP, GAP_EV_NEW_SETTINGS, CONTROLLER_INDEX, - (uint8_t *) &ev, sizeof(ev)); -} - -static int gap_event_cb(struct ble_gap_event *event, void *arg) -{ - struct ble_gap_conn_desc desc; - int rc; - - switch (event->type) { - case BLE_GAP_EVENT_ADV_COMPLETE: - console_printf("advertising complete; reason=%d\n", - event->adv_complete.reason); - break; - case BLE_GAP_EVENT_CONNECT: - console_printf("connection %s; status=%d ", - event->connect.status == 0 ? "established" : "failed", - event->connect.status); - if (event->connect.status == 0) { - rc = ble_gap_conn_find(event->connect.conn_handle, &desc); - assert(rc == 0); - print_conn_desc(&desc); - } - - if (desc.role == BLE_GAP_ROLE_SLAVE) { - adv_complete(); - } - - le_connected(event->connect.conn_handle, - event->connect.status); - break; - case BLE_GAP_EVENT_DISCONNECT: - console_printf("disconnect; reason=%d ", event->disconnect.reason); - print_conn_desc(&event->disconnect.conn); - le_disconnected(&event->disconnect.conn, - event->disconnect.reason); - break; - case BLE_GAP_EVENT_ENC_CHANGE: - console_printf("encryption change event; status=%d ", event->enc_change.status); - rc = ble_gap_conn_find(event->enc_change.conn_handle, &desc); - assert(rc == 0); - print_conn_desc(&desc); - le_encryption_changed(&desc); - break; - case BLE_GAP_EVENT_PASSKEY_ACTION: - console_printf("passkey action event; action=%d", - event->passkey.params.action); - if (event->passkey.params.action == BLE_SM_IOACT_NUMCMP) { - console_printf(" numcmp=%lu", - (unsigned long)event->passkey.params.numcmp); - } - console_printf("\n"); - le_passkey_action(event->passkey.conn_handle, - &event->passkey.params); - break; - case BLE_GAP_EVENT_IDENTITY_RESOLVED: - console_printf("identity resolved "); - rc = ble_gap_conn_find(event->identity_resolved.conn_handle, &desc); - assert(rc == 0); - print_conn_desc(&desc); - le_identity_resolved(event->identity_resolved.conn_handle); - break; - case BLE_GAP_EVENT_NOTIFY_RX: - console_printf("notification rx event; attr_handle=%d indication=%d " - "len=%d data=", - event->notify_rx.attr_handle, - event->notify_rx.indication, - OS_MBUF_PKTLEN(event->notify_rx.om)); - - print_mbuf(event->notify_rx.om); - console_printf("\n"); - tester_gatt_notify_rx_ev(event->notify_rx.conn_handle, - event->notify_rx.attr_handle, - event->notify_rx.indication, - event->notify_rx.om); - break; - case BLE_GAP_EVENT_SUBSCRIBE: - console_printf("subscribe event; conn_handle=%d attr_handle=%d " - "reason=%d prevn=%d curn=%d previ=%d curi=%d\n", - event->subscribe.conn_handle, - event->subscribe.attr_handle, - event->subscribe.reason, - event->subscribe.prev_notify, - event->subscribe.cur_notify, - event->subscribe.prev_indicate, - event->subscribe.cur_indicate); - tester_gatt_subscribe_ev(event->subscribe.conn_handle, - event->subscribe.attr_handle, - event->subscribe.reason, - event->subscribe.prev_notify, - event->subscribe.cur_notify, - event->subscribe.prev_indicate, - event->subscribe.cur_indicate); - break; - case BLE_GAP_EVENT_REPEAT_PAIRING: - console_printf("repeat pairing event; conn_handle=%d " - "cur_key_sz=%d cur_auth=%d cur_sc=%d " - "new_key_sz=%d new_auth=%d new_sc=%d " - "new_bonding=%d\n", - event->repeat_pairing.conn_handle, - event->repeat_pairing.cur_key_size, - event->repeat_pairing.cur_authenticated, - event->repeat_pairing.cur_sc, - event->repeat_pairing.new_key_size, - event->repeat_pairing.new_authenticated, - event->repeat_pairing.new_sc, - event->repeat_pairing.new_bonding); - rc = ble_gap_conn_find(event->repeat_pairing.conn_handle, &desc); - assert(rc == 0); - rc = ble_store_util_delete_peer(&desc.peer_id_addr); - assert(rc == 0); - return BLE_GAP_REPEAT_PAIRING_RETRY; - case BLE_GAP_EVENT_CONN_UPDATE: - console_printf("connection update event; status=%d ", - event->conn_update.status); - rc = ble_gap_conn_find(event->conn_update.conn_handle, &desc); - assert(rc == 0); - print_conn_desc(&desc); - le_conn_param_update(&desc); - break; - case BLE_GAP_EVENT_CONN_UPDATE_REQ: - console_printf("connection update request event; " - "conn_handle=%d itvl_min=%d itvl_max=%d " - "latency=%d supervision_timoeut=%d " - "min_ce_len=%d max_ce_len=%d\n", - event->conn_update_req.conn_handle, - event->conn_update_req.peer_params->itvl_min, - event->conn_update_req.peer_params->itvl_max, - event->conn_update_req.peer_params->latency, - event->conn_update_req.peer_params->supervision_timeout, - event->conn_update_req.peer_params->min_ce_len, - event->conn_update_req.peer_params->max_ce_len); - - *event->conn_update_req.self_params = - *event->conn_update_req.peer_params; - break; - default: - break; - } - - return 0; -} - -static void connect(const uint8_t *data, uint16_t len) -{ - uint8_t status = BTP_STATUS_SUCCESS; - - SYS_LOG_DBG(""); - - if (ble_gap_connect(own_addr_type, (ble_addr_t *) data, 0, - &dflt_conn_params, gap_event_cb, NULL)) { - status = BTP_STATUS_FAILED; - } - - tester_rsp(BTP_SERVICE_ID_GAP, GAP_CONNECT, CONTROLLER_INDEX, status); -} - -static void disconnect(const uint8_t *data, uint16_t len) -{ - struct ble_gap_conn_desc desc; - uint8_t status; - int rc; - - SYS_LOG_DBG(""); - - rc = gap_conn_find_by_addr((ble_addr_t *)data, &desc); - if (rc) { - status = BTP_STATUS_FAILED; - goto rsp; - } - - if (ble_gap_terminate(desc.conn_handle, BLE_ERR_REM_USER_CONN_TERM)) { - status = BTP_STATUS_FAILED; - } else { - status = BTP_STATUS_SUCCESS; - } - -rsp: - tester_rsp(BTP_SERVICE_ID_GAP, GAP_DISCONNECT, CONTROLLER_INDEX, - status); -} - -static void set_io_cap(const uint8_t *data, uint16_t len) -{ - const struct gap_set_io_cap_cmd *cmd = (void *) data; - uint8_t status; - - SYS_LOG_DBG(""); - - switch (cmd->io_cap) { - case GAP_IO_CAP_DISPLAY_ONLY: - ble_hs_cfg.sm_io_cap = BLE_SM_IO_CAP_DISP_ONLY; - ble_hs_cfg.sm_mitm = 1; - break; - case GAP_IO_CAP_KEYBOARD_DISPLAY: - ble_hs_cfg.sm_io_cap = BLE_SM_IO_CAP_KEYBOARD_DISP; - ble_hs_cfg.sm_mitm = 1; - break; - case GAP_IO_CAP_NO_INPUT_OUTPUT: - ble_hs_cfg.sm_io_cap = BLE_SM_IO_CAP_NO_IO; - ble_hs_cfg.sm_mitm = 0; - break; - case GAP_IO_CAP_KEYBOARD_ONLY: - ble_hs_cfg.sm_io_cap = BLE_SM_IO_CAP_KEYBOARD_ONLY; - ble_hs_cfg.sm_mitm = 1; - break; - case GAP_IO_CAP_DISPLAY_YESNO: - ble_hs_cfg.sm_io_cap = BLE_SM_IO_CAP_DISP_YES_NO; - ble_hs_cfg.sm_mitm = 1; - break; - default: - status = BTP_STATUS_FAILED; - goto rsp; - } - - status = BTP_STATUS_SUCCESS; - -rsp: - tester_rsp(BTP_SERVICE_ID_GAP, GAP_SET_IO_CAP, CONTROLLER_INDEX, - status); -} - -static void pair(const uint8_t *data, uint16_t len) -{ - struct ble_gap_conn_desc desc; - uint8_t status; - int rc; - - SYS_LOG_DBG(""); - - rc = gap_conn_find_by_addr((ble_addr_t *)data, &desc); - if (rc) { - status = BTP_STATUS_FAILED; - goto rsp; - } - - if (ble_gap_security_initiate(desc.conn_handle)) { - status = BTP_STATUS_FAILED; - goto rsp; - } - - status = BTP_STATUS_SUCCESS; - -rsp: - tester_rsp(BTP_SERVICE_ID_GAP, GAP_PAIR, CONTROLLER_INDEX, status); -} - -static void unpair(const uint8_t *data, uint16_t len) -{ - uint8_t status; - int err; - - SYS_LOG_DBG(""); - - err = ble_gap_unpair((ble_addr_t *) data); - status = (uint8_t) (err != 0 ? BTP_STATUS_FAILED : BTP_STATUS_SUCCESS); - tester_rsp(BTP_SERVICE_ID_GAP, GAP_UNPAIR, CONTROLLER_INDEX, status); -} - -static void passkey_entry(const uint8_t *data, uint16_t len) -{ - const struct gap_passkey_entry_cmd *cmd = (void *) data; - struct ble_gap_conn_desc desc; - struct ble_sm_io pk; - uint8_t status; - int rc; - - SYS_LOG_DBG(""); - - rc = gap_conn_find_by_addr((ble_addr_t *)data, &desc); - if (rc) { - status = BTP_STATUS_FAILED; - goto rsp; - } - - pk.action = BLE_SM_IOACT_INPUT; - pk.passkey = sys_le32_to_cpu(cmd->passkey); - - rc = ble_sm_inject_io(desc.conn_handle, &pk); - if (rc) { - status = BTP_STATUS_FAILED; - goto rsp; - } - - status = BTP_STATUS_SUCCESS; - -rsp: - tester_rsp(BTP_SERVICE_ID_GAP, GAP_PASSKEY_ENTRY, CONTROLLER_INDEX, - status); -} - -static void passkey_confirm(const uint8_t *data, uint16_t len) -{ - const struct gap_passkey_confirm_cmd *cmd = (void *) data; - struct ble_gap_conn_desc desc; - struct ble_sm_io pk; - uint8_t status; - int rc; - - SYS_LOG_DBG(""); - - rc = gap_conn_find_by_addr((ble_addr_t *)data, &desc); - if (rc) { - status = BTP_STATUS_FAILED; - goto rsp; - } - - pk.action = BLE_SM_IOACT_NUMCMP; - pk.numcmp_accept = cmd->match; - - rc = ble_sm_inject_io(desc.conn_handle, &pk); - if (rc) { - console_printf("sm inject io failed"); - status = BTP_STATUS_FAILED; - goto rsp; - } - - status = BTP_STATUS_SUCCESS; - -rsp: - tester_rsp(BTP_SERVICE_ID_GAP, GAP_PASSKEY_CONFIRM, CONTROLLER_INDEX, - status); -} - -static void start_direct_adv(const uint8_t *data, uint16_t len) -{ - const struct gap_start_direct_adv_cmd *cmd = (void *) data; - struct gap_start_advertising_rp rp; - static struct ble_gap_adv_params adv_params = { - .conn_mode = BLE_GAP_CONN_MODE_DIR, - }; - int err; - - SYS_LOG_DBG(""); - - adv_params.high_duty_cycle = cmd->high_duty; - - err = ble_gap_adv_start(own_addr_type, (ble_addr_t *)data, - BLE_HS_FOREVER, &adv_params, - gap_event_cb, NULL); - if (err) { - SYS_LOG_ERR("Advertising failed: err %d", err); - goto fail; - } - - current_settings |= BIT(GAP_SETTINGS_ADVERTISING); - rp.current_settings = sys_cpu_to_le32(current_settings); - - tester_send(BTP_SERVICE_ID_GAP, GAP_START_DIRECT_ADV, CONTROLLER_INDEX, - (uint8_t *) &rp, sizeof(rp)); - return; -fail: - tester_rsp(BTP_SERVICE_ID_GAP, GAP_START_DIRECT_ADV, CONTROLLER_INDEX, - BTP_STATUS_FAILED); -} - -static void conn_param_update_cb(uint16_t conn_handle, int status, void *arg) -{ - console_printf("conn param update complete; conn_handle=%d status=%d\n", - conn_handle, status); -} - -static int conn_param_update_slave(uint16_t conn_handle, - const struct gap_conn_param_update_cmd *cmd) -{ - int rc; - struct ble_l2cap_sig_update_params params; - - params.itvl_min = cmd->conn_itvl_min; - params.itvl_max = cmd->conn_itvl_max; - params.slave_latency = cmd->conn_latency; - params.timeout_multiplier = cmd->supervision_timeout; - - rc = ble_l2cap_sig_update(conn_handle, ¶ms, - conn_param_update_cb, NULL); - if (rc) { - SYS_LOG_ERR("Failed to send update params: rc=%d", rc); - } - - return 0; -} - -static int conn_param_update_master(uint16_t conn_handle, - const struct gap_conn_param_update_cmd *cmd) -{ - int rc; - struct ble_gap_upd_params params; - - params.itvl_min = cmd->conn_itvl_min; - params.itvl_max = cmd->conn_itvl_max; - params.latency = cmd->conn_latency; - params.supervision_timeout = cmd->supervision_timeout; - params.min_ce_len = 0; - params.max_ce_len = 0; - rc = ble_gap_update_params(conn_handle, ¶ms); - if (rc) { - SYS_LOG_ERR("Failed to send update params: rc=%d", rc); - } - - return rc; -} - -static void conn_param_update(struct os_event *ev) -{ - struct ble_gap_conn_desc desc; - int rc; - - SYS_LOG_DBG(""); - - rc = gap_conn_find_by_addr((ble_addr_t *)&update_params, &desc); - if (rc) { - goto rsp; - } - - if ((desc.conn_itvl >= update_params.conn_itvl_min) && - (desc.conn_itvl <= update_params.conn_itvl_max) && - (desc.conn_latency == update_params.conn_latency) && - (desc.supervision_timeout == update_params.supervision_timeout)) { - goto rsp; - } - - if (desc.role == BLE_GAP_ROLE_MASTER) { - rc = conn_param_update_master(desc.conn_handle, &update_params); - } else { - rc = conn_param_update_slave(desc.conn_handle, &update_params); - } - - if (rc == 0) { - return; - } - -rsp: - SYS_LOG_ERR("Conn param update fail; rc=%d", rc); -} - -static void conn_param_update_async(const uint8_t *data, uint16_t len) -{ - const struct gap_conn_param_update_cmd *cmd = (void *) data; - update_params = *cmd; - - os_callout_reset(&update_params_co, 0); - - tester_rsp(BTP_SERVICE_ID_GAP, GAP_CONN_PARAM_UPDATE, CONTROLLER_INDEX, - BTP_STATUS_SUCCESS); -} - -static void oob_legacy_set_data(const uint8_t *data, uint16_t len) -{ - const struct gap_oob_legacy_set_data_cmd *cmd = (void *) data; - - ble_hs_cfg.sm_oob_data_flag = 1; - memcpy(oob, cmd->oob_data, sizeof(oob)); - - tester_rsp(BTP_SERVICE_ID_GAP, GAP_OOB_LEGACY_SET_DATA, - CONTROLLER_INDEX, BTP_STATUS_SUCCESS); -} - -static void oob_sc_get_local_data(const uint8_t *data, uint16_t len) -{ - struct gap_oob_sc_get_local_data_rp rp; - - memcpy(rp.r, oob_data_local.r, 16); - memcpy(rp.c, oob_data_local.c, 16); - - tester_send(BTP_SERVICE_ID_GAP, GAP_OOB_SC_GET_LOCAL_DATA, - CONTROLLER_INDEX, (uint8_t *) &rp, sizeof(rp)); -} - -static void oob_sc_set_remote_data(const uint8_t *data, uint16_t len) -{ - const struct gap_oob_sc_set_remote_data_cmd *cmd = (void *) data; - - ble_hs_cfg.sm_oob_data_flag = 1; - memcpy(oob_data_remote.r, cmd->r, 16); - memcpy(oob_data_remote.c, cmd->c, 16); - - tester_rsp(BTP_SERVICE_ID_GAP, GAP_OOB_SC_SET_REMOTE_DATA, - CONTROLLER_INDEX, BTP_STATUS_SUCCESS); -} - -static void set_mitm(const uint8_t *data, uint16_t len) -{ - const struct gap_set_mitm_cmd *cmd = (void *) data; - - ble_hs_cfg.sm_mitm = cmd->mitm; - - tester_rsp(BTP_SERVICE_ID_GAP, GAP_SET_MITM, - CONTROLLER_INDEX, BTP_STATUS_SUCCESS); -} - -void tester_handle_gap(uint8_t opcode, uint8_t index, uint8_t *data, - uint16_t len) -{ - switch (opcode) { - case GAP_READ_SUPPORTED_COMMANDS: - case GAP_READ_CONTROLLER_INDEX_LIST: - if (index != BTP_INDEX_NONE){ - tester_rsp(BTP_SERVICE_ID_GAP, opcode, index, - BTP_STATUS_FAILED); - return; - } - break; - default: - if (index != CONTROLLER_INDEX){ - tester_rsp(BTP_SERVICE_ID_GAP, opcode, index, - BTP_STATUS_FAILED); - return; - } - break; - } - - switch (opcode) { - case GAP_READ_SUPPORTED_COMMANDS: - supported_commands(data, len); - return; - case GAP_READ_CONTROLLER_INDEX_LIST: - controller_index_list(data, len); - return; - case GAP_READ_CONTROLLER_INFO: - controller_info(data, len); - return; - case GAP_SET_CONNECTABLE: - set_connectable(data, len); - return; - case GAP_SET_DISCOVERABLE: - set_discoverable(data, len); - return; - case GAP_SET_BONDABLE: - set_bondable(data, len); - return; - case GAP_START_ADVERTISING: - start_advertising(data, len); - return; - case GAP_STOP_ADVERTISING: - stop_advertising(data, len); - return; - case GAP_START_DISCOVERY: - start_discovery(data, len); - return; - case GAP_STOP_DISCOVERY: - stop_discovery(data, len); - return; - case GAP_CONNECT: - connect(data, len); - return; - case GAP_DISCONNECT: - disconnect(data, len); - return; - case GAP_SET_IO_CAP: - set_io_cap(data, len); - return; - case GAP_PAIR: - pair(data, len); - return; - case GAP_UNPAIR: - unpair(data, len); - return; - case GAP_PASSKEY_ENTRY: - passkey_entry(data, len); - return; - case GAP_PASSKEY_CONFIRM: - passkey_confirm(data, len); - return; - case GAP_START_DIRECT_ADV: - start_direct_adv(data, len); - return; - case GAP_CONN_PARAM_UPDATE: - conn_param_update_async(data, len); - return; - case GAP_OOB_LEGACY_SET_DATA: - oob_legacy_set_data(data, len); - return; - case GAP_OOB_SC_GET_LOCAL_DATA: - oob_sc_get_local_data(data, len); - return; - case GAP_OOB_SC_SET_REMOTE_DATA: - oob_sc_set_remote_data(data, len); - return; - case GAP_SET_MITM: - set_mitm(data, len); - return; - default: - tester_rsp(BTP_SERVICE_ID_GAP, opcode, index, - BTP_STATUS_UNKNOWN_CMD); - return; - } -} - -static void tester_init_gap_cb(int err) -{ - if (err) { - tester_rsp(BTP_SERVICE_ID_CORE, CORE_REGISTER_SERVICE, - BTP_INDEX_NONE, BTP_STATUS_FAILED); - return; - } - - current_settings = 0; - current_settings |= BIT(GAP_SETTINGS_POWERED); - current_settings |= BIT(GAP_SETTINGS_LE); - - os_callout_init(&update_params_co, os_eventq_dflt_get(), - conn_param_update, NULL); - - os_callout_init(&connected_ev_co, os_eventq_dflt_get(), - device_connected_ev_send, NULL); - - tester_rsp(BTP_SERVICE_ID_CORE, CORE_REGISTER_SERVICE, BTP_INDEX_NONE, - BTP_STATUS_SUCCESS); -} - -uint8_t tester_init_gap(void) -{ -#if MYNEWT_VAL(BLE_SM_SC) - int rc; - - rc = ble_sm_sc_oob_generate_data(&oob_data_local); - if (rc) { - console_printf("Error: generating oob data; reason=%d\n", rc); - return BTP_STATUS_FAILED; - } -#endif - - adv_buf = NET_BUF_SIMPLE(ADV_BUF_LEN); - - tester_init_gap_cb(BTP_STATUS_SUCCESS); - return BTP_STATUS_SUCCESS; -} - -uint8_t tester_unregister_gap(void) -{ - return BTP_STATUS_SUCCESS; -} diff --git a/apps/bttester/src/gatt.c b/apps/bttester/src/gatt.c deleted file mode 100644 index d40de262bc..0000000000 --- a/apps/bttester/src/gatt.c +++ /dev/null @@ -1,2098 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -/* gatt.c - Bluetooth GATT Server Tester */ - -/* - * Copyright (c) 2015-2016 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include -#include -#include - -#include "host/ble_gap.h" -#include "host/ble_gatt.h" -#include "console/console.h" -#include "services/gatt/ble_svc_gatt.h" -#include "../../../nimble/host/src/ble_att_priv.h" -#include "../../../nimble/host/src/ble_gatt_priv.h" - -#include "bttester.h" - -#define CONTROLLER_INDEX 0 -#define MAX_BUFFER_SIZE 2048 - -/* 0000xxxx-8c26-476f-89a7-a108033a69c7 */ -#define PTS_UUID_DECLARE(uuid16) \ - ((const ble_uuid_t *) (&(ble_uuid128_t) BLE_UUID128_INIT( \ - 0xc7, 0x69, 0x3a, 0x03, 0x08, 0xa1, 0xa7, 0x89, \ - 0x6f, 0x47, 0x26, 0x8c, uuid16, uuid16 >> 8, 0x00, 0x00 \ - ))) - -/* 0000xxxx-8c26-476f-89a7-a108033a69c6 */ -#define PTS_UUID_DECLARE_ALT(uuid16) \ - ((const ble_uuid_t *) (&(ble_uuid128_t) BLE_UUID128_INIT( \ - 0xc6, 0x69, 0x3a, 0x03, 0x08, 0xa1, 0xa7, 0x89, \ - 0x6f, 0x47, 0x26, 0x8c, uuid16, uuid16 >> 8, 0x00, 0x00 \ - ))) - -#define PTS_SVC 0x0001 -#define PTS_CHR_READ 0x0002 -#define PTS_CHR_WRITE 0x0003 -#define PTS_CHR_RELIABLE_WRITE 0x0004 -#define PTS_CHR_WRITE_NO_RSP 0x0005 -#define PTS_CHR_READ_WRITE 0x0006 -#define PTS_CHR_READ_WRITE_ENC 0x0007 -#define PTS_CHR_READ_WRITE_AUTHEN 0x0008 -#define PTS_DSC_READ 0x0009 -#define PTS_DSC_WRITE 0x000a -#define PTS_DSC_READ_WRITE 0x000b -#define PTS_CHR_NOTIFY 0x0025 -#define PTS_LONG_CHR_READ_WRITE 0x0015 -#define PTS_LONG_CHR_READ_WRITE_ALT 0x0016 -#define PTS_LONG_DSC_READ_WRITE 0x001b -#define PTS_INC_SVC 0x001e -#define PTS_CHR_READ_WRITE_ALT 0x001f - -static uint8_t gatt_svr_pts_static_long_val[300]; -static uint8_t gatt_svr_pts_static_val[30]; -static uint8_t gatt_svr_pts_static_short_val; -static uint8_t notify_state; -static uint8_t indicate_state; -static uint16_t myconn_handle; -static struct os_callout notify_tx_timer; -uint16_t notify_handle; -uint8_t notify_value = 90; - -struct find_attr_data { - ble_uuid_any_t *uuid; - int attr_type; - void *ptr; - uint16_t handle; -}; - -static int -gatt_svr_read_write_test(uint16_t conn_handle, uint16_t attr_handle, - struct ble_gatt_access_ctxt *ctxt, - void *arg); - -static int -gatt_svr_read_write_auth_test(uint16_t conn_handle, uint16_t attr_handle, - struct ble_gatt_access_ctxt *ctxt, - void *arg); - -static int -gatt_svr_read_write_enc_test(uint16_t conn_handle, uint16_t attr_handle, - struct ble_gatt_access_ctxt *ctxt, - void *arg); - -static int -gatt_svr_dsc_read_write_test(uint16_t conn_handle, uint16_t attr_handle, - struct ble_gatt_access_ctxt *ctxt, - void *arg); - -static int -gatt_svr_write_no_rsp_test(uint16_t conn_handle, uint16_t attr_handle, - struct ble_gatt_access_ctxt *ctxt, - void *arg); - -static int -gatt_svr_rel_write_test(uint16_t conn_handle, uint16_t attr_handle, - struct ble_gatt_access_ctxt *ctxt, - void *arg); - -static int -gatt_svr_read_write_long_test(uint16_t conn_handle, uint16_t attr_handle, - struct ble_gatt_access_ctxt *ctxt, - void *arg); - -static int -gatt_svr_dsc_read_test(uint16_t conn_handle, uint16_t attr_handle, - struct ble_gatt_access_ctxt *ctxt, - void *arg); - -static int -gatt_svr_dsc_read_write_long_test(uint16_t conn_handle, uint16_t attr_handle, - struct ble_gatt_access_ctxt *ctxt, - void *arg); - -static const struct ble_gatt_svc_def gatt_svr_inc_svcs[] = { - { - .type = BLE_GATT_SVC_TYPE_PRIMARY, - .uuid = PTS_UUID_DECLARE(PTS_INC_SVC), - .characteristics = (struct ble_gatt_chr_def[]) {{ - .uuid = PTS_UUID_DECLARE(PTS_CHR_READ_WRITE_ALT), - .access_cb = gatt_svr_read_write_test, - .flags = BLE_GATT_CHR_F_WRITE | - BLE_GATT_CHR_F_READ, - }, { - 0, - } }, - }, - - { - 0, /* No more services. */ - }, -}; - -static const struct ble_gatt_svc_def *inc_svcs[] = { - &gatt_svr_inc_svcs[0], - NULL, -}; - -static const struct ble_gatt_svc_def gatt_svr_svcs[] = { - { - /*** Service: PTS test. */ - .type = BLE_GATT_SVC_TYPE_PRIMARY, - .uuid = PTS_UUID_DECLARE(PTS_SVC), - .includes = inc_svcs, - .characteristics = (struct ble_gatt_chr_def[]) { { - .uuid = PTS_UUID_DECLARE(PTS_CHR_READ_WRITE), - .access_cb = gatt_svr_read_write_test, - .flags = BLE_GATT_CHR_F_READ | - BLE_GATT_CHR_F_WRITE, - .descriptors = (struct ble_gatt_dsc_def[]) { { - .uuid = PTS_UUID_DECLARE(PTS_DSC_READ_WRITE), - .access_cb = gatt_svr_dsc_read_write_test, - .att_flags = BLE_ATT_F_READ | - BLE_ATT_F_WRITE, - }, { - .uuid = PTS_UUID_DECLARE(PTS_LONG_DSC_READ_WRITE), - .access_cb = gatt_svr_dsc_read_write_long_test, - .att_flags = BLE_ATT_F_READ | - BLE_ATT_F_WRITE, - }, { - .uuid = PTS_UUID_DECLARE(PTS_DSC_READ), - .access_cb = gatt_svr_dsc_read_test, - .att_flags = BLE_ATT_F_READ, - }, { - 0, /* No more descriptors in this characteristic */ - } } - }, { - .uuid = PTS_UUID_DECLARE(PTS_CHR_WRITE_NO_RSP), - .access_cb = gatt_svr_write_no_rsp_test, - .flags = BLE_GATT_CHR_F_READ | - BLE_GATT_CHR_F_WRITE | - BLE_GATT_CHR_F_WRITE_NO_RSP, - }, { - .uuid = PTS_UUID_DECLARE(PTS_CHR_READ_WRITE_AUTHEN), - .access_cb = gatt_svr_read_write_auth_test, - .flags = BLE_GATT_CHR_F_READ_AUTHEN | - BLE_GATT_CHR_F_READ | - BLE_GATT_CHR_F_WRITE_AUTHEN | - BLE_GATT_CHR_F_WRITE | - BLE_GATT_CHR_F_WRITE_AUTHEN, - }, { - .uuid = PTS_UUID_DECLARE(PTS_CHR_RELIABLE_WRITE), - .access_cb = gatt_svr_rel_write_test, - .flags = BLE_GATT_CHR_F_WRITE | - BLE_GATT_CHR_F_RELIABLE_WRITE, - }, { - .uuid = PTS_UUID_DECLARE(PTS_CHR_READ_WRITE_ENC), - .access_cb = gatt_svr_read_write_enc_test, - .flags = BLE_GATT_CHR_F_READ_ENC | - BLE_GATT_CHR_F_READ | - BLE_GATT_CHR_F_WRITE | - BLE_GATT_CHR_F_WRITE_ENC, - .min_key_size = 16, - }, { - .uuid = PTS_UUID_DECLARE(PTS_LONG_CHR_READ_WRITE), - .access_cb = gatt_svr_read_write_long_test, - .flags = BLE_GATT_CHR_F_WRITE | - BLE_GATT_CHR_F_READ, - }, { - .uuid = PTS_UUID_DECLARE(PTS_LONG_CHR_READ_WRITE_ALT), - .access_cb = gatt_svr_read_write_long_test, - .flags = BLE_GATT_CHR_F_WRITE | - BLE_GATT_CHR_F_READ, - }, { - .uuid = PTS_UUID_DECLARE(PTS_CHR_NOTIFY), - .access_cb = gatt_svr_read_write_test, - .val_handle = ¬ify_handle, - .flags = BLE_GATT_CHR_F_NOTIFY | - BLE_GATT_CHR_F_INDICATE, - }, { - 0, /* No more characteristics in this service. */ - } }, - }, - - { - .type = BLE_GATT_SVC_TYPE_PRIMARY, - .uuid = PTS_UUID_DECLARE_ALT(PTS_SVC), - .characteristics = (struct ble_gatt_chr_def[]) { { - .uuid = PTS_UUID_DECLARE_ALT(PTS_CHR_READ_WRITE), - .access_cb = gatt_svr_read_write_test, - .flags = BLE_GATT_CHR_F_WRITE | - BLE_GATT_CHR_F_READ, - }, { - 0, /* No more characteristics in this service */ - } }, - }, - - { - 0, /* No more services. */ - }, -}; - -static void attr_value_changed_ev(uint16_t handle, struct os_mbuf *data) -{ - struct gatt_attr_value_changed_ev *ev; - struct os_mbuf *buf = os_msys_get(0, 0); - - SYS_LOG_DBG(""); - - net_buf_simple_init(buf, 0); - ev = net_buf_simple_add(buf, sizeof(*ev)); - - ev->handle = sys_cpu_to_le16(handle); - ev->data_length = sys_cpu_to_le16(os_mbuf_len(data)); - os_mbuf_appendfrom(buf, data, 0, os_mbuf_len(data)); - - tester_send_buf(BTP_SERVICE_ID_GATT, GATT_EV_ATTR_VALUE_CHANGED, - CONTROLLER_INDEX, buf); -} - -static int -gatt_svr_chr_write(uint16_t conn_handle, uint16_t attr_handle, - struct os_mbuf *om, uint16_t min_len, uint16_t max_len, - void *dst, uint16_t *len) -{ - uint16_t om_len; - int rc; - - om_len = OS_MBUF_PKTLEN(om); - if (om_len < min_len || om_len > max_len) { - return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; - } - - rc = ble_hs_mbuf_to_flat(om, dst, max_len, len); - if (rc != 0) { - return BLE_ATT_ERR_UNLIKELY; - } - - attr_value_changed_ev(attr_handle, om); - - return 0; -} - -static uint16_t -extract_uuid16_from_pts_uuid128(const ble_uuid_t *uuid) -{ - const uint8_t *u8ptr; - uint16_t uuid16; - - u8ptr = BLE_UUID128(uuid)->value; - uuid16 = u8ptr[12]; - uuid16 |= (uint16_t)u8ptr[13] << 8; - return uuid16; -} - -static int -gatt_svr_read_write_test(uint16_t conn_handle, uint16_t attr_handle, - struct ble_gatt_access_ctxt *ctxt, - void *arg) -{ - uint16_t uuid16; - int rc; - - uuid16 = extract_uuid16_from_pts_uuid128(ctxt->chr->uuid); - assert(uuid16 != 0); - - switch (uuid16) { - case PTS_CHR_READ_WRITE: - case PTS_CHR_READ_WRITE_ALT: - if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) { - rc = gatt_svr_chr_write(conn_handle, attr_handle, - ctxt->om, 0, - sizeof gatt_svr_pts_static_short_val, - &gatt_svr_pts_static_short_val, NULL); - return rc; - } else if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) { - rc = os_mbuf_append(ctxt->om, &gatt_svr_pts_static_short_val, - sizeof gatt_svr_pts_static_short_val); - return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; - } - default: - assert(0); - return BLE_ATT_ERR_UNLIKELY; - } -} - -static int -gatt_svr_read_write_long_test(uint16_t conn_handle, uint16_t attr_handle, - struct ble_gatt_access_ctxt *ctxt, - void *arg) -{ - uint16_t uuid16; - int rc; - - uuid16 = extract_uuid16_from_pts_uuid128(ctxt->chr->uuid); - assert(uuid16 != 0); - - switch (uuid16) { - case PTS_LONG_CHR_READ_WRITE: - case PTS_LONG_CHR_READ_WRITE_ALT: - if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) { - rc = gatt_svr_chr_write(conn_handle, attr_handle, - ctxt->om, 0, - sizeof gatt_svr_pts_static_long_val, - &gatt_svr_pts_static_long_val, NULL); - return rc; - } else if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) { - rc = os_mbuf_append(ctxt->om, &gatt_svr_pts_static_long_val, - sizeof gatt_svr_pts_static_long_val); - return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; - } - default: - assert(0); - return BLE_ATT_ERR_UNLIKELY; - } -} - -static int -gatt_svr_read_write_auth_test(uint16_t conn_handle, uint16_t attr_handle, - struct ble_gatt_access_ctxt *ctxt, - void *arg) -{ - uint16_t uuid16; - int rc; - - uuid16 = extract_uuid16_from_pts_uuid128(ctxt->chr->uuid); - assert(uuid16 != 0); - - switch (uuid16) { - case PTS_CHR_READ_WRITE_AUTHEN: - if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) { - rc = gatt_svr_chr_write(conn_handle, attr_handle, - ctxt->om, 0, - sizeof gatt_svr_pts_static_val, - &gatt_svr_pts_static_val, NULL); - return rc; - } else if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) { - rc = os_mbuf_append(ctxt->om, &gatt_svr_pts_static_val, - sizeof gatt_svr_pts_static_val); - return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; - } - default: - assert(0); - return BLE_ATT_ERR_UNLIKELY; - } -} - -static int -gatt_svr_read_write_enc_test(uint16_t conn_handle, uint16_t attr_handle, - struct ble_gatt_access_ctxt *ctxt, - void *arg) -{ - uint16_t uuid16; - int rc; - - uuid16 = extract_uuid16_from_pts_uuid128(ctxt->chr->uuid); - assert(uuid16 != 0); - - switch (uuid16) { - case PTS_CHR_READ_WRITE_ENC: - if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) { - rc = os_mbuf_append(ctxt->om, &gatt_svr_pts_static_val, - sizeof gatt_svr_pts_static_val); - return rc; - } else if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) { - rc = gatt_svr_chr_write(conn_handle, attr_handle, - ctxt->om, 0, - sizeof gatt_svr_pts_static_val, - &gatt_svr_pts_static_val, NULL); - return rc; - } - default: - assert(0); - return BLE_ATT_ERR_UNLIKELY; - } -} - -static int -gatt_svr_dsc_read_write_test(uint16_t conn_handle, uint16_t attr_handle, - struct ble_gatt_access_ctxt *ctxt, - void *arg) -{ - uint16_t uuid16; - int rc; - - uuid16 = extract_uuid16_from_pts_uuid128(ctxt->chr->uuid); - assert(uuid16 != 0); - - switch (uuid16) { - case PTS_DSC_READ_WRITE: - if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_DSC) { - rc = gatt_svr_chr_write(conn_handle, attr_handle, - ctxt->om, 0, - sizeof gatt_svr_pts_static_short_val, - &gatt_svr_pts_static_short_val, NULL); - return rc; - } else if (ctxt->op == BLE_GATT_ACCESS_OP_READ_DSC) { - rc = os_mbuf_append(ctxt->om, &gatt_svr_pts_static_short_val, - sizeof gatt_svr_pts_static_short_val); - return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; - } - default: - assert(0); - return BLE_ATT_ERR_UNLIKELY; - } -} - -static int -gatt_svr_dsc_read_write_long_test(uint16_t conn_handle, uint16_t attr_handle, - struct ble_gatt_access_ctxt *ctxt, - void *arg) -{ - uint16_t uuid16; - int rc; - - uuid16 = extract_uuid16_from_pts_uuid128(ctxt->chr->uuid); - assert(uuid16 != 0); - - switch (uuid16) { - case PTS_LONG_DSC_READ_WRITE: - if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_DSC) { - rc = gatt_svr_chr_write(conn_handle, attr_handle, - ctxt->om, 0, - sizeof gatt_svr_pts_static_long_val, - &gatt_svr_pts_static_long_val, NULL); - return rc; - } else if (ctxt->op == BLE_GATT_ACCESS_OP_READ_DSC) { - rc = os_mbuf_append(ctxt->om, &gatt_svr_pts_static_long_val, - sizeof gatt_svr_pts_static_long_val); - return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; - } - default: - assert(0); - return BLE_ATT_ERR_UNLIKELY; - } -} - -static int -gatt_svr_dsc_read_test(uint16_t conn_handle, uint16_t attr_handle, - struct ble_gatt_access_ctxt *ctxt, - void *arg) -{ - uint16_t uuid16; - int rc; - - uuid16 = extract_uuid16_from_pts_uuid128(ctxt->chr->uuid); - assert(uuid16 != 0); - - switch (uuid16) { - case PTS_DSC_READ: - if (ctxt->op == BLE_GATT_ACCESS_OP_READ_DSC) { - rc = os_mbuf_append(ctxt->om, &gatt_svr_pts_static_long_val, - sizeof gatt_svr_pts_static_long_val); - return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; - } - default: - assert(0); - return BLE_ATT_ERR_UNLIKELY; - } -} - -static int -gatt_svr_write_no_rsp_test(uint16_t conn_handle, uint16_t attr_handle, - struct ble_gatt_access_ctxt *ctxt, - void *arg) -{ - uint16_t uuid16; - int rc; - - uuid16 = extract_uuid16_from_pts_uuid128(ctxt->chr->uuid); - assert(uuid16 != 0); - - switch (uuid16) { - case PTS_CHR_WRITE_NO_RSP: - if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) { - rc = gatt_svr_chr_write(conn_handle, attr_handle, - ctxt->om, 0, - sizeof gatt_svr_pts_static_short_val, - &gatt_svr_pts_static_short_val, NULL); - return rc; - } else if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) { - rc = os_mbuf_append(ctxt->om, &gatt_svr_pts_static_short_val, - sizeof gatt_svr_pts_static_short_val); - return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; - } - default: - assert(0); - return BLE_ATT_ERR_UNLIKELY; - } -} - -static int -gatt_svr_rel_write_test(uint16_t conn_handle, uint16_t attr_handle, - struct ble_gatt_access_ctxt *ctxt, - void *arg) -{ - uint16_t uuid16; - int rc; - - uuid16 = extract_uuid16_from_pts_uuid128(ctxt->chr->uuid); - assert(uuid16 != 0); - - switch (uuid16) { - case PTS_CHR_RELIABLE_WRITE: - if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) { - rc = gatt_svr_chr_write(conn_handle, attr_handle, - ctxt->om, 0, - sizeof gatt_svr_pts_static_val, - &gatt_svr_pts_static_val, NULL); - return rc; - } - - default: - assert(0); - return BLE_ATT_ERR_UNLIKELY; - } -} - -static void start_server(uint8_t *data, uint16_t len) -{ - struct gatt_start_server_rp rp; - - SYS_LOG_DBG(""); - - ble_gatts_show_local(); - - ble_svc_gatt_changed(0x0001, 0xffff); - - rp.db_attr_off = 0; - rp.db_attr_cnt = 0; - - tester_send(BTP_SERVICE_ID_GATT, GATT_START_SERVER, CONTROLLER_INDEX, - (uint8_t *) &rp, sizeof(rp)); -} - -/* Convert UUID from BTP command to bt_uuid */ -static uint8_t btp2bt_uuid(const uint8_t *uuid, uint8_t len, - ble_uuid_any_t *bt_uuid) -{ - uint16_t le16; - - switch (len) { - case 0x02: /* UUID 16 */ - bt_uuid->u.type = BLE_UUID_TYPE_16; - memcpy(&le16, uuid, sizeof(le16)); - BLE_UUID16(bt_uuid)->value = sys_le16_to_cpu(le16); - break; - case 0x10: /* UUID 128*/ - bt_uuid->u.type = BLE_UUID_TYPE_128; - memcpy(BLE_UUID128(bt_uuid)->value, uuid, 16); - break; - default: - return BTP_STATUS_FAILED; - } - return BTP_STATUS_SUCCESS; -} - -/* - * gatt_buf - cache used by a gatt client (to cache data read/discovered) - * and gatt server (to store attribute user_data). - * It is not intended to be used by client and server at the same time. - */ -static struct { - uint16_t len; - uint8_t buf[MAX_BUFFER_SIZE]; -} gatt_buf; - -static void *gatt_buf_add(const void *data, size_t len) -{ - void *ptr = gatt_buf.buf + gatt_buf.len; - - if ((len + gatt_buf.len) > MAX_BUFFER_SIZE) { - return NULL; - } - - if (data) { - memcpy(ptr, data, len); - } else { - (void)memset(ptr, 0, len); - } - - gatt_buf.len += len; - - SYS_LOG_DBG("%d/%d used", gatt_buf.len, MAX_BUFFER_SIZE); - - return ptr; -} - -static void *gatt_buf_reserve(size_t len) -{ - return gatt_buf_add(NULL, len); -} - -static void gatt_buf_clear(void) -{ - (void)memset(&gatt_buf, 0, sizeof(gatt_buf)); -} - -static void discover_destroy(void) -{ - gatt_buf_clear(); -} - -static void read_destroy() -{ - gatt_buf_clear(); -} - -static int read_cb(uint16_t conn_handle, - const struct ble_gatt_error *error, - struct ble_gatt_attr *attr, - void *arg) -{ - struct gatt_read_rp *rp = (void *) gatt_buf.buf; - uint8_t btp_opcode = (uint8_t) (int) arg; - - SYS_LOG_DBG("status=%d", error->status); - - if (error->status != 0 && error->status != BLE_HS_EDONE) { - rp->att_response = (uint8_t) BLE_HS_ATT_ERR(error->status); - tester_send(BTP_SERVICE_ID_GATT, btp_opcode, - CONTROLLER_INDEX, gatt_buf.buf, gatt_buf.len); - read_destroy(); - return 0; - } - - if (!gatt_buf_add(attr->om->om_data, attr->om->om_len)) { - tester_rsp(BTP_SERVICE_ID_GATT, btp_opcode, - CONTROLLER_INDEX, BTP_STATUS_FAILED); - read_destroy(); - return 0; - } - - rp->data_length += attr->om->om_len; - tester_send(BTP_SERVICE_ID_GATT, btp_opcode, - CONTROLLER_INDEX, gatt_buf.buf, gatt_buf.len); - read_destroy(); - - return 0; -} - -static void read(uint8_t *data, uint16_t len) -{ - const struct gatt_read_cmd *cmd = (void *) data; - struct ble_gap_conn_desc conn; - int rc; - - SYS_LOG_DBG(""); - - rc = ble_gap_conn_find_by_addr((ble_addr_t *)data, &conn); - if (rc) { - goto fail; - } - - /* Clear buffer */ - read_destroy(); - - if (!gatt_buf_reserve(sizeof(struct gatt_read_rp))) { - goto fail; - } - - if (ble_gattc_read(conn.conn_handle, sys_le16_to_cpu(cmd->handle), - read_cb, (void *)GATT_READ)) { - read_destroy(); - goto fail; - } - - return; - -fail: - tester_rsp(BTP_SERVICE_ID_GATT, GATT_READ, CONTROLLER_INDEX, - BTP_STATUS_FAILED); -} - -static int read_long_cb(uint16_t conn_handle, - const struct ble_gatt_error *error, - struct ble_gatt_attr *attr, - void *arg) -{ - struct gatt_read_rp *rp = (void *) gatt_buf.buf; - uint8_t btp_opcode = (uint8_t) (int) arg; - - SYS_LOG_DBG("status=%d", error->status); - - if (error->status != 0 && error->status != BLE_HS_EDONE) { - rp->att_response = (uint8_t) BLE_HS_ATT_ERR(error->status); - tester_send(BTP_SERVICE_ID_GATT, btp_opcode, - CONTROLLER_INDEX, gatt_buf.buf, gatt_buf.len); - read_destroy(); - return 0; - } - - if (error->status == BLE_HS_EDONE) { - tester_send(BTP_SERVICE_ID_GATT, btp_opcode, - CONTROLLER_INDEX, gatt_buf.buf, gatt_buf.len); - read_destroy(); - return 0; - } - - if (gatt_buf_add(attr->om->om_data, attr->om->om_len) == NULL) { - tester_rsp(BTP_SERVICE_ID_GATT, btp_opcode, - CONTROLLER_INDEX, BTP_STATUS_FAILED); - read_destroy(); - return BLE_HS_ENOMEM; - } - - rp->data_length += attr->om->om_len; - - return 0; -} - -static void read_long(uint8_t *data, uint16_t len) -{ - const struct gatt_read_long_cmd *cmd = (void *) data; - struct ble_gap_conn_desc conn; - int rc; - - SYS_LOG_DBG(""); - - rc = ble_gap_conn_find_by_addr((ble_addr_t *)data, &conn); - if (rc) { - goto fail; - } - - /* Clear buffer */ - read_destroy(); - - if (!gatt_buf_reserve(sizeof(struct gatt_read_rp))) { - goto fail; - } - - if (ble_gattc_read_long(conn.conn_handle, - sys_le16_to_cpu(cmd->handle), - sys_le16_to_cpu(cmd->offset), - read_long_cb, (void *)GATT_READ_LONG)) { - read_destroy(); - goto fail; - } - - return; - -fail: - tester_rsp(BTP_SERVICE_ID_GATT, GATT_READ_LONG, CONTROLLER_INDEX, - BTP_STATUS_FAILED); -} - -static void read_multiple(uint8_t *data, uint16_t len) -{ - const struct gatt_read_multiple_cmd *cmd = (void *) data; - uint16_t handles[cmd->handles_count]; - struct ble_gap_conn_desc conn; - int rc, i; - - SYS_LOG_DBG(""); - - for (i = 0; i < ARRAY_SIZE(handles); i++) { - handles[i] = sys_le16_to_cpu(cmd->handles[i]); - } - - rc = ble_gap_conn_find_by_addr((ble_addr_t *)data, &conn); - if (rc) { - goto fail; - } - - /* Clear buffer */ - read_destroy(); - - if (!gatt_buf_reserve(sizeof(struct gatt_read_rp))) { - goto fail; - } - - if (ble_gattc_read_mult(conn.conn_handle, handles, - cmd->handles_count, read_cb, - (void *)GATT_READ_MULTIPLE)) { - read_destroy(); - goto fail; - } - - return; - -fail: - tester_rsp(BTP_SERVICE_ID_GATT, GATT_READ_MULTIPLE, CONTROLLER_INDEX, - BTP_STATUS_FAILED); -} - -static void write_without_rsp(uint8_t *data, uint16_t len, uint8_t op, bool sign) -{ - const struct gatt_write_without_rsp_cmd *cmd = (void *) data; - struct ble_gap_conn_desc conn; - uint8_t status = BTP_STATUS_SUCCESS; - int rc; - - SYS_LOG_DBG(""); - - rc = ble_gap_conn_find_by_addr((ble_addr_t *)data, &conn); - if (rc) { - status = BTP_STATUS_FAILED; - goto rsp; - } - - if (ble_gattc_write_no_rsp_flat(conn.conn_handle, - sys_le16_to_cpu(cmd->handle), cmd->data, - sys_le16_to_cpu(cmd->data_length))) { - status = BTP_STATUS_FAILED; - } - -rsp: - tester_rsp(BTP_SERVICE_ID_GATT, op, CONTROLLER_INDEX, status); -} - -static int write_rsp(uint16_t conn_handle, const struct ble_gatt_error *error, - struct ble_gatt_attr *attr, - void *arg) -{ - uint8_t err = (uint8_t) error->status; - uint8_t btp_opcode = (uint8_t) (int) arg; - - SYS_LOG_DBG(""); - - tester_send(BTP_SERVICE_ID_GATT, btp_opcode, - CONTROLLER_INDEX, &err, sizeof(err)); - return 0; -} - -static void write(uint8_t *data, uint16_t len) -{ - const struct gatt_write_cmd *cmd = (void *) data; - struct ble_gap_conn_desc conn; - int rc; - - SYS_LOG_DBG(""); - - rc = ble_gap_conn_find_by_addr((ble_addr_t *)data, &conn); - if (rc) { - goto fail; - } - - if (ble_gattc_write_flat(conn.conn_handle, sys_le16_to_cpu(cmd->handle), - cmd->data, sys_le16_to_cpu(cmd->data_length), - write_rsp, (void *) GATT_WRITE)) { - goto fail; - } - - return; - -fail: - tester_rsp(BTP_SERVICE_ID_GATT, GATT_WRITE, CONTROLLER_INDEX, - BTP_STATUS_FAILED); -} - -static void write_long(uint8_t *data, uint16_t len) -{ - const struct gatt_write_long_cmd *cmd = (void *) data; - struct ble_gap_conn_desc conn; - struct os_mbuf *om = NULL; - int rc = 0; - - SYS_LOG_DBG(""); - - rc = ble_gap_conn_find_by_addr((ble_addr_t *)data, &conn); - if (rc) { - goto fail; - } - - om = ble_hs_mbuf_from_flat(cmd->data, sys_le16_to_cpu(cmd->data_length)); - if (!om) { - SYS_LOG_ERR("Insufficient resources"); - goto fail; - } - - rc = ble_gattc_write_long(conn.conn_handle, - sys_le16_to_cpu(cmd->handle), - sys_le16_to_cpu(cmd->offset), - om, write_rsp, - (void *) GATT_WRITE_LONG); - if (!rc) { - return; - } - -fail: - SYS_LOG_ERR("Failed to send Write Long request, rc=%d", rc); - os_mbuf_free_chain(om); - tester_rsp(BTP_SERVICE_ID_GATT, GATT_WRITE_LONG, CONTROLLER_INDEX, - BTP_STATUS_FAILED); -} - -static int reliable_write_rsp(uint16_t conn_handle, - const struct ble_gatt_error *error, - struct ble_gatt_attr *attrs, - uint8_t num_attrs, - void *arg) -{ - uint8_t err = (uint8_t) error->status; - - SYS_LOG_DBG("Reliable write status %d", err); - - tester_send(BTP_SERVICE_ID_GATT, GATT_RELIABLE_WRITE, - CONTROLLER_INDEX, &err, sizeof(err)); - return 0; -} - -static void reliable_write(uint8_t *data, uint16_t len) -{ - const struct gatt_reliable_write_cmd *cmd = (void *) data; - struct ble_gap_conn_desc conn; - struct ble_gatt_attr attr; - struct os_mbuf *om = NULL; - int rc; - - SYS_LOG_DBG(""); - - rc = ble_gap_conn_find_by_addr((ble_addr_t *)data, &conn); - if (rc) { - goto fail; - } - - om = ble_hs_mbuf_from_flat(cmd->data, sys_le16_to_cpu(cmd->data_length)); - /* This is required, because Nimble checks if - * the data is longer than offset - */ - if (os_mbuf_extend(om, sys_le16_to_cpu(cmd->offset) + 1) == NULL) { - goto fail; - } - - attr.handle = sys_le16_to_cpu(cmd->handle); - attr.offset = sys_le16_to_cpu(cmd->offset); - attr.om = om; - - if (ble_gattc_write_reliable(conn.conn_handle, &attr, 1, - reliable_write_rsp, NULL)) { - goto fail; - } - - return; - -fail: - os_mbuf_free_chain(om); - - tester_rsp(BTP_SERVICE_ID_GATT, GATT_WRITE_LONG, CONTROLLER_INDEX, - BTP_STATUS_FAILED); -} - -static struct bt_gatt_subscribe_params { - uint16_t ccc_handle; - uint16_t value; - uint16_t value_handle; -} subscribe_params; - -static void read_uuid(uint8_t *data, uint16_t len) -{ - const struct gatt_read_uuid_cmd *cmd = (void *) data; - struct ble_gap_conn_desc conn; - ble_uuid_any_t uuid; - int rc; - - SYS_LOG_DBG(""); - - rc = ble_gap_conn_find_by_addr((ble_addr_t *)data, &conn); - if (rc) { - goto fail; - } - - if (btp2bt_uuid(cmd->uuid, cmd->uuid_length, &uuid)) { - goto fail; - } - - /* Clear buffer */ - read_destroy(); - - if (!gatt_buf_reserve(sizeof(struct gatt_read_rp))) { - goto fail; - } - - if (ble_gattc_read_by_uuid(conn.conn_handle, - sys_le16_to_cpu(cmd->start_handle), - sys_le16_to_cpu(cmd->end_handle), &uuid.u, - read_long_cb, (void *)GATT_READ_UUID)) { - read_destroy(); - goto fail; - } - - return; - -fail: - tester_rsp(BTP_SERVICE_ID_GATT, GATT_READ, CONTROLLER_INDEX, - BTP_STATUS_FAILED); -} - -static int disc_prim_uuid_cb(uint16_t conn_handle, - const struct ble_gatt_error *error, - const struct ble_gatt_svc *gatt_svc, void *arg) -{ - struct gatt_disc_prim_uuid_rp *rp = (void *) gatt_buf.buf; - struct gatt_service *service; - const ble_uuid_any_t *uuid; - uint8_t uuid_length; - uint8_t opcode = (uint8_t) (int) arg; - - SYS_LOG_DBG(""); - - if (error->status != 0 && error->status != BLE_HS_EDONE) { - tester_rsp(BTP_SERVICE_ID_GATT, opcode, - CONTROLLER_INDEX, BTP_STATUS_FAILED); - discover_destroy(); - return 0; - } - - if (error->status == BLE_HS_EDONE) { - tester_send(BTP_SERVICE_ID_GATT, opcode, - CONTROLLER_INDEX, gatt_buf.buf, gatt_buf.len); - discover_destroy(); - return 0; - } - - uuid = &gatt_svc->uuid; - uuid_length = (uint8_t) (uuid->u.type == BLE_UUID_TYPE_16 ? 2 : 16); - - service = gatt_buf_reserve(sizeof(*service) + uuid_length); - if (!service) { - tester_rsp(BTP_SERVICE_ID_GATT, opcode, - CONTROLLER_INDEX, BTP_STATUS_FAILED); - discover_destroy(); - return BLE_HS_ENOMEM; - } - - service->start_handle = sys_cpu_to_le16(gatt_svc->start_handle); - service->end_handle = sys_cpu_to_le16(gatt_svc->end_handle); - service->uuid_length = uuid_length; - - if (uuid->u.type == BLE_UUID_TYPE_16) { - uint16_t u16 = sys_cpu_to_le16(BLE_UUID16(uuid)->value); - memcpy(service->uuid, &u16, uuid_length); - } else { - memcpy(service->uuid, BLE_UUID128(uuid)->value, - uuid_length); - } - - rp->services_count++; - - return 0; -} - -static int disc_all_desc_cb(uint16_t conn_handle, - const struct ble_gatt_error *error, - uint16_t chr_val_handle, - const struct ble_gatt_dsc *gatt_dsc, - void *arg) -{ - struct gatt_disc_all_desc_rp *rp = (void *) gatt_buf.buf; - struct gatt_descriptor *dsc; - const ble_uuid_any_t *uuid; - uint8_t uuid_length; - - SYS_LOG_DBG(""); - - if (error->status != 0 && error->status != BLE_HS_EDONE) { - tester_rsp(BTP_SERVICE_ID_GATT, GATT_DISC_ALL_DESC, - CONTROLLER_INDEX, BTP_STATUS_FAILED); - discover_destroy(); - return 0; - } - - if (error->status == BLE_HS_EDONE) { - tester_send(BTP_SERVICE_ID_GATT, GATT_DISC_ALL_DESC, - CONTROLLER_INDEX, gatt_buf.buf, gatt_buf.len); - discover_destroy(); - return 0; - } - - uuid = &gatt_dsc->uuid; - uuid_length = (uint8_t) (uuid->u.type == BLE_UUID_TYPE_16 ? 2 : 16); - - dsc = gatt_buf_reserve(sizeof(*dsc) + uuid_length); - if (!dsc) { - tester_rsp(BTP_SERVICE_ID_GATT, GATT_DISC_ALL_DESC, - CONTROLLER_INDEX, BTP_STATUS_FAILED); - discover_destroy(); - return BLE_HS_ENOMEM; - } - - dsc->descriptor_handle = sys_cpu_to_le16(gatt_dsc->handle); - dsc->uuid_length = uuid_length; - - if (uuid->u.type == BLE_UUID_TYPE_16) { - uint16_t u16 = sys_cpu_to_le16(BLE_UUID16(uuid)->value); - memcpy(dsc->uuid, &u16, uuid_length); - } else { - memcpy(dsc->uuid, BLE_UUID128(uuid)->value, uuid_length); - } - - rp->descriptors_count++; - - return 0; -} - -static void disc_all_prim_svcs(uint8_t *data, uint16_t len) -{ - struct ble_gap_conn_desc conn; - int rc; - - SYS_LOG_DBG(""); - - rc = ble_gap_conn_find_by_addr((ble_addr_t *)data, &conn); - if (rc) { - goto fail; - } - - if (!gatt_buf_reserve(sizeof(struct gatt_disc_all_prim_svcs_rp))) { - goto fail; - } - - if (ble_gattc_disc_all_svcs(conn.conn_handle, disc_prim_uuid_cb, - (void *) GATT_DISC_ALL_PRIM_SVCS)) { - discover_destroy(); - goto fail; - } - - return; - -fail: - tester_rsp(BTP_SERVICE_ID_GATT, GATT_DISC_ALL_PRIM_SVCS, - CONTROLLER_INDEX, BTP_STATUS_FAILED); -} - -static void disc_all_desc(uint8_t *data, uint16_t len) -{ - const struct gatt_disc_all_desc_cmd *cmd = (void *) data; - struct ble_gap_conn_desc conn; - uint16_t start_handle, end_handle; - int rc; - - SYS_LOG_DBG(""); - - rc = ble_gap_conn_find_by_addr((ble_addr_t *)data, &conn); - if (rc) { - goto fail; - } - - if (!gatt_buf_reserve(sizeof(struct gatt_disc_all_desc_rp))) { - goto fail; - } - - start_handle = sys_le16_to_cpu(cmd->start_handle) - 1; - end_handle = sys_le16_to_cpu(cmd->end_handle); - - rc = ble_gattc_disc_all_dscs(conn.conn_handle, start_handle, end_handle, - disc_all_desc_cb, NULL); - - SYS_LOG_DBG("rc=%d", rc); - - if (rc) { - discover_destroy(); - goto fail; - } - - return; - -fail: - tester_rsp(BTP_SERVICE_ID_GATT, GATT_DISC_ALL_DESC, CONTROLLER_INDEX, - BTP_STATUS_FAILED); -} - -static int find_included_cb(uint16_t conn_handle, - const struct ble_gatt_error *error, - const struct ble_gatt_svc *gatt_svc, void *arg) -{ - struct gatt_find_included_rp *rp = (void *) gatt_buf.buf; - struct gatt_included *included; - const ble_uuid_any_t *uuid; - int service_handle = (int) arg; - uint8_t uuid_length; - - SYS_LOG_DBG(""); - - if (error->status != 0 && error->status != BLE_HS_EDONE) { - tester_rsp(BTP_SERVICE_ID_GATT, GATT_FIND_INCLUDED, - CONTROLLER_INDEX, BTP_STATUS_FAILED); - discover_destroy(); - return 0; - } - - if (error->status == BLE_HS_EDONE) { - tester_send(BTP_SERVICE_ID_GATT, GATT_FIND_INCLUDED, - CONTROLLER_INDEX, gatt_buf.buf, gatt_buf.len); - discover_destroy(); - return 0; - } - - uuid = &gatt_svc->uuid; - uuid_length = (uint8_t) (uuid->u.type == BLE_UUID_TYPE_16 ? 2 : 16); - - - included = gatt_buf_reserve(sizeof(*included) + uuid_length); - if (!included) { - tester_rsp(BTP_SERVICE_ID_GATT, GATT_FIND_INCLUDED, - CONTROLLER_INDEX, BTP_STATUS_FAILED); - discover_destroy(); - return BLE_HS_ENOMEM; - } - - /* FIXME */ - included->included_handle = sys_cpu_to_le16(service_handle + 1 + - rp->services_count); - included->service.start_handle = sys_cpu_to_le16(gatt_svc->start_handle); - included->service.end_handle = sys_cpu_to_le16(gatt_svc->end_handle); - included->service.uuid_length = uuid_length; - - if (uuid->u.type == BLE_UUID_TYPE_16) { - uint16_t u16 = sys_cpu_to_le16(BLE_UUID16(uuid)->value); - memcpy(included->service.uuid, &u16, uuid_length); - } else { - memcpy(included->service.uuid, BLE_UUID128(uuid)->value, - uuid_length); - } - - rp->services_count++; - - return 0; -} - -static int disc_chrc_cb(uint16_t conn_handle, - const struct ble_gatt_error *error, - const struct ble_gatt_chr *gatt_chr, void *arg) -{ - struct gatt_disc_chrc_rp *rp = (void *) gatt_buf.buf; - struct gatt_characteristic *chrc; - const ble_uuid_any_t *uuid; - uint8_t btp_opcode = (uint8_t) (int) arg; - uint8_t uuid_length; - - SYS_LOG_DBG(""); - - if (error->status != 0 && error->status != BLE_HS_EDONE) { - tester_rsp(BTP_SERVICE_ID_GATT, btp_opcode, - CONTROLLER_INDEX, BTP_STATUS_FAILED); - discover_destroy(); - return 0; - } - - if (error->status == BLE_HS_EDONE) { - tester_send(BTP_SERVICE_ID_GATT, btp_opcode, - CONTROLLER_INDEX, gatt_buf.buf, gatt_buf.len); - discover_destroy(); - return 0; - } - - uuid = &gatt_chr->uuid; - uuid_length = (uint8_t) (uuid->u.type == BLE_UUID_TYPE_16 ? 2 : 16); - - chrc = gatt_buf_reserve(sizeof(*chrc) + uuid_length); - if (!chrc) { - tester_rsp(BTP_SERVICE_ID_GATT, btp_opcode, - CONTROLLER_INDEX, BTP_STATUS_FAILED); - discover_destroy(); - return BLE_HS_ENOMEM; - } - - chrc->characteristic_handle = sys_cpu_to_le16(gatt_chr->def_handle); - chrc->properties = gatt_chr->properties; - chrc->value_handle = sys_cpu_to_le16(gatt_chr->val_handle); - chrc->uuid_length = uuid_length; - - if (uuid->u.type == BLE_UUID_TYPE_16) { - uint16_t u16 = sys_cpu_to_le16(BLE_UUID16(uuid)->value); - memcpy(chrc->uuid, &u16, uuid_length); - } else { - memcpy(chrc->uuid, BLE_UUID128(uuid)->value, - uuid_length); - } - - rp->characteristics_count++; - - return 0; -} - -static void disc_chrc_uuid(uint8_t *data, uint16_t len) -{ - const struct gatt_disc_chrc_uuid_cmd *cmd = (void *) data; - struct ble_gap_conn_desc conn; - uint16_t start_handle, end_handle; - ble_uuid_any_t uuid; - int rc; - - SYS_LOG_DBG(""); - - rc = ble_gap_conn_find_by_addr((ble_addr_t *)data, &conn); - if (rc) { - goto fail; - } - - if (btp2bt_uuid(cmd->uuid, cmd->uuid_length, &uuid)) { - goto fail; - } - - if (!gatt_buf_reserve(sizeof(struct gatt_disc_chrc_rp))) { - goto fail; - } - - start_handle = sys_le16_to_cpu(cmd->start_handle); - end_handle = sys_le16_to_cpu(cmd->end_handle); - - if (ble_gattc_disc_chrs_by_uuid(conn.conn_handle, start_handle, - end_handle, &uuid.u, disc_chrc_cb, - (void *)GATT_DISC_CHRC_UUID)) { - discover_destroy(); - goto fail; - } - - return; - -fail: - tester_rsp(BTP_SERVICE_ID_GATT, GATT_DISC_CHRC_UUID, CONTROLLER_INDEX, - BTP_STATUS_FAILED); -} - -static void disc_prim_uuid(uint8_t *data, uint16_t len) -{ - const struct gatt_disc_prim_uuid_cmd *cmd = (void *) data; - struct ble_gap_conn_desc conn; - ble_uuid_any_t uuid; - int rc; - - SYS_LOG_DBG(""); - - rc = ble_gap_conn_find_by_addr((ble_addr_t *)data, &conn); - if (rc) { - goto fail; - } - - if (btp2bt_uuid(cmd->uuid, cmd->uuid_length, &uuid)) { - goto fail; - } - - if (!gatt_buf_reserve(sizeof(struct gatt_disc_prim_uuid_rp))) { - goto fail; - } - - if (ble_gattc_disc_svc_by_uuid(conn.conn_handle, - &uuid.u, disc_prim_uuid_cb, - (void *) GATT_DISC_PRIM_UUID)) { - discover_destroy(); - goto fail; - } - - return; - -fail: - tester_rsp(BTP_SERVICE_ID_GATT, GATT_DISC_PRIM_UUID, CONTROLLER_INDEX, - BTP_STATUS_FAILED); -} - -static void disc_all_chrc(uint8_t *data, uint16_t len) -{ - const struct gatt_disc_all_chrc_cmd *cmd = (void *) data; - struct ble_gap_conn_desc conn; - uint16_t start_handle, end_handle; - int rc; - - SYS_LOG_DBG(""); - - rc = ble_gap_conn_find_by_addr((ble_addr_t *)data, &conn); - if (rc) { - SYS_LOG_DBG("Conn find failed"); - goto fail; - } - - if (!gatt_buf_reserve(sizeof(struct gatt_disc_chrc_rp))) { - SYS_LOG_DBG("Buf reserve failed"); - goto fail; - } - - start_handle = sys_le16_to_cpu(cmd->start_handle); - end_handle = sys_le16_to_cpu(cmd->end_handle); - - rc = ble_gattc_disc_all_chrs(conn.conn_handle, start_handle, end_handle, - disc_chrc_cb, (void *)GATT_DISC_ALL_CHRC); - if (rc) { - discover_destroy(); - goto fail; - } - - return; - -fail: - tester_rsp(BTP_SERVICE_ID_GATT, GATT_DISC_ALL_CHRC, CONTROLLER_INDEX, - BTP_STATUS_FAILED); -} - -static void find_included(uint8_t *data, uint16_t len) -{ - const struct gatt_find_included_cmd *cmd = (void *) data; - struct ble_gap_conn_desc conn; - uint16_t start_handle, end_handle; - int service_handle_arg; - int rc; - - SYS_LOG_DBG(""); - - rc = ble_gap_conn_find_by_addr((ble_addr_t *)data, &conn); - if (rc) { - goto fail; - } - - if (!gatt_buf_reserve(sizeof(struct gatt_find_included_rp))) { - goto fail; - } - - start_handle = sys_le16_to_cpu(cmd->start_handle); - end_handle = sys_le16_to_cpu(cmd->end_handle); - service_handle_arg = start_handle; - - if (ble_gattc_find_inc_svcs(conn.conn_handle, start_handle, end_handle, - find_included_cb, - (void *)service_handle_arg)) { - discover_destroy(); - goto fail; - } - - return; - -fail: - tester_rsp(BTP_SERVICE_ID_GATT, GATT_FIND_INCLUDED, CONTROLLER_INDEX, - BTP_STATUS_FAILED); -} - -static int exchange_func(uint16_t conn_handle, - const struct ble_gatt_error *error, - uint16_t mtu, void *arg) -{ - SYS_LOG_DBG(""); - - if (error->status) { - tester_rsp(BTP_SERVICE_ID_GATT, GATT_EXCHANGE_MTU, - CONTROLLER_INDEX, BTP_STATUS_FAILED); - - return 0; -} - - tester_rsp(BTP_SERVICE_ID_GATT, GATT_EXCHANGE_MTU, CONTROLLER_INDEX, - BTP_STATUS_SUCCESS); - - return 0; -} - -static void exchange_mtu(uint8_t *data, uint16_t len) -{ - struct ble_gap_conn_desc conn; - int rc; - - SYS_LOG_DBG(""); - - rc = ble_gap_conn_find_by_addr((ble_addr_t *)data, &conn); - if (rc) { - goto fail; - } - - if (ble_gattc_exchange_mtu(conn.conn_handle, exchange_func, NULL)) { - goto fail; - } - - return; -fail: - tester_rsp(BTP_SERVICE_ID_GATT, GATT_EXCHANGE_MTU, - CONTROLLER_INDEX, BTP_STATUS_FAILED); -} - -static int enable_subscription(uint16_t conn_handle, uint16_t ccc_handle, - uint16_t value) -{ - uint8_t op; - - SYS_LOG_DBG(""); - - op = (uint8_t) (value == 0x0001 ? GATT_CFG_NOTIFY : GATT_CFG_INDICATE); - - if (ble_gattc_write_flat(conn_handle, ccc_handle, - &value, sizeof(value), NULL, NULL)) { - return -EINVAL; - } - - subscribe_params.ccc_handle = value; - - tester_rsp(BTP_SERVICE_ID_GATT, op, CONTROLLER_INDEX, - BTP_STATUS_SUCCESS); - return 0; -} - -static int disable_subscription(uint16_t conn_handle, uint16_t ccc_handle) -{ - uint16_t value = 0x00; - - SYS_LOG_DBG(""); - - /* Fail if CCC handle doesn't match */ - if (ccc_handle != subscribe_params.ccc_handle) { - SYS_LOG_ERR("CCC handle doesn't match"); - return -EINVAL; - } - - if (ble_gattc_write_no_rsp_flat(conn_handle, ccc_handle, - &value, sizeof(value))) { - return -EINVAL; - } - - subscribe_params.ccc_handle = 0; - return 0; -} - -static void config_subscription(uint8_t *data, uint16_t len, uint8_t op) -{ - const struct gatt_cfg_notify_cmd *cmd = (void *) data; - struct ble_gap_conn_desc conn; - uint16_t ccc_handle = sys_le16_to_cpu(cmd->ccc_handle); - uint8_t status; - int rc; - - SYS_LOG_DBG(""); - - rc = ble_gap_conn_find_by_addr((ble_addr_t *)data, &conn); - if (rc) { - tester_rsp(BTP_SERVICE_ID_GATT, op, CONTROLLER_INDEX, - BTP_STATUS_FAILED); - return; - } - - if (cmd->enable) { - uint16_t value; - - if (op == GATT_CFG_NOTIFY) { - value = 0x0001; - } else { - value = 0x0002; - } - - /* on success response will be sent from callback */ - if (enable_subscription(conn.conn_handle, - ccc_handle, value) == 0) { - return; - } - - status = BTP_STATUS_FAILED; - } else { - if (disable_subscription(conn.conn_handle, ccc_handle) < 0) { - status = BTP_STATUS_FAILED; - } else { - status = BTP_STATUS_SUCCESS; - } - } - - SYS_LOG_DBG("Config subscription (op %u) status %u", op, status); - - tester_rsp(BTP_SERVICE_ID_GATT, op, CONTROLLER_INDEX, status); -} - -#define BTP_PERM_F_READ 0x01 -#define BTP_PERM_F_WRITE 0x02 -#define BTP_PERM_F_READ_ENC 0x04 -#define BTP_PERM_F_WRITE_ENC 0x08 -#define BTP_PERM_F_READ_AUTHEN 0x10 -#define BTP_PERM_F_WRITE_AUTHEN 0x20 -#define BTP_PERM_F_READ_AUTHOR 0x40 -#define BTP_PERM_F_WRITE_AUTHOR 0x80 - -static int flags_hs2btp_map[] = { - BTP_PERM_F_READ, - BTP_PERM_F_WRITE, - BTP_PERM_F_READ_ENC, - BTP_PERM_F_READ_AUTHEN, - BTP_PERM_F_READ_AUTHOR, - BTP_PERM_F_WRITE_ENC, - BTP_PERM_F_WRITE_AUTHEN, - BTP_PERM_F_WRITE_AUTHOR, -}; - -static uint8_t flags_hs2btp(uint8_t flags) -{ - int i; - uint8_t ret = 0; - - for (i = 0; i < 8; ++i) { - if (flags & BIT(i)) { - ret |= flags_hs2btp_map[i]; - } - } - - return ret; -} - -static void get_attrs(uint8_t *data, uint16_t len) -{ - const struct gatt_get_attributes_cmd *cmd = (void *) data; - struct gatt_get_attributes_rp *rp; - struct gatt_attr *gatt_attr; - struct os_mbuf *buf = os_msys_get(0, 0); - uint16_t start_handle, end_handle; - struct ble_att_svr_entry *entry = NULL; - ble_uuid_any_t uuid; - ble_uuid_t *uuid_ptr = NULL; - uint8_t count = 0; - char str[BLE_UUID_STR_LEN]; - - SYS_LOG_DBG(""); - - memset(str, 0, sizeof(str)); - memset(&uuid, 0, sizeof(uuid)); - start_handle = sys_le16_to_cpu(cmd->start_handle); - end_handle = sys_le16_to_cpu(cmd->end_handle); - - if (cmd->type_length) { - if (btp2bt_uuid(cmd->type, cmd->type_length, &uuid)) { - goto fail; - } - - ble_uuid_to_str(&uuid.u, str); - SYS_LOG_DBG("start 0x%04x end 0x%04x, uuid %s", start_handle, - end_handle, str); - - uuid_ptr = &uuid.u; - } else { - SYS_LOG_DBG("start 0x%04x end 0x%04x", start_handle, end_handle); - } - - net_buf_simple_init(buf, 0); - rp = net_buf_simple_add(buf, sizeof(*rp)); - - entry = ble_att_svr_find_by_uuid(entry, uuid_ptr, end_handle); - while (entry) { - - if (entry->ha_handle_id < start_handle) { - entry = ble_att_svr_find_by_uuid(entry, - uuid_ptr, end_handle); - continue; - } - - gatt_attr = net_buf_simple_add(buf, sizeof(*gatt_attr)); - gatt_attr->handle = sys_cpu_to_le16(entry->ha_handle_id); - gatt_attr->permission = flags_hs2btp(entry->ha_flags); - - if (entry->ha_uuid->type == BLE_UUID_TYPE_16) { - gatt_attr->type_length = 2; - net_buf_simple_add_le16(buf, - BLE_UUID16(entry->ha_uuid)->value); - } else { - gatt_attr->type_length = 16; - net_buf_simple_add_mem(buf, - BLE_UUID128(entry->ha_uuid)->value, - gatt_attr->type_length); - } - - count++; - - entry = ble_att_svr_find_by_uuid(entry, uuid_ptr, end_handle); - } - - rp->attrs_count = count; - - tester_send_buf(BTP_SERVICE_ID_GATT, GATT_GET_ATTRIBUTES, - CONTROLLER_INDEX, buf); - - goto free; -fail: - tester_rsp(BTP_SERVICE_ID_GATT, GATT_GET_ATTRIBUTES, CONTROLLER_INDEX, - BTP_STATUS_FAILED); -free: - os_mbuf_free_chain(buf); -} - -static void get_attr_val(uint8_t *data, uint16_t len) -{ - const struct gatt_get_attribute_value_cmd *cmd = (void *) data; - struct gatt_get_attribute_value_rp *rp; - struct ble_gap_conn_desc conn; - struct os_mbuf *buf = os_msys_get(0, 0); - uint16_t handle = sys_cpu_to_le16(cmd->handle); - uint8_t out_att_err; - int conn_status; - - conn_status = ble_gap_conn_find_by_addr((ble_addr_t *)data, &conn); - - if (conn_status) { - net_buf_simple_init(buf, 0); - rp = net_buf_simple_add(buf, sizeof(*rp)); - - ble_att_svr_read_handle(BLE_HS_CONN_HANDLE_NONE, - handle, 0, buf, - &out_att_err); - - rp->att_response = out_att_err; - rp->value_length = os_mbuf_len(buf) - sizeof(*rp); - - tester_send_buf(BTP_SERVICE_ID_GATT, GATT_GET_ATTRIBUTE_VALUE, - CONTROLLER_INDEX, buf); - - goto free; - } else { - net_buf_simple_init(buf, 0); - rp = net_buf_simple_add(buf, sizeof(*rp)); - - ble_att_svr_read_handle(conn.conn_handle, - handle, 0, buf, - &out_att_err); - - rp->att_response = out_att_err; - rp->value_length = os_mbuf_len(buf) - sizeof(*rp); - - tester_send_buf(BTP_SERVICE_ID_GATT, GATT_GET_ATTRIBUTE_VALUE, - CONTROLLER_INDEX, buf); - - goto free; - } - -free: - os_mbuf_free_chain(buf); -} - -static void change_database(uint8_t *data, uint16_t len) -{ - const struct gatt_change_database *cmd = (void *) data; - - SYS_LOG_DBG("") - - ble_gatts_show_local(); - - ble_svc_gatt_changed(cmd->start_handle, cmd->end_handle); - - tester_rsp(BTP_SERVICE_ID_GATT, GATT_CHANGE_DATABASE, CONTROLLER_INDEX, - BTP_STATUS_SUCCESS); - - return; -} - -static void supported_commands(uint8_t *data, uint16_t len) -{ - uint8_t cmds[4]; - struct gatt_read_supported_commands_rp *rp = (void *) cmds; - - SYS_LOG_DBG(""); - - memset(cmds, 0, sizeof(cmds)); - - tester_set_bit(cmds, GATT_READ_SUPPORTED_COMMANDS); - tester_set_bit(cmds, GATT_START_SERVER); - tester_set_bit(cmds, GATT_EXCHANGE_MTU); - tester_set_bit(cmds, GATT_DISC_ALL_PRIM_SVCS); - tester_set_bit(cmds, GATT_DISC_PRIM_UUID); - tester_set_bit(cmds, GATT_FIND_INCLUDED); - tester_set_bit(cmds, GATT_DISC_ALL_CHRC); - tester_set_bit(cmds, GATT_DISC_CHRC_UUID); - tester_set_bit(cmds, GATT_DISC_ALL_DESC); - tester_set_bit(cmds, GATT_READ); - tester_set_bit(cmds, GATT_READ_LONG); - tester_set_bit(cmds, GATT_READ_MULTIPLE); - tester_set_bit(cmds, GATT_WRITE_WITHOUT_RSP); -#if 0 - tester_set_bit(cmds, GATT_SIGNED_WRITE_WITHOUT_RSP); -#endif - tester_set_bit(cmds, GATT_WRITE); - tester_set_bit(cmds, GATT_WRITE_LONG); - tester_set_bit(cmds, GATT_CFG_NOTIFY); - tester_set_bit(cmds, GATT_CFG_INDICATE); - tester_set_bit(cmds, GATT_GET_ATTRIBUTES); - tester_set_bit(cmds, GATT_GET_ATTRIBUTE_VALUE); - tester_set_bit(cmds, GATT_CHANGE_DATABASE); - - tester_send(BTP_SERVICE_ID_GATT, GATT_READ_SUPPORTED_COMMANDS, - CONTROLLER_INDEX, (uint8_t *) rp, sizeof(cmds)); -} - -enum attr_type { - BLE_GATT_ATTR_SVC = 0, - BLE_GATT_ATTR_CHR, - BLE_GATT_ATTR_DSC, -}; - -void tester_handle_gatt(uint8_t opcode, uint8_t index, uint8_t *data, - uint16_t len) -{ - switch (opcode) { - case GATT_READ_SUPPORTED_COMMANDS: - supported_commands(data, len); - return; - case GATT_START_SERVER: - start_server(data, len); - return; - case GATT_EXCHANGE_MTU: - exchange_mtu(data, len); - return; - case GATT_DISC_ALL_PRIM_SVCS: - disc_all_prim_svcs(data, len); - return; - case GATT_DISC_PRIM_UUID: - disc_prim_uuid(data, len); - return; - case GATT_FIND_INCLUDED: - find_included(data, len); - return; - case GATT_DISC_ALL_CHRC: - disc_all_chrc(data, len); - return; - case GATT_DISC_CHRC_UUID: - disc_chrc_uuid(data, len); - return; - case GATT_DISC_ALL_DESC: - disc_all_desc(data, len); - return; - case GATT_CHANGE_DATABASE: - change_database(data, len); - return; - case GATT_READ: - read(data, len); - return; - case GATT_READ_UUID: - read_uuid(data, len); - return; - case GATT_READ_LONG: - read_long(data, len); - return; - case GATT_READ_MULTIPLE: - read_multiple(data, len); - return; - case GATT_WRITE_WITHOUT_RSP: - write_without_rsp(data, len, opcode, false); - return; -#if 0 - case GATT_SIGNED_WRITE_WITHOUT_RSP: - write_without_rsp(data, len, opcode, true); - return; -#endif - case GATT_WRITE: - write(data, len); - return; - case GATT_WRITE_LONG: - write_long(data, len); - return; - case GATT_RELIABLE_WRITE: - reliable_write(data, len); - return; - case GATT_CFG_NOTIFY: - case GATT_CFG_INDICATE: - config_subscription(data, len, opcode); - return; - case GATT_GET_ATTRIBUTES: - get_attrs(data, len); - return; - case GATT_GET_ATTRIBUTE_VALUE: - get_attr_val(data, len); - return; - default: - tester_rsp(BTP_SERVICE_ID_GATT, opcode, index, - BTP_STATUS_UNKNOWN_CMD); - return; - } -} - -int tester_gatt_notify_rx_ev(uint16_t conn_handle, uint16_t attr_handle, - uint8_t indication, struct os_mbuf *om) -{ - struct gatt_notification_ev *ev; - struct ble_gap_conn_desc conn; - struct os_mbuf *buf = os_msys_get(0, 0); - const ble_addr_t *addr; - - SYS_LOG_DBG(""); - - if (!subscribe_params.ccc_handle) { - goto fail; - } - - if (ble_gap_conn_find(conn_handle, &conn)) { - goto fail; - } - - net_buf_simple_init(buf, 0); - ev = net_buf_simple_add(buf, sizeof(*ev)); - - addr = &conn.peer_ota_addr; - - ev->address_type = addr->type; - memcpy(ev->address, addr->val, sizeof(ev->address)); - ev->type = (uint8_t) (indication ? 0x02 : 0x01); - ev->handle = sys_cpu_to_le16(attr_handle); - ev->data_length = sys_cpu_to_le16(os_mbuf_len(om)); - os_mbuf_appendfrom(buf, om, 0, os_mbuf_len(om)); - - tester_send_buf(BTP_SERVICE_ID_GATT, GATT_EV_NOTIFICATION, - CONTROLLER_INDEX, buf); - -fail: - os_mbuf_free_chain(buf); - return 0; -} - -void notify_test_stop(void) -{ - os_callout_stop(¬ify_tx_timer); -} - -void notify_test_reset(void) -{ - int rc; - - rc = os_callout_reset(¬ify_tx_timer, OS_TICKS_PER_SEC); - assert(rc == 0); -} - -void notify_test(struct os_event *ev) -{ - static uint8_t ntf[1]; - struct os_mbuf *om; - int rc; - - if (!notify_state && !indicate_state) { - notify_test_stop(); - notify_value = 90; - return; - } - - ntf[0] = notify_value; - - notify_value++; - if (notify_value == 160) { - notify_value = 90; - } - - om = ble_hs_mbuf_from_flat(ntf, sizeof(ntf)); - - if (notify_state) { - rc = ble_gattc_notify_custom(myconn_handle, notify_handle, om); - assert(rc == 0); - } - - if (indicate_state) { - rc = ble_gattc_indicate_custom(myconn_handle, notify_handle, om); - assert(rc == 0); - } -} - -int tester_gatt_subscribe_ev(uint16_t conn_handle, uint16_t attr_handle, uint8_t reason, - uint8_t prev_notify, uint8_t cur_notify, - uint8_t prev_indicate, uint8_t cur_indicate) -{ - SYS_LOG_DBG(""); - myconn_handle = conn_handle; - - if (cur_notify == 0 && cur_indicate == 0) { - SYS_LOG_INF("Unsubscribed"); - memset(&subscribe_params, 0, sizeof(subscribe_params)); - return 0; - } - - if (cur_notify) { - SYS_LOG_INF("Subscribed to notifications"); - if (attr_handle == notify_handle) { - notify_state = cur_notify; - } - } - - if (cur_indicate) { - SYS_LOG_INF("Subscribed to indications"); - if (attr_handle == notify_handle) { - indicate_state = cur_indicate; - } - } - - - if (notify_state || indicate_state) { - notify_test_reset(); - } else { - notify_test_stop(); - } - - return 0; -} - -void -gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg) -{ - char buf[BLE_UUID_STR_LEN]; - - switch (ctxt->op) { - case BLE_GATT_REGISTER_OP_SVC: - MODLOG_DFLT(DEBUG, "registered service %s with handle=%d\n", - ble_uuid_to_str(ctxt->svc.svc_def->uuid, buf), - ctxt->svc.handle); - break; - - case BLE_GATT_REGISTER_OP_CHR: - MODLOG_DFLT(DEBUG, "registering characteristic %s with " - "def_handle=%d val_handle=%d\n", - ble_uuid_to_str(ctxt->chr.chr_def->uuid, buf), - ctxt->chr.def_handle, - ctxt->chr.val_handle); - break; - - case BLE_GATT_REGISTER_OP_DSC: - MODLOG_DFLT(DEBUG, "registering descriptor %s with handle=%d\n", - ble_uuid_to_str(ctxt->dsc.dsc_def->uuid, buf), - ctxt->dsc.handle); - break; - - default: - assert(0); - break; - } -} - -int gatt_svr_init(void) -{ - int rc; - - rc = ble_gatts_count_cfg(gatt_svr_inc_svcs); - if (rc != 0) { - return rc; - } - - rc = ble_gatts_add_svcs(gatt_svr_inc_svcs); - if (rc != 0) { - return rc; - } - - rc = ble_gatts_count_cfg(gatt_svr_svcs); - if (rc != 0) { - return rc; - } - - rc = ble_gatts_add_svcs(gatt_svr_svcs); - if (rc != 0) { - return rc; - } - - return 0; -} - -uint8_t tester_init_gatt(void) -{ - os_callout_init(¬ify_tx_timer, os_eventq_dflt_get(), - notify_test, NULL); - - return BTP_STATUS_SUCCESS; -} - -uint8_t tester_unregister_gatt(void) -{ - return BTP_STATUS_SUCCESS; -} diff --git a/apps/bttester/src/glue.c b/apps/bttester/src/glue.c deleted file mode 100644 index 3e606062a3..0000000000 --- a/apps/bttester/src/glue.c +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#include "syscfg/syscfg.h" - -#if !MYNEWT_VAL(BLE_MESH) -#include -#include -#include "os/os.h" -#include "os/os_mbuf.h" -#include "glue.h" - - -#define ASSERT_NOT_CHAIN(om) assert(SLIST_NEXT(om, om_next) == NULL) - -const char *bt_hex(const void *buf, size_t len) -{ - static const char hex[] = "0123456789abcdef"; - static char hexbufs[4][137]; - static uint8_t curbuf; - const uint8_t *b = buf; - char *str; - int i; - - str = hexbufs[curbuf++]; - curbuf %= ARRAY_SIZE(hexbufs); - - len = min(len, (sizeof(hexbufs[0]) - 1) / 2); - - for (i = 0; i < len; i++) { - str[i * 2] = hex[b[i] >> 4]; - str[i * 2 + 1] = hex[b[i] & 0xf]; - } - - str[i * 2] = '\0'; - - return str; -} - -struct os_mbuf * NET_BUF_SIMPLE(uint16_t size) -{ - struct os_mbuf *buf; - - buf = os_msys_get(size, 0); - assert(buf); - - return buf; -} - -/* This is by purpose */ -void net_buf_simple_init(struct os_mbuf *buf, - size_t reserve_head) -{ - /* This is called in Zephyr after init. - * Note in Mynewt case we don't care abour reserved head*/ - buf->om_data = &buf->om_databuf[buf->om_pkthdr_len] + reserve_head; - buf->om_len = 0; -} - -void -net_buf_simple_add_le16(struct os_mbuf *om, uint16_t val) -{ - val = htole16(val); - os_mbuf_append(om, &val, sizeof(val)); - ASSERT_NOT_CHAIN(om); -} - -void -net_buf_simple_add_be16(struct os_mbuf *om, uint16_t val) -{ - val = htobe16(val); - os_mbuf_append(om, &val, sizeof(val)); - ASSERT_NOT_CHAIN(om); -} - -void -net_buf_simple_add_be32(struct os_mbuf *om, uint32_t val) -{ - val = htobe32(val); - os_mbuf_append(om, &val, sizeof(val)); - ASSERT_NOT_CHAIN(om); -} - -void -net_buf_simple_add_u8(struct os_mbuf *om, uint8_t val) -{ - os_mbuf_append(om, &val, 1); - ASSERT_NOT_CHAIN(om); -} - -void* -net_buf_simple_add(struct os_mbuf *om, uint8_t len) -{ - void * tmp; - - tmp = os_mbuf_extend(om, len); - ASSERT_NOT_CHAIN(om); - - return tmp; -} - -uint8_t * -net_buf_simple_push(struct os_mbuf *om, uint8_t len) -{ - uint8_t headroom = om->om_data - &om->om_databuf[om->om_pkthdr_len]; - - assert(headroom >= len); - om->om_data -= len; - om->om_len += len; - - return om->om_data; -} -#endif diff --git a/apps/bttester/src/glue.h b/apps/bttester/src/glue.h deleted file mode 100644 index 6508560151..0000000000 --- a/apps/bttester/src/glue.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef __GLUE_H__ -#define __GLUE_H__ - -#include "os/endian.h" - -#define uint8_t uint8_t -#define int8_t int8_t -#define uint16_t uint16_t -#define uint32_t uint32_t -#define int32_t int32_t - -#ifndef BIT -#define BIT(n) (1UL << (n)) -#endif - -#define __packed __attribute__((__packed__)) - -#define sys_le16_to_cpu le16toh - -struct bt_data { - uint8_t type; - uint8_t data_len; - const uint8_t *data; -}; - -#define BT_DATA(_type, _data, _data_len) \ - { \ - .type = (_type), \ - .data_len = (_data_len), \ - .data = (const uint8_t *)(_data), \ - } - -struct os_mbuf * NET_BUF_SIMPLE(uint16_t size); -void net_buf_simple_init(struct os_mbuf *buf, size_t reserve_head); -void net_buf_simple_add_le16(struct os_mbuf *om, uint16_t val); -void net_buf_simple_add_u8(struct os_mbuf *om, uint8_t val); -void *net_buf_simple_add(struct os_mbuf *om, uint8_t len); -uint8_t *net_buf_simple_push(struct os_mbuf *om, uint8_t len); - -#define net_buf_simple_add_mem(a,b,c) os_mbuf_append(a,b,c) - -const char *bt_hex(const void *buf, size_t len); - -#endif /* __GLUE_H__ */ diff --git a/apps/bttester/src/l2cap.c b/apps/bttester/src/l2cap.c deleted file mode 100644 index b9b97ec199..0000000000 --- a/apps/bttester/src/l2cap.c +++ /dev/null @@ -1,701 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -/* l2cap.c - Bluetooth L2CAP Tester */ - -/* - * Copyright (c) 2016 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "syscfg/syscfg.h" - -#if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) - -#include "console/console.h" -#include "host/ble_gap.h" -#include "host/ble_l2cap.h" - -#include "../../../nimble/host/src/ble_l2cap_priv.h" - -#include "bttester.h" - -#define CONTROLLER_INDEX 0 -#define CHANNELS MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) -#define TESTER_COC_MTU MYNEWT_VAL(BTTESTER_L2CAP_COC_MTU) -#define TESTER_COC_BUF_COUNT (3 * MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM)) - -static os_membuf_t tester_sdu_coc_mem[ - OS_MEMPOOL_SIZE(TESTER_COC_BUF_COUNT, TESTER_COC_MTU) -]; - -struct os_mbuf_pool sdu_os_mbuf_pool; -static struct os_mempool sdu_coc_mbuf_mempool; - -static struct channel { - uint8_t chan_id; /* Internal number that identifies L2CAP channel. */ - uint8_t state; - struct ble_l2cap_chan *chan; -} channels[CHANNELS]; - -static uint8_t recv_cb_buf[TESTER_COC_MTU + sizeof(struct l2cap_data_received_ev)]; - -static struct channel *get_free_channel(void) -{ - uint8_t i; - struct channel *chan; - - for (i = 0; i < CHANNELS; i++) { - if (channels[i].state) { - continue; - } - - chan = &channels[i]; - chan->chan_id = i; - - return chan; - } - - return NULL; -} - -struct channel *find_channel(struct ble_l2cap_chan *chan) -{ - int i; - - for (i = 0; i < CHANNELS; ++i) { - if (channels[i].chan == chan) { - return &channels[i]; - } - } - - return NULL; -} - -struct channel *get_channel(uint8_t chan_id) -{ - if (chan_id >= CHANNELS) { - return NULL; - } - - return &channels[chan_id]; -} - -static void -tester_l2cap_coc_recv(struct ble_l2cap_chan *chan, struct os_mbuf *sdu) -{ - SYS_LOG_DBG("LE CoC SDU received, chan: 0x%08lx, data len %d", - (uint32_t) chan, OS_MBUF_PKTLEN(sdu)); - - os_mbuf_free_chain(sdu); - sdu = os_mbuf_get_pkthdr(&sdu_os_mbuf_pool, 0); - assert(sdu != NULL); - - ble_l2cap_recv_ready(chan, sdu); -} - -static void recv_cb(uint16_t conn_handle, struct ble_l2cap_chan *chan, - struct os_mbuf *buf, void *arg) -{ - struct l2cap_data_received_ev *ev = (void *) recv_cb_buf; - struct channel *channel = find_channel(chan); - assert(channel != NULL); - - ev->chan_id = channel->chan_id; - ev->data_length = OS_MBUF_PKTLEN(buf); - - if (ev->data_length > TESTER_COC_MTU) { - SYS_LOG_ERR("Too large sdu received, truncating data"); - ev->data_length = TESTER_COC_MTU; - } - os_mbuf_copydata(buf, 0, ev->data_length, ev->data); - - tester_send(BTP_SERVICE_ID_L2CAP, L2CAP_EV_DATA_RECEIVED, - CONTROLLER_INDEX, recv_cb_buf, sizeof(*ev) + ev->data_length); - - tester_l2cap_coc_recv(chan, buf); -} - -static void unstalled_cb(uint16_t conn_handle, struct ble_l2cap_chan *chan, - int status, void *arg) -{ - if (status) { - tester_rsp(BTP_SERVICE_ID_L2CAP, L2CAP_SEND_DATA, - CONTROLLER_INDEX, BTP_STATUS_FAILED); - } else { - tester_rsp(BTP_SERVICE_ID_L2CAP, L2CAP_SEND_DATA, - CONTROLLER_INDEX, BTP_STATUS_SUCCESS); - } -} - -static void reconfigured_ev(uint16_t conn_handle, struct ble_l2cap_chan *chan, - struct ble_l2cap_chan_info *chan_info, - int status) -{ - struct l2cap_reconfigured_ev ev; - struct channel *channel; - - if (status != 0) { - return; - } - - channel = find_channel(chan); - assert(channel != NULL); - - ev.chan_id = channel->chan_id; - ev.peer_mtu = chan_info->peer_coc_mtu; - ev.peer_mps = chan_info->peer_l2cap_mtu; - ev.our_mtu = chan_info->our_coc_mtu; - ev.our_mps = chan_info->our_l2cap_mtu; - - tester_send(BTP_SERVICE_ID_L2CAP, L2CAP_EV_RECONFIGURED, - CONTROLLER_INDEX, (uint8_t *) &ev, sizeof(ev)); -} - -static void connected_cb(uint16_t conn_handle, struct ble_l2cap_chan *chan, - struct ble_l2cap_chan_info *chan_info, void *arg) -{ - struct l2cap_connected_ev ev; - struct ble_gap_conn_desc desc; - struct channel *channel = find_channel(chan); - - if (channel == NULL) { - channel = get_free_channel(); - } - - ev.chan_id = channel->chan_id; - ev.psm = chan_info->psm; - ev.peer_mtu = chan_info->peer_coc_mtu; - ev.peer_mps = chan_info->peer_l2cap_mtu; - ev.our_mtu = chan_info->our_coc_mtu; - ev.our_mps = chan_info->our_l2cap_mtu; - channel->state = 1; - channel->chan = chan; - - if (!ble_gap_conn_find(conn_handle, &desc)) { - ev.address_type = desc.peer_ota_addr.type; - memcpy(ev.address, desc.peer_ota_addr.val, - sizeof(ev.address)); - } - - tester_send(BTP_SERVICE_ID_L2CAP, L2CAP_EV_CONNECTED, CONTROLLER_INDEX, - (uint8_t *) &ev, sizeof(ev)); -} - -static void disconnected_cb(uint16_t conn_handle, struct ble_l2cap_chan *chan, - struct ble_l2cap_chan_info *chan_info, void *arg) -{ - struct l2cap_disconnected_ev ev; - struct ble_gap_conn_desc desc; - struct channel *channel; - - memset(&ev, 0, sizeof(struct l2cap_disconnected_ev)); - - channel = find_channel(chan); - assert(channel != NULL); - - channel->state = 0; - channel->chan = chan; - ev.chan_id = channel->chan_id; - ev.psm = chan_info->psm; - - if (!ble_gap_conn_find(conn_handle, &desc)) { - ev.address_type = desc.peer_ota_addr.type; - memcpy(ev.address, desc.peer_ota_addr.val, - sizeof(ev.address)); - } - - tester_send(BTP_SERVICE_ID_L2CAP, L2CAP_EV_DISCONNECTED, - CONTROLLER_INDEX, (uint8_t *) &ev, sizeof(ev)); -} - -static int accept_cb(uint16_t conn_handle, uint16_t peer_mtu, - struct ble_l2cap_chan *chan) -{ - struct os_mbuf *sdu_rx; - - SYS_LOG_DBG("LE CoC accepting, chan: 0x%08lx, peer_mtu %d", - (uint32_t) chan, peer_mtu); - - sdu_rx = os_mbuf_get_pkthdr(&sdu_os_mbuf_pool, 0); - if (!sdu_rx) { - return BLE_HS_ENOMEM; - } - - ble_l2cap_recv_ready(chan, sdu_rx); - - return 0; -} - -static int -tester_l2cap_event(struct ble_l2cap_event *event, void *arg) -{ - struct ble_l2cap_chan_info chan_info; - int accept_response; - struct ble_gap_conn_desc conn; - - switch (event->type) { - case BLE_L2CAP_EVENT_COC_CONNECTED: - if (ble_l2cap_get_chan_info(event->connect.chan, &chan_info)) { - assert(0); - } - - if (event->connect.status) { - console_printf("LE COC error: %d\n", event->connect.status); - disconnected_cb(event->connect.conn_handle, - event->connect.chan, &chan_info, arg); - return 0; - } - - console_printf("LE COC connected, conn: %d, chan: 0x%08lx, " - "psm: 0x%02x, scid: 0x%04x, dcid: 0x%04x, " - "our_mps: %d, our_mtu: %d, peer_mps: %d, " - "peer_mtu: %d\n", event->connect.conn_handle, - (uint32_t) event->connect.chan, chan_info.psm, - chan_info.scid, chan_info.dcid, - chan_info.our_l2cap_mtu, chan_info.our_coc_mtu, - chan_info.peer_l2cap_mtu, chan_info.peer_coc_mtu); - - connected_cb(event->connect.conn_handle, - event->connect.chan, &chan_info, arg); - - return 0; - case BLE_L2CAP_EVENT_COC_DISCONNECTED: - if (ble_l2cap_get_chan_info(event->disconnect.chan, - &chan_info)) { - assert(0); - } - console_printf("LE CoC disconnected, chan: 0x%08lx\n", - (uint32_t) event->disconnect.chan); - - disconnected_cb(event->disconnect.conn_handle, - event->disconnect.chan, &chan_info, arg); - return 0; - case BLE_L2CAP_EVENT_COC_ACCEPT: - ble_l2cap_get_chan_info(event->accept.chan, &chan_info); - if (chan_info.psm == 0x00F2) { - /* TSPX_psm_authentication_required */ - ble_gap_conn_find(event->accept.conn_handle, &conn); - if (!conn.sec_state.authenticated) { - return BLE_HS_EAUTHEN; - } - } else if (chan_info.psm == 0x00F3) { - /* TSPX_psm_authorization_required */ - ble_gap_conn_find(event->accept.conn_handle, &conn); - if (!conn.sec_state.encrypted) { - return BLE_HS_EAUTHOR; - } - return BLE_HS_EAUTHOR; - } else if (chan_info.psm == 0x00F4) { - /* TSPX_psm_encryption_key_size_required */ - ble_gap_conn_find(event->accept.conn_handle, &conn); - if (conn.sec_state.key_size < 16) { - return BLE_HS_EENCRYPT_KEY_SZ; - } - } - - accept_response = POINTER_TO_INT(arg); - if (accept_response) { - return accept_response; - } - - console_printf("LE CoC accept, chan: 0x%08lx, handle: %u, sdu_size: %u\n", - (uint32_t) event->accept.chan, - event->accept.conn_handle, - event->accept.peer_sdu_size); - - return accept_cb(event->accept.conn_handle, - event->accept.peer_sdu_size, - event->accept.chan); - - case BLE_L2CAP_EVENT_COC_DATA_RECEIVED: - console_printf("LE CoC data received, chan: 0x%08lx, handle: %u, sdu_len: %u\n", - (uint32_t) event->receive.chan, - event->receive.conn_handle, - OS_MBUF_PKTLEN(event->receive.sdu_rx)); - - recv_cb(event->receive.conn_handle, event->receive.chan, - event->receive.sdu_rx, arg); - return 0; - case BLE_L2CAP_EVENT_COC_TX_UNSTALLED: - console_printf("LE CoC tx unstalled, chan: 0x%08lx, handle: %u, status: %d\n", - (uint32_t) event->tx_unstalled.chan, - event->tx_unstalled.conn_handle, - event->tx_unstalled.status); - - unstalled_cb(event->tx_unstalled.conn_handle, - event->tx_unstalled.chan, - event->tx_unstalled.status, arg); - return 0; - case BLE_L2CAP_EVENT_COC_RECONFIG_COMPLETED: - if (ble_l2cap_get_chan_info(event->reconfigured.chan, - &chan_info)) { - assert(0); - } - console_printf("LE CoC reconfigure completed status 0x%02x, " - "chan: 0x%08lx\n", event->reconfigured.status, - (uint32_t) event->reconfigured.chan); - - if (event->reconfigured.status == 0) { - console_printf("\t our_mps: %d our_mtu %d\n", - chan_info.our_l2cap_mtu, chan_info.our_coc_mtu); - } - - reconfigured_ev(event->reconfigured.conn_handle, - event->reconfigured.chan, - &chan_info, - event->reconfigured.status); - return 0; - case BLE_L2CAP_EVENT_COC_PEER_RECONFIGURED: - if (ble_l2cap_get_chan_info(event->reconfigured.chan, - &chan_info)) { - assert(0); - } - console_printf("LE CoC peer reconfigured status 0x%02x, " - "chan: 0x%08lx\n", event->reconfigured.status, - (uint32_t) event->reconfigured.chan); - - if (event->reconfigured.status == 0) { - console_printf("\t peer_mps: %d peer_mtu %d\n", - chan_info.peer_l2cap_mtu, chan_info.peer_coc_mtu); - } - - reconfigured_ev(event->reconfigured.conn_handle, - event->reconfigured.chan, - &chan_info, - event->reconfigured.status); - return 0; - default: - return 0; - } -} - -static void connect(uint8_t *data, uint16_t len) -{ - const struct l2cap_connect_cmd *cmd = (void *) data; - uint8_t rp_buf[sizeof(struct l2cap_connect_rp) + cmd->num]; - struct l2cap_connect_rp *rp = (void *) rp_buf; - struct ble_gap_conn_desc desc; - struct channel *chan; - struct os_mbuf *sdu_rx[cmd->num]; - ble_addr_t *addr = (void *) data; - uint16_t mtu = htole16(cmd->mtu); - int rc; - int i; - - SYS_LOG_DBG("connect: type: %d addr: %s", addr->type, bt_hex(addr->val, 6)); - - if (mtu == 0 || mtu > TESTER_COC_MTU) { - mtu = TESTER_COC_MTU; - } - - rc = ble_gap_conn_find_by_addr(addr, &desc); - if (rc) { - SYS_LOG_ERR("GAP conn find failed"); - goto fail; - } - - rp->num = cmd->num; - - for (i = 0; i < cmd->num; i++) { - chan = get_free_channel(); - if (!chan) { - SYS_LOG_ERR("No free channels"); - goto fail; - } - - rp->chan_ids[i] = chan->chan_id; - - sdu_rx[i] = os_mbuf_get_pkthdr(&sdu_os_mbuf_pool, 0); - if (sdu_rx[i] == NULL) { - SYS_LOG_ERR("Failed to alloc buf"); - goto fail; - } - } - - if (cmd->num == 1) { - rc = ble_l2cap_connect(desc.conn_handle, htole16(cmd->psm), - mtu, sdu_rx[0], - tester_l2cap_event, NULL); - } else if (cmd->num > 1) { - rc = ble_l2cap_enhanced_connect(desc.conn_handle, - htole16(cmd->psm), mtu, - cmd->num, sdu_rx, - tester_l2cap_event, NULL); - } else { - SYS_LOG_ERR("Invalid 'num' parameter value"); - goto fail; - } - - if (rc) { - SYS_LOG_ERR("L2CAP connect failed\n"); - goto fail; - } - - tester_send(BTP_SERVICE_ID_L2CAP, L2CAP_CONNECT, CONTROLLER_INDEX, - (uint8_t *) rp, sizeof(rp_buf)); - - return; - -fail: - tester_rsp(BTP_SERVICE_ID_L2CAP, L2CAP_CONNECT, CONTROLLER_INDEX, - BTP_STATUS_FAILED); -} - -static void disconnect(const uint8_t *data, uint16_t len) -{ - const struct l2cap_disconnect_cmd *cmd = (void *) data; - struct channel *chan; - uint8_t status; - int err; - - SYS_LOG_DBG(""); - - chan = get_channel(cmd->chan_id); - assert(chan != NULL); - - err = ble_l2cap_disconnect(chan->chan); - if (err) { - status = BTP_STATUS_FAILED; - goto rsp; - } - - status = BTP_STATUS_SUCCESS; - -rsp: - tester_rsp(BTP_SERVICE_ID_L2CAP, L2CAP_DISCONNECT, CONTROLLER_INDEX, - status); -} - -static void send_data(const uint8_t *data, uint16_t len) -{ - const struct l2cap_send_data_cmd *cmd = (void *) data; - struct os_mbuf *sdu_tx = NULL; - int rc; - uint16_t data_len = sys_le16_to_cpu(cmd->data_len); - struct channel *chan = get_channel(cmd->chan_id); - - SYS_LOG_DBG("cmd->chan_id=%d", cmd->chan_id); - - if (!chan) { - SYS_LOG_ERR("Invalid channel\n"); - goto fail; - } - - /* FIXME: For now, fail if data length exceeds buffer length */ - if (data_len > TESTER_COC_MTU) { - SYS_LOG_ERR("Data length exceeds buffer length"); - goto fail; - } - - sdu_tx = os_mbuf_get_pkthdr(&sdu_os_mbuf_pool, 0); - if (sdu_tx == NULL) { - SYS_LOG_ERR("No memory in the test sdu pool\n"); - goto fail; - } - - os_mbuf_append(sdu_tx, cmd->data, data_len); - - /* ble_l2cap_send takes ownership of the sdu */ - rc = ble_l2cap_send(chan->chan, sdu_tx); - if (rc == 0 || rc == BLE_HS_ESTALLED) { - tester_rsp(BTP_SERVICE_ID_L2CAP, L2CAP_SEND_DATA, CONTROLLER_INDEX, - BTP_STATUS_SUCCESS); - return; - } - - SYS_LOG_ERR("Unable to send data: %d", rc); - os_mbuf_free_chain(sdu_tx); - -fail: - tester_rsp(BTP_SERVICE_ID_L2CAP, L2CAP_SEND_DATA, CONTROLLER_INDEX, - BTP_STATUS_FAILED); -} - -static int -l2cap_coc_err2hs_err(uint16_t coc_err) -{ - switch (coc_err) { - case BLE_L2CAP_COC_ERR_UNKNOWN_LE_PSM: - return BLE_HS_ENOTSUP; - case BLE_L2CAP_COC_ERR_NO_RESOURCES: - return BLE_HS_ENOMEM; - case BLE_L2CAP_COC_ERR_INSUFFICIENT_AUTHEN: - return BLE_HS_EAUTHEN; - case BLE_L2CAP_COC_ERR_INSUFFICIENT_AUTHOR: - return BLE_HS_EAUTHOR; - case BLE_L2CAP_COC_ERR_INSUFFICIENT_ENC: - return BLE_HS_EENCRYPT; - case BLE_L2CAP_COC_ERR_INSUFFICIENT_KEY_SZ: - return BLE_HS_EENCRYPT_KEY_SZ; - case BLE_L2CAP_COC_ERR_UNACCEPTABLE_PARAMETERS: - return BLE_HS_EINVAL; - default: - return 0; - } -} - - -static void listen(const uint8_t *data, uint16_t len) -{ - const struct l2cap_listen_cmd *cmd = (void *) data; - uint16_t mtu = htole16(cmd->mtu); - uint16_t rsp = htole16(cmd->response); - int rc; - - SYS_LOG_DBG(""); - - if (mtu == 0 || mtu > TESTER_COC_MTU) { - mtu = TESTER_COC_MTU; - } - - rsp = l2cap_coc_err2hs_err(rsp); - - /* TODO: Handle cmd->transport flag */ - rc = ble_l2cap_create_server(cmd->psm, mtu, tester_l2cap_event, - INT_TO_POINTER(rsp)); - if (rc) { - goto fail; - } - - tester_rsp(BTP_SERVICE_ID_L2CAP, L2CAP_LISTEN, CONTROLLER_INDEX, - BTP_STATUS_SUCCESS); - return; - -fail: - tester_rsp(BTP_SERVICE_ID_L2CAP, L2CAP_LISTEN, CONTROLLER_INDEX, - BTP_STATUS_FAILED); -} - -static void reconfigure(const uint8_t *data, uint16_t len) -{ - const struct l2cap_reconfigure_cmd *cmd = (void *) data; - uint16_t mtu = htole16(cmd->mtu); - struct ble_gap_conn_desc desc; - ble_addr_t *addr = (void *) data; - struct ble_l2cap_chan *chans[cmd->num]; - struct channel *channel; - int rc; - int i; - - SYS_LOG_DBG(""); - - if (mtu == 0 || mtu > TESTER_COC_MTU) { - mtu = TESTER_COC_MTU; - } - - rc = ble_gap_conn_find_by_addr(addr, &desc); - if (rc) { - SYS_LOG_ERR("GAP conn find failed"); - goto fail; - } - - for (i = 0; i < cmd->num; ++i) { - channel = get_channel(cmd->idxs[i]); - if (channel == NULL) { - goto fail; - } - chans[i] = channel->chan; - } - - rc = ble_l2cap_reconfig(chans, cmd->num, mtu); - if (rc) { - goto fail; - } - - tester_rsp(BTP_SERVICE_ID_L2CAP, L2CAP_RECONFIGURE, CONTROLLER_INDEX, - BTP_STATUS_SUCCESS); - return; - -fail: - tester_rsp(BTP_SERVICE_ID_L2CAP, L2CAP_RECONFIGURE, CONTROLLER_INDEX, - BTP_STATUS_FAILED); -} - -static void supported_commands(uint8_t *data, uint16_t len) -{ - uint8_t cmds[1]; - struct l2cap_read_supported_commands_rp *rp = (void *) cmds; - - memset(cmds, 0, sizeof(cmds)); - - tester_set_bit(cmds, L2CAP_READ_SUPPORTED_COMMANDS); - tester_set_bit(cmds, L2CAP_CONNECT); - tester_set_bit(cmds, L2CAP_DISCONNECT); - tester_set_bit(cmds, L2CAP_LISTEN); - tester_set_bit(cmds, L2CAP_SEND_DATA); - tester_set_bit(cmds, L2CAP_RECONFIGURE); - - tester_send(BTP_SERVICE_ID_L2CAP, L2CAP_READ_SUPPORTED_COMMANDS, - CONTROLLER_INDEX, (uint8_t *) rp, sizeof(cmds)); -} - -void tester_handle_l2cap(uint8_t opcode, uint8_t index, uint8_t *data, - uint16_t len) -{ - switch (opcode) { - case L2CAP_READ_SUPPORTED_COMMANDS: - supported_commands(data, len); - return; - case L2CAP_CONNECT: - connect(data, len); - return; - case L2CAP_DISCONNECT: - disconnect(data, len); - return; - case L2CAP_SEND_DATA: - send_data(data, len); - return; - case L2CAP_LISTEN: - listen(data, len); - return; - case L2CAP_RECONFIGURE: - reconfigure(data, len); - return; - default: - tester_rsp(BTP_SERVICE_ID_L2CAP, opcode, index, - BTP_STATUS_UNKNOWN_CMD); - return; - } -} - -uint8_t tester_init_l2cap(void) -{ - int rc; - - /* For testing we want to support all the available channels */ - rc = os_mempool_init(&sdu_coc_mbuf_mempool, TESTER_COC_BUF_COUNT, - TESTER_COC_MTU, tester_sdu_coc_mem, - "tester_coc_sdu_pool"); - assert(rc == 0); - - rc = os_mbuf_pool_init(&sdu_os_mbuf_pool, &sdu_coc_mbuf_mempool, - TESTER_COC_MTU, TESTER_COC_BUF_COUNT); - assert(rc == 0); - - return BTP_STATUS_SUCCESS; -} - -uint8_t tester_unregister_l2cap(void) -{ - return BTP_STATUS_SUCCESS; -} - -#endif diff --git a/apps/bttester/src/main.c b/apps/bttester/src/main.c index ea130805c9..242133056e 100644 --- a/apps/bttester/src/main.c +++ b/apps/bttester/src/main.c @@ -31,42 +31,41 @@ #include "host/ble_uuid.h" #include "host/ble_hs.h" -#include "bttester.h" +#include "btp/btp.h" -static void on_reset(int reason) +static void +on_reset(int reason) { - MODLOG_DFLT(ERROR, "Resetting state; reason=%d\n", reason); + MODLOG_DFLT(ERROR, "Resetting state; reason=%d\n", reason); } -static void on_sync(void) +static void +on_sync(void) { - MODLOG_DFLT(INFO, "Bluetooth initialized\n"); + MODLOG_DFLT(INFO, "Bluetooth initialized\n"); - tester_init(); + tester_init(); } -int main(int argc, char **argv) +int +mynewt_main(int argc, char **argv) { - int rc; + int rc; -#ifdef ARCH_sim - mcu_sim_parse_args(argc, argv); -#endif + /* Initialize OS */ + sysinit(); - /* Initialize OS */ - sysinit(); + /* Initialize the NimBLE host configuration. */ + ble_hs_cfg.reset_cb = on_reset; + ble_hs_cfg.sync_cb = on_sync; + ble_hs_cfg.gatts_register_cb = gatt_svr_register_cb, + ble_hs_cfg.store_status_cb = ble_store_util_status_rr; - /* Initialize the NimBLE host configuration. */ - ble_hs_cfg.reset_cb = on_reset; - ble_hs_cfg.sync_cb = on_sync; - ble_hs_cfg.gatts_register_cb = gatt_svr_register_cb, - ble_hs_cfg.store_status_cb = ble_store_util_status_rr; + rc = gatt_svr_init(); + assert(rc == 0); - rc = gatt_svr_init(); - assert(rc == 0); - - while (1) { - os_eventq_run(os_eventq_dflt_get()); - } - return 0; + while (1) { + os_eventq_run(os_eventq_dflt_get()); + } + return 0; } diff --git a/apps/bttester/src/mesh.c b/apps/bttester/src/mesh.c deleted file mode 100644 index 87bdbea430..0000000000 --- a/apps/bttester/src/mesh.c +++ /dev/null @@ -1,993 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -/* mesh.c - Bluetooth Mesh Tester */ - -/* - * Copyright (c) 2017 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "syscfg/syscfg.h" - -#if MYNEWT_VAL(BLE_MESH) - -#include - -#include "mesh/mesh.h" -#include "mesh/glue.h" -#include "mesh/testing.h" -#include "console/console.h" - -#include "bttester.h" - -extern uint8_t own_addr_type; - -#define CONTROLLER_INDEX 0 -#define CID_LOCAL 0x0002 - -/* Health server data */ -#define CUR_FAULTS_MAX 4 -#define HEALTH_TEST_ID 0x00 - -static uint8_t cur_faults[CUR_FAULTS_MAX]; -static uint8_t reg_faults[CUR_FAULTS_MAX * 2]; - -/* Provision node data */ -static uint8_t net_key[16]; -static uint16_t net_key_idx; -static uint8_t flags; -static uint32_t iv_index; -static uint16_t addr; -static uint8_t dev_key[16]; -static uint8_t input_size; - -/* Configured provisioning data */ -static uint8_t dev_uuid[16]; -static uint8_t static_auth[16]; - -/* Vendor Model data */ -#define VND_MODEL_ID_1 0x1234 - -/* Model send data */ -#define MODEL_BOUNDS_MAX 2 - -static struct model_data { - struct bt_mesh_model *model; - uint16_t addr; - uint16_t appkey_idx; -} model_bound[MODEL_BOUNDS_MAX]; - -static struct { - uint16_t local; - uint16_t dst; - uint16_t net_idx; -} net = { - .local = BT_MESH_ADDR_UNASSIGNED, - .dst = BT_MESH_ADDR_UNASSIGNED, -}; - -static void supported_commands(uint8_t *data, uint16_t len) -{ - struct os_mbuf *buf = NET_BUF_SIMPLE(BTP_DATA_MAX_SIZE); - - net_buf_simple_init(buf, 0); - - /* 1st octet */ - memset(net_buf_simple_add(buf, 1), 0, 1); - tester_set_bit(buf->om_data, MESH_READ_SUPPORTED_COMMANDS); - tester_set_bit(buf->om_data, MESH_CONFIG_PROVISIONING); - tester_set_bit(buf->om_data, MESH_PROVISION_NODE); - tester_set_bit(buf->om_data, MESH_INIT); - tester_set_bit(buf->om_data, MESH_RESET); - tester_set_bit(buf->om_data, MESH_INPUT_NUMBER); - tester_set_bit(buf->om_data, MESH_INPUT_STRING); - /* 2nd octet */ - tester_set_bit(buf->om_data, MESH_IVU_TEST_MODE); - tester_set_bit(buf->om_data, MESH_IVU_TOGGLE_STATE); - tester_set_bit(buf->om_data, MESH_NET_SEND); - tester_set_bit(buf->om_data, MESH_HEALTH_GENERATE_FAULTS); - tester_set_bit(buf->om_data, MESH_HEALTH_CLEAR_FAULTS); - tester_set_bit(buf->om_data, MESH_LPN); - tester_set_bit(buf->om_data, MESH_LPN_POLL); - tester_set_bit(buf->om_data, MESH_MODEL_SEND); - /* 3rd octet */ - memset(net_buf_simple_add(buf, 1), 0, 1); -#if MYNEWT_VAL(BLE_MESH_TESTING) - tester_set_bit(buf->om_data, MESH_LPN_SUBSCRIBE); - tester_set_bit(buf->om_data, MESH_LPN_UNSUBSCRIBE); - tester_set_bit(buf->om_data, MESH_RPL_CLEAR); -#endif /* CONFIG_BT_TESTING */ - tester_set_bit(buf->om_data, MESH_PROXY_IDENTITY); - - tester_send_buf(BTP_SERVICE_ID_MESH, MESH_READ_SUPPORTED_COMMANDS, - CONTROLLER_INDEX, buf); -} - -static void get_faults(uint8_t *faults, uint8_t faults_size, uint8_t *dst, uint8_t *count) -{ - uint8_t i, limit = *count; - - for (i = 0, *count = 0; i < faults_size && *count < limit; i++) { - if (faults[i]) { - *dst++ = faults[i]; - (*count)++; - } - } -} - -static int fault_get_cur(struct bt_mesh_model *model, uint8_t *test_id, - uint16_t *company_id, uint8_t *faults, uint8_t *fault_count) -{ - SYS_LOG_DBG(""); - - *test_id = HEALTH_TEST_ID; - *company_id = CID_LOCAL; - - get_faults(cur_faults, sizeof(cur_faults), faults, fault_count); - - return 0; -} - -static int fault_get_reg(struct bt_mesh_model *model, uint16_t company_id, - uint8_t *test_id, uint8_t *faults, uint8_t *fault_count) -{ - SYS_LOG_DBG("company_id 0x%04x", company_id); - - if (company_id != CID_LOCAL) { - return -EINVAL; - } - - *test_id = HEALTH_TEST_ID; - - get_faults(reg_faults, sizeof(reg_faults), faults, fault_count); - - return 0; -} - -static int fault_clear(struct bt_mesh_model *model, uint16_t company_id) -{ - SYS_LOG_DBG("company_id 0x%04x", company_id); - - if (company_id != CID_LOCAL) { - return -EINVAL; - } - - memset(reg_faults, 0, sizeof(reg_faults)); - - return 0; -} - -static int fault_test(struct bt_mesh_model *model, uint8_t test_id, - uint16_t company_id) -{ - SYS_LOG_DBG("test_id 0x%02x company_id 0x%04x", test_id, company_id); - - if (company_id != CID_LOCAL || test_id != HEALTH_TEST_ID) { - return -EINVAL; - } - - return 0; -} - -static const struct bt_mesh_health_srv_cb health_srv_cb = { - .fault_get_cur = fault_get_cur, - .fault_get_reg = fault_get_reg, - .fault_clear = fault_clear, - .fault_test = fault_test, -}; - -static struct bt_mesh_health_srv health_srv = { - .cb = &health_srv_cb, -}; - -static struct bt_mesh_model_pub health_pub; - -static void -health_pub_init(void) -{ - health_pub.msg = BT_MESH_HEALTH_FAULT_MSG(CUR_FAULTS_MAX); -} - -static struct bt_mesh_cfg_cli cfg_cli = { -}; - -void show_faults(uint8_t test_id, uint16_t cid, uint8_t *faults, size_t fault_count) -{ - size_t i; - - if (!fault_count) { - SYS_LOG_DBG("Health Test ID 0x%02x Company ID 0x%04x: " - "no faults", test_id, cid); - return; - } - - SYS_LOG_DBG("Health Test ID 0x%02x Company ID 0x%04x Fault Count %zu: ", - test_id, cid, fault_count); - - for (i = 0; i < fault_count; i++) { - SYS_LOG_DBG("0x%02x", faults[i]); - } -} - -static void health_current_status(struct bt_mesh_health_cli *cli, uint16_t addr, - uint8_t test_id, uint16_t cid, uint8_t *faults, - size_t fault_count) -{ - SYS_LOG_DBG("Health Current Status from 0x%04x", addr); - show_faults(test_id, cid, faults, fault_count); -} - -static struct bt_mesh_health_cli health_cli = { - .current_status = health_current_status, -}; - -static struct bt_mesh_model root_models[] = { - BT_MESH_MODEL_CFG_SRV, - BT_MESH_MODEL_CFG_CLI(&cfg_cli), - BT_MESH_MODEL_HEALTH_SRV(&health_srv, &health_pub), - BT_MESH_MODEL_HEALTH_CLI(&health_cli), -}; - -static struct bt_mesh_model vnd_models[] = { - BT_MESH_MODEL_VND(CID_LOCAL, VND_MODEL_ID_1, BT_MESH_MODEL_NO_OPS, NULL, - NULL), -}; - -static struct bt_mesh_elem elements[] = { - BT_MESH_ELEM(0, root_models, vnd_models), -}; - -static void link_open(bt_mesh_prov_bearer_t bearer) -{ - struct mesh_prov_link_open_ev ev; - - SYS_LOG_DBG("bearer 0x%02x", bearer); - - switch (bearer) { - case BT_MESH_PROV_ADV: - ev.bearer = MESH_PROV_BEARER_PB_ADV; - break; - case BT_MESH_PROV_GATT: - ev.bearer = MESH_PROV_BEARER_PB_GATT; - break; - default: - SYS_LOG_ERR("Invalid bearer"); - - return; - } - - tester_send(BTP_SERVICE_ID_MESH, MESH_EV_PROV_LINK_OPEN, - CONTROLLER_INDEX, (uint8_t *) &ev, sizeof(ev)); -} - -static void link_close(bt_mesh_prov_bearer_t bearer) -{ - struct mesh_prov_link_closed_ev ev; - - SYS_LOG_DBG("bearer 0x%02x", bearer); - - switch (bearer) { - case BT_MESH_PROV_ADV: - ev.bearer = MESH_PROV_BEARER_PB_ADV; - break; - case BT_MESH_PROV_GATT: - ev.bearer = MESH_PROV_BEARER_PB_GATT; - break; - default: - SYS_LOG_ERR("Invalid bearer"); - - return; - } - - tester_send(BTP_SERVICE_ID_MESH, MESH_EV_PROV_LINK_CLOSED, - CONTROLLER_INDEX, (uint8_t *) &ev, sizeof(ev)); -} - -static int output_number(bt_mesh_output_action_t action, uint32_t number) -{ - struct mesh_out_number_action_ev ev; - - SYS_LOG_DBG("action 0x%04x number 0x%08lx", action, number); - - ev.action = sys_cpu_to_le16(action); - ev.number = sys_cpu_to_le32(number); - - tester_send(BTP_SERVICE_ID_MESH, MESH_EV_OUT_NUMBER_ACTION, - CONTROLLER_INDEX, (uint8_t *) &ev, sizeof(ev)); - - return 0; -} - -static int output_string(const char *str) -{ - struct mesh_out_string_action_ev *ev; - struct os_mbuf *buf = NET_BUF_SIMPLE(BTP_DATA_MAX_SIZE); - - SYS_LOG_DBG("str %s", str); - - net_buf_simple_init(buf, 0); - - ev = net_buf_simple_add(buf, sizeof(*ev)); - ev->string_len = strlen(str); - - net_buf_simple_add_mem(buf, str, ev->string_len); - - tester_send_buf(BTP_SERVICE_ID_MESH, MESH_EV_OUT_STRING_ACTION, - CONTROLLER_INDEX, buf); - - os_mbuf_free_chain(buf); - return 0; -} - -static int input(bt_mesh_input_action_t action, uint8_t size) -{ - struct mesh_in_action_ev ev; - - SYS_LOG_DBG("action 0x%04x number 0x%02x", action, size); - - input_size = size; - - ev.action = sys_cpu_to_le16(action); - ev.size = size; - - tester_send(BTP_SERVICE_ID_MESH, MESH_EV_IN_ACTION, CONTROLLER_INDEX, - (uint8_t *) &ev, sizeof(ev)); - - return 0; -} - -static uint8_t vnd_app_key[16]; -static uint16_t vnd_app_key_idx = 0x000f; - -static void prov_complete(uint16_t net_idx, uint16_t addr) -{ - SYS_LOG_DBG("net_idx 0x%04x addr 0x%04x", net_idx, addr); - - net.net_idx = net_idx, - net.local = addr; - net.dst = addr; - - tester_send(BTP_SERVICE_ID_MESH, MESH_EV_PROVISIONED, CONTROLLER_INDEX, - NULL, 0); -} - -static void prov_reset(void) -{ - SYS_LOG_DBG(""); - - bt_mesh_prov_enable(BT_MESH_PROV_ADV | BT_MESH_PROV_GATT); -} - -static const struct bt_mesh_comp comp = { - .cid = CID_LOCAL, - .elem = elements, - .elem_count = ARRAY_SIZE(elements), -}; - -static struct bt_mesh_prov prov = { - .uuid = dev_uuid, - .static_val = static_auth, - .static_val_len = sizeof(static_auth), - .output_number = output_number, - .output_string = output_string, - .input = input, - .link_open = link_open, - .link_close = link_close, - .complete = prov_complete, - .reset = prov_reset, -}; - -static void config_prov(uint8_t *data, uint16_t len) -{ - const struct mesh_config_provisioning_cmd *cmd = (void *) data; - - SYS_LOG_DBG(""); - - memcpy(dev_uuid, cmd->uuid, sizeof(dev_uuid)); - memcpy(static_auth, cmd->static_auth, sizeof(static_auth)); - - prov.output_size = cmd->out_size; - prov.output_actions = sys_le16_to_cpu(cmd->out_actions); - prov.input_size = cmd->in_size; - prov.input_actions = sys_le16_to_cpu(cmd->in_actions); - - tester_rsp(BTP_SERVICE_ID_MESH, MESH_CONFIG_PROVISIONING, - CONTROLLER_INDEX, BTP_STATUS_SUCCESS); -} - -static void provision_node(uint8_t *data, uint16_t len) -{ - const struct mesh_provision_node_cmd *cmd = (void *) data; - - SYS_LOG_DBG(""); - - memcpy(dev_key, cmd->dev_key, sizeof(dev_key)); - memcpy(net_key, cmd->net_key, sizeof(net_key)); - - addr = sys_le16_to_cpu(cmd->addr); - flags = cmd->flags; - iv_index = sys_le32_to_cpu(cmd->iv_index); - net_key_idx = sys_le16_to_cpu(cmd->net_key_idx); - - tester_rsp(BTP_SERVICE_ID_MESH, MESH_PROVISION_NODE, - CONTROLLER_INDEX, BTP_STATUS_SUCCESS); -} - -static void init(uint8_t *data, uint16_t len) -{ - uint8_t status = BTP_STATUS_SUCCESS; - int err; - - SYS_LOG_DBG(""); - - err = bt_mesh_init(own_addr_type, &prov, &comp); - if (err) { - status = BTP_STATUS_FAILED; - - goto rsp; - } - - if (addr) { - err = bt_mesh_provision(net_key, net_key_idx, flags, iv_index, - addr, dev_key); - if (err) { - status = BTP_STATUS_FAILED; - } - } else { - err = bt_mesh_prov_enable(BT_MESH_PROV_ADV | BT_MESH_PROV_GATT); - if (err) { - status = BTP_STATUS_FAILED; - } - } - -rsp: - tester_rsp(BTP_SERVICE_ID_MESH, MESH_INIT, CONTROLLER_INDEX, - status); -} - -static void reset(uint8_t *data, uint16_t len) -{ - SYS_LOG_DBG(""); - - bt_mesh_reset(); - - tester_rsp(BTP_SERVICE_ID_MESH, MESH_RESET, CONTROLLER_INDEX, - BTP_STATUS_SUCCESS); -} - -static void input_number(uint8_t *data, uint16_t len) -{ - const struct mesh_input_number_cmd *cmd = (void *) data; - uint8_t status = BTP_STATUS_SUCCESS; - uint32_t number; - int err; - - number = sys_le32_to_cpu(cmd->number); - - SYS_LOG_DBG("number 0x%04lx", number); - - err = bt_mesh_input_number(number); - if (err) { - status = BTP_STATUS_FAILED; - } - - tester_rsp(BTP_SERVICE_ID_MESH, MESH_INPUT_NUMBER, CONTROLLER_INDEX, - status); -} - -static void input_string(uint8_t *data, uint16_t len) -{ - const struct mesh_input_string_cmd *cmd = (void *) data; - uint8_t status = BTP_STATUS_SUCCESS; - uint8_t str_auth[16]; - int err; - - SYS_LOG_DBG(""); - - if (cmd->string_len > sizeof(str_auth)) { - SYS_LOG_ERR("Too long input (%u chars required)", input_size); - status = BTP_STATUS_FAILED; - goto rsp; - } else if (cmd->string_len < input_size) { - SYS_LOG_ERR("Too short input (%u chars required)", input_size); - status = BTP_STATUS_FAILED; - goto rsp; - } - - strncpy((char *)str_auth, (char *)cmd->string, cmd->string_len); - - err = bt_mesh_input_string((char *)str_auth); - if (err) { - status = BTP_STATUS_FAILED; - } - -rsp: - tester_rsp(BTP_SERVICE_ID_MESH, MESH_INPUT_STRING, CONTROLLER_INDEX, - status); -} - -static void ivu_test_mode(uint8_t *data, uint16_t len) -{ - const struct mesh_ivu_test_mode_cmd *cmd = (void *) data; - - SYS_LOG_DBG("enable 0x%02x", cmd->enable); - - bt_mesh_iv_update_test(cmd->enable ? true : false); - - tester_rsp(BTP_SERVICE_ID_MESH, MESH_IVU_TEST_MODE, CONTROLLER_INDEX, - BTP_STATUS_SUCCESS); -} - -static void ivu_toggle_state(uint8_t *data, uint16_t len) -{ - bool result; - - SYS_LOG_DBG(""); - - result = bt_mesh_iv_update(); - if (!result) { - SYS_LOG_ERR("Failed to toggle the IV Update state"); - } - - tester_rsp(BTP_SERVICE_ID_MESH, MESH_IVU_TOGGLE_STATE, CONTROLLER_INDEX, - result ? BTP_STATUS_SUCCESS : BTP_STATUS_FAILED); -} - -static void lpn(uint8_t *data, uint16_t len) -{ - struct mesh_lpn_set_cmd *cmd = (void *) data; - bool enable; - int err; - - SYS_LOG_DBG("enable 0x%02x", cmd->enable); - - enable = cmd->enable ? true : false; - err = bt_mesh_lpn_set(enable); - if (err) { - SYS_LOG_ERR("Failed to toggle LPN (err %d)", err); - } - - tester_rsp(BTP_SERVICE_ID_MESH, MESH_LPN, CONTROLLER_INDEX, - err ? BTP_STATUS_FAILED : BTP_STATUS_SUCCESS); -} - -static void lpn_poll(uint8_t *data, uint16_t len) -{ - int err; - - SYS_LOG_DBG(""); - - err = bt_mesh_lpn_poll(); - if (err) { - SYS_LOG_ERR("Failed to send poll msg (err %d)", err); - } - - tester_rsp(BTP_SERVICE_ID_MESH, MESH_LPN_POLL, CONTROLLER_INDEX, - err ? BTP_STATUS_FAILED : BTP_STATUS_SUCCESS); -} - -static void net_send(uint8_t *data, uint16_t len) -{ - struct mesh_net_send_cmd *cmd = (void *) data; - struct os_mbuf *msg = NET_BUF_SIMPLE(UINT8_MAX); - struct bt_mesh_msg_ctx ctx = { - .net_idx = net.net_idx, - .app_idx = vnd_app_key_idx, - .addr = sys_le16_to_cpu(cmd->dst), - .send_ttl = cmd->ttl, - }; - int err; - - SYS_LOG_DBG("ttl 0x%02x dst 0x%04x payload_len %d", ctx.send_ttl, - ctx.addr, cmd->payload_len); - - if (!bt_mesh_app_key_get(vnd_app_key_idx)) { - (void)bt_mesh_app_key_add(vnd_app_key_idx, net.net_idx, - vnd_app_key); - vnd_models[0].keys[0] = vnd_app_key_idx; - } - - net_buf_simple_add_mem(msg, cmd->payload, cmd->payload_len); - - err = bt_mesh_model_send(&vnd_models[0], &ctx, msg, NULL, NULL); - if (err) { - SYS_LOG_ERR("Failed to send (err %d)", err); - } - - tester_rsp(BTP_SERVICE_ID_MESH, MESH_NET_SEND, CONTROLLER_INDEX, - err ? BTP_STATUS_FAILED : BTP_STATUS_SUCCESS); - - os_mbuf_free_chain(msg); -} - -static void health_generate_faults(uint8_t *data, uint16_t len) -{ - struct mesh_health_generate_faults_rp *rp; - struct os_mbuf *buf = NET_BUF_SIMPLE(sizeof(*rp) + sizeof(cur_faults) + - sizeof(reg_faults)); - uint8_t some_faults[] = { 0x01, 0x02, 0x03, 0xff, 0x06 }; - uint8_t cur_faults_count, reg_faults_count; - - rp = net_buf_simple_add(buf, sizeof(*rp)); - - cur_faults_count = min(sizeof(cur_faults), sizeof(some_faults)); - memcpy(cur_faults, some_faults, cur_faults_count); - net_buf_simple_add_mem(buf, cur_faults, cur_faults_count); - rp->cur_faults_count = cur_faults_count; - - reg_faults_count = min(sizeof(reg_faults), sizeof(some_faults)); - memcpy(reg_faults, some_faults, reg_faults_count); - net_buf_simple_add_mem(buf, reg_faults, reg_faults_count); - rp->reg_faults_count = reg_faults_count; - - bt_mesh_fault_update(&elements[0]); - - tester_send_buf(BTP_SERVICE_ID_MESH, MESH_HEALTH_GENERATE_FAULTS, - CONTROLLER_INDEX, buf); -} - -static void health_clear_faults(uint8_t *data, uint16_t len) -{ - SYS_LOG_DBG(""); - - memset(cur_faults, 0, sizeof(cur_faults)); - memset(reg_faults, 0, sizeof(reg_faults)); - - bt_mesh_fault_update(&elements[0]); - - tester_rsp(BTP_SERVICE_ID_MESH, MESH_HEALTH_CLEAR_FAULTS, - CONTROLLER_INDEX, BTP_STATUS_SUCCESS); -} - -static void model_send(uint8_t *data, uint16_t len) -{ - struct mesh_model_send_cmd *cmd = (void *) data; - struct os_mbuf *msg = NET_BUF_SIMPLE(UINT8_MAX); - struct bt_mesh_msg_ctx ctx = { - .net_idx = net.net_idx, - .app_idx = BT_MESH_KEY_DEV, - .addr = sys_le16_to_cpu(cmd->dst), - .send_ttl = BT_MESH_TTL_DEFAULT, - }; - struct bt_mesh_model *model = NULL; - int err, i; - uint16_t src = sys_le16_to_cpu(cmd->src); - - /* Lookup source address */ - for (i = 0; i < ARRAY_SIZE(model_bound); i++) { - if (bt_mesh_model_elem(model_bound[i].model)->addr == src) { - model = model_bound[i].model; - ctx.app_idx = model_bound[i].appkey_idx; - - break; - } - } - - if (!model) { - SYS_LOG_ERR("Model not found"); - err = -EINVAL; - - goto fail; - } - - SYS_LOG_DBG("src 0x%04x dst 0x%04x model %p payload_len %d", src, - ctx.addr, model, cmd->payload_len); - - net_buf_simple_add_mem(msg, cmd->payload, cmd->payload_len); - - err = bt_mesh_model_send(model, &ctx, msg, NULL, NULL); - if (err) { - SYS_LOG_ERR("Failed to send (err %d)", err); - } - -fail: - tester_rsp(BTP_SERVICE_ID_MESH, MESH_MODEL_SEND, CONTROLLER_INDEX, - err ? BTP_STATUS_FAILED : BTP_STATUS_SUCCESS); - - os_mbuf_free_chain(msg); -} - -#if MYNEWT_VAL(BLE_MESH_TESTING) -static void lpn_subscribe(uint8_t *data, uint16_t len) -{ - struct mesh_lpn_subscribe_cmd *cmd = (void *) data; - uint16_t address = sys_le16_to_cpu(cmd->address); - int err; - - SYS_LOG_DBG("address 0x%04x", address); - - err = bt_test_mesh_lpn_group_add(address); - if (err) { - SYS_LOG_ERR("Failed to subscribe (err %d)", err); - } - - tester_rsp(BTP_SERVICE_ID_MESH, MESH_LPN_SUBSCRIBE, CONTROLLER_INDEX, - err ? BTP_STATUS_FAILED : BTP_STATUS_SUCCESS); -} - -static void lpn_unsubscribe(uint8_t *data, uint16_t len) -{ - struct mesh_lpn_unsubscribe_cmd *cmd = (void *) data; - uint16_t address = sys_le16_to_cpu(cmd->address); - int err; - - SYS_LOG_DBG("address 0x%04x", address); - - err = bt_test_mesh_lpn_group_remove(&address, 1); - if (err) { - SYS_LOG_ERR("Failed to unsubscribe (err %d)", err); - } - - tester_rsp(BTP_SERVICE_ID_MESH, MESH_LPN_UNSUBSCRIBE, CONTROLLER_INDEX, - err ? BTP_STATUS_FAILED : BTP_STATUS_SUCCESS); -} - -static void rpl_clear(uint8_t *data, uint16_t len) -{ - int err; - - SYS_LOG_DBG(""); - - err = bt_test_mesh_rpl_clear(); - if (err) { - SYS_LOG_ERR("Failed to clear RPL (err %d)", err); - } - - tester_rsp(BTP_SERVICE_ID_MESH, MESH_RPL_CLEAR, CONTROLLER_INDEX, - err ? BTP_STATUS_FAILED : BTP_STATUS_SUCCESS); -} -#endif /* MYNEWT_VAL(BLE_MESH_TESTING) */ - -static void proxy_identity_enable(uint8_t *data, uint16_t len) -{ - int err; - - SYS_LOG_DBG(""); - - err = bt_mesh_proxy_identity_enable(); - if (err) { - SYS_LOG_ERR("Failed to enable proxy identity (err %d)", err); - } - - tester_rsp(BTP_SERVICE_ID_MESH, MESH_PROXY_IDENTITY, CONTROLLER_INDEX, - err ? BTP_STATUS_FAILED : BTP_STATUS_SUCCESS); -} - -void tester_handle_mesh(uint8_t opcode, uint8_t index, uint8_t *data, uint16_t len) -{ - switch (opcode) { - case MESH_READ_SUPPORTED_COMMANDS: - supported_commands(data, len); - break; - case MESH_CONFIG_PROVISIONING: - config_prov(data, len); - break; - case MESH_PROVISION_NODE: - provision_node(data, len); - break; - case MESH_INIT: - init(data, len); - break; - case MESH_RESET: - reset(data, len); - break; - case MESH_INPUT_NUMBER: - input_number(data, len); - break; - case MESH_INPUT_STRING: - input_string(data, len); - break; - case MESH_IVU_TEST_MODE: - ivu_test_mode(data, len); - break; - case MESH_IVU_TOGGLE_STATE: - ivu_toggle_state(data, len); - break; - case MESH_LPN: - lpn(data, len); - break; - case MESH_LPN_POLL: - lpn_poll(data, len); - break; - case MESH_NET_SEND: - net_send(data, len); - break; - case MESH_HEALTH_GENERATE_FAULTS: - health_generate_faults(data, len); - break; - case MESH_HEALTH_CLEAR_FAULTS: - health_clear_faults(data, len); - break; - case MESH_MODEL_SEND: - model_send(data, len); - break; -#if MYNEWT_VAL(BLE_MESH_TESTING) - case MESH_LPN_SUBSCRIBE: - lpn_subscribe(data, len); - break; - case MESH_LPN_UNSUBSCRIBE: - lpn_unsubscribe(data, len); - break; - case MESH_RPL_CLEAR: - rpl_clear(data, len); - break; -#endif /* MYNEWT_VAL(BLE_MESH_TESTING) */ - case MESH_PROXY_IDENTITY: - proxy_identity_enable(data, len); - break; - default: - tester_rsp(BTP_SERVICE_ID_MESH, opcode, index, - BTP_STATUS_UNKNOWN_CMD); - break; - } -} - -void net_recv_ev(uint8_t ttl, uint8_t ctl, uint16_t src, uint16_t dst, const void *payload, - size_t payload_len) -{ - struct os_mbuf *buf = NET_BUF_SIMPLE(UINT8_MAX); - struct mesh_net_recv_ev *ev; - - SYS_LOG_DBG("ttl 0x%02x ctl 0x%02x src 0x%04x dst 0x%04x " - "payload_len %d", ttl, ctl, src, dst, payload_len); - - if (payload_len > net_buf_simple_tailroom(buf)) { - SYS_LOG_ERR("Payload size exceeds buffer size"); - - goto done; - } - - ev = net_buf_simple_add(buf, sizeof(*ev)); - ev->ttl = ttl; - ev->ctl = ctl; - ev->src = sys_cpu_to_le16(src); - ev->dst = sys_cpu_to_le16(dst); - ev->payload_len = payload_len; - net_buf_simple_add_mem(buf, payload, payload_len); - - tester_send_buf(BTP_SERVICE_ID_MESH, MESH_EV_NET_RECV, CONTROLLER_INDEX, - buf); -done: - os_mbuf_free_chain(buf); -} - -static void model_bound_cb(uint16_t addr, struct bt_mesh_model *model, - uint16_t key_idx) -{ - int i; - - SYS_LOG_DBG("remote addr 0x%04x key_idx 0x%04x model %p", - addr, key_idx, model); - - for (i = 0; i < ARRAY_SIZE(model_bound); i++) { - if (!model_bound[i].model) { - model_bound[i].model = model; - model_bound[i].addr = addr; - model_bound[i].appkey_idx = key_idx; - - return; - } - } - - SYS_LOG_ERR("model_bound is full"); -} - -static void model_unbound_cb(uint16_t addr, struct bt_mesh_model *model, - uint16_t key_idx) -{ - int i; - - SYS_LOG_DBG("remote addr 0x%04x key_idx 0x%04x model %p", - addr, key_idx, model); - - for (i = 0; i < ARRAY_SIZE(model_bound); i++) { - if (model_bound[i].model == model) { - model_bound[i].model = NULL; - model_bound[i].addr = 0x0000; - model_bound[i].appkey_idx = BT_MESH_KEY_UNUSED; - - return; - } - } - - SYS_LOG_INF("model not found"); -} - -static void invalid_bearer_cb(uint8_t opcode) -{ - struct mesh_invalid_bearer_ev ev = { - .opcode = opcode, - }; - - SYS_LOG_DBG("opcode 0x%02x", opcode); - - tester_send(BTP_SERVICE_ID_MESH, MESH_EV_INVALID_BEARER, - CONTROLLER_INDEX, (uint8_t *) &ev, sizeof(ev)); -} - -static void incomp_timer_exp_cb(void) -{ - tester_send(BTP_SERVICE_ID_MESH, MESH_EV_INCOMP_TIMER_EXP, - CONTROLLER_INDEX, NULL, 0); -} - -static struct bt_test_cb bt_test_cb = { - .mesh_net_recv = net_recv_ev, - .mesh_model_bound = model_bound_cb, - .mesh_model_unbound = model_unbound_cb, - .mesh_prov_invalid_bearer = invalid_bearer_cb, - .mesh_trans_incomp_timer_exp = incomp_timer_exp_cb, -}; - -static void lpn_established(uint16_t friend_addr) -{ - - struct bt_mesh_lpn *lpn = &bt_mesh.lpn; - struct mesh_lpn_established_ev ev = { lpn->sub->net_idx, friend_addr, lpn->queue_size, - lpn->recv_win }; - - SYS_LOG_DBG("Friendship (as LPN) established with " - "Friend 0x%04x Queue Size %d Receive Window %d", - friend_addr, lpn->queue_size, lpn->recv_win); - - tester_send(BTP_SERVICE_ID_MESH, MESH_EV_LPN_ESTABLISHED, - CONTROLLER_INDEX, (uint8_t *) &ev, sizeof(ev)); -} - -static void lpn_terminated(uint16_t friend_addr) -{ - struct bt_mesh_lpn *lpn = &bt_mesh.lpn; - struct mesh_lpn_terminated_ev ev = { lpn->sub->net_idx, friend_addr }; - - SYS_LOG_DBG("Friendship (as LPN) lost with Friend " - "0x%04x", friend_addr); - - tester_send(BTP_SERVICE_ID_MESH, MESH_EV_LPN_TERMINATED, - CONTROLLER_INDEX, (uint8_t *) &ev, sizeof(ev)); -} - -void lpn_cb(uint16_t friend_addr, bool established) -{ - if (established) { - lpn_established(friend_addr); - } else { - lpn_terminated(friend_addr); - } -} - -uint8_t tester_init_mesh(void) -{ - health_pub_init(); - - if (IS_ENABLED(CONFIG_BT_TESTING)) { - bt_mesh_lpn_set_cb(lpn_cb); - bt_test_cb_register(&bt_test_cb); - } - - return BTP_STATUS_SUCCESS; -} - -uint8_t tester_unregister_mesh(void) -{ - return BTP_STATUS_SUCCESS; -} - -#endif /* MYNEWT_VAL(BLE_MESH) */ diff --git a/apps/bttester/src/rtt_pipe.c b/apps/bttester/src/rtt_pipe.c index 4e66770926..d1a8bd4a46 100644 --- a/apps/bttester/src/rtt_pipe.c +++ b/apps/bttester/src/rtt_pipe.c @@ -19,6 +19,10 @@ #include "syscfg/syscfg.h" +#ifndef min +#define min(a, b) ((a) < (b) ? (a) : (b)) +#endif + #if MYNEWT_VAL(BTTESTER_PIPE_RTT) #include "os/mynewt.h" diff --git a/apps/bttester/src/uart_pipe.c b/apps/bttester/src/uart_pipe.c index 1118d9af57..ac7f11d6dd 100644 --- a/apps/bttester/src/uart_pipe.c +++ b/apps/bttester/src/uart_pipe.c @@ -41,14 +41,14 @@ struct uart_pipe_ring { static struct uart_dev *uart_dev; static struct uart_pipe_ring cr_tx; static uint8_t cr_tx_buf[MYNEWT_VAL(BTTESTER_BTP_DATA_SIZE_MAX)]; -typedef void (*console_write_char)(struct uart_dev*, uint8_t); +typedef void (*console_write_char)(struct uart_dev *, uint8_t); static console_write_char write_char_cb; static struct uart_pipe_ring cr_rx; static uint8_t cr_rx_buf[MYNEWT_VAL(BTTESTER_BTP_DATA_SIZE_MAX)]; static volatile bool uart_console_rx_stalled; -struct os_event rx_ev; +static struct os_event rx_ev; static inline int inc_and_wrap(int i, int max) @@ -217,39 +217,39 @@ bttester_pipe_send(const uint8_t *data, int len) int bttester_pipe_send_buf(struct os_mbuf *buf) { - int i, len; - struct os_mbuf *om; - - /* Assure that there is a write cb installed; this enables to debug - * code that is faulting before the console was initialized. - */ - if (!write_char_cb) { - return -1; - } - - for (om = buf; om; om = SLIST_NEXT(om, om_next)) { - len = om->om_len; - for (i = 0; i < len; ++i) { - write_char_cb(uart_dev, om->om_data[i]); - } - } - - uart_start_tx(uart_dev); - - return 0; + int i, len; + struct os_mbuf *om; + + /* Assure that there is a write cb installed; this enables to debug + * code that is faulting before the console was initialized. + */ + if (!write_char_cb) { + return -1; + } + + for (om = buf; om; om = SLIST_NEXT(om, om_next)) { + len = om->om_len; + for (i = 0; i < len; ++i) { + write_char_cb(uart_dev, om->om_data[i]); + } + } + + uart_start_tx(uart_dev); + + return 0; } int bttester_pipe_init(void) { struct uart_conf uc = { - .uc_speed = MYNEWT_VAL(CONSOLE_UART_BAUD), - .uc_databits = 8, - .uc_stopbits = 1, - .uc_parity = UART_PARITY_NONE, - .uc_flow_ctl = MYNEWT_VAL(CONSOLE_UART_FLOW_CONTROL), - .uc_tx_char = uart_console_tx_char, - .uc_rx_char = uart_console_rx_char, + .uc_speed = MYNEWT_VAL(BTTESTER_UART_BAUD), + .uc_databits = 8, + .uc_stopbits = 1, + .uc_parity = UART_PARITY_NONE, + .uc_flow_ctl = MYNEWT_VAL(BTTESTER_UART_FLOW_CONTROL), + .uc_tx_char = uart_console_tx_char, + .uc_rx_char = uart_console_rx_char, }; cr_tx.size = sizeof(cr_tx_buf); @@ -262,8 +262,9 @@ bttester_pipe_init(void) rx_ev.ev_cb = uart_console_rx_char_event; if (!uart_dev) { - uart_dev = (struct uart_dev *)os_dev_open(MYNEWT_VAL(CONSOLE_UART_DEV), - OS_TIMEOUT_NEVER, &uc); + uart_dev = + (struct uart_dev *) os_dev_open(MYNEWT_VAL(BTTESTER_UART_DEV), + OS_TIMEOUT_NEVER, &uc); if (!uart_dev) { return -1; } @@ -274,8 +275,9 @@ bttester_pipe_init(void) void bttester_pipe_register(uint8_t *buf, size_t len, bttester_pipe_recv_cb cb) { - recv_buf = buf; - recv_buf_len = len; - app_cb = cb; + recv_buf = buf; + recv_buf_len = len; + app_cb = cb; } + #endif /* MYNEWT_VAL(BTTESTER_PIPE_UART) */ diff --git a/apps/bttester/syscfg.yml b/apps/bttester/syscfg.yml index 7f99ded013..c66bcdbd27 100644 --- a/apps/bttester/syscfg.yml +++ b/apps/bttester/syscfg.yml @@ -16,9 +16,27 @@ # under the License. # -# Package: apps/blemesh - syscfg.defs: + BTTESTER_NODEFAULT: + description: > + Disable any NimBLE configuration in bttester app. + This is useful for building bttester apps with custom configuration. + value: 0 + BTTESTER_LEAUDIO: + description: 'Enable NimBLE LE Audio support in bttester app' + value: 0 + BTTESTER_UART_BAUD: + description: 'Console UART baud rate.' + value: '115200' + + BTTESTER_UART_FLOW_CONTROL: + description: 'Console UART flow control.' + value: 'UART_FLOW_CTL_RTS_CTS' + + BTTESTER_UART_DEV: + description: 'Console UART device.' + value: '"uart0"' + BTTESTER_PIPE_UART: description: 'Set communication pipe to UART' value: 1 @@ -59,10 +77,6 @@ syscfg.defs: description: Maximum BTP payload value: 2048 - BTTESTER_CONN_PARAM_UPDATE: - description: Trigger conn param update after connection establish - value: 0 - BTTESTER_DEBUG: description: Enable debug logging value: 0 @@ -73,40 +87,83 @@ syscfg.defs: BTTESTER_L2CAP_COC_MTU: description: Maximum MTU size the application can handle - value: 230 + value: 260 + + BTTESTER_NRPA_TIMEOUT: + description: NRPA rotation timeout in seconds + value: 5 + + BROADCASTER_CHAN_NUM: + description: Number of channels used for broadcast + value: 1 + BROADCASTER_BROADCAST_NAME: + description: Broadcast name + value: '"test_broadcast"' syscfg.vals: + CONSOLE_IMPLEMENTATION: full + LOG_IMPLEMENTATION: full + STATS_IMPLEMENTATION: full + OS_MAIN_STACK_SIZE: 512 SHELL_TASK: 0 SHELL_NEWTMGR: 0 - LOG_LEVEL: 12 + LOG_LEVEL: 1 MSYS_1_BLOCK_COUNT: 100 BLE_MONITOR_RTT: 1 CONSOLE_RTT: 0 CONSOLE_UART: 0 + CONSOLE_UART_FLOW_CONTROL: UART_FLOW_CTL_RTS_CTS RTT_NUM_BUFFERS_UP: 0 RTT_NUM_BUFFERS_DOWN: 0 - BLE_L2CAP_COC_MAX_NUM: 2 + BLE_STORE_CONFIG_PERSIST: 0 + +syscfg.vals.BTTESTER_LEAUDIO: + BLE_ISO: 1 + BLE_AUDIO: 1 + BLE_AUDIO_BROADCAST_SINK: 1 + BLE_AUDIO_BROADCAST_SINK_MAX: 2 + BLE_AUDIO_MAX_CODEC_RECORDS: 3 + BLE_PERIODIC_ADV_SYNC_TRANSFER: 1 + BLE_PERIODIC_ADV_SYNC_BIGINFO_REPORTS: 1 + BLE_ROLE_BROADCASTER: 1 + BLE_ISO_BROADCAST_SOURCE: 1 + BLE_ISO_BROADCAST_SINK: 1 + BLE_ISO_MAX_BISES: 3 + BLE_ISO_MAX_BIGS: 3 + BLE_EXT_ADV: 1 + BLE_PHY_2M: 1 + BLE_EXT_ADV_MAX_SIZE: 40 + BLE_PERIODIC_ADV: 1 + BLE_MULTI_ADV_INSTANCES: 3 + BLE_SVC_AUDIO_BASS_METADATA_MAX_SZ: 256 + BLE_SVC_AUDIO_BASS_SUB_NUM_MAX: 10 + +syscfg.vals.!BTTESTER_NODEFAULT: + BLE_VERSION: 54 + + BTTESTER_LEAUDIO: 1 + BLE_L2CAP_COC_MAX_NUM: 5 BLE_L2CAP_SIG_MAX_PROCS: 2 BLE_L2CAP_ENHANCED_COC: 1 - BLE_VERSION: 52 + BLE_EATT_CHAN_NUM: 5 # Some testcases require MPS < MTU BLE_L2CAP_COC_MPS: 100 BLE_RPA_TIMEOUT: 30 BLE_SM_BONDING: 1 BLE_SM_MITM: 0 BLE_SM_SC: 1 - BLE_SM_OUR_KEY_DIST: 7 - BLE_SM_THEIR_KEY_DIST: 7 + BLE_SM_OUR_KEY_DIST: 3 + BLE_SM_THEIR_KEY_DIST: 3 BLE_SVC_GAP_CENTRAL_ADDRESS_RESOLUTION: 1 BLE_SVC_GAP_PPCP_MIN_CONN_INTERVAL: 9 BLE_SVC_GAP_PPCP_MAX_CONN_INTERVAL: 30 BLE_SVC_GAP_PPCP_SUPERVISION_TMO: 2000 BLE_SVC_GAP_APPEARANCE_WRITE_PERM: 0 BLE_SVC_GAP_DEVICE_NAME_WRITE_PERM: 0 - BLE_STORE_CONFIG_PERSIST: 0 + BLE_SVC_GAP_DEVICE_NAME_MAX_LENGTH: 6 BLE_MESH: 1 BLE_MESH_SHELL: 0 @@ -132,6 +189,4 @@ syscfg.vals: BLE_MESH_RX_SEG_MAX: 13 BLE_MESH_TX_SEG_MSG_COUNT: 2 BLE_MAX_CONNECTIONS: 8 - - BLE_MESH_ADV_BUF_COUNT: 20 - BLE_MESH_TX_SEG_MAX: 6 + BLE_CONN_SUBRATING: 1 diff --git a/apps/central/pkg.yml b/apps/central/pkg.yml old mode 100755 new mode 100644 index c10ad93336..90913711e6 --- a/apps/central/pkg.yml +++ b/apps/central/pkg.yml @@ -24,11 +24,10 @@ pkg.author: "Krzysztof Kopyściński " pkg.deps: - "@apache-mynewt-core/kernel/os" - - "@apache-mynewt-core/sys/console/full" - - "@apache-mynewt-core/sys/log/full" - - "@apache-mynewt-core/sys/stats/full" + - "@apache-mynewt-core/sys/console" + - "@apache-mynewt-core/sys/log" + - "@apache-mynewt-core/sys/stats" - "@apache-mynewt-core/sys/log/modlog" - "@apache-mynewt-nimble/nimble/host" - "@apache-mynewt-nimble/nimble/host/util/" - "@apache-mynewt-nimble/nimble/host/store/config" - - "@apache-mynewt-nimble/nimble/transport" diff --git a/apps/central/src/main.c b/apps/central/src/main.c index b2370359bf..1373ad07b5 100755 --- a/apps/central/src/main.c +++ b/apps/central/src/main.c @@ -22,7 +22,6 @@ #include "console/console.h" #include "host/ble_hs.h" #include "host/util/util.h" -#include "console/console.h" #include "log/log.h" static uint8_t g_own_addr_type; @@ -169,7 +168,7 @@ on_reset(int reason) } int -main(int argc, char **argv) +mynewt_main(int argc, char **argv) { /* Initialize all packages. */ sysinit(); diff --git a/apps/central/syscfg.yml b/apps/central/syscfg.yml index c23ba04206..3761c496ed 100644 --- a/apps/central/syscfg.yml +++ b/apps/central/syscfg.yml @@ -17,6 +17,10 @@ syscfg.vals: + CONSOLE_IMPLEMENTATION: full + LOG_IMPLEMENTATION: full + STATS_IMPLEMENTATION: full + BLE_ROLE_BROADCASTER: 0 BLE_ROLE_CENTRAL: 1 BLE_ROLE_OBSERVER: 1 diff --git a/apps/dtm/pkg.yml b/apps/dtm/pkg.yml new file mode 100644 index 0000000000..bf1ced3640 --- /dev/null +++ b/apps/dtm/pkg.yml @@ -0,0 +1,34 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +pkg.name: apps/dtm +pkg.type: app +pkg.description: "Bluetooth DTM shell application" +pkg.author: "Apache Mynewt " +pkg.homepage: "https://mynewt.apache.org/" +pkg.keywords: + +pkg.deps: + - "@apache-mynewt-core/sys/log" + - "@apache-mynewt-core/sys/stats" + - "@apache-mynewt-core/sys/shell" + - "@apache-mynewt-core/sys/console" + - "@apache-mynewt-core/kernel/os" + - "@apache-mynewt-core/util/parse_arg" + - "@apache-mynewt-nimble/nimble/host" + - "@apache-mynewt-mcumgr/cmd/img_mgmt" + - "@mcuboot/boot/bootutil" diff --git a/apps/dtm/src/main.c b/apps/dtm/src/main.c new file mode 100644 index 0000000000..1f8fc11319 --- /dev/null +++ b/apps/dtm/src/main.c @@ -0,0 +1,330 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "os/mynewt.h" +#include +#include +#include +#include "nimble/ble.h" +#include "nimble/nimble_opt.h" +#include "host/ble_hs.h" +#include "host/ble_hs_hci.h" +#include "host/ble_dtm.h" +#include +#include + +static const struct parse_arg_kv_pair phy_opts[] = { + { "1M", 0x01 }, + { "2M", 0x02 }, + { "coded", 0x03 }, + { NULL } +}; + +static const struct parse_arg_kv_pair modulation_index_opts[] = { + { "standard", 0x00 }, + { "stable", 0x01 }, + { NULL } +}; + +static int +cmd_rx_test(int argc, char **argv) +{ + struct ble_dtm_rx_params params; + int rc; + + rc = parse_arg_init(argc - 1, argv + 1); + if (rc != 0) { + return rc; + } + + params.channel = parse_arg_uint8("channel", &rc); + if ((rc != 0) || (params.channel > 39)) { + console_printf("invalid channel\n"); + return rc; + } + + params.phy = parse_arg_kv_dflt("phy", phy_opts, 0x01, &rc); + if (rc != 0) { + console_printf("invalid 'phy' parameter\n"); + return rc; + } + + params.modulation_index = parse_arg_kv_dflt("modulation_index", + modulation_index_opts, 0x00, &rc); + if (rc != 0) { + console_printf("invalid 'modulation_index' parameter\n"); + return rc; + } + + rc = ble_dtm_rx_start(¶ms); + if (rc) { + console_printf("failed to start RX test\n"); + return rc; + } + + console_printf("RX test started\n"); + return 0; +} + +static int +cmd_tx_test(int argc, char **argv) +{ + struct ble_dtm_tx_params params; + int rc; + + rc = parse_arg_init(argc - 1, argv + 1); + if (rc != 0) { + return rc; + } + + params.channel = parse_arg_uint8("channel", &rc); + if ((rc != 0) || (params.channel > 39)) { + console_printf("invalid channel\n"); + return rc; + } + + params.phy = parse_arg_kv_dflt("phy", phy_opts, 0x01, &rc); + if (rc != 0) { + console_printf("invalid 'phy' parameter\n"); + return rc; + } + + params.payload = parse_arg_uint8("payload", &rc); + if ((rc != 0) || ((params.payload > 7 && params.payload != 255))) { + console_printf("invalid 'payload' parameter\n"); + return rc; + } + + params.test_data_len = parse_arg_uint8_dflt("data_length", 0, &rc); + if (rc != 0) { + console_printf("invalid 'data_length' parameter\n"); + return rc; + } + + rc = ble_dtm_tx_start(¶ms); + if (rc) { + console_printf("failed to start TX test\n"); + return rc; + } + + console_printf("TX test started\n"); + return 0; +} + +static int +cmd_stop_test(int argc, char **argv) +{ + uint16_t num_packets; + int rc; + + rc = parse_arg_init(argc - 1, argv + 1); + if (rc != 0) { + return rc; + } + + rc = ble_dtm_stop(&num_packets); + if (rc) { + console_printf("failed to stop test\n"); + return rc; + } + + console_printf("Test stopped (%u packets)\n", num_packets); + return 0; +} + +static int +cmd_tx_power(int argc, char **argv) +{ + struct ble_hci_vs_set_tx_pwr_cp cmd; + struct ble_hci_vs_set_tx_pwr_rp rsp; + int rc; + + rc = parse_arg_init(argc - 1, argv + 1); + if (rc != 0) { + return rc; + } + + cmd.tx_power = parse_arg_long_bounds_dflt("power", + -127, 127, 127, &rc); + if (rc != 0) { + console_printf("invalid 'power' parameter\n"); + return rc; + } + + rc = ble_hs_hci_send_vs_cmd(BLE_HCI_OCF_VS_SET_TX_PWR, &cmd, sizeof(cmd), + &rsp, sizeof(rsp)); + if (rc) { + console_printf("failed to set TX power\n"); + return rc; + } + + console_printf("TX power set to %d dBm\n", rsp.tx_power); + return 0; +} + +static int +cmd_set_antenna(int argc, char **argv) +{ + struct ble_hci_vs_set_antenna_cp cmd; + int rc; + + rc = parse_arg_init(argc - 1, argv + 1); + if (rc != 0) { + return rc; + } + + cmd.antenna = parse_arg_uint8_dflt("antenna", 0, &rc); + if (rc != 0 || ((cmd.antenna > 2))) { + console_printf("invalid 'antenna' parameter\n"); + return rc; + } + + rc = ble_hs_hci_send_vs_cmd(BLE_HCI_OCF_VS_SET_ANTENNA, &cmd, sizeof(cmd), + NULL, 0); + if (rc) { + console_printf("failed to set antenna\n"); + return rc; + } + + console_printf("Antenna set to %u\n", cmd.antenna); + return 0; +} + +static const struct shell_param cmd_rx_test_params[] = { + {"channel", "RX channel, usage: =[0-39]"}, + {"phy", "usage: =[1M|2M], default: 1M"}, + {"modulation_index", "usage: =[standard|stable], default=standard"}, + {NULL} +}; + +static const struct shell_cmd_help cmd_rx_test_help = { + .summary = "start DTM RX test", + .usage = NULL, + .params = cmd_rx_test_params, +}; + +static const struct shell_param cmd_tx_test_params[] = { + {"channel", "TX channel, usage: =[0-39]"}, + {"phy", "usage: =[1M|2M], default: 1M"}, + {"data_length", "usage: =[0-255], default: 0"}, + {"payload", "usage: =[0-7, 255]"}, + {NULL} +}; + +static const struct shell_cmd_help cmd_tx_test_help = { + .summary = "start DTM TX test", + .usage = NULL, + .params = cmd_tx_test_params, +}; + +static const struct shell_cmd_help cmd_stop_test_help = { + .summary = "stop DTM test", + .usage = NULL, + .params = NULL, +}; + +static const struct shell_param cmd_tx_power_params[] = { + {"power", "usage: =[-127-127], default: 127"}, + {NULL} +}; + +static const struct shell_cmd_help cmd_tx_power_help = { + .summary = "set TX power", + .usage = NULL, + .params = cmd_tx_power_params, +}; + +static const struct shell_param cmd_set_antenna_params[] = { + {"antenna", "usage: =[0,1,2], default: 0"}, + {NULL} +}; + +static const struct shell_cmd_help cmd_set_antenna_help = { + .summary = "set active antenna ", + .usage = NULL, + .params = cmd_set_antenna_params, +}; + +static const struct shell_cmd dtm_commands[] = { + { + .sc_cmd = "rx-test", + .sc_cmd_func = cmd_rx_test, + .help = &cmd_rx_test_help, + }, + { + .sc_cmd = "tx-test", + .sc_cmd_func = cmd_tx_test, + .help = &cmd_tx_test_help, + }, + { + .sc_cmd = "stop-test", + .sc_cmd_func = cmd_stop_test, + .help = &cmd_stop_test_help, + }, + { + .sc_cmd = "tx-power", + .sc_cmd_func = cmd_tx_power, + .help = &cmd_tx_power_help, + }, + { + .sc_cmd = "set-antenna", + .sc_cmd_func = cmd_set_antenna, + .help = &cmd_set_antenna_help, + }, + { } +}; + +static void +on_sync(void) +{ + console_printf("Host and controller synced\n"); +} + +static void +on_reset(int reason) +{ + console_printf("Error: Resetting state; reason=%d\n", reason); +} + +int +mynewt_main(int argc, char **argv) +{ + struct image_version the_version; + char prompt[50]; + + sysinit(); + + img_mgmt_read_info(0, &the_version, NULL, NULL); + + snprintf(prompt, sizeof(prompt), "dtm_%u.%u.%u", + the_version.iv_major, the_version.iv_minor, the_version.iv_revision); + + /* Initialize the NimBLE host configuration. */ + ble_hs_cfg.reset_cb = on_reset; + ble_hs_cfg.sync_cb = on_sync; + + shell_register(prompt, dtm_commands); + shell_register_default_module(prompt); + + while (1) { + os_eventq_run(os_eventq_dflt_get()); + } + + return 0; +} diff --git a/apps/dtm/syscfg.yml b/apps/dtm/syscfg.yml new file mode 100644 index 0000000000..82517013e3 --- /dev/null +++ b/apps/dtm/syscfg.yml @@ -0,0 +1,31 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +syscfg.vals: + # Enable the shell task. + SHELL_TASK: 1 + SHELL_CMD_HELP: 1 + CONSOLE_HISTORY: ram + CONSOLE_HISTORY_RAM_HISTORY_SIZE: 50 + + BLE_PHY_2M: 1 + BLE_PHY_CODED: 1 + + BLE_LL_DTM: 1 + BLE_LL_DTM_EXTENSIONS: 1 + + BLE_HCI_VS: 1 diff --git a/apps/ext_advertiser/pkg.yml b/apps/ext_advertiser/pkg.yml index 097764b206..baf1ea0b05 100644 --- a/apps/ext_advertiser/pkg.yml +++ b/apps/ext_advertiser/pkg.yml @@ -25,16 +25,14 @@ pkg.homepage: "http://mynewt.apache.org/" pkg.keywords: pkg.deps: - - nimble/controller - nimble/host - nimble/host/util - nimble/host/services/gap - nimble/host/services/gatt - nimble/host/store/config - - nimble/transport/ram - "@apache-mynewt-core/kernel/os" - - "@apache-mynewt-core/sys/console/full" - - "@apache-mynewt-core/sys/log/full" - - "@apache-mynewt-core/sys/stats/full" + - "@apache-mynewt-core/sys/console" + - "@apache-mynewt-core/sys/log" + - "@apache-mynewt-core/sys/stats" - "@apache-mynewt-core/sys/sysinit" - "@apache-mynewt-core/sys/id" diff --git a/apps/ext_advertiser/src/main.c b/apps/ext_advertiser/src/main.c index 86b728436e..13c8955834 100644 --- a/apps/ext_advertiser/src/main.c +++ b/apps/ext_advertiser/src/main.c @@ -86,7 +86,7 @@ start_ext_max_events(uint8_t pattern, bool configure) params.primary_phy = BLE_HCI_LE_PHY_1M; params.secondary_phy = BLE_HCI_LE_PHY_1M; params.tx_power = 127; - params.sid = pattern % 16; + params.sid = 4; /* allow larger interval, 400 * 0.625ms with 100 events will give up to * ~2.5 seconds for instance @@ -94,7 +94,7 @@ start_ext_max_events(uint8_t pattern, bool configure) params.itvl_min = BLE_GAP_ADV_FAST_INTERVAL1_MIN; params.itvl_max = 400; - /* configure instance 0 */ + /* configure instance 4 */ rc = ble_gap_ext_adv_configure(instance, ¶ms, NULL, start_ext_max_events_gap_event, NULL); assert (rc == 0); @@ -184,9 +184,9 @@ start_legacy_duration(uint8_t pattern, bool configure) params.primary_phy = BLE_HCI_LE_PHY_1M; params.secondary_phy = BLE_HCI_LE_PHY_1M; params.tx_power = 127; - params.sid = pattern % 16; + params.sid = 3; - /* configure instance 0 */ + /* configure instance 3 */ rc = ble_gap_ext_adv_configure(instance, ¶ms, NULL, start_legacy_duration_gap_event, NULL); assert (rc == 0); @@ -251,7 +251,7 @@ start_scannable_legacy_ext(void) params.tx_power = 127; params.sid = 2; - /* configure instance 0 */ + /* configure instance 2 */ rc = ble_gap_ext_adv_configure(instance, ¶ms, NULL, NULL, NULL); assert (rc == 0); @@ -335,7 +335,7 @@ start_scannable_ext(void) params.tx_power = 127; params.sid = 1; - /* configure instance 0 */ + /* configure instance 1 */ rc = ble_gap_ext_adv_configure(instance, ¶ms, NULL, scannable_ext_gap_event, NULL); assert (rc == 0); @@ -387,7 +387,7 @@ start_non_connectable_ext(void) params.tx_power = 127; params.sid = 0; - /* configure instance */ + /* configure instance 0 */ rc = ble_gap_ext_adv_configure(instance, ¶ms, NULL, NULL, NULL); assert (rc == 0); @@ -421,7 +421,7 @@ static void start_periodic(void) ble_addr_t addr; int rc; - /* For periodic we use nstance with non-connectable advertising */ + /* For periodic we use instance with non-connectable advertising */ memset (¶ms, 0, sizeof(params)); /* advertise using random addr */ @@ -430,9 +430,9 @@ static void start_periodic(void) params.primary_phy = BLE_HCI_LE_PHY_1M; params.secondary_phy = BLE_HCI_LE_PHY_1M; params.tx_power = 127; - params.sid = 2; + params.sid = 5; - /* configure instance 0 */ + /* configure instance 5 */ rc = ble_gap_ext_adv_configure(instance, ¶ms, NULL, NULL, NULL); assert (rc == 0); @@ -475,11 +475,11 @@ static void start_periodic(void) rc = os_mbuf_append(data, ext_adv_pattern_1, sizeof(ext_adv_pattern_1)); assert(rc == 0); - rc = ble_gap_periodic_adv_set_data(instance, data); + rc = ble_gap_periodic_adv_set_data(instance, data, NULL); assert (rc == 0); /* start periodic advertising */ - rc = ble_gap_periodic_adv_start(instance); + rc = ble_gap_periodic_adv_start(instance, NULL); assert (rc == 0); /* start advertising */ @@ -526,7 +526,7 @@ on_sync(void) * @return int NOTE: this function should never return! */ int -main(void) +mynewt_main(int argc, char **argv) { /* Initialize OS */ sysinit(); diff --git a/apps/ext_advertiser/syscfg.yml b/apps/ext_advertiser/syscfg.yml index f157ab82b0..410433fdf8 100644 --- a/apps/ext_advertiser/syscfg.yml +++ b/apps/ext_advertiser/syscfg.yml @@ -17,6 +17,10 @@ syscfg.vals: + CONSOLE_IMPLEMENTATION: full + LOG_IMPLEMENTATION: full + STATS_IMPLEMENTATION: full + # Disable not used GAP roles (we only do non-connectable # advertising here) BLE_ROLE_BROADCASTER: 1 diff --git a/apps/mesh_badge/pkg.yml b/apps/mesh_badge/pkg.yml index 0718236f6a..238104d71c 100644 --- a/apps/mesh_badge/pkg.yml +++ b/apps/mesh_badge/pkg.yml @@ -26,14 +26,12 @@ pkg.deps: - "@apache-mynewt-core/hw/drivers/display/cfb" - "@apache-mynewt-core/hw/drivers/display/ssd1673" - "@apache-mynewt-core/kernel/os" - - "@apache-mynewt-core/sys/console/full" - - "@apache-mynewt-core/sys/log/full" + - "@apache-mynewt-core/sys/console" + - "@apache-mynewt-core/sys/log" - "@apache-mynewt-core/sys/log/modlog" - - "@apache-mynewt-core/sys/stats/full" + - "@apache-mynewt-core/sys/stats" - "@apache-mynewt-core/sys/shell" - - nimble/controller - nimble/host - nimble/host/services/gap - nimble/host/services/gatt - nimble/host/store/config - - nimble/transport/ram diff --git a/apps/mesh_badge/src/main.c b/apps/mesh_badge/src/main.c index d856d81632..b6b931fce7 100644 --- a/apps/mesh_badge/src/main.c +++ b/apps/mesh_badge/src/main.c @@ -360,7 +360,8 @@ int bt_set_name(const char *name) return 0; } -int main(void) +int +mynewt_main(int argc, char **argv) { int err; diff --git a/apps/mesh_badge/src/mesh.c b/apps/mesh_badge/src/mesh.c index ee999172b7..8137ab9217 100644 --- a/apps/mesh_badge/src/mesh.c +++ b/apps/mesh_badge/src/mesh.c @@ -11,6 +11,10 @@ #include "mesh.h" #include "board.h" +#ifndef min +#define min(a, b) ((a) < (b) ? (a) : (b)) +#endif + #define BT_COMP_ID_LF 0x05f1 #define MOD_LF 0x0000 diff --git a/apps/mesh_badge/src/reel_board.c b/apps/mesh_badge/src/reel_board.c index bc8229377f..3cf527b9e6 100644 --- a/apps/mesh_badge/src/reel_board.c +++ b/apps/mesh_badge/src/reel_board.c @@ -20,6 +20,10 @@ #define printk console_printf +#ifndef min +#define min(a, b) ((a) < (b) ? (a) : (b)) +#endif + enum font_size { FONT_BIG = 0, FONT_MEDIUM = 1, @@ -49,8 +53,8 @@ struct font_info { static struct os_dev *epd_dev; static bool pressed; static bool stats_view; -static struct k_delayed_work epd_work; -static struct k_delayed_work long_press_work; +static struct k_work_delayable epd_work; +static struct k_work_delayable long_press_work; static struct { int pin; @@ -61,7 +65,7 @@ static struct { { .pin = RGB_LED_BLU, }, }; -struct k_delayed_work led_timer; +struct k_work_delayable led_timer; static size_t print_line(enum font_size font_size, int row, const char *text, size_t len, bool center) @@ -121,7 +125,7 @@ static size_t get_len(enum font_size font, const char *text) void board_blink_leds(void) { - k_delayed_work_submit(&led_timer, K_MSEC(100)); + k_work_reschedule(&led_timer, K_MSEC(100)); } void board_show_text(const char *text, bool center, int32_t duration) @@ -151,7 +155,7 @@ void board_show_text(const char *text, bool center, int32_t duration) cfb_framebuffer_finalize(epd_dev); if (duration != K_FOREVER) { - k_delayed_work_submit(&epd_work, duration); + k_work_reschedule(&epd_work, duration); } } @@ -381,11 +385,11 @@ static void button_interrupt(struct os_event *ev) printk("Button %s\n", pressed ? "pressed" : "released"); if (pressed) { - k_delayed_work_submit(&long_press_work, LONG_PRESS_TIMEOUT); + k_work_reschedule(&long_press_work, LONG_PRESS_TIMEOUT); return; } - k_delayed_work_cancel(&long_press_work); + k_work_cancel_delayable(&long_press_work); if (!mesh_is_initialized()) { return; @@ -441,7 +445,7 @@ static void led_timeout(struct ble_npl_event *work) i = led_cntr++ % ARRAY_SIZE(leds); hal_gpio_write(leds[i].pin, 0); - k_delayed_work_submit(&led_timer, K_MSEC(100)); + k_work_reschedule(&led_timer, K_MSEC(100)); } static int configure_leds(void) @@ -452,7 +456,7 @@ static int configure_leds(void) hal_gpio_init_out(leds[i].pin, 1); } - k_delayed_work_init(&led_timer, led_timeout); + k_work_init_delayable(&led_timer, led_timeout); return 0; } @@ -466,7 +470,7 @@ static int erase_storage(void) void board_refresh_display(void) { - k_delayed_work_submit(&epd_work, K_NO_WAIT); + k_work_reschedule(&epd_work, K_NO_WAIT); } int board_init(void) @@ -494,8 +498,8 @@ int board_init(void) return -EIO; } - k_delayed_work_init(&epd_work, epd_update); - k_delayed_work_init(&long_press_work, long_press); + k_work_init_delayable(&epd_work, epd_update); + k_work_init_delayable(&long_press_work, long_press); pressed = button_is_pressed(); if (pressed) { diff --git a/apps/mesh_badge/syscfg.yml b/apps/mesh_badge/syscfg.yml index 2b8f457d55..81f1d75ff7 100644 --- a/apps/mesh_badge/syscfg.yml +++ b/apps/mesh_badge/syscfg.yml @@ -19,6 +19,10 @@ # Package: apps/mesh_badge syscfg.vals: + CONSOLE_IMPLEMENTATION: full + LOG_IMPLEMENTATION: full + STATS_IMPLEMENTATION: full + # Enable the shell task. SHELL_TASK: 1 diff --git a/apps/peripheral/pkg.yml b/apps/peripheral/pkg.yml old mode 100755 new mode 100644 index 6167edabcd..82ff496a71 --- a/apps/peripheral/pkg.yml +++ b/apps/peripheral/pkg.yml @@ -25,13 +25,11 @@ pkg.author: "Krzysztof Kopyściński krzysztof.kopyscinski@codecoup.pl" pkg.deps: - "@apache-mynewt-core/kernel/os" - - "@apache-mynewt-core/sys/console/full" - - "@apache-mynewt-core/sys/log/full" - - "@apache-mynewt-core/sys/stats/full" + - "@apache-mynewt-core/sys/console" + - "@apache-mynewt-core/sys/log" + - "@apache-mynewt-core/sys/stats" - "@apache-mynewt-core/sys/log/modlog" - "@apache-mynewt-nimble/nimble/host" - "@apache-mynewt-nimble/nimble/host/util/" - "@apache-mynewt-nimble/nimble/host/services/gap" - "@apache-mynewt-nimble/nimble/host/store/config" - - "@apache-mynewt-nimble/nimble/transport" - diff --git a/apps/peripheral/src/main.c b/apps/peripheral/src/main.c index f22579a732..03816b4db4 100755 --- a/apps/peripheral/src/main.c +++ b/apps/peripheral/src/main.c @@ -50,6 +50,7 @@ adv_event(struct ble_gap_event *event, void *arg) MODLOG_DFLT(INFO, "connection %s; status=%d\n", event->connect.status == 0 ? "established" : "failed", event->connect.status); + conn_handle = event->connect.conn_handle; break; case BLE_GAP_EVENT_CONN_UPDATE_REQ: /* connected device requests update of connection parameters, @@ -144,7 +145,7 @@ on_reset(int reason) } int -main(int argc, char **argv) +mynewt_main(int argc, char **argv) { int rc; diff --git a/apps/peripheral/syscfg.yml b/apps/peripheral/syscfg.yml index 0b9542316d..891ce0f59b 100644 --- a/apps/peripheral/syscfg.yml +++ b/apps/peripheral/syscfg.yml @@ -17,6 +17,10 @@ syscfg.vals: + CONSOLE_IMPLEMENTATION: full + LOG_IMPLEMENTATION: full + STATS_IMPLEMENTATION: full + BLE_ROLE_BROADCASTER: 1 BLE_ROLE_CENTRAL: 0 BLE_ROLE_OBSERVER: 0 diff --git a/apps/scanner/pkg.yml b/apps/scanner/pkg.yml index 15c2adbbff..5e17add142 100644 --- a/apps/scanner/pkg.yml +++ b/apps/scanner/pkg.yml @@ -25,11 +25,10 @@ pkg.author: "Krzysztof Kopyściński " pkg.deps: - "@apache-mynewt-core/kernel/os" - - "@apache-mynewt-core/sys/console/full" - - "@apache-mynewt-core/sys/log/full" - - "@apache-mynewt-core/sys/stats/full" + - "@apache-mynewt-core/sys/console" + - "@apache-mynewt-core/sys/log" + - "@apache-mynewt-core/sys/stats" - "@apache-mynewt-core/sys/log/modlog" - "@apache-mynewt-nimble/nimble/host" - "@apache-mynewt-nimble/nimble/host/util/" - "@apache-mynewt-nimble/nimble/host/store/config" - - "@apache-mynewt-nimble/nimble/transport" \ No newline at end of file diff --git a/apps/scanner/src/main.c b/apps/scanner/src/main.c index d21bba4bbe..016a567c77 100644 --- a/apps/scanner/src/main.c +++ b/apps/scanner/src/main.c @@ -22,7 +22,6 @@ #include "console/console.h" #include "host/ble_hs.h" #include "host/util/util.h" -#include "console/console.h" #include "log/log.h" /* scan_event() calls scan(), so forward declaration is required */ @@ -244,7 +243,7 @@ on_reset(int reason) } int -main(int argc, char **argv) +mynewt_main(int argc, char **argv) { /* Initialize all packages. */ sysinit(); diff --git a/apps/scanner/syscfg.yml b/apps/scanner/syscfg.yml index 568a2c6b7d..75d9dff251 100644 --- a/apps/scanner/syscfg.yml +++ b/apps/scanner/syscfg.yml @@ -17,6 +17,10 @@ syscfg.vals: + CONSOLE_IMPLEMENTATION: full + LOG_IMPLEMENTATION: full + STATS_IMPLEMENTATION: full + BLE_ROLE_BROADCASTER: 0 BLE_ROLE_CENTRAL: 0 BLE_ROLE_OBSERVER: 1 diff --git a/babblesim/README.md b/babblesim/README.md new file mode 100644 index 0000000000..c9ba3ef370 --- /dev/null +++ b/babblesim/README.md @@ -0,0 +1 @@ +BabbleSim support for Apache NimBLE diff --git a/babblesim/core/include/argparse.h b/babblesim/core/include/argparse.h new file mode 100644 index 0000000000..7f98b02822 --- /dev/null +++ b/babblesim/core/include/argparse.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2017 Oticon A/S + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef BSIM_NRF_ARGS_H +#define BSIM_NRF_ARGS_H + +#include +#include "NRF_hw_args.h" +#include "bs_cmd_line.h" +#include "bs_cmd_line_typical.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct nrf52_bsim_args_t { + BS_BASIC_DEVICE_OPTIONS_FIELDS + nrf_hw_sub_args_t nrf_hw; +}; + +struct nrf52_bsim_args_t *nrfbsim_argsparse(int argc, char *argv[]); +void nrfbsim_register_args(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/babblesim/core/include/cmsis.h b/babblesim/core/include/cmsis.h new file mode 100644 index 0000000000..8f9a6a3d4c --- /dev/null +++ b/babblesim/core/include/cmsis.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2020 Oticon A/S + * Copyright (c) 2021 Codecoup + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * This header defines replacements for inline + * ARM Cortex-M CMSIS intrinsics. + */ + +#ifndef BOARDS_POSIX_NRF52_BSIM_CMSIS_H +#define BOARDS_POSIX_NRF52_BSIM_CMSIS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Implement the following ARM intrinsics as no-op: + * - ARM Data Synchronization Barrier + * - ARM Data Memory Synchronization Barrier + * - ARM Instruction Synchronization Barrier + * - ARM No Operation + */ +#ifndef __DMB +#define __DMB() +#endif + +#ifndef __DSB +#define __DSB() +#endif + +#ifndef __ISB +#define __ISB() +#endif + +#ifndef __NOP +#define __NOP() +#endif + +void NVIC_SystemReset(void); +void __disable_irq(void); +void __enable_irq(void); +uint32_t __get_PRIMASK(void); + +#ifdef __cplusplus +} +#endif + +#endif /* BOARDS_POSIX_NRF52_BSIM_CMSIS_H */ diff --git a/babblesim/core/include/core_cm4.h b/babblesim/core/include/core_cm4.h new file mode 100644 index 0000000000..8b35f4a515 --- /dev/null +++ b/babblesim/core/include/core_cm4.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2020 Oticon A/S + * Copyright (c) 2021 Codecoup + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _BSIM_CORE_CM4_H +#define _BSIM_CORE_CM4_H + +#include + +/* Include the original ext_NRF52_hw_models core_cm4.h */ +#include <../HW_models/core_cm4.h> + +/* Add missing function definitions */ +extern void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority); +extern void NVIC_EnableIRQ(IRQn_Type IRQn); +extern void NVIC_DisableIRQ(IRQn_Type IRQn); +extern void NVIC_SetPendingIRQ(IRQn_Type IRQn); +extern void NVIC_ClearPendingIRQ(IRQn_Type IRQn); + +void __WFI(void); + +#ifndef __REV +#define __REV __builtin_bswap32 +#endif + +#endif diff --git a/babblesim/core/include/time_machine.h b/babblesim/core/include/time_machine.h new file mode 100644 index 0000000000..da28d01399 --- /dev/null +++ b/babblesim/core/include/time_machine.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2017 Oticon A/S + * Copyright (c) 2021 Codecoup + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _TIME_MACHINE_H +#define _TIME_MACHINE_H + +#include "bs_types.h" + +#ifdef __cplusplus +extern "C"{ +#endif + +extern bs_time_t now; +bs_time_t tm_get_abs_time(void); +bs_time_t tm_get_hw_time(void); +bs_time_t tm_hw_time_to_abs_time(bs_time_t hwtime); +bs_time_t tm_abs_time_to_hw_time(bs_time_t abstime); + +void tm_reset_hw_times(void); + +void tm_find_next_timer_to_trigger(void); +bs_time_t tm_get_next_timer_abstime(void); + +void tm_update_last_phy_sync_time(bs_time_t abs_time); + +void tm_set_phy_max_resync_offset(bs_time_t offset_in_us); + +void tm_run_forever(void); + +void tm_sleep_until_hw_time(bs_time_t hw_time); + +void tm_sleep_until_abs_time(bs_time_t time); + +void tm_start(void); + +void tm_tick(void); + +void tm_tick_limited(bs_time_t max_time_diff); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/porting/targets/dummy_bsp/pkg.yml b/babblesim/core/pkg.yml similarity index 85% rename from porting/targets/dummy_bsp/pkg.yml rename to babblesim/core/pkg.yml index 8b8484960a..1a1ec76629 100644 --- a/porting/targets/dummy_bsp/pkg.yml +++ b/babblesim/core/pkg.yml @@ -17,11 +17,16 @@ # under the License. # -pkg.name: porting/targets/dummy_bsp -pkg.type: bsp -pkg.description: A dummy BSP definition +pkg.name: babblesim/core +pkg.description: time machine, irq handeler, core pkg.author: "Apache Mynewt " pkg.homepage: "http://mynewt.apache.org/" pkg.keywords: -pkg.cflags: + pkg.deps: + - "babblesim/sdk" + +pkg.cflags: -std=gnu99 + +pkg.init: + bsim_start: 9999 diff --git a/babblesim/core/src/argparse.c b/babblesim/core/src/argparse.c new file mode 100644 index 0000000000..c1b6cdafd2 --- /dev/null +++ b/babblesim/core/src/argparse.c @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2017 Oticon A/S + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include "bs_tracing.h" +#include "bs_oswrap.h" +#include "bs_dump_files.h" +#include "argparse.h" +#include "NRF_hw_args.h" +#include "bs_cmd_line.h" +#include "bs_dynargs.h" +#include "bs_cmd_line_typical.h" +#include "NRF_HWLowL.h" +#include "controller/ble_ll.h" + +static bs_args_struct_t *args_struct; +static struct nrf52_bsim_args_t arg; +const char *bogus_sim_id = "bogus"; + +static void cmd_trace_lvl_found(char *argv, int offset) +{ + bs_trace_set_level(arg.verb); +} + +static void cmd_gdev_nbr_found(char *argv, int offset) +{ + bs_trace_set_prefix_dev(arg.global_device_nbr); +} + +static bool nosim; +static void cmd_nosim_found(char *argv, int offset) +{ + hwll_set_nosim(true); +} + +static void cmd_bdaddr_found(char *argv, int offset) +{ + union { + uint64_t u64; + uint8_t u8[8]; + } bdaddr; + char *endptr; + + if (sscanf(&argv[offset], "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", + &bdaddr.u8[5], &bdaddr.u8[4], &bdaddr.u8[3], &bdaddr.u8[2], + &bdaddr.u8[1], &bdaddr.u8[0]) < 6) { + bdaddr.u64 = strtoull(&argv[offset], &endptr, 0); + if (*endptr) { + return; + } + + bdaddr.u64 = htole64(bdaddr.u64); + } + + ble_ll_set_public_addr(bdaddr.u8); +} + +static void print_no_sim_warning(void) +{ + bs_trace_warning("Neither simulation id or the device number " + "have been set. I assume you want to run " + "without a BabbleSim phy (-nosim)\n"); + bs_trace_warning("If this is not what you wanted, check with " + "--help how to set them\n"); + bs_trace_raw(3, "setting sim_id to 'bogus', device number to 0 " + "and nosim\n"); +} + +void nrfbsim_register_args(void) +{ +#define args (&arg) + /* This define is quite ugly, but allows reusing the definitions + * provided by the utils library */ + static bs_args_struct_t args_struct_toadd[] = { + ARG_TABLE_S_ID, + ARG_TABLE_P_ID_2G4, + ARG_TABLE_DEV_NBR, + ARG_TABLE_GDEV_NBR, + ARG_TABLE_VERB, + ARG_TABLE_SEED, + ARG_TABLE_COLOR, + ARG_TABLE_NOCOLOR, + ARG_TABLE_FORCECOLOR, + _NRF_HW_SUB_CMD_ARG_STRUCT, + /* + * Fields: + * manual, mandatory, switch, + * option_name, var_name, type, + * destination, callback, + * description + */ + { false, false , false, + "A", "bdaddr", 's', + NULL, cmd_bdaddr_found, "Device public address"}, + {false, false, true, + "nosim", "", 'b', + (void *)&nosim, cmd_nosim_found, + "(debug feature) Do not connect to the phy"}, + BS_DUMP_FILES_ARGS, + {true, false, false, + "argsmain", "arg", 'l', + NULL, NULL, + "The arguments that follow will be passed to main (default)"}, + ARG_TABLE_ENDMARKER + }; +#undef args + + bs_add_dynargs(&args_struct, args_struct_toadd); +} + +/** + * Check the arguments provided in the command line: set args based on it or + * defaults, and check they are correct + */ +struct nrf52_bsim_args_t *nrfbsim_argsparse(int argc, char *argv[]) +{ + bs_args_set_defaults(args_struct); + arg.verb = 2; + bs_trace_set_level(arg.verb); + nrf_hw_sub_cmline_set_defaults(&arg.nrf_hw); + static const char default_phy[] = "2G4"; + + for (int i = 1; i < argc; i++) { + if (bs_is_option(argv[i], "argsmain", 0)) { + continue; + } + + if (!bs_args_parse_one_arg(argv[i], args_struct)) { + bs_args_print_switches_help(args_struct); + bs_trace_error_line("Incorrect option %s\n", + argv[i]); + } + } + + /** + * If the user did not set the simulation id or device number + * we assume he wanted to run with nosim (but warn him) + */ + if ((!nosim) && (arg.s_id == NULL) && (arg.device_nbr == UINT_MAX)) { + print_no_sim_warning(); + nosim = true; + hwll_set_nosim(true); + } + if (nosim) { + if (arg.s_id == NULL) { + arg.s_id = (char *)bogus_sim_id; + } + if (arg.device_nbr == UINT_MAX) { + arg.device_nbr = 0; + } + } + + if (arg.device_nbr == UINT_MAX) { + bs_args_print_switches_help(args_struct); + bs_trace_error_line("The command line option " + "needs to be set\n"); + } + if (arg.global_device_nbr == UINT_MAX) { + arg.global_device_nbr = arg.device_nbr; + bs_trace_set_prefix_dev(arg.global_device_nbr); + } + if (!arg.s_id) { + bs_args_print_switches_help(args_struct); + bs_trace_error_line("The command line option " + "needs to be set\n"); + } + if (!arg.p_id) { + arg.p_id = (char *)default_phy; + } + + if (arg.rseed == UINT_MAX) { + arg.rseed = 0x1000 + arg.device_nbr; + } + return &arg; +} diff --git a/babblesim/core/src/cmsis.c b/babblesim/core/src/cmsis.c new file mode 100644 index 0000000000..1ac6b2414c --- /dev/null +++ b/babblesim/core/src/cmsis.c @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2020 Nordic Semiconductor ASA + * Copyright (c) 2020 Oticon A/S + * Copyright (c) 2021 Codecoup + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "irq_ctrl.h" + +#include +#include "cmsis.h" +#include "os/sim.h" + +#include +#include + +extern void (* systemVectors[256])(void); + +/* + * Replacement for ARMs NVIC functions() + */ +void NVIC_SetPendingIRQ(IRQn_Type IRQn) +{ + hw_irq_ctrl_raise_im_from_sw(IRQn); +} + +void NVIC_ClearPendingIRQ(IRQn_Type IRQn) +{ + hw_irq_ctrl_clear_irq(IRQn); +} + +void NVIC_DisableIRQ(IRQn_Type IRQn) +{ + hw_irq_ctrl_disable_irq(IRQn); +} + +void NVIC_EnableIRQ(IRQn_Type IRQn) +{ + hw_irq_ctrl_enable_irq(IRQn); +} + +void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority) +{ + hw_irq_ctrl_prio_set(IRQn, priority); +} + +uint32_t NVIC_GetPriority(IRQn_Type IRQn) +{ + return hw_irq_ctrl_get_prio(IRQn); +} + +void NVIC_SystemReset(void) +{ + inner_main_clean_up(1); +} + +/* + * Replacements for some other CMSIS functions + */ +void __enable_irq(void) +{ + hw_irq_ctrl_change_lock(false); +} + +void __disable_irq(void) +{ + hw_irq_ctrl_change_lock(true); +} + +uint32_t __get_PRIMASK(void) +{ + return hw_irq_ctrl_get_current_lock(); +} + +void NVIC_SetVector(IRQn_Type IRQn, uint32_t vector) +{ + systemVectors[(int32_t)IRQn + 16] = (void(*)(void))vector; +} diff --git a/babblesim/core/src/irq_handler.c b/babblesim/core/src/irq_handler.c new file mode 100644 index 0000000000..05eb881a6d --- /dev/null +++ b/babblesim/core/src/irq_handler.c @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2017 Oticon A/S + * + * SPDX-License-Identifier: Apache-2.0 + * + * SW side of the IRQ handling + */ + +#include +#include "irq_ctrl.h" +#include "os/sim.h" + +static int currently_running_irq = -1; +extern void (* const systemVectors[256])(void); + +/** + * When an interrupt is raised, this function is called to handle it and, if + * needed, swap to a re-enabled thread + * + * Note that even that this function is executing in a Zephyr thread, it is + * effectively the model of the interrupt controller passing context to the IRQ + * handler and therefore its priority handling + */ + +int +os_arch_in_isr(void) +{ + return currently_running_irq >= 0; +} + +void posix_interrupt_raised(void) +{ + uint64_t irq_lock; + int irq_nbr; + + irq_lock = hw_irq_ctrl_get_current_lock(); + + if (irq_lock) { + /* "spurious" wakes can happen with interrupts locked */ + return; + } + + while ((irq_nbr = hw_irq_ctrl_get_highest_prio_irq()) != -1) { + int last_current_running_prio = hw_irq_ctrl_get_cur_prio(); + int last_running_irq = currently_running_irq; + + hw_irq_ctrl_set_cur_prio(hw_irq_ctrl_get_prio(irq_nbr)); + hw_irq_ctrl_clear_irq(irq_nbr); + + currently_running_irq = irq_nbr; + systemVectors[irq_nbr + 16](); + currently_running_irq = last_running_irq; + + hw_irq_ctrl_set_cur_prio(last_current_running_prio); + } +} + +/** + * Thru this function the IRQ controller can raise an immediate interrupt which + * will interrupt the SW itself + * (this function should only be called from the HW model code, from SW threads) + */ +void posix_irq_handler_im_from_sw(void) +{ + /* + * if a higher priority interrupt than the possibly currently running is + * pending we go immediately into irq_handler() to vector into its + * handler + */ + if (hw_irq_ctrl_get_highest_prio_irq() != -1) { + posix_interrupt_raised(); + } +} diff --git a/babblesim/core/src/main_config.c b/babblesim/core/src/main_config.c new file mode 100644 index 0000000000..39a03c3cd5 --- /dev/null +++ b/babblesim/core/src/main_config.c @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2017-2018 Oticon A/S + * Copyright (c) 2021 Codecoup + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "NRF_HW_model_top.h" +#include "NRF_HWLowL.h" +#include "bs_tracing.h" +#include "bs_symbols.h" +#include "bs_types.h" +#include "bs_rand_main.h" +#include "bs_pc_backchannel.h" +#include "bs_dump_files.h" +#include "argparse.h" +#include "time_machine.h" +#include "os/mynewt.h" +#include +#include "os/sim.h" + +uint global_device_nbr; +struct nrf52_bsim_args_t *args; + +extern int mynewt_main(int argc, char **argv); + +void +bst_tick(bs_time_t time) +{ + return; +} + +uint8_t +inner_main_clean_up(int exit_code) +{ + hwll_terminate_simulation(); + nrf_hw_models_free_all(); + bs_dump_files_close_all(); + + bs_clean_back_channels(); + return 0; +} + +uint8_t +main_clean_up_trace_wrap(void) +{ + return inner_main_clean_up(0); +} + +int +main(int argc, char** argv) +{ + setvbuf(stdout, NULL, _IOLBF, 512); + setvbuf(stderr, NULL, _IOLBF, 512); + + bs_trace_register_cleanup_function(main_clean_up_trace_wrap); + bs_trace_register_time_function(tm_get_abs_time); + + nrf_hw_pre_init(); + nrfbsim_register_args(); + + args = nrfbsim_argsparse(argc, argv); + global_device_nbr = args->global_device_nbr; + + bs_read_function_names_from_Tsymbols(argv[0]); + + nrf_hw_initialize(&args->nrf_hw); + os_init(mynewt_main); + os_start(); + + while (1) { + sleep(1); + } +} + +void +bsim_start(void) +{ + bs_trace_raw(9, "%s: Connecting to phy...\n", __func__); + hwll_connect_to_phy(args->device_nbr, args->s_id, args->p_id); + bs_trace_raw(9, "%s: Connected\n", __func__); + + bs_random_init(args->rseed); + bs_dump_files_open(args->s_id, args->global_device_nbr); +} diff --git a/babblesim/core/src/time_machine.c b/babblesim/core/src/time_machine.c new file mode 100644 index 0000000000..38b3f424a5 --- /dev/null +++ b/babblesim/core/src/time_machine.c @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2017-2018 Oticon A/S + * Copyright (c) 2021 Codecoup + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "NRF_HW_model_top.h" +#include "NRF_HWLowL.h" +#include "bs_tracing.h" +#include "bs_types.h" +#include "bs_utils.h" +#include +#include +#include +#include +#include + +/* Note: All timers are relative to hw_time and NOT to 'now' */ +extern bs_time_t timer_nrf_main_timer; + +/* The events priorities are as in this list from top to bottom + * Priority being which timer executes first if several trigger at the same + * instant + */ +static enum { + NRF_HW_MAIN_TIMER = 0, + NUMBER_OF_TIMERS, + NONE +} next_timer_index = NONE; + +static bs_time_t *Timer_list[NUMBER_OF_TIMERS] = { + &timer_nrf_main_timer, +}; +static bs_time_t next_timer_time = TIME_NEVER; + +/* + * Current absolute time of this device, as the device knows it. + * It is never reset: + */ +bs_time_t now; +/* Current time the HW of this device things it is */ +static bs_time_t hw_time; +/* + * Offset between the current absolute time of the device and the HW time + * That is, the absolute time when the HW_time got reset + */ +static bs_time_t hw_time_delta; + +/* Last time we synchronized with the bsim PHY, in device abs time */ +static bs_time_t last_bsim_phy_sync_time; + +#define BSIM_DEFAULT_PHY_MAX_RESYNC_OFFSET 1000000 +/* At least every second we will inform the simulator about our timing */ +static bs_time_t max_resync_offset = BSIM_DEFAULT_PHY_MAX_RESYNC_OFFSET; + +/** + * Set the maximum amount of time the device will spend without talking + * (synching) with the phy. + * This does not change the functional behavior of the Zephyr code or of the + * radio emulation, and it is only relevant if special test code running in the + * device interacts behind the scenes with other devices test code. + * Setting for example a value of 5ms will ensure that this device time + * will never be more than 5ms away from the phy. Setting it in all devices + * to 5ms would then ensure no device time is farther apart than 5ms from any + * other. + * + * Note that setting low values has a performance penalty. + */ +void +tm_set_phy_max_resync_offset(bs_time_t offset_in_us) +{ + max_resync_offset = offset_in_us; +} + +/** + * Return the absolute current time (no HW model except the RADIO + * should look into this) + */ +bs_time_t +tm_get_abs_time(void) +{ + return now; +} + +/** + * Return the current HW time + */ +bs_time_t +tm_get_hw_time(void) +{ + return hw_time; +} + +bs_time_t +posix_get_hw_cycle(void) +{ + return tm_get_hw_time(); +} + +/** + * Reset the HW time + */ +static void +tm_reset_hw_time(void) +{ + hw_time = 0; + hw_time_delta = now; + if (now != 0) { + bs_trace_error_line("Reset not supposed to happen after " + "initialization\n"); + } +} + +/** + * Update the current hw_time value given the absolute time + */ +INLINE void +tm_update_HW_time(void) +{ + hw_time = now - hw_time_delta; +} + +/* + * Reset the HW time + */ +void +tm_reset_hw_times(void) +{ + tm_reset_hw_time(); +} + +/** + * Advance the internal time values of this device until time + */ +void +tm_sleep_until_abs_time(bs_time_t time) +{ + if (time >= now) { + /* + * Ensure that at least we sync with the phy + * every max_resync_offset + */ + if (time > last_bsim_phy_sync_time + max_resync_offset) { + hwll_sync_time_with_phy(time); + last_bsim_phy_sync_time = time; + } + + now = time; + } else { + /* LCOV_EXCL_START */ + bs_trace_warning_manual_time_line(now, "next_time_time " + "corrupted (%"PRItime"<= %"PRItime", timer idx=%i)\n", + time, now, next_timer_index); + /* LCOV_EXCL_STOP */ + } + tm_update_HW_time(); +} + +/** + * Keep track of the last time we synchronized the time with the scheduler + */ +void +tm_update_last_phy_sync_time(bs_time_t abs_time) +{ + last_bsim_phy_sync_time = abs_time; +} + +/** + * Advance the internal time values of this device + * until the HW time reaches hw_time + */ +void +tm_sleep_until_hw_time(bs_time_t hw_time) +{ + bs_time_t next_time = TIME_NEVER; + + if (hw_time != TIME_NEVER) { + next_time = hw_time + hw_time_delta; + } + + tm_sleep_until_abs_time(next_time); +} + +/** + * Look into all timers and update next_timer accordingly + * To be called each time a "timed process" updates its timer + */ +void +tm_find_next_timer_to_trigger(void) +{ + next_timer_time = *Timer_list[0]; + next_timer_index = 0; + + for (uint i = 1; i < NUMBER_OF_TIMERS; i++) { + if (next_timer_time > *Timer_list[i]) { + next_timer_time = *Timer_list[i]; + next_timer_index = i; + } + } +} + +bs_time_t +tm_get_next_timer_abstime(void) +{ + return next_timer_time + hw_time_delta; +} + +bs_time_t +tm_hw_time_to_abs_time(bs_time_t hwtime) +{ + if (hwtime == TIME_NEVER) { + return TIME_NEVER; + } + return hwtime + hw_time_delta; +} + +bs_time_t +tm_abs_time_to_hw_time(bs_time_t abstime) +{ + if (abstime == TIME_NEVER) { + return TIME_NEVER; + } + return abstime - hw_time_delta; +} + +void +tm_tick_limited(bs_time_t max_time_diff) +{ + bs_time_t time_to_wait; + + if (max_time_diff != TIME_NEVER && now + max_time_diff < next_timer_time) { + time_to_wait = now + max_time_diff; + } else { + time_to_wait = next_timer_time; + } + + tm_sleep_until_hw_time(time_to_wait); + switch (next_timer_index) { + case NRF_HW_MAIN_TIMER: + nrf_hw_some_timer_reached(); + break; + default: + bs_trace_error_time_line("next_timer_index " + "corrupted\n"); + break; + } + tm_find_next_timer_to_trigger(); +} + +void +tm_tick(void) +{ + tm_tick_limited(TIME_NEVER); +} diff --git a/babblesim/edtt/hci_test/pkg.yml b/babblesim/edtt/hci_test/pkg.yml new file mode 100644 index 0000000000..6f1dd4bbbe --- /dev/null +++ b/babblesim/edtt/hci_test/pkg.yml @@ -0,0 +1,32 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# +pkg.name: babblesim/edtt/hci_test +pkg.type: app +pkg.description: nRF52 on BabbleSim - EDTT tester +pkg.author: "Codecoup" +pkg.homepage: "http://mynewt.apache.org/" +pkg.keywords: + +pkg.deps: + - "@apache-mynewt-core/sys/console/stub" + - "@apache-mynewt-core/sys/log/stub" + - "@apache-mynewt-core/sys/stats/full" + - "@apache-mynewt-core/kernel/os" + - nimble/transport + - babblesim/edtt/hci_transport diff --git a/babblesim/edtt/hci_test/src/main.c b/babblesim/edtt/hci_test/src/main.c new file mode 100644 index 0000000000..43ef621264 --- /dev/null +++ b/babblesim/edtt/hci_test/src/main.c @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2021 Codecoup + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "os/mynewt.h" +#include "ble_hci_edtt.h" + +int +mynewt_main(int argc, char **argv) +{ + sysinit(); + + edtt_init(); + + while (1) { + os_eventq_run(os_eventq_dflt_get()); + } + return 0; +} diff --git a/babblesim/edtt/hci_test/syscfg.yml b/babblesim/edtt/hci_test/syscfg.yml new file mode 100644 index 0000000000..8a7909a6af --- /dev/null +++ b/babblesim/edtt/hci_test/syscfg.yml @@ -0,0 +1,30 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +syscfg.vals: + BLE_TRANSPORT_LL: native + BLE_TRANSPORT_HS: custom + + # EDTT requires 0x123456789ABC address for first device + # and 0x456789ABCDEF for second + BLE_LL_PUBLIC_DEV_ADDR: 0x123456789ABC +# BLE_LL_PUBLIC_DEV_ADDR: 0x456789ABCDEF + + # For LL/CON/ADV/BV-09-C, LL/CON/ADV/BV-10-C + BLE_LL_CFG_FEAT_LE_CSA2: 1 diff --git a/nimble/controller/include/controller/ble_ll_test.h b/babblesim/edtt/hci_transport/include/ble_hci_edtt.h similarity index 89% rename from nimble/controller/include/controller/ble_ll_test.h rename to babblesim/edtt/hci_transport/include/ble_hci_edtt.h index 32984c6b3e..d590b11d0b 100644 --- a/nimble/controller/include/controller/ble_ll_test.h +++ b/babblesim/edtt/hci_transport/include/ble_hci_edtt.h @@ -1,4 +1,6 @@ /* + * Copyright (c) 2021 Codecoup + * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information @@ -17,16 +19,14 @@ * under the License. */ -#ifndef H_LL_TEST_ -#define H_LL_TEST_ - -#include +#ifndef H_BLE_HCI_EDTT_ +#define H_BLE_HCI_EDTT_ #ifdef __cplusplus extern "C" { #endif -int ble_ll_csa2_test_all(void); +int edtt_init(void); #ifdef __cplusplus } diff --git a/babblesim/edtt/hci_transport/include/commands.h b/babblesim/edtt/hci_transport/include/commands.h new file mode 100644 index 0000000000..d0f8cce2a9 --- /dev/null +++ b/babblesim/edtt/hci_transport/include/commands.h @@ -0,0 +1,242 @@ +/* + * Copyright (c) 2019 Oticon A/S + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef EDDT_APP_COMMANDS_H +#define EDDT_APP_COMMANDS_H + +enum commands_t { + CMD_NOTHING = 0, + CMD_ECHO_REQ, + CMD_ECHO_RSP, + CMD_INQUIRE_REQ, + CMD_INQUIRE_RSP, + CMD_DISCONNECT_REQ, + CMD_DISCONNECT_RSP, + CMD_READ_REMOTE_VERSION_INFORMATION_REQ, + CMD_READ_REMOTE_VERSION_INFORMATION_RSP, + CMD_SET_EVENT_MASK_REQ, + CMD_SET_EVENT_MASK_RSP, + CMD_RESET_REQ, + CMD_RESET_RSP, + CMD_READ_TRANSMIT_POWER_LEVEL_REQ, + CMD_READ_TRANSMIT_POWER_LEVEL_RSP, + CMD_SET_CONTROLLER_TO_HOST_FLOW_CONTROL_REQ, + CMD_SET_CONTROLLER_TO_HOST_FLOW_CONTROL_RSP, + CMD_HOST_BUFFER_SIZE_REQ, + CMD_HOST_BUFFER_SIZE_RSP, + CMD_HOST_NUMBER_OF_COMPLETED_PACKETS_REQ, + CMD_HOST_NUMBER_OF_COMPLETED_PACKETS_RSP, + CMD_SET_EVENT_MASK_PAGE_2_REQ, + CMD_SET_EVENT_MASK_PAGE_2_RSP, + CMD_WRITE_LE_HOST_SUPPORT_REQ, + CMD_WRITE_LE_HOST_SUPPORT_RSP, + CMD_READ_AUTHENTICATED_PAYLOAD_TIMEOUT_REQ, + CMD_READ_AUTHENTICATED_PAYLOAD_TIMEOUT_RSP, + CMD_WRITE_AUTHENTICATED_PAYLOAD_TIMEOUT_REQ, + CMD_WRITE_AUTHENTICATED_PAYLOAD_TIMEOUT_RSP, + CMD_READ_LOCAL_VERSION_INFORMATION_REQ, + CMD_READ_LOCAL_VERSION_INFORMATION_RSP, + CMD_READ_LOCAL_SUPPORTED_COMMANDS_REQ, + CMD_READ_LOCAL_SUPPORTED_COMMANDS_RSP, + CMD_READ_LOCAL_SUPPORTED_FEATURES_REQ, + CMD_READ_LOCAL_SUPPORTED_FEATURES_RSP, + CMD_READ_BUFFER_SIZE_REQ, + CMD_READ_BUFFER_SIZE_RSP, + CMD_READ_BD_ADDR_REQ, + CMD_READ_BD_ADDR_RSP, + CMD_READ_RSSI_REQ, + CMD_READ_RSSI_RSP, + CMD_LE_SET_EVENT_MASK_REQ, + CMD_LE_SET_EVENT_MASK_RSP, + CMD_LE_READ_BUFFER_SIZE_REQ, + CMD_LE_READ_BUFFER_SIZE_RSP, + CMD_LE_READ_LOCAL_SUPPORTED_FEATURES_REQ, + CMD_LE_READ_LOCAL_SUPPORTED_FEATURES_RSP, + CMD_LE_SET_RANDOM_ADDRESS_REQ, + CMD_LE_SET_RANDOM_ADDRESS_RSP, + CMD_LE_SET_ADVERTISING_PARAMETERS_REQ, + CMD_LE_SET_ADVERTISING_PARAMETERS_RSP, + CMD_LE_READ_ADVERTISING_CHANNEL_TX_POWER_REQ, + CMD_LE_READ_ADVERTISING_CHANNEL_TX_POWER_RSP, + CMD_LE_SET_ADVERTISING_DATA_REQ, + CMD_LE_SET_ADVERTISING_DATA_RSP, + CMD_LE_SET_SCAN_RESPONSE_DATA_REQ, + CMD_LE_SET_SCAN_RESPONSE_DATA_RSP, + CMD_LE_SET_ADVERTISING_ENABLE_REQ, + CMD_LE_SET_ADVERTISING_ENABLE_RSP, + CMD_LE_SET_SCAN_PARAMETERS_REQ, + CMD_LE_SET_SCAN_PARAMETERS_RSP, + CMD_LE_SET_SCAN_ENABLE_REQ, + CMD_LE_SET_SCAN_ENABLE_RSP, + CMD_LE_CREATE_CONNECTION_REQ, + CMD_LE_CREATE_CONNECTION_RSP, + CMD_LE_CREATE_CONNECTION_CANCEL_REQ, + CMD_LE_CREATE_CONNECTION_CANCEL_RSP, + CMD_LE_READ_FILTER_ACCEPT_LIST_SIZE_REQ, + CMD_LE_READ_FILTER_ACCEPT_LIST_SIZE_RSP, + CMD_LE_CLEAR_FILTER_ACCEPT_LIST_REQ, + CMD_LE_CLEAR_FILTER_ACCEPT_LIST_RSP, + CMD_LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST_REQ, + CMD_LE_ADD_DEVICE_TO_FILTER_ACCEPT_LIST_RSP, + CMD_LE_REMOVE_DEVICE_FROM_FILTER_ACCEPT_LIST_REQ, + CMD_LE_REMOVE_DEVICE_FROM_FILTER_ACCEPT_LIST_RSP, + CMD_LE_CONNECTION_UPDATE_REQ, + CMD_LE_CONNECTION_UPDATE_RSP, + CMD_LE_SET_HOST_CHANNEL_CLASSIFICATION_REQ, + CMD_LE_SET_HOST_CHANNEL_CLASSIFICATION_RSP, + CMD_LE_READ_CHANNEL_MAP_REQ, + CMD_LE_READ_CHANNEL_MAP_RSP, + CMD_LE_READ_REMOTE_FEATURES_REQ, + CMD_LE_READ_REMOTE_FEATURES_RSP, + CMD_LE_ENCRYPT_REQ, + CMD_LE_ENCRYPT_RSP, + CMD_LE_RAND_REQ, + CMD_LE_RAND_RSP, + CMD_LE_START_ENCRYPTION_REQ, + CMD_LE_START_ENCRYPTION_RSP, + CMD_LE_LONG_TERM_KEY_REQUEST_REPLY_REQ, + CMD_LE_LONG_TERM_KEY_REQUEST_REPLY_RSP, + CMD_LE_LONG_TERM_KEY_REQUEST_NEGATIVE_REPLY_REQ, + CMD_LE_LONG_TERM_KEY_REQUEST_NEGATIVE_REPLY_RSP, + CMD_LE_READ_SUPPORTED_STATES_REQ, + CMD_LE_READ_SUPPORTED_STATES_RSP, + CMD_LE_RECEIVER_TEST_REQ, + CMD_LE_RECEIVER_TEST_RSP, + CMD_LE_TRANSMITTER_TEST_REQ, + CMD_LE_TRANSMITTER_TEST_RSP, + CMD_LE_TEST_END_REQ, + CMD_LE_TEST_END_RSP, + CMD_LE_REMOTE_CONNECTION_PARAMETER_REQUEST_REPLY_REQ, + CMD_LE_REMOTE_CONNECTION_PARAMETER_REQUEST_REPLY_RSP, + CMD_LE_REMOTE_CONNECTION_PARAMETER_REQUEST_NEGATIVE_REPLY_REQ, + CMD_LE_REMOTE_CONNECTION_PARAMETER_REQUEST_NEGATIVE_REPLY_RSP, + CMD_LE_SET_DATA_LENGTH_REQ, + CMD_LE_SET_DATA_LENGTH_RSP, + CMD_LE_READ_SUGGESTED_DEFAULT_DATA_LENGTH_REQ, + CMD_LE_READ_SUGGESTED_DEFAULT_DATA_LENGTH_RSP, + CMD_LE_WRITE_SUGGESTED_DEFAULT_DATA_LENGTH_REQ, + CMD_LE_WRITE_SUGGESTED_DEFAULT_DATA_LENGTH_RSP, + CMD_LE_READ_LOCAL_P_256_PUBLIC_KEY_COMMAND_REQ, + CMD_LE_READ_LOCAL_P_256_PUBLIC_KEY_COMMAND_RSP, + CMD_LE_GENERATE_DHKEY_COMMAND_REQ, + CMD_LE_GENERATE_DHKEY_COMMAND_RSP, + CMD_LE_ADD_DEVICE_TO_RESOLVING_LIST_REQ, + CMD_LE_ADD_DEVICE_TO_RESOLVING_LIST_RSP, + CMD_LE_REMOVE_DEVICE_FROM_RESOLVING_LIST_REQ, + CMD_LE_REMOVE_DEVICE_FROM_RESOLVING_LIST_RSP, + CMD_LE_CLEAR_RESOLVING_LIST_REQ, + CMD_LE_CLEAR_RESOLVING_LIST_RSP, + CMD_LE_READ_RESOLVING_LIST_SIZE_REQ, + CMD_LE_READ_RESOLVING_LIST_SIZE_RSP, + CMD_LE_READ_PEER_RESOLVABLE_ADDRESS_REQ, + CMD_LE_READ_PEER_RESOLVABLE_ADDRESS_RSP, + CMD_LE_READ_LOCAL_RESOLVABLE_ADDRESS_REQ, + CMD_LE_READ_LOCAL_RESOLVABLE_ADDRESS_RSP, + CMD_LE_SET_ADDRESS_RESOLUTION_ENABLE_REQ, + CMD_LE_SET_ADDRESS_RESOLUTION_ENABLE_RSP, + CMD_LE_SET_RESOLVABLE_PRIVATE_ADDRESS_TIMEOUT_REQ, + CMD_LE_SET_RESOLVABLE_PRIVATE_ADDRESS_TIMEOUT_RSP, + CMD_LE_READ_MAXIMUM_DATA_LENGTH_REQ, + CMD_LE_READ_MAXIMUM_DATA_LENGTH_RSP, + CMD_LE_READ_PHY_REQ, + CMD_LE_READ_PHY_RSP, + CMD_LE_SET_DEFAULT_PHY_REQ, + CMD_LE_SET_DEFAULT_PHY_RSP, + CMD_LE_SET_PHY_REQ, + CMD_LE_SET_PHY_RSP, + CMD_LE_ENHANCED_RECEIVER_TEST_REQ, + CMD_LE_ENHANCED_RECEIVER_TEST_RSP, + CMD_LE_ENHANCED_TRANSMITTER_TEST_REQ, + CMD_LE_ENHANCED_TRANSMITTER_TEST_RSP, + CMD_LE_SET_EXTENDED_ADVERTISING_PARAMETERS_REQ, + CMD_LE_SET_EXTENDED_ADVERTISING_PARAMETERS_RSP, + CMD_LE_SET_EXTENDED_ADVERTISING_DATA_REQ, + CMD_LE_SET_EXTENDED_ADVERTISING_DATA_RSP, + CMD_LE_SET_EXTENDED_SCAN_RESPONSE_DATA_REQ, + CMD_LE_SET_EXTENDED_SCAN_RESPONSE_DATA_RSP, + CMD_LE_SET_EXTENDED_ADVERTISING_ENABLE_REQ, + CMD_LE_SET_EXTENDED_ADVERTISING_ENABLE_RSP, + CMD_LE_READ_MAXIMUM_ADVERTISING_DATA_LENGTH_REQ, + CMD_LE_READ_MAXIMUM_ADVERTISING_DATA_LENGTH_RSP, + CMD_LE_READ_NUMBER_OF_SUPPORTED_ADVERTISING_SETS_REQ, + CMD_LE_READ_NUMBER_OF_SUPPORTED_ADVERTISING_SETS_RSP, + CMD_LE_REMOVE_ADVERTISING_SET_REQ, + CMD_LE_REMOVE_ADVERTISING_SET_RSP, + CMD_LE_CLEAR_ADVERTISING_SETS_REQ, + CMD_LE_CLEAR_ADVERTISING_SETS_RSP, + CMD_LE_SET_PERIODIC_ADVERTISING_PARAMETERS_REQ, + CMD_LE_SET_PERIODIC_ADVERTISING_PARAMETERS_RSP, + CMD_LE_SET_PERIODIC_ADVERTISING_DATA_REQ, + CMD_LE_SET_PERIODIC_ADVERTISING_DATA_RSP, + CMD_LE_SET_PERIODIC_ADVERTISING_ENABLE_REQ, + CMD_LE_SET_PERIODIC_ADVERTISING_ENABLE_RSP, + CMD_LE_SET_EXTENDED_SCAN_PARAMETERS_REQ, + CMD_LE_SET_EXTENDED_SCAN_PARAMETERS_RSP, + CMD_LE_SET_EXTENDED_SCAN_ENABLE_REQ, + CMD_LE_SET_EXTENDED_SCAN_ENABLE_RSP, + CMD_LE_EXTENDED_CREATE_CONNECTION_REQ, + CMD_LE_EXTENDED_CREATE_CONNECTION_RSP, + CMD_LE_PERIODIC_ADVERTISING_CREATE_SYNC_REQ, + CMD_LE_PERIODIC_ADVERTISING_CREATE_SYNC_RSP, + CMD_LE_PERIODIC_ADVERTISING_CREATE_SYNC_CANCEL_REQ, + CMD_LE_PERIODIC_ADVERTISING_CREATE_SYNC_CANCEL_RSP, + CMD_LE_PERIODIC_ADVERTISING_TERMINATE_SYNC_REQ, + CMD_LE_PERIODIC_ADVERTISING_TERMINATE_SYNC_RSP, + CMD_LE_ADD_DEVICE_TO_PERIODIC_ADVERTISER_LIST_REQ, + CMD_LE_ADD_DEVICE_TO_PERIODIC_ADVERTISER_LIST_RSP, + CMD_LE_REMOVE_DEVICE_FROM_PERIODIC_ADVERTISER_LIST_REQ, + CMD_LE_REMOVE_DEVICE_FROM_PERIODIC_ADVERTISER_LIST_RSP, + CMD_LE_CLEAR_PERIODIC_ADVERTISER_LIST_REQ, + CMD_LE_CLEAR_PERIODIC_ADVERTISER_LIST_RSP, + CMD_LE_READ_PERIODIC_ADVERTISER_LIST_SIZE_REQ, + CMD_LE_READ_PERIODIC_ADVERTISER_LIST_SIZE_RSP, + CMD_LE_READ_TRANSMIT_POWER_REQ, + CMD_LE_READ_TRANSMIT_POWER_RSP, + CMD_LE_READ_RF_PATH_COMPENSATION_REQ, + CMD_LE_READ_RF_PATH_COMPENSATION_RSP, + CMD_LE_WRITE_RF_PATH_COMPENSATION_REQ, + CMD_LE_WRITE_RF_PATH_COMPENSATION_RSP, + CMD_LE_SET_PRIVACY_MODE_REQ, + CMD_LE_SET_PRIVACY_MODE_RSP, + CMD_WRITE_BD_ADDR_REQ, + CMD_WRITE_BD_ADDR_RSP, + CMD_FLUSH_EVENTS_REQ, + CMD_FLUSH_EVENTS_RSP, + CMD_HAS_EVENT_REQ, + CMD_HAS_EVENT_RSP, + CMD_GET_EVENT_REQ, + CMD_GET_EVENT_RSP, + CMD_LE_FLUSH_DATA_REQ, + CMD_LE_FLUSH_DATA_RSP, + CMD_LE_DATA_READY_REQ, + CMD_LE_DATA_READY_RSP, + CMD_LE_DATA_WRITE_REQ, + CMD_LE_DATA_WRITE_RSP, + CMD_LE_DATA_READ_REQ, + CMD_LE_DATA_READ_RSP, + CMD_GATT_SERVICE_SET_REQ, + CMD_GATT_SERVICE_SET_RSP, + CMD_GATT_SERVICE_NOTIFY_REQ, + CMD_GATT_SERVICE_NOTIFY_RSP, + CMD_GATT_SERVICE_INDICATE_REQ, + CMD_GATT_SERVICE_INDICATE_RSP, + CMD_GAP_ADVERTISING_MODE_REQ, + CMD_GAP_ADVERTISING_MODE_RSP, + CMD_GAP_ADVERTISING_DATA_REQ, + CMD_GAP_ADVERTISING_DATA_RSP, + CMD_GAP_SCANNING_MODE_REQ, + CMD_GAP_SCANNING_MODE_RSP, + CMD_READ_STATIC_ADDRESSES_REQ, + CMD_READ_STATIC_ADDRESSES_RSP, + CMD_READ_KEY_HIERARCHY_ROOTS_REQ, + CMD_READ_KEY_HIERARCHY_ROOTS_RSP, + CMD_GAP_READ_IRK_REQ, + CMD_GAP_READ_IRK_RSP, + CMD_GAP_ROLE_REQ, + CMD_GAP_ROLE_RSP +}; + +#endif /* EDDT_APP_COMMANDS_H */ diff --git a/babblesim/edtt/hci_transport/include/edtt_driver.h b/babblesim/edtt/hci_transport/include/edtt_driver.h new file mode 100644 index 0000000000..3b7d253346 --- /dev/null +++ b/babblesim/edtt/hci_transport/include/edtt_driver.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2019 Oticon A/S + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef EDTT_DRIVER_H +#define EDTT_DRIVER_H + +#include +#include + +#define EDTTT_NONBLOCK 0 +#define EDTTT_BLOCK 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Generic EDTT interface + */ +bool edtt_start(void); +bool edtt_stop(void); +int edtt_read(uint8_t *ptr, size_t size, int flags); +int edtt_write(uint8_t *ptr, size_t size, int flags); + +/** + * Exclusive functions for the BabbleSim driver + */ +void enable_edtt_mode(void); +void set_edtt_autoshutdown(bool mode); + +#ifdef __cplusplus +} +#endif + +#endif /* EDTT_DRIVER_H */ diff --git a/babblesim/edtt/hci_transport/pkg.yml b/babblesim/edtt/hci_transport/pkg.yml new file mode 100644 index 0000000000..8ad24cd3c6 --- /dev/null +++ b/babblesim/edtt/hci_transport/pkg.yml @@ -0,0 +1,38 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +pkg.name: babblesim/edtt/hci_transport +pkg.description: Provides communication with EDTT bridge over named pipes +pkg.author: "Apache Mynewt " +pkg.homepage: "http://mynewt.apache.org/" +pkg.deps: + - "@apache-mynewt-core/sys/console/stub" + - "@apache-mynewt-core/sys/log/stub" + - "@apache-mynewt-core/sys/stats/full" + - "@apache-mynewt-core/kernel/os" + - nimble/controller + +# allows to override settings from nimble/transport +pkg.subpriority: 1 + +pkg.apis: + - ble_transport + +pkg.init: + ble_hci_edtt_init: 249 diff --git a/babblesim/edtt/hci_transport/src/ble_hci_edtt.c b/babblesim/edtt/hci_transport/src/ble_hci_edtt.c new file mode 100644 index 0000000000..5f84fa7b49 --- /dev/null +++ b/babblesim/edtt/hci_transport/src/ble_hci_edtt.c @@ -0,0 +1,819 @@ +/* + * Copyright (c) 2019 Oticon A/S + * Copyright (c) 2021 Codecoup + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include "sysinit/sysinit.h" +#include "syscfg/syscfg.h" +#include "os/os_eventq.h" +#include "controller/ble_ll.h" + +/* BLE */ +#include "nimble/ble.h" +#include "nimble/hci_common.h" + +#include "bs_symbols.h" +#include "bs_types.h" +#include "time_machine.h" +#include "ble_hci_edtt.h" +#include "edtt_driver.h" +#include "commands.h" + +#define BLE_HCI_EDTT_NONE 0x00 +#define BLE_HCI_EDTT_CMD 0x01 +#define BLE_HCI_EDTT_ACL 0x02 +#define BLE_HCI_EDTT_EVT 0x04 + +#define BT_HCI_OP_VS_WRITE_BD_ADDR 0xFC06 + +/* A packet for queueing EDTT/HCI commands and events */ +struct ble_hci_edtt_pkt { + struct os_event ev; + STAILQ_ENTRY(ble_hci_edtt_pkt) next; + uint32_t timestamp; + uint8_t type; + void *data; +}; + +static struct os_eventq edtt_q_svc; +static struct os_eventq edtt_q_data; +static struct os_eventq edtt_q_event; +static uint8_t edtt_q_event_count; + +static uint16_t waiting_opcode; +static enum commands_t waiting_response; + +static struct os_task edtt_poller_task; +static struct os_task edtt_service_task; + +#if EDTT_HCI_LOGS +extern unsigned int global_device_nbr; +static FILE *fptr; + +static void +log_hex_array(uint8_t *buf, int len) +{ + int i; + for (i = 0; i < len; i++) { + fprintf(fptr, "%02X ", buf[i]); + } +} + +static void +log_hci_cmd(uint16_t opcode, uint8_t *buf, int len) +{ + if (fptr) { + fprintf(fptr, "> %llu %02d %02d ", now, BLE_HCI_OCF(opcode), (BLE_HCI_OGF(opcode))); + log_hex_array(buf, len); + fputs("\n\n", fptr); + fflush(fptr); + } +} + +static void +log_hci_evt(struct ble_hci_ev *hdr) +{ + if (fptr) { + fprintf(fptr, "< %llu %02d ", now, hdr->opcode); + log_hex_array(hdr->data, hdr->length); + fputs("\n\n", fptr); + fflush(fptr); + } +} + +static void +log_hci_init() +{ + int flen = (int) strlen(MYNEWT_VAL(EDTT_HCI_LOG_FILE)) + 7; + char *fpath = (char *) calloc(flen, sizeof(char)); + sprintf(fpath, "%s_%02d.log", MYNEWT_VAL(EDTT_HCI_LOG_FILE), global_device_nbr); + fptr = fopen(fpath, "w"); + free(fpath); +} +#endif + +static int +ble_hci_edtt_acl_tx(struct os_mbuf *om) +{ + struct ble_hci_edtt_pkt *pkt; + + /* If this packet is zero length, just free it */ + if (OS_MBUF_PKTLEN(om) == 0) { + os_mbuf_free_chain(om); + return 0; + } + + pkt = calloc(1, sizeof(*pkt)); + pkt->type = BLE_HCI_EDTT_ACL; + pkt->data = om; + + os_eventq_put(&edtt_q_svc, &pkt->ev); + + return 0; +} + +static int +ble_hci_edtt_cmdevt_tx(uint8_t *hci_ev, uint8_t edtt_type) +{ + struct ble_hci_edtt_pkt *pkt; + + pkt = calloc(1, sizeof(*pkt)); + pkt->type = edtt_type; + pkt->data = hci_ev; + + os_eventq_put(&edtt_q_svc, &pkt->ev); + + return 0; +} + +/** + * Sends an HCI event from the controller to the host. + * + * @param cmd The HCI event to send. This buffer must be + * allocated via ble_hci_trans_buf_alloc(). + * + * @return 0 on success; + * A BLE_ERR_[...] error code on failure. + */ +int +ble_transport_to_hs_evt_impl(void *buf) +{ + return ble_hci_edtt_cmdevt_tx(buf, BLE_HCI_EDTT_EVT); +} + +/** + * Sends ACL data from controller to host. + * + * @param om The ACL data packet to send. + * + * @return 0 on success; + * A BLE_ERR_[...] error code on failure. + */ +int +ble_transport_to_hs_acl_impl(struct os_mbuf *om) +{ + return ble_hci_edtt_acl_tx(om); +} + +void +ble_transport_hs_init(void) +{ + +} + +/** + * @brief Clean out excess bytes from the input buffer + */ +static void +read_excess_bytes(uint16_t size) +{ + if (size > 0) { + uint8_t buffer[size]; + + edtt_read((uint8_t *) buffer, size, EDTTT_BLOCK); + bs_trace_raw_time(3, "command size wrong! (%u extra bytes removed)", size); + } +} + +/** + * @brief Provide an error response when an HCI command send failed + */ +static void +error_response(int error) +{ + uint16_t response = waiting_response; + int le_error = error; + uint16_t size = sizeof(le_error); + + edtt_write((uint8_t *) &response, sizeof(response), EDTTT_BLOCK); + edtt_write((uint8_t *) &size, sizeof(size), EDTTT_BLOCK); + edtt_write((uint8_t *) &le_error, sizeof(le_error), EDTTT_BLOCK); + waiting_response = CMD_NOTHING; + waiting_opcode = 0; +} + +/** + * @brief Allocate buffer for HCI command, fill in parameters and send the + * command + */ +static int +send_hci_cmd_to_ctrl(uint16_t opcode, uint8_t param_len, uint16_t response) { + struct ble_hci_cmd *buf; + int err = 0; + waiting_response = response; + waiting_opcode = opcode; + + buf = ble_transport_alloc_cmd(); + if (buf != NULL) { + buf->opcode = opcode; + buf->length = param_len; + + if (param_len) { + edtt_read((uint8_t *) buf->data, param_len, EDTTT_BLOCK); + } + +#if EDTT_HCI_LOGS + log_hci_cmd(opcode, buf->data, param_len); +#endif + + err = ble_transport_to_ll_cmd(buf); + if (err) { + ble_transport_free(buf); + bs_trace_raw_time(3, "Failed to send HCI command %d (err %d)", opcode, err); + error_response(err); + } + } else { + bs_trace_raw_time(3, "Failed to create buffer for HCI command 0x%04x", opcode); + error_response(-1); + } + return err; +} + +/** + * @brief Echo function - echo input received + */ +static void +echo(uint16_t size) +{ + uint16_t response = CMD_ECHO_RSP; + + edtt_write((uint8_t *) &response, sizeof(response), EDTTT_BLOCK); + edtt_write((uint8_t *) &size, sizeof(size), EDTTT_BLOCK); + + if (size > 0) { + uint8_t buff[size]; + + edtt_read(buff, size, EDTTT_BLOCK); + edtt_write(buff, size, EDTTT_BLOCK); + } +} + +/** + * @brief Handle Command Complete HCI event + */ +static void +command_complete(struct ble_hci_ev *evt) +{ + struct ble_hci_ev_command_complete *evt_cc = (void *) evt->data; + uint16_t response = waiting_response; + uint16_t size = evt->length - sizeof(evt_cc->num_packets) - sizeof(evt_cc->opcode); + + if (evt_cc->opcode == 0) { + /* ignore nop */ + } else if (evt_cc->opcode == waiting_opcode) { + bs_trace_raw_time(9, "Command complete for 0x%04x", waiting_opcode); + + edtt_write((uint8_t *) &response, sizeof(response), EDTTT_BLOCK); + edtt_write((uint8_t *) &size, sizeof(size), EDTTT_BLOCK); + edtt_write((uint8_t *) &evt_cc->status, sizeof(evt_cc->status), EDTTT_BLOCK); + edtt_write((uint8_t *) &evt_cc->return_params, size - sizeof(evt_cc->status), EDTTT_BLOCK); + waiting_opcode = 0; + } else { + bs_trace_raw_time(5, "Not waiting for 0x(%04x) command status," + " expected 0x(%04x)", evt_cc->opcode, waiting_opcode); + } +} + +/** + * @brief Handle Command Status HCI event + */ +static void +command_status(struct ble_hci_ev *evt) +{ + struct ble_hci_ev_command_status *evt_cs = (void *) evt->data; + uint16_t opcode = evt_cs->opcode; + uint16_t response = waiting_response; + uint16_t size; + + size = evt->length - sizeof(evt_cs->num_packets) - sizeof(evt_cs->opcode); + + if (opcode == waiting_opcode) { + bs_trace_raw_time(9, "Command status for 0x%04x", waiting_opcode); + + edtt_write((uint8_t *) &response, sizeof(response), EDTTT_BLOCK); + edtt_write((uint8_t *) &size, sizeof(size), EDTTT_BLOCK); + edtt_write((uint8_t *) &evt_cs->status, sizeof(evt_cs->status), EDTTT_BLOCK); + edtt_write((uint8_t *) &evt_cs->num_packets, size - sizeof(evt_cs->status), EDTTT_BLOCK); + waiting_opcode = 0; + } else { + bs_trace_raw_time(5, "Not waiting for 0x(%04x) command status," + " expected 0x(%04x)", opcode, waiting_opcode); + } +} + +static void +free_data(struct ble_hci_edtt_pkt *pkt) +{ + assert(pkt); + os_mbuf_free_chain(pkt->data); + free(pkt); +} + +static void +free_event(struct ble_hci_edtt_pkt *pkt) +{ + assert(pkt); + ble_transport_free(pkt->data); + free(pkt); +} + +/** + * @brief Allocate and store an event in the event queue + */ +static struct ble_hci_edtt_pkt * +queue_event(struct ble_hci_ev *evt) +{ + struct ble_hci_edtt_pkt *pkt; + + pkt = calloc(1, sizeof(*pkt)); + assert(pkt); + pkt->timestamp = tm_get_hw_time(); + pkt->type = BLE_HCI_EDTT_EVT; + pkt->data = evt; + + os_eventq_put(&edtt_q_event, &pkt->ev); + edtt_q_event_count++; + + return pkt; +} + +static struct ble_hci_edtt_pkt * +queue_data(struct os_mbuf *om) +{ + struct ble_hci_edtt_pkt *pkt; + + pkt = calloc(1, sizeof(*pkt)); + assert(pkt); + pkt->timestamp = tm_get_hw_time(); + pkt->type = BLE_HCI_EDTT_ACL; + pkt->data = om; + + os_eventq_put(&edtt_q_data, &pkt->ev); + + return pkt; +} + + +static void * +dup_complete_evt(void *evt) +{ + struct ble_hci_ev *evt_copy; + + /* max evt size is always 257 */ + evt_copy = ble_transport_alloc_evt(0); + memcpy(evt_copy, evt, 257); + ble_transport_free(evt); + + return evt_copy; +} + +/** + * @brief Thread to service events and ACL data packets from the HCI input queue + */ +static void +service_events(void *arg) +{ + struct ble_hci_edtt_pkt *pkt; + struct ble_hci_ev *evt; + struct ble_hci_ev_num_comp_pkts *evt_ncp; + + while (1) { + pkt = (void *)os_eventq_get(&edtt_q_svc); + + if (pkt->type == BLE_HCI_EDTT_EVT) { + evt = (void *)pkt->data; + +#if EDTT_HCI_LOGS + log_hci_evt(hdr); +#endif + + /* Prepare and send EDTT events */ + switch (evt->opcode) { + case BLE_HCI_EVCODE_COMMAND_COMPLETE: + evt = dup_complete_evt(evt); + queue_event(evt); + command_complete(evt); + break; + case BLE_HCI_EVCODE_COMMAND_STATUS: + evt = dup_complete_evt(evt); + queue_event(evt); + command_status(evt); + break; + case BLE_HCI_EVCODE_NUM_COMP_PKTS: + evt_ncp = (void *)evt->data; + /* This should always be true for NimBLE LL */ + assert(evt_ncp->count == 1); + if (evt_ncp->completed[0].packets == 0) { + /* Discard, because EDTT does not like it */ + ble_transport_free(evt); + } else { + queue_event(evt); + } + break; + case BLE_HCI_OPCODE_NOP: + /* Ignore noop bytes from Link layer */ + ble_transport_free(evt); + break; + default: + /* Queue HCI events. We will send them to EDTT + * on CMD_GET_EVENT_REQ. */ + queue_event(evt); + } + } else if (pkt->type == BLE_HCI_EDTT_ACL) { + queue_data(pkt->data); + } + + free(pkt); + } +} + +/** + * @brief Flush all HCI events from the input-copy queue + */ +static void +flush_events(uint16_t size) +{ + uint16_t response = CMD_FLUSH_EVENTS_RSP; + struct ble_hci_edtt_pkt *pkt; + + while ((pkt = (void *)os_eventq_get_no_wait(&edtt_q_event))) { + free_event(pkt); + edtt_q_event_count--; + } + read_excess_bytes(size); + size = 0; + + edtt_write((uint8_t *)&response, sizeof(response), EDTTT_BLOCK); + edtt_write((uint8_t *)&size, sizeof(size), EDTTT_BLOCK); +} + +/** + * @brief Get next available HCI event from the input-copy queue + */ +static void +get_event(uint16_t size) +{ + uint16_t response = CMD_GET_EVENT_RSP; + struct ble_hci_edtt_pkt *pkt; + struct ble_hci_ev *evt; + + read_excess_bytes(size); + size = 0; + + edtt_write((uint8_t *)&response, sizeof(response), EDTTT_BLOCK); + pkt = (void*)os_eventq_get(&edtt_q_event); + if (pkt) { + evt = pkt->data; + size = sizeof(pkt->timestamp) + sizeof(*evt) + evt->length; + + edtt_write((uint8_t *)&size, sizeof(size), EDTTT_BLOCK); + edtt_write((uint8_t *)&pkt->timestamp, sizeof(pkt->timestamp), EDTTT_BLOCK); + edtt_write((uint8_t *)evt, sizeof(*evt) + evt->length, EDTTT_BLOCK); + + free_event(pkt); + + edtt_q_event_count--; + } else { + edtt_write((uint8_t *)&size, sizeof(size), EDTTT_BLOCK); + } +} + +/** + * @brief Get next available HCI events from the input-copy queue + */ +static void +get_events(uint16_t size) +{ + uint16_t response = CMD_GET_EVENT_RSP; + struct ble_hci_edtt_pkt *pkt; + struct ble_hci_ev *evt; + uint8_t count = edtt_q_event_count; + + read_excess_bytes(size); + size = 0; + + edtt_write((uint8_t *)&response, sizeof(response), EDTTT_BLOCK); + edtt_write((uint8_t *)&count, sizeof(count), EDTTT_BLOCK); + + while (count--) { + pkt = (void *)os_eventq_get_no_wait(&edtt_q_event); + assert(pkt); + evt = pkt->data; + size = sizeof(pkt->timestamp) + sizeof(*evt) + evt->length; + + edtt_write((uint8_t *)&size, sizeof(size), EDTTT_BLOCK); + edtt_write((uint8_t *)&pkt->timestamp, sizeof(pkt->timestamp), EDTTT_BLOCK); + edtt_write((uint8_t *)evt, sizeof(*evt) + evt->length, EDTTT_BLOCK); + + free_event(pkt); + + edtt_q_event_count--; + } +} + +/** + * @brief Check whether an HCI event is available in the input-copy queue + */ +static void +has_event(uint16_t size) +{ + struct has_event_resp { + uint16_t response; + uint16_t size; + uint8_t count; + } __attribute__((packed)); + struct has_event_resp le_response = { + .response = CMD_HAS_EVENT_RSP, + .size = 1, + .count = edtt_q_event_count + }; + + if (size > 0) { + read_excess_bytes(size); + } + edtt_write((uint8_t *) &le_response, sizeof(le_response), EDTTT_BLOCK); +} + +/** + * @brief Flush all ACL Data Packages from the input-copy queue + */ +static void +le_flush_data(uint16_t size) +{ + uint16_t response = CMD_LE_FLUSH_DATA_RSP; + struct ble_hci_edtt_pkt *pkt; + + while ((pkt = (void *)os_eventq_get_no_wait(&edtt_q_data))) { + free_data(pkt); + } + + read_excess_bytes(size); + size = 0; + + edtt_write((uint8_t *)&response, sizeof(response), EDTTT_BLOCK); + edtt_write((uint8_t *)&size, sizeof(size), EDTTT_BLOCK); +} + +/** + * @brief Check whether an ACL Data Package is available in the input-copy queue + */ +static void +le_data_ready(uint16_t size) +{ + struct has_data_resp { + uint16_t response; + uint16_t size; + uint8_t empty; + } __attribute__((packed)); + struct has_data_resp le_response = { + .response = CMD_LE_DATA_READY_RSP, + .size = 1, + .empty = 0 + }; + + if (size > 0) { + read_excess_bytes(size); + } + + /* There's no API to check if eventq is empty but a little hack will do... */ + if (edtt_q_data.evq_list.stqh_first == NULL) { + le_response.empty = 1; + } + + edtt_write((uint8_t *) &le_response, sizeof(le_response), EDTTT_BLOCK); +} + +/** + * @brief Get next available HCI Data Package from the input-copy queue + */ +static void +le_data_read(uint16_t size) +{ + uint16_t response = CMD_LE_DATA_READ_RSP; + struct ble_hci_edtt_pkt *pkt; + struct os_mbuf *om; + + read_excess_bytes(size); + size = 0; + + edtt_write((uint8_t *)&response, sizeof(response), EDTTT_BLOCK); + pkt = (void *)os_eventq_get(&edtt_q_data); + if (pkt) { + om = pkt->data; + + size = sizeof(pkt->timestamp) + OS_MBUF_PKTLEN(om); + + edtt_write((uint8_t *)&size, sizeof(size), EDTTT_BLOCK); + edtt_write((uint8_t *)&pkt->timestamp, sizeof(pkt->timestamp), EDTTT_BLOCK); + + while (om != NULL) { + edtt_write((uint8_t *)om->om_data, om->om_len, EDTTT_BLOCK); + om = SLIST_NEXT(om, om_next); + } + + free_data(pkt); + } else { + edtt_write((uint8_t *)&size, sizeof(size), EDTTT_BLOCK); + } +} + +/** + * @brief Write ACL Data Package to the Controller + */ +static void +le_data_write(uint16_t size) +{ + struct data_write_resp { + uint16_t code; + uint16_t size; + uint8_t status; + } __attribute__((packed)); + struct data_write_resp response = { + .code = CMD_LE_DATA_WRITE_RSP, + .size = 1, + .status = 0 + }; + struct os_mbuf *om; + struct hci_data_hdr hdr; + int err; + + if (size >= sizeof(hdr)) { + om = ble_transport_alloc_acl_from_hs(); + if (om) { + edtt_read((void *)&hdr, sizeof(hdr), EDTTT_BLOCK); + size -= sizeof(hdr); + + os_mbuf_append(om, &hdr, sizeof(hdr)); + + if (size >= hdr.hdh_len) { + /* Don't care, we have plenty of stack */ + uint8_t tmp[hdr.hdh_len]; + + edtt_read(tmp, hdr.hdh_len, EDTTT_BLOCK); + size -= hdr.hdh_len; + + os_mbuf_append(om, tmp, hdr.hdh_len); + } + + err = ble_transport_to_ll_acl(om); + if (err) { + bs_trace_raw_time(3, "Failed to send ACL Data (err %d)", err); + } + } else { + err = -2; /* Failed to allocate data buffer */ + bs_trace_raw_time(3, "Failed to create buffer for ACL Data."); + } + } else { + /* Size too small for header (handle and data length) */ + err = -3; + } + read_excess_bytes(size); + + response.status = err; + edtt_write((uint8_t *) &response, sizeof(response), EDTTT_BLOCK); +} + +static void +fake_write_bd_addr_cc() +{ + struct ble_hci_ev_command_complete *ev; + struct ble_hci_ev *hci_ev; + waiting_opcode = BT_HCI_OP_VS_WRITE_BD_ADDR; + waiting_response = CMD_WRITE_BD_ADDR_RSP; + + hci_ev = ble_transport_alloc_evt(0); + if (hci_ev) { + hci_ev->opcode = BLE_HCI_EVCODE_COMMAND_COMPLETE; + hci_ev->length = sizeof(*ev); + ev = (void *) hci_ev->data; + + ev->num_packets = 1; + ev->opcode = waiting_opcode; + ev->status = 0; + ble_hci_edtt_cmdevt_tx((uint8_t *) hci_ev, BLE_HCI_EDTT_EVT); + } +} + +/* Reads and executes EDTT commands. */ +static void +edtt_poller(void *arg) { + uint16_t command; + uint16_t size; + uint16_t opcode; + uint8_t bdaddr[6]; + + /* Initialize HCI command opcode and response variables */ + waiting_opcode = 0; + waiting_response = CMD_NOTHING; + edtt_q_event_count = 0; + + /* Initialize and start EDTT system */ + enable_edtt_mode(); + set_edtt_autoshutdown(true); + edtt_start(); + +#if EDTT_HCI_LOGS + log_hci_init(); +#endif + + while (1) { + edtt_read((uint8_t *) &command, sizeof(command), EDTTT_BLOCK); + edtt_read((uint8_t *) &size, sizeof(size), EDTTT_BLOCK); + + bs_trace_raw_time(4, "command 0x%04X received (size %u) " + "events=%u\n", + command, size, edtt_q_event_count); + + switch (command) { + case CMD_ECHO_REQ: + echo(size); + break; + case CMD_FLUSH_EVENTS_REQ: + flush_events(size); + break; + case CMD_HAS_EVENT_REQ: + has_event(size); + break; + case CMD_GET_EVENT_REQ: { + uint8_t multiple; + + edtt_read((uint8_t *) &multiple, sizeof(multiple), EDTTT_BLOCK); + if (multiple) + get_events(--size); + else + get_event(--size); + } + break; + case CMD_LE_FLUSH_DATA_REQ: + le_flush_data(size); + break; + case CMD_LE_DATA_READY_REQ: + le_data_ready(size); + break; + case CMD_LE_DATA_WRITE_REQ: + le_data_write(size); + break; + case CMD_LE_DATA_READ_REQ: + le_data_read(size); + break; + case CMD_WRITE_BD_ADDR_REQ: + edtt_read((uint8_t *) &opcode, sizeof(opcode), EDTTT_BLOCK); + + if (opcode == BT_HCI_OP_VS_WRITE_BD_ADDR) { + edtt_read((uint8_t *) &bdaddr, sizeof(bdaddr), EDTTT_BLOCK); + ble_ll_set_public_addr(bdaddr); + fake_write_bd_addr_cc(); + } else { + assert(0); + } + break; + default: + if (size >= 2) { + edtt_read((uint8_t *) &opcode, sizeof(opcode), EDTTT_BLOCK); + send_hci_cmd_to_ctrl(opcode, size - 2, command + 1); + } + } + } +} + +int +edtt_init(void) +{ + os_stack_t dummy_stack; + int rc; + + rc = os_task_init(&edtt_poller_task, "edttpoll", edtt_poller, NULL, + MYNEWT_VAL(EDTT_POLLER_PRIO), OS_WAIT_FOREVER, + &dummy_stack, 1); + assert(rc == 0); + + rc = os_task_init(&edtt_service_task, "edttsvc", service_events, NULL, + MYNEWT_VAL(EDTT_POLLER_PRIO) + 1, OS_WAIT_FOREVER, + &dummy_stack, 1); + assert(rc == 0); + + return 0; +} + +/** + * Initializes the EDTT HCI transport module. + * + * @return 0 on success; + * A BLE_ERR_[...] error code on failure. + */ +void +ble_hci_edtt_init(void) +{ + /* Ensure this function only gets called by sysinit. */ + SYSINIT_ASSERT_ACTIVE(); + + os_eventq_init(&edtt_q_svc); + os_eventq_init(&edtt_q_event); + os_eventq_init(&edtt_q_data); +} diff --git a/babblesim/edtt/hci_transport/src/edtt_driver_bsim.c b/babblesim/edtt/hci_transport/src/edtt_driver_bsim.c new file mode 100644 index 0000000000..5fce52633a --- /dev/null +++ b/babblesim/edtt/hci_transport/src/edtt_driver_bsim.c @@ -0,0 +1,289 @@ +/* + * Copyright (c) 2019 Oticon A/S + * Copyright (c) 2021 Codecoup + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include + +#include "bs_tracing.h" +#include "bs_oswrap.h" +#include "bs_pc_base_fifo_user.h" + +#include +#include "edtt_driver.h" +#include "os/os_sched.h" + +/* Recheck if something arrived from the EDTT every 5ms */ +#define EDTT_IF_RECHECK_DELTA 5 /* ms */ + +/* We want the runs to be deterministic => we want to resync with the Phy + * before we retry any read so the bridge device may also run + */ +#define EDTT_SIMU_RESYNC_TIME_WITH_EDTT \ + (EDTT_IF_RECHECK_DELTA * 1000 - 1) + +static int edtt_mode_enabled = 0; + +/* In this mode, when the EDTTool closes the FIFO we automatically terminate + * this simulated device. If false, we just continue running + */ +static int edtt_autoshutdown; + +#define TO_DEVICE 0 +#define TO_BRIDGE 1 +static int fifo[2] = { -1, -1 }; +static char *fifo_path[2] = {NULL, NULL}; + +extern unsigned int global_device_nbr; + +static void edttd_clean_up(void); +static void edptd_create_fifo_if(void); +static int fifo_low_level_read(uint8_t *bufptr, int size); + +bool edtt_start(void) +{ + if (edtt_mode_enabled == false) { + /* otherwise we don't try to open the EDTT interface */ + return true; + } + + edptd_create_fifo_if(); + + extern void tm_set_phy_max_resync_offset(uint64_t offset_in_us); + tm_set_phy_max_resync_offset(EDTT_SIMU_RESYNC_TIME_WITH_EDTT); + return true; +} + +bool edtt_stop(void) +{ + if (edtt_mode_enabled == false) { + /* otherwise we don't try to open the EDTT interface */ + return true; + } + + bs_trace_raw(9, "EDTTT: %s called\n", __func__); + edttd_clean_up(); + edtt_mode_enabled = false; + return true; +} + +static void +print_hex_array(int lvl, uint8_t *buf, int len) +{ + char str[2*len]; + char *p = str; + int i; + for (i = 0; i < len; i++) { + if (i > 0) *p++ = ' '; + sprintf(p++, "%02X", buf[i]); + } + *p = '\n'; + bs_trace_raw(lvl, str); +} + +/** + * Attempt to read size bytes thru the EDTT IF into the buffer <*ptr> + * can be set to EDTTT_BLOCK or EDTTT_NONBLOCK + * + * If set to EDTTT_BLOCK it will block the calling thread until + * bytes have been read or the interface has been closed. + * If set to EDTTT_NONBLOCK it returns as soon as there is no more data to be + * read + * + * Returns the amount of read bytes, or -1 on error + */ +int edtt_read(uint8_t *ptr, size_t size, int flags) +{ + uint8_t *buf = ptr; + + if (edtt_mode_enabled == false) { + return -1; + } + + bs_trace_raw_time(8, "EDTT: Asked to read %i bytes\n", size); + int read = 0; + + while (size > 0) { + int received_bytes; + + received_bytes = fifo_low_level_read(ptr, size); + if (received_bytes < 0) { + return -1; + } else if (received_bytes > 0) { + size -= received_bytes; + ptr += received_bytes; + read += received_bytes; + } else { + if (flags & EDTTT_BLOCK) { + bs_trace_raw_time(9, "EDTT: No enough data yet," + "sleeping for %i ms\n", + EDTT_IF_RECHECK_DELTA); + os_sched_sleep(os_sched_get_current_task(), + os_time_ms_to_ticks32(EDTT_IF_RECHECK_DELTA)); + os_sched(NULL); + } else { + bs_trace_raw_time(9, "EDTT: No enough data yet," + "returning\n"); + break; + } + } + } + + if (read > 0) { + bs_trace_raw_time(8, "Read %i bytes:\n", read); + print_hex_array(8, buf, read); + } + return read; +} + +/** + * Write bytes from toward the EDTTool + * + * is ignored in this driver, all writes to the tool are + * instantaneous + */ +int edtt_write(uint8_t *ptr, size_t size, int flags) +{ + if (edtt_mode_enabled == false) { + return -1; + } + + bs_trace_raw_time(6, "EDTT: Asked to write %i bytes: ", size); + print_hex_array(6, ptr, size); + + if (write(fifo[TO_BRIDGE], ptr, size) != size) { + if (errno == EPIPE) { + bs_trace_error_line("EDTT IF suddenly closed by other " + "end\n"); + } + if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) { + bs_trace_error_line("EDTT IF to bridge filled up (FIFO " + "size needs to be increased)\n"); + } + bs_trace_error_line("EDTT IF: Unexpected error on write\n"); + } + return size; +} + +/* + * Applications may want to enable the EDTT interface only in some + * cases. By default it is not enabled in this driver. This function + * must be called once before starting it to do so + */ +void enable_edtt_mode(void) +{ + edtt_mode_enabled = true; +} + +/** + * Automatically terminate this device execution once the EDTTool disconnects + */ +void set_edtt_autoshutdown(bool Mode) +{ + edtt_autoshutdown = Mode; +} + +static void edptd_create_fifo_if(void) +{ + int flags; + + bs_trace_raw_time(9, "Bringing EDTT IF up (waiting for other side)\n"); + + if (pb_com_path == NULL) { + bs_trace_error_line("Not connected to Phy." + "EDTT IF cannot be brough up\n"); + } + + /* At this point we have connected to the Phy so the COM folder does + * already exist + * also SIGPIPE is already ignored + */ + + fifo_path[TO_DEVICE] = (char *)bs_calloc(pb_com_path_length + 30, + sizeof(char)); + fifo_path[TO_BRIDGE] = (char *)bs_calloc(pb_com_path_length + 30, + sizeof(char)); + sprintf(fifo_path[TO_DEVICE], "%s/Device%i.PTTin", + pb_com_path, global_device_nbr); + sprintf(fifo_path[TO_BRIDGE], "%s/Device%i.PTTout", + pb_com_path, global_device_nbr); + + if ((pb_create_fifo_if_not_there(fifo_path[TO_DEVICE]) != 0) + || (pb_create_fifo_if_not_there(fifo_path[TO_BRIDGE]) != 0)) { + bs_trace_error_line("Couldnt create FIFOs for EDTT IF\n"); + } + + /* we block here until the bridge opens its end */ + fifo[TO_BRIDGE] = open(fifo_path[TO_BRIDGE], O_WRONLY); + if (fifo[TO_BRIDGE] == -1) { + bs_trace_error_line("Couldn't create FIFOs for EDTT IF\n"); + } + + flags = fcntl(fifo[TO_BRIDGE], F_GETFL); + flags |= O_NONBLOCK; + fcntl(fifo[TO_BRIDGE], F_SETFL, flags); + + /* we will block here until the bridge opens its end */ + fifo[TO_DEVICE] = open(fifo_path[TO_DEVICE], O_RDONLY); + if (fifo[TO_DEVICE] == -1) { + bs_trace_error_line("Couldn't create FIFOs for EDTT IF\n"); + } + + flags = fcntl(fifo[TO_DEVICE], F_GETFL); + flags |= O_NONBLOCK; + fcntl(fifo[TO_DEVICE], F_SETFL, flags); +} + +static void edttd_clean_up(void) +{ + for (int dir = TO_DEVICE ; dir <= TO_BRIDGE ; dir++) { + if (fifo_path[dir]) { + if (fifo[dir] != -1) { + close(fifo[dir]); + remove(fifo_path[dir]); + fifo[dir] = -1; + } + free(fifo_path[dir]); + fifo_path[dir] = NULL; + } + } + if (pb_com_path != NULL) { + rmdir(pb_com_path); + } +} + +static int fifo_low_level_read(uint8_t *bufptr, int size) +{ + int received_bytes = read(fifo[TO_DEVICE], bufptr, size); + + if ((received_bytes == -1) && (errno == EAGAIN)) { + return 0; + } else if (received_bytes == EOF || received_bytes == 0) { + /*The FIFO was closed by the bridge*/ + if (edtt_autoshutdown) { + bs_trace_raw_time(3, "EDTT: FIFO closed " + "(ptt_autoshutdown==true) =>" + " Terminate\n"); + edttd_clean_up(); + bs_trace_exit_line("\n"); + } else { + bs_trace_raw_time(3, "EDTT: FIFO closed " + "(ptt_autoshutdown==false) => We close " + "the FIFOs and move on\n"); + edttd_clean_up(); + edtt_mode_enabled = false; + return -1; + } + } else if (received_bytes == -1) { + bs_trace_error_line("EDTT: Unexpected error\n"); + } + + return received_bytes; +} diff --git a/babblesim/edtt/hci_transport/syscfg.yml b/babblesim/edtt/hci_transport/syscfg.yml new file mode 100644 index 0000000000..ad12f7b5bc --- /dev/null +++ b/babblesim/edtt/hci_transport/syscfg.yml @@ -0,0 +1,40 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +syscfg.defs: + EDTT_HCI_LOG_FILE: + description: > + Path to the HCI log file. Skip file extension + because device id and .log will be appended. + value: "hci_logs" + EDTT_HCI_LOGS: + description: Turn on HCI commands logging. + value: 0 + EDTT_POLLER_PRIO: + description: 'Priority of native EDTT poller task.' + type: task_priority + value: 2 + +syscfg.vals: + BLE_TRANSPORT_ACL_COUNT: 32 + BLE_TRANSPORT_EVT_COUNT: 64 + +syscfg.restrictions: + - BLE_TRANSPORT_HS == "custom" + - BLE_TRANSPORT_LL == "native" \ No newline at end of file diff --git a/porting/targets/dummy_bsp/bsp.yml b/babblesim/hw/bsp/nrf52_bsim/bsp.yml similarity index 67% rename from porting/targets/dummy_bsp/bsp.yml rename to babblesim/hw/bsp/nrf52_bsim/bsp.yml index ecd1d42041..edd2189d16 100644 --- a/porting/targets/dummy_bsp/bsp.yml +++ b/babblesim/hw/bsp/nrf52_bsim/bsp.yml @@ -17,11 +17,15 @@ # under the License. # -bsp.name: "dummy" -bsp.url: -bsp.maker: -bsp.arch: dummy +bsp.name: "nRF52 DK" +bsp.url: https://www.nordicsemi.com/Software-and-Tools/Development-Kits/nRF52-DK +bsp.maker: "Nordic Semiconductor" +bsp.arch: bsim_arch bsp.compiler: "@apache-mynewt-core/compiler/sim" +bsp.downloadscript: "hw/bsp/nrf52_bsim/nordic_pca10040_download.sh" +bsp.debugscript: "hw/bsp/nrf52_bsim/nordic_pca10040_debug.sh" +bsp.downloadscript.WINDOWS.OVERWRITE: "hw/bsp/nrf52_bsim/nordic_pca10040_download.cmd" +bsp.debugscript.WINDOWS.OVERWRITE: "hw/bsp/nrf52_bsim/nordic_pca10040_debug.cmd" bsp.flash_map: areas: @@ -29,28 +33,28 @@ bsp.flash_map: FLASH_AREA_BOOTLOADER: device: 0 offset: 0x00000000 - size: 32kB + size: 16kB FLASH_AREA_IMAGE_0: device: 0 - offset: 0x0000c000 - size: 472kB + offset: 0x00008000 + size: 232kB FLASH_AREA_IMAGE_1: device: 0 - offset: 0x00082000 - size: 472kB + offset: 0x00042000 + size: 232kB FLASH_AREA_IMAGE_SCRATCH: device: 0 - offset: 0x000f8000 - size: 16kB + offset: 0x0007c000 + size: 4kB # User areas. FLASH_AREA_REBOOT_LOG: user_id: 0 device: 0 - offset: 0x00008000 + offset: 0x00004000 size: 16kB FLASH_AREA_NFFS: user_id: 1 device: 0 - offset: 0x000fc000 - size: 16kB + offset: 0x0007d000 + size: 12kB diff --git a/babblesim/hw/bsp/nrf52_bsim/include/bsp/bsp.h b/babblesim/hw/bsp/nrf52_bsim/include/bsp/bsp.h new file mode 100644 index 0000000000..c096b887c2 --- /dev/null +++ b/babblesim/hw/bsp/nrf52_bsim/include/bsp/bsp.h @@ -0,0 +1,91 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_BSP_H +#define H_BSP_H + +#include + +#include "os/mynewt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Define special stackos sections */ +#define sec_data_core __attribute__((section(".data.core"))) +#define sec_bss_core __attribute__((section(".bss.core"))) +#define sec_bss_nz_core __attribute__((section(".bss.core.nz"))) + +/* More convenient section placement macros. */ +#define bssnz_t sec_bss_nz_core + +extern uint8_t _ram_start; +#define RAM_SIZE 0x10000 + +/* LED pins */ +#define LED_1 (17) +#define LED_2 (18) +#define LED_3 (19) +#define LED_4 (20) +#define LED_BLINK_PIN (LED_1) + +/* Buttons */ +#define BUTTON_1 (13) +#define BUTTON_2 (14) +#define BUTTON_3 (15) +#define BUTTON_4 (16) + +/* Arduino pins */ +#define ARDUINO_PIN_D0 11 +#define ARDUINO_PIN_D1 12 +#define ARDUINO_PIN_D2 13 +#define ARDUINO_PIN_D3 14 +#define ARDUINO_PIN_D4 15 +#define ARDUINO_PIN_D5 16 +#define ARDUINO_PIN_D6 17 +#define ARDUINO_PIN_D7 18 +#define ARDUINO_PIN_D8 19 +#define ARDUINO_PIN_D9 20 +#define ARDUINO_PIN_D10 22 +#define ARDUINO_PIN_D11 23 +#define ARDUINO_PIN_D12 24 +#define ARDUINO_PIN_D13 25 +#define ARDUINO_PIN_A0 3 +#define ARDUINO_PIN_A1 4 +#define ARDUINO_PIN_A2 28 +#define ARDUINO_PIN_A3 29 +#define ARDUINO_PIN_A4 30 +#define ARDUINO_PIN_A5 31 + +#define ARDUINO_PIN_RX ARDUINO_PIN_D0 +#define ARDUINO_PIN_TX ARDUINO_PIN_D1 + +#define ARDUINO_PIN_SCL 27 +#define ARDUINO_PIN_SDA 26 + +#define ARDUINO_PIN_SCK ARDUINO_PIN_D13 +#define ARDUINO_PIN_MOSI ARDUINO_PIN_D11 +#define ARDUINO_PIN_MISO ARDUINO_PIN_D12 + +#ifdef __cplusplus +} +#endif + +#endif /* H_BSP_H */ diff --git a/babblesim/hw/bsp/nrf52_bsim/include/os/os_arch.h b/babblesim/hw/bsp/nrf52_bsim/include/os/os_arch.h new file mode 100644 index 0000000000..574f1e8133 --- /dev/null +++ b/babblesim/hw/bsp/nrf52_bsim/include/os/os_arch.h @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _OS_ARCH_ARM_H +#define _OS_ARCH_ARM_H + +#include +#include "syscfg/syscfg.h" +#include "mcu/cmsis_nvic.h" +#include "mcu/cortex_m4.h" +#include +#include "mcu/mcu_sim.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* CPU status register */ +typedef uint32_t os_sr_t; + +/* Stack element */ +typedef uint32_t os_stack_t; + +struct stack_frame; +void os_arch_frame_init(struct stack_frame *sf); + +/* Stack sizes for common OS tasks */ +#define OS_SANITY_STACK_SIZE (2000) +#if MYNEWT_VAL(OS_SYSVIEW) +#define OS_IDLE_STACK_SIZE (80) +#else +#define OS_IDLE_STACK_SIZE (4000) +#endif + +/* Implemented in irq_handler */ +int os_arch_in_isr(void); + +/* Include common arch definitions and APIs */ +#include "os/arch/common.h" + +#ifdef __cplusplus +} +#endif + +#endif /* _OS_ARCH_ARM_H */ diff --git a/babblesim/hw/bsp/nrf52_bsim/include/os/sim.h b/babblesim/hw/bsp/nrf52_bsim/include/os/sim.h new file mode 100644 index 0000000000..3d8837b810 --- /dev/null +++ b/babblesim/hw/bsp/nrf52_bsim/include/os/sim.h @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_KERNEL_SIM_ +#define H_KERNEL_SIM_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include "os/mynewt.h" +#include "mcu/mcu_sim.h" +struct os_task; +struct stack_frame; + +struct stack_frame { + int sf_mainsp; /* stack on which main() is executing */ + sigjmp_buf sf_jb; + struct os_task *sf_task; +}; + +void sim_task_start(struct stack_frame *sf, int rc); +os_stack_t *sim_task_stack_init(struct os_task *t, os_stack_t *stack_top, + int size); +os_error_t sim_os_start(void); +void sim_os_stop(void); +os_error_t sim_os_init(void); +void sim_ctx_sw(struct os_task *next_t); +os_sr_t sim_save_sr(void); +void sim_restore_sr(os_sr_t osr); +int sim_in_critical(void); +void sim_tick_idle(os_time_t ticks); +int sig_block_irq_on(); +void sig_unblock_irq_off(); + +uint8_t inner_main_clean_up(int exit_code); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/babblesim/hw/bsp/nrf52_bsim/nordic_pca10040_debug.cmd b/babblesim/hw/bsp/nrf52_bsim/nordic_pca10040_debug.cmd new file mode 100755 index 0000000000..3444fd3279 --- /dev/null +++ b/babblesim/hw/bsp/nrf52_bsim/nordic_pca10040_debug.cmd @@ -0,0 +1,22 @@ +@rem +@rem Licensed to the Apache Software Foundation (ASF) under one +@rem or more contributor license agreements. See the NOTICE file +@rem distributed with this work for additional information +@rem regarding copyright ownership. The ASF licenses this file +@rem to you under the Apache License, Version 2.0 (the +@rem "License"); you may not use this file except in compliance +@rem with the License. You may obtain a copy of the License at +@rem +@rem http://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, +@rem software distributed under the License is distributed on an +@rem "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@rem KIND, either express or implied. See the License for the +@rem specific language governing permissions and limitations +@rem under the License. +@rem + +@rem Execute a shell with a script of the same name and .sh extension + +@bash "%~dp0%~n0.sh" diff --git a/babblesim/hw/bsp/nrf52_bsim/nordic_pca10040_debug.sh b/babblesim/hw/bsp/nrf52_bsim/nordic_pca10040_debug.sh new file mode 100755 index 0000000000..1e248e4e6a --- /dev/null +++ b/babblesim/hw/bsp/nrf52_bsim/nordic_pca10040_debug.sh @@ -0,0 +1,45 @@ +#!/bin/sh +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +# Called with following variables set: +# - CORE_PATH is absolute path to @apache-mynewt-core +# - BSP_PATH is absolute path to hw/bsp/bsp_name +# - BIN_BASENAME is the path to prefix to target binary, +# .elf appended to name is the ELF file +# - FEATURES holds the target features string +# - EXTRA_JTAG_CMD holds extra parameters to pass to jtag software +# - RESET set if target should be reset when attaching +# - NO_GDB set if we should not start gdb to debug +# + +. $CORE_PATH/hw/scripts/jlink.sh + +FILE_NAME=$BIN_BASENAME.elf + +if [ $# -gt 2 ]; then + SPLIT_ELF_NAME=$3.elf + # TODO -- this magic number 0x42000 is the location of the second image + # slot. we should either get this from a flash map file or somehow learn + # this from the image itself + EXTRA_GDB_CMDS="add-symbol-file $SPLIT_ELF_NAME 0x8000 -readnow" +fi + +JLINK_DEV="nRF52" + +jlink_debug diff --git a/babblesim/hw/bsp/nrf52_bsim/nordic_pca10040_download.cmd b/babblesim/hw/bsp/nrf52_bsim/nordic_pca10040_download.cmd new file mode 100755 index 0000000000..3444fd3279 --- /dev/null +++ b/babblesim/hw/bsp/nrf52_bsim/nordic_pca10040_download.cmd @@ -0,0 +1,22 @@ +@rem +@rem Licensed to the Apache Software Foundation (ASF) under one +@rem or more contributor license agreements. See the NOTICE file +@rem distributed with this work for additional information +@rem regarding copyright ownership. The ASF licenses this file +@rem to you under the Apache License, Version 2.0 (the +@rem "License"); you may not use this file except in compliance +@rem with the License. You may obtain a copy of the License at +@rem +@rem http://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, +@rem software distributed under the License is distributed on an +@rem "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@rem KIND, either express or implied. See the License for the +@rem specific language governing permissions and limitations +@rem under the License. +@rem + +@rem Execute a shell with a script of the same name and .sh extension + +@bash "%~dp0%~n0.sh" diff --git a/babblesim/hw/bsp/nrf52_bsim/nordic_pca10040_download.sh b/babblesim/hw/bsp/nrf52_bsim/nordic_pca10040_download.sh new file mode 100755 index 0000000000..08d45b4641 --- /dev/null +++ b/babblesim/hw/bsp/nrf52_bsim/nordic_pca10040_download.sh @@ -0,0 +1,40 @@ +#!/bin/sh +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +# Called with following variables set: +# - CORE_PATH is absolute path to @apache-mynewt-core +# - BSP_PATH is absolute path to hw/bsp/bsp_name +# - BIN_BASENAME is the path to prefix to target binary, +# .elf appended to name is the ELF file +# - IMAGE_SLOT is the image slot to download to (for non-mfg-image, non-boot) +# - FEATURES holds the target features string +# - EXTRA_JTAG_CMD holds extra parameters to pass to jtag software +# - MFG_IMAGE is "1" if this is a manufacturing image +# - FLASH_OFFSET contains the flash offset to download to +# - BOOT_LOADER is set if downloading a bootloader + +. $CORE_PATH/hw/scripts/jlink.sh + +if [ "$MFG_IMAGE" ]; then + FLASH_OFFSET=0x0 +fi + +JLINK_DEV="nRF52" + +common_file_to_load +jlink_load diff --git a/babblesim/hw/bsp/nrf52_bsim/pkg.yml b/babblesim/hw/bsp/nrf52_bsim/pkg.yml new file mode 100644 index 0000000000..e22e767452 --- /dev/null +++ b/babblesim/hw/bsp/nrf52_bsim/pkg.yml @@ -0,0 +1,37 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +pkg.name: babblesim/hw/bsp/nrf52_bsim +pkg.type: bsp +pkg.description: nRF52 on BabbleSim +pkg.author: "Apache Mynewt " +pkg.homepage: "http://mynewt.apache.org/" + +pkg.cflags: + - '-DNRF52832_XXAA' + - '-DBABBLESIM' + +pkg.cflags.HARDFLOAT: + - -mfloat-abi=hard -mfpu=fpv4-sp-d16 + +pkg.deps: + - "babblesim/core" + - "babblesim/hw/mcu/nordic/nrf52_bsim" + - "@apache-mynewt-core/hw/drivers/uart/uart_hal" + - "@apache-mynewt-nimble/nimble/controller" diff --git a/babblesim/hw/bsp/nrf52_bsim/src/arch/bsim_arch/os_arch.c b/babblesim/hw/bsp/nrf52_bsim/src/arch/bsim_arch/os_arch.c new file mode 100644 index 0000000000..b545688cc4 --- /dev/null +++ b/babblesim/hw/bsp/nrf52_bsim/src/arch/bsim_arch/os_arch.c @@ -0,0 +1,169 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include + +static pthread_mutex_t bsim_ctx_sw_mutex = PTHREAD_MUTEX_INITIALIZER; +static int bsim_pend_sv; + +struct task_info { + pthread_t tid; + pthread_cond_t cond; + void *arg; +}; + +static void * +task_wrapper(void *arg) +{ + struct os_task *me = arg; + struct task_info *ti = me->t_arg; + + pthread_mutex_lock(&bsim_ctx_sw_mutex); + if (g_current_task != me) { + pthread_cond_wait(&ti->cond, &bsim_ctx_sw_mutex); + assert(g_current_task == me); + } + + me->t_func(ti->arg); + + assert(0); +} + +os_stack_t * +os_arch_task_stack_init(struct os_task *t, os_stack_t *stack_top, int size) +{ + struct task_info *ti; + int err; + + ti = calloc(1, sizeof(*ti)); + + pthread_cond_init(&ti->cond, NULL); + ti->arg = t->t_arg; + t->t_arg = ti; + + err = pthread_create(&ti->tid, NULL, task_wrapper, t); + assert(err == 0); + + pthread_setname_np(ti->tid, t->t_name); + + return stack_top; +} + +os_error_t +os_arch_os_start(void) +{ + struct os_task *next_t; + struct task_info *ti; + + os_tick_init(OS_TICKS_PER_SEC, 7); + + next_t = os_sched_next_task(); + assert(next_t); + os_sched_set_current_task(next_t); + + g_os_started = 1; + + ti = next_t->t_arg; + pthread_cond_signal(&ti->cond); + + return 0; +} + +os_error_t +os_arch_os_init(void) +{ + STAILQ_INIT(&g_os_task_list); + TAILQ_INIT(&g_os_run_list); + TAILQ_INIT(&g_os_sleep_list); + + os_init_idle_task(); + + return OS_OK; +} + +void +os_arch_ctx_sw(struct os_task *next_t) +{ + os_sched_ctx_sw_hook(next_t); + bsim_pend_sv = 1; +} + +static void +do_ctx_sw(void) +{ + struct os_task *next_t; + struct os_task *me; + struct task_info *ti, *next_ti; + + next_t = os_sched_next_task(); + assert(next_t); + + bsim_pend_sv = 0; + + assert(g_current_task); + me = g_current_task; + ti = me->t_arg; + + if (me == next_t) { + return; + } + + g_current_task = next_t; + next_ti = g_current_task->t_arg; + + pthread_cond_signal(&next_ti->cond); + pthread_cond_wait(&ti->cond, &bsim_ctx_sw_mutex); + assert(g_current_task == me); +} + +os_sr_t +os_arch_save_sr(void) +{ + return hw_irq_ctrl_change_lock(1); +} + +void +os_arch_restore_sr(os_sr_t osr) +{ + hw_irq_ctrl_change_lock(osr); + + if (!osr && bsim_pend_sv && !os_arch_in_isr()) { + do_ctx_sw(); + } +} + +int +os_arch_in_critical(void) +{ + return hw_irq_ctrl_get_current_lock(); +} + +void +__assert_func(const char *file, int line, const char *func, const char *e) +{ +#if MYNEWT_VAL(OS_ASSERT_CB) + os_assert_cb(); +#endif + _Exit(1); +} diff --git a/babblesim/hw/bsp/nrf52_bsim/src/arch/bsim_arch/startup_nrf52_bsim.c b/babblesim/hw/bsp/nrf52_bsim/src/arch/bsim_arch/startup_nrf52_bsim.c new file mode 100644 index 0000000000..d4810689bc --- /dev/null +++ b/babblesim/hw/bsp/nrf52_bsim/src/arch/bsim_arch/startup_nrf52_bsim.c @@ -0,0 +1,231 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "nrf.h" + +/************************************************************************************************** + Macros +**************************************************************************************************/ + +/*! Weak symbol reference. */ +#define WEAK __attribute__ ((weak)) + +/************************************************************************************************** + Functions +**************************************************************************************************/ + +extern void SystemInit(void); +static void SystemDefaultHandler(void); + +/* Core vectors. */ +void WEAK Reset_Handler(void); +void WEAK NMI_Handler(void); +void WEAK HardFault_Handler(void); +void WEAK MemoryManagement_Handler(void); +void WEAK BusFault_Handler(void); +void WEAK UsageFault_Handler(void); +void WEAK SVC_Handler(void); +void WEAK DebugMon_Handler(void); +void WEAK PendSV_Handler(void); +void WEAK SysTick_Handler(void); +void WEAK POWER_CLOCK_IRQHandler(void); +void WEAK RADIO_IRQHandler(void); +void WEAK UARTE0_UART0_IRQHandler(void); +void WEAK SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQHandler(void); +void WEAK SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1_IRQHandler(void); +void WEAK NFCT_IRQHandler(void); +void WEAK GPIOTE_IRQHandler(void); +void WEAK SAADC_IRQHandler(void); +void WEAK TIMER0_IRQHandler(void); +void WEAK TIMER1_IRQHandler(void); +void WEAK TIMER2_IRQHandler(void); +void WEAK RTC0_IRQHandler(void); +void WEAK TEMP_IRQHandler(void); +void WEAK RNG_IRQHandler(void); +void WEAK ECB_IRQHandler(void); +void WEAK CCM_AAR_IRQHandler(void); +void WEAK WDT_IRQHandler(void); +void WEAK RTC1_IRQHandler(void); +void WEAK QDEC_IRQHandler(void); +void WEAK COMP_LPCOMP_IRQHandler(void); +void WEAK SWI0_EGU0_IRQHandler(void); +void WEAK SWI1_EGU1_IRQHandler(void); +void WEAK SWI2_EGU2_IRQHandler(void); +void WEAK SWI3_EGU3_IRQHandler(void); +void WEAK SWI4_EGU4_IRQHandler(void); +void WEAK SWI5_EGU5_IRQHandler(void); +void WEAK TIMER3_IRQHandler(void); +void WEAK TIMER4_IRQHandler(void); +void WEAK PWM0_IRQHandler(void); +void WEAK PDM_IRQHandler(void); +void WEAK MWU_IRQHandler(void); +void WEAK PWM1_IRQHandler(void); +void WEAK PWM2_IRQHandler(void); +void WEAK SPIM2_SPIS2_SPI2_IRQHandler(void); +void WEAK RTC2_IRQHandler(void); +void WEAK I2S_IRQHandler(void); +void WEAK FPU_IRQHandler(void); + +/* Assign default weak references. Override these values by defining a new function with the same name. */ +#pragma weak NMI_Handler = SystemDefaultHandler +#pragma weak HardFault_Handler = SystemDefaultHandler +#pragma weak MemoryManagement_Handler = SystemDefaultHandler +#pragma weak BusFault_Handler = SystemDefaultHandler +#pragma weak UsageFault_Handler = SystemDefaultHandler +#pragma weak SVC_Handler = SystemDefaultHandler +#pragma weak DebugMon_Handler = SystemDefaultHandler +#pragma weak PendSV_Handler = SystemDefaultHandler +#pragma weak SysTick_Handler = SystemDefaultHandler +#pragma weak POWER_CLOCK_IRQHandler = SystemDefaultHandler +#pragma weak RADIO_IRQHandler = SystemDefaultHandler +#pragma weak UARTE0_UART0_IRQHandler = SystemDefaultHandler +#pragma weak SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQHandler = SystemDefaultHandler +#pragma weak SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1_IRQHandler = SystemDefaultHandler +#pragma weak NFCT_IRQHandler = SystemDefaultHandler +#pragma weak GPIOTE_IRQHandler = SystemDefaultHandler +#pragma weak SAADC_IRQHandler = SystemDefaultHandler +#pragma weak TIMER0_IRQHandler = SystemDefaultHandler +#pragma weak TIMER1_IRQHandler = SystemDefaultHandler +#pragma weak TIMER2_IRQHandler = SystemDefaultHandler +#pragma weak RTC0_IRQHandler = SystemDefaultHandler +#pragma weak TEMP_IRQHandler = SystemDefaultHandler +#pragma weak RNG_IRQHandler = SystemDefaultHandler +#pragma weak ECB_IRQHandler = SystemDefaultHandler +#pragma weak CCM_AAR_IRQHandler = SystemDefaultHandler +#pragma weak WDT_IRQHandler = SystemDefaultHandler +#pragma weak RTC1_IRQHandler = SystemDefaultHandler +#pragma weak QDEC_IRQHandler = SystemDefaultHandler +#pragma weak COMP_LPCOMP_IRQHandler = SystemDefaultHandler +#pragma weak SWI0_EGU0_IRQHandler = SystemDefaultHandler +#pragma weak SWI1_EGU1_IRQHandler = SystemDefaultHandler +#pragma weak SWI2_EGU2_IRQHandler = SystemDefaultHandler +#pragma weak SWI3_EGU3_IRQHandler = SystemDefaultHandler +#pragma weak SWI4_EGU4_IRQHandler = SystemDefaultHandler +#pragma weak SWI5_EGU5_IRQHandler = SystemDefaultHandler +#pragma weak TIMER3_IRQHandler = SystemDefaultHandler +#pragma weak TIMER4_IRQHandler = SystemDefaultHandler +#pragma weak PWM0_IRQHandler = SystemDefaultHandler +#pragma weak PDM_IRQHandler = SystemDefaultHandler +#pragma weak MWU_IRQHandler = SystemDefaultHandler +#pragma weak PWM1_IRQHandler = SystemDefaultHandler +#pragma weak PWM2_IRQHandler = SystemDefaultHandler +#pragma weak SPIM2_SPIS2_SPI2_IRQHandler = SystemDefaultHandler +#pragma weak RTC2_IRQHandler = SystemDefaultHandler +#pragma weak I2S_IRQHandler = SystemDefaultHandler +#pragma weak FPU_IRQHandler = SystemDefaultHandler + +/************************************************************************************************** + Global variables +**************************************************************************************************/ + +/*! Core vector table */ +void (* systemVectors[256])(void) = +{ + 0, /* 0: The initial stack pointer */ + Reset_Handler, /* 1: The reset handler */ + NMI_Handler, /* 2: The NMI handler */ + HardFault_Handler, /* 3: The hard fault handler */ + MemoryManagement_Handler, /* 4: The MPU fault handler */ + BusFault_Handler, /* 5: The bus fault handler */ + UsageFault_Handler, /* 6: The usage fault handler */ + 0, /* 7: Reserved */ + 0, /* 8: Reserved */ + 0, /* 9: Reserved */ + 0, /* 10: Reserved */ + SVC_Handler, /* 11: SVCall handler */ + DebugMon_Handler, /* 12: Debug monitor handler */ + 0, /* 13: Reserved */ + PendSV_Handler, /* 14: The PendSV handler */ + SysTick_Handler, /* 15: The SysTick handler */ + + /* External interrupts */ + POWER_CLOCK_IRQHandler, /* 16: POWER_CLOCK */ + RADIO_IRQHandler, /* 17: RADIO */ + UARTE0_UART0_IRQHandler, /* 18: UART0 */ + SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQHandler, /* 19: SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0 */ + SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1_IRQHandler, /* 20: SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1 */ + NFCT_IRQHandler, /* 21: NFCT */ + GPIOTE_IRQHandler, /* 22: GPIOTE */ + SAADC_IRQHandler, /* 23: SAADC */ + TIMER0_IRQHandler, /* 24: TIMER0 */ + TIMER1_IRQHandler, /* 25: TIMER1 */ + TIMER2_IRQHandler, /* 26: TIMER2 */ + RTC0_IRQHandler, /* 27: RTC0 */ + TEMP_IRQHandler, /* 28: TEMP */ + RNG_IRQHandler, /* 29: RNG */ + ECB_IRQHandler, /* 30: ECB */ + CCM_AAR_IRQHandler, /* 31: CCM_AAR */ + WDT_IRQHandler, /* 32: WDT */ + RTC1_IRQHandler, /* 33: RTC1 */ + QDEC_IRQHandler, /* 34: QDEC */ + COMP_LPCOMP_IRQHandler, /* 35: COMP_LPCOMP */ + SWI0_EGU0_IRQHandler, /* 36: SWI0_EGU0 */ + SWI1_EGU1_IRQHandler, /* 37: SWI1_EGU1 */ + SWI2_EGU2_IRQHandler, /* 38: SWI2_EGU2 */ + SWI3_EGU3_IRQHandler, /* 39: SWI3_EGU3 */ + SWI4_EGU4_IRQHandler, /* 40: SWI4_EGU4 */ + SWI5_EGU5_IRQHandler, /* 41: SWI5_EGU5 */ + TIMER3_IRQHandler, /* 42: TIMER3 */ + TIMER4_IRQHandler, /* 43: TIMER4 */ + PWM0_IRQHandler, /* 44: PWM0 */ + PDM_IRQHandler, /* 45: PDM */ + 0, /* 46: Reserved */ + 0, /* 47: Reserved */ + MWU_IRQHandler, /* 48: MWU */ + PWM1_IRQHandler, /* 49: PWM1 */ + PWM2_IRQHandler, /* 50: PWM2 */ + SPIM2_SPIS2_SPI2_IRQHandler, /* 51: SPIM2_SPIS2_SPI2 */ + RTC2_IRQHandler, /* 52: RTC2 */ + I2S_IRQHandler, /* 53: I2S */ + FPU_IRQHandler, /* 54: FPU */ + 0, /* 55: Reserved */ + 0, /* 56: Reserved */ + 0, /* 57: Reserved */ + 0, /* 58: Reserved */ + 0, /* 59: Reserved */ + 0, /* 60: Reserved */ + 0, /* 61: Reserved */ + 0, /* 62: Reserved */ + 0 /* 63: Reserved */ + /* 64..127: Reserved */ +}; + +/*************************************************************************************************/ +/*! + * \brief Reset handler. + */ +/*************************************************************************************************/ +void Reset_Handler(void) +{ + /* Core initialization. */ + SystemInit(); +} + +/*************************************************************************************************/ +/*! + * \brief Default vector handler. + * + * \param None. + */ +/*************************************************************************************************/ +static void SystemDefaultHandler(void) +{ + volatile unsigned int forever = 1; + while (forever); +} diff --git a/babblesim/hw/bsp/nrf52_bsim/src/hal_bsp.c b/babblesim/hw/bsp/nrf52_bsim/src/hal_bsp.c new file mode 100644 index 0000000000..502f9a9277 --- /dev/null +++ b/babblesim/hw/bsp/nrf52_bsim/src/hal_bsp.c @@ -0,0 +1,160 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#include "os/mynewt.h" +#include "nrfx.h" +#include "flash_map/flash_map.h" +#include "hal/hal_bsp.h" +#include "hal/hal_flash.h" +#include "hal/hal_system.h" +#include "mcu/nrf52_hal.h" +#include "mcu/nrf52_periph.h" +#include "mcu/native_bsp.h" +#include "bsp/bsp.h" +#include "defs/sections.h" +#include "uart_hal/uart_hal.h" +#include "uart/uart.h" + +/* + * What memory to include in coredump. + */ +static const struct hal_bsp_mem_dump dump_cfg[] = { + [0] = { + .hbmd_start = &_ram_start, + .hbmd_size = RAM_SIZE + } +}; + +const struct hal_flash * +hal_bsp_flash_dev(uint8_t id) +{ + switch (id) { + case 0: + return &native_flash_dev; + default: + return NULL; + } +} + +const struct hal_bsp_mem_dump * +hal_bsp_core_dump(int *area_cnt) +{ + *area_cnt = sizeof(dump_cfg) / sizeof(dump_cfg[0]); + return dump_cfg; +} + +int +hal_bsp_power_state(int state) +{ + return (0); +} + +/** + * Returns the configured priority for the given interrupt. If no priority + * configured, return the priority passed in + * + * @param irq_num + * @param pri + * + * @return uint32_t + */ +uint32_t +hal_bsp_get_nvic_priority(int irq_num, uint32_t pri) +{ + uint32_t cfg_pri; + + switch (irq_num) { + /* Radio gets highest priority */ + case RADIO_IRQn: + cfg_pri = 0; + break; + default: + cfg_pri = pri; + } + return cfg_pri; +} + +static void +nrf52_periph_create_timers(void) +{ + int rc; + + (void)rc; + +#if MYNEWT_VAL(TIMER_0) + rc = hal_timer_init(0, NULL); + assert(rc == 0); +#endif +#if MYNEWT_VAL(TIMER_1) + rc = hal_timer_init(1, NULL); + assert(rc == 0); +#endif +#if MYNEWT_VAL(TIMER_2) + rc = hal_timer_init(2, NULL); + assert(rc == 0); +#endif +#if MYNEWT_VAL(TIMER_3) + rc = hal_timer_init(3, NULL); + assert(rc == 0); +#endif +#if MYNEWT_VAL(TIMER_4) + rc = hal_timer_init(4, NULL); + assert(rc == 0); +#endif +#if MYNEWT_VAL(TIMER_5) + rc = hal_timer_init(5, NULL); + assert(rc == 0); +#endif + +#if MYNEWT_VAL(OS_CPUTIME_TIMER_NUM) >= 0 + rc = os_cputime_init(MYNEWT_VAL(OS_CPUTIME_FREQ)); + assert(rc == 0); +#endif +} + +static struct uart_dev os_bsp_uart0; +static struct uart_dev os_bsp_uart1; + +void +hal_bsp_init(void) +{ + /* Make sure system clocks have started */ + hal_system_clock_start(); + + /* Create all available nRF52840 peripherals */ +// nrf52_periph_create(); + nrf52_periph_create_timers(); + + int rc; + + rc = os_dev_create((struct os_dev *) &os_bsp_uart0, "uart0", + OS_DEV_INIT_PRIMARY, 0, uart_hal_init, (void *) NULL); + assert(rc == 0); + rc = os_dev_create((struct os_dev *) &os_bsp_uart1, "uart1", + OS_DEV_INIT_PRIMARY, 0, uart_hal_init, (void *) NULL); + assert(rc == 0); +} + +void +hal_bsp_deinit(void) +{ +} diff --git a/babblesim/hw/bsp/nrf52_bsim/syscfg.yml b/babblesim/hw/bsp/nrf52_bsim/syscfg.yml new file mode 100644 index 0000000000..e5733dd521 --- /dev/null +++ b/babblesim/hw/bsp/nrf52_bsim/syscfg.yml @@ -0,0 +1,76 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +syscfg.defs: + BABBLESIM: 1 + BSP_NRF52: + description: 'Set to indicate that BSP has NRF52' + value: 1 + SOFT_PWM: + description: 'Enable soft PWM' + value: 0 + ENC_FLASH_DEV: + description: 'Encrypting flash driver over interal flash for testing' + value: 0 + UARTBB_0: + description: 'Enable bit-banger UART 0' + value: 0 + RAM_RESIDENT: + description: 'Compile app to be loaded to RAM' + value: 0 + +syscfg.vals: + HAL_SBRK: 0 + OS_TICKS_PER_SEC: 1024 + OS_MAIN_STACK_SIZE: 8000 + MCU_TIMER_POLLER_PRIO: 0 + BLE_LL_PRIO: 1 + MCU_UART_POLLER_PRIO: 9 + + # Enable nRF52832 MCU + MCU_TARGET: nRF52832 + # Set default pins for peripherals + UART_0_PIN_TX: 6 + UART_0_PIN_RX: 8 + UART_0_PIN_RTS: 5 + UART_0_PIN_CTS: 7 + SPI_0_MASTER_PIN_SCK: 23 + SPI_0_MASTER_PIN_MOSI: 24 + SPI_0_MASTER_PIN_MISO: 25 + SPI_0_SLAVE_PIN_SCK: 23 + SPI_0_SLAVE_PIN_MOSI: 24 + SPI_0_SLAVE_PIN_MISO: 25 + SPI_0_SLAVE_PIN_SS: 22 + I2C_0_PIN_SCL: 27 + I2C_0_PIN_SDA: 26 + + CONFIG_FCB_FLASH_AREA: FLASH_AREA_NFFS + REBOOT_LOG_FLASH_AREA: FLASH_AREA_REBOOT_LOG + NFFS_FLASH_AREA: FLASH_AREA_NFFS + COREDUMP_FLASH_AREA: FLASH_AREA_IMAGE_1 + MCU_DCDC_ENABLED: 1 + MCU_LFCLK_SOURCE: LFXO + BOOT_SERIAL_DETECT_PIN: 13 # Button 1 + +syscfg.vals.BLE_CONTROLLER: + TIMER_0: 0 + TIMER_5: 1 + OS_CPUTIME_FREQ: 32768 + OS_CPUTIME_TIMER_NUM: 5 + BLE_LL_RFMGMT_ENABLE_TIME: 1500 + BLE_LL_STACK_SIZE: 4000 diff --git a/babblesim/hw/mcu/nordic/nrf52_bsim/include/mcu/cmsis_nvic.h b/babblesim/hw/mcu/nordic/nrf52_bsim/include/mcu/cmsis_nvic.h new file mode 100644 index 0000000000..11a812d337 --- /dev/null +++ b/babblesim/hw/mcu/nordic/nrf52_bsim/include/mcu/cmsis_nvic.h @@ -0,0 +1,28 @@ +/* mbed Microcontroller Library - cmsis_nvic + * Copyright (c) 2009-2011 ARM Limited. All rights reserved. + * + * CMSIS-style functionality to support dynamic vectors + */ + +#ifndef MBED_CMSIS_NVIC_H +#define MBED_CMSIS_NVIC_H + +#include +#include "nrf.h" + +#define NVIC_NUM_VECTORS (16 + 38) // CORE + MCU Peripherals +#define NVIC_USER_IRQ_OFFSET 16 + +#ifdef __cplusplus +extern "C" { +#endif + +void NVIC_Relocate(void); +void NVIC_SetVector(IRQn_Type IRQn, uint32_t vector); +uint32_t NVIC_GetVector(IRQn_Type IRQn); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/porting/targets/dummy_bsp/include/bsp/bsp.h b/babblesim/hw/mcu/nordic/nrf52_bsim/include/mcu/cortex_m4.h similarity index 86% rename from porting/targets/dummy_bsp/include/bsp/bsp.h rename to babblesim/hw/mcu/nordic/nrf52_bsim/include/mcu/cortex_m4.h index 69e8b1cfbb..93f2044473 100644 --- a/porting/targets/dummy_bsp/include/bsp/bsp.h +++ b/babblesim/hw/mcu/nordic/nrf52_bsim/include/mcu/cortex_m4.h @@ -17,8 +17,11 @@ * under the License. */ -#ifndef H_BSP_H -#define H_BSP_H +#ifndef __MCU_CORTEX_M4_H__ +#define __MCU_CORTEX_M4_H__ + +#include "nrf.h" +#include #ifdef __cplusplus extern "C" { @@ -28,4 +31,4 @@ extern "C" { } #endif -#endif /* H_BSP_H */ +#endif /* __MCU_CORTEX_M4_H__ */ diff --git a/babblesim/hw/mcu/nordic/nrf52_bsim/include/mcu/mcu.h b/babblesim/hw/mcu/nordic/nrf52_bsim/include/mcu/mcu.h new file mode 100644 index 0000000000..1950c85fde --- /dev/null +++ b/babblesim/hw/mcu/nordic/nrf52_bsim/include/mcu/mcu.h @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef __MCU_MCU_H_ +#define __MCU_MCU_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Defines for naming GPIOs. NOTE: the nordic chip docs use numeric labels for + * ports. Port A corresponds to Port 0, B to 1, etc. The nrf52832 has only one + * port and thus uses pins 0 - 31. The nrf52840 has two ports but Port 1 only + * has 16 pins. + */ +#define MCU_GPIO_PORTA(pin) ((0 * 16) + (pin)) +#define MCU_GPIO_PORTB(pin) ((1 * 16) + (pin)) + +#if NRF52 + +#define MCU_SYSVIEW_INTERRUPTS \ + "I#1=Reset,I#2=MNI,I#3=HardFault,I#4=MemoryMgmt,I#5=BusFault,I#6=UsageFault," \ + "I#11=SVCall,I#12=DebugMonitor,I#14=PendSV,I#15=SysTick," \ + "I#16=POWER_CLOCK,I#17=RADIO,I#18=UARTE0_UART0,I#19=SPIx0_TWIx0," \ + "I#20=SPIx1_TWIx1,I#21=NFCT,I#22=GPIOTE,I#23=SAADC," \ + "I#24=TIMER0,I#25=TIMER1,I#26=TIMER2,I#27=RTC0,I#28=TEMP,I#29=RNG,I#30=ECB," \ + "I#31=CCM_AAR,I#32=WDT,I#33=RTC1,I#34=QDEC,I#35=COMP_LPCOMP,I#36=SWI0_EGU0," \ + "I#37=SWI1_EGU1,I#38=SWI2_EGU2,I#39=SWI3_EGU3,I#40=SWI4_EGU4,I#41=SWI5_EGU5," \ + "I#42=TIMER3,I#43=TIMER4,I#44=PWM0,I#45=PDM,I#48=MWU,I#49=PWM1,I#50=PWM2," \ + "I#51=SPIx2,I#52=RTC2,I#53=I2S,I#54=FPU" + +#elif NRF52840_XXAA + +#define MCU_SYSVIEW_INTERRUPTS \ + "I#1=Reset,I#2=MNI,I#3=HardFault,I#4=MemoryMgmt,I#5=BusFault,I#6=UsageFault," \ + "I#11=SVCall,I#12=DebugMonitor,I#14=PendSV,I#15=SysTick," \ + "I#16=POWER_CLOCK,I#17=RADIO,I#18=UARTE0_UART0,I#19=SPIx0_TWIx0," \ + "I#20=SPIx1_TWIx1,I#21=NFCT,I#22=GPIOTE,I#23=SAADC," \ + "I#24=TIMER0,I#25=TIMER1,I#26=TIMER2,I#27=RTC0,I#28=TEMP,I#29=RNG,I#30=ECB," \ + "I#31=CCM_AAR,I#32=WDT,I#33=RTC1,I#34=QDEC,I#35=COMP_LPCOMP,I#36=SWI0_EGU0," \ + "I#37=SWI1_EGU1,I#38=SWI2_EGU2,I#39=SWI3_EGU3,I#40=SWI4_EGU4,I#41=SWI5_EGU5," \ + "I#42=TIMER3,I#43=TIMER4,I#44=PWM0,I#45=PDM,I#48=MWU,I#49=PWM1,I#50=PWM2," \ + "I#51=SPIx2,I#52=RTC2,I#53=I2S,I#54=FPU,I#55=USBD," \ + "I#56=UARTE1,I#57=QSPI,I#58=CRYPTOCELL,I#61=PWM3,I#63=SPIM3" + +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __MCU_MCU_H_ */ diff --git a/babblesim/hw/mcu/nordic/nrf52_bsim/include/mcu/mcu_sim.h b/babblesim/hw/mcu/nordic/nrf52_bsim/include/mcu/mcu_sim.h new file mode 100644 index 0000000000..0cb6fc52b7 --- /dev/null +++ b/babblesim/hw/mcu/nordic/nrf52_bsim/include/mcu/mcu_sim.h @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +#ifndef __MCU_SIM_H__ +#define __MCU_SIM_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +extern char *native_flash_file; +extern char *native_uart_log_file; +extern const char *native_uart_dev_strs[]; + +void static inline hal_debug_break(void) {} + +#ifdef __cplusplus +} +#endif + +#endif /* __MCU_SIM_H__ */ diff --git a/babblesim/hw/mcu/nordic/nrf52_bsim/include/mcu/native_bsp.h b/babblesim/hw/mcu/nordic/nrf52_bsim/include/mcu/native_bsp.h new file mode 100644 index 0000000000..dd794871a8 --- /dev/null +++ b/babblesim/hw/mcu/nordic/nrf52_bsim/include/mcu/native_bsp.h @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +#ifndef H_NATIVE_BSP_ +#define H_NATIVE_BSP_ + +#ifdef __cplusplus +extern "C" { +#endif + +extern const struct hal_flash native_flash_dev; + +int uart_set_dev(int port, const char *dev_str); + +#ifdef __cplusplus +} +#endif + +#endif /* H_NATIVE_BSP_ */ diff --git a/babblesim/hw/mcu/nordic/nrf52_bsim/include/mcu/nrf52_clock.h b/babblesim/hw/mcu/nordic/nrf52_bsim/include/mcu/nrf52_clock.h new file mode 100644 index 0000000000..d86aa98bf2 --- /dev/null +++ b/babblesim/hw/mcu/nordic/nrf52_bsim/include/mcu/nrf52_clock.h @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_NRF52_CLOCK_ +#define H_NRF52_CLOCK_ + +#ifdef __cplusplus + extern "C" { +#endif + +/** + * Request HFXO clock be turned on. Note that each request must have a + * corresponding release. + * + * @return int 0: hfxo was already on. 1: hfxo was turned on. + */ +int nrf52_clock_hfxo_request(void); + +/** + * Release the HFXO; caller no longer needs the HFXO to be turned on. Each call + * to release should have been preceeded by a corresponding call to request the + * HFXO + * + * + * @return int 0: HFXO not stopped by this call (others using it) 1: HFXO + * stopped. + */ +int nrf52_clock_hfxo_release(void); + +#ifdef __cplusplus +} +#endif + +#endif /* H_NRF52_CLOCK_ */ diff --git a/babblesim/hw/mcu/nordic/nrf52_bsim/include/mcu/nrf52_hal.h b/babblesim/hw/mcu/nordic/nrf52_bsim/include/mcu/nrf52_hal.h new file mode 100644 index 0000000000..df9a016542 --- /dev/null +++ b/babblesim/hw/mcu/nordic/nrf52_bsim/include/mcu/nrf52_hal.h @@ -0,0 +1,101 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_NRF52_HAL_ +#define H_NRF52_HAL_ + +#include "cmsis.h" + +#ifdef __cplusplus + extern "C" { +#endif + +/* Helper functions to enable/disable interrupts. */ +#define __HAL_DISABLE_INTERRUPTS(x) \ + do { \ + x = __get_PRIMASK(); \ + __disable_irq(); \ + } while(0); + +#define __HAL_ENABLE_INTERRUPTS(x) \ + do { \ + if (!x) { \ + __enable_irq(); \ + } \ + } while(0); + +struct nrf52_uart_cfg { + int8_t suc_pin_tx; /* pins for IO */ + int8_t suc_pin_rx; + int8_t suc_pin_rts; + int8_t suc_pin_cts; +}; +const struct nrf52_uart_cfg *bsp_uart_config(void); + +struct nrf52_hal_i2c_cfg { + int scl_pin; + int sda_pin; + uint32_t i2c_frequency; +}; +struct hal_flash; +extern const struct hal_flash nrf52k_flash_dev; +extern const struct hal_flash nrf52k_qspi_dev; + +/* SPI configuration (used for both master and slave) */ +struct nrf52_hal_spi_cfg { + uint8_t sck_pin; + uint8_t mosi_pin; + uint8_t miso_pin; + uint8_t ss_pin; +}; + +/* + * GPIO pin mapping + * + * The logical GPIO pin numbers (0 to N) are mapped to ports in the following + * manner: + * pins 0 - 31: Port 0 + * pins 32 - 48: Port 1. + * + * The nrf52832 has only one port with 32 pins. The nrf52840 has 48 pins and + * uses two ports. + * + * NOTE: in order to save code space, there is no checking done to see if the + * user specifies a pin that is not used by the processor. If an invalid pin + * number is used unexpected and/or erroneous behavior will result. + */ +#if defined(NRF52832_XXAA) || defined(NRF52810_XXAA) || defined(NRF52811_XXAA) +#define HAL_GPIO_INDEX(pin) (pin) +#define HAL_GPIO_PORT(pin) (NRF_P0) +#define HAL_GPIO_MASK(pin) (1 << pin) +#define HAL_GPIOTE_PIN_MASK GPIOTE_CONFIG_PSEL_Msk +#endif + +#ifdef NRF52840_XXAA +#define HAL_GPIO_INDEX(pin) ((pin) & 0x1F) +#define HAL_GPIO_PORT(pin) ((pin) > 31 ? NRF_P1 : NRF_P0) +#define HAL_GPIO_MASK(pin) (1 << HAL_GPIO_INDEX(pin)) +#define HAL_GPIOTE_PIN_MASK (0x3FUL << GPIOTE_CONFIG_PSEL_Pos) +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* H_NRF52_HAL_ */ diff --git a/nimble/transport/uart/include/transport/uart/ble_hci_uart.h b/babblesim/hw/mcu/nordic/nrf52_bsim/include/mcu/nrf52_periph.h similarity index 87% rename from nimble/transport/uart/include/transport/uart/ble_hci_uart.h rename to babblesim/hw/mcu/nordic/nrf52_bsim/include/mcu/nrf52_periph.h index e5e1084107..0e49371bad 100644 --- a/nimble/transport/uart/include/transport/uart/ble_hci_uart.h +++ b/babblesim/hw/mcu/nordic/nrf52_bsim/include/mcu/nrf52_periph.h @@ -17,17 +17,17 @@ * under the License. */ -#ifndef H_BLE_HCI_UART_ -#define H_BLE_HCI_UART_ +#ifndef H_NRF52_PERIPH_ +#define H_NRF52_PERIPH_ #ifdef __cplusplus -extern "C" { + extern "C" { #endif -void ble_hci_uart_init(void); +void nrf52_periph_create(void); #ifdef __cplusplus } #endif -#endif +#endif /* H_NRF52_PERIPH_ */ diff --git a/babblesim/hw/mcu/nordic/nrf52_bsim/pkg.yml b/babblesim/hw/mcu/nordic/nrf52_bsim/pkg.yml new file mode 100644 index 0000000000..5e4279b32c --- /dev/null +++ b/babblesim/hw/mcu/nordic/nrf52_bsim/pkg.yml @@ -0,0 +1,32 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +pkg.name: babblesim/hw/mcu/nordic/nrf52_bsim +pkg.description: nRF52 on BabbleSim +pkg.author: "Apache Mynewt " +pkg.homepage: "http://mynewt.apache.org/" + +pkg.lflags: + - -lpthread + +pkg.deps: + - "babblesim/core" + +pkg.deps.BLE_CONTROLLER: + - "@apache-mynewt-nimble/nimble/drivers/nrf5x" diff --git a/babblesim/hw/mcu/nordic/nrf52_bsim/src/hal_flash.c b/babblesim/hw/mcu/nordic/nrf52_bsim/src/hal_flash.c new file mode 100644 index 0000000000..b39b5158ce --- /dev/null +++ b/babblesim/hw/mcu/nordic/nrf52_bsim/src/hal_flash.c @@ -0,0 +1,289 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "os/mynewt.h" + +#include "hal/hal_flash_int.h" +#include "mcu/mcu_sim.h" + +char *native_flash_file; +static int file = -1; +static void *file_loc; + +static int native_flash_init(const struct hal_flash *dev); +static int native_flash_read(const struct hal_flash *dev, uint32_t address, + void *dst, uint32_t length); +static int native_flash_write(const struct hal_flash *dev, uint32_t address, + const void *src, uint32_t length); +static int native_flash_erase_sector(const struct hal_flash *dev, + uint32_t sector_address); +static int native_flash_sector_info(const struct hal_flash *dev, int idx, + uint32_t *address, uint32_t *size); + +static const struct hal_flash_funcs native_flash_funcs = { + .hff_read = native_flash_read, + .hff_write = native_flash_write, + .hff_erase_sector = native_flash_erase_sector, + .hff_sector_info = native_flash_sector_info, + .hff_init = native_flash_init +}; + +#if MYNEWT_VAL(MCU_FLASH_STYLE_ST) +static const uint32_t native_flash_sectors[] = { + 0x00000000, /* 16 * 1024 */ + 0x00004000, /* 16 * 1024 */ + 0x00008000, /* 16 * 1024 */ + 0x0000c000, /* 16 * 1024 */ + 0x00010000, /* 64 * 1024 */ + 0x00020000, /* 128 * 1024 */ + 0x00040000, /* 128 * 1024 */ + 0x00060000, /* 128 * 1024 */ + 0x00080000, /* 128 * 1024 */ + 0x000a0000, /* 128 * 1024 */ + 0x000c0000, /* 128 * 1024 */ + 0x000e0000, /* 128 * 1024 */ +}; +#elif MYNEWT_VAL(MCU_FLASH_STYLE_NORDIC) +static uint32_t native_flash_sectors[1024 * 1024 / 2048]; +#else +#error "Need to specify either MCU_FLASH_STYLE_NORDIC or MCU_FLASH_STYLE_ST" +#endif + +#define FLASH_NUM_AREAS (int)(sizeof native_flash_sectors / \ + sizeof native_flash_sectors[0]) + +const struct hal_flash native_flash_dev = { + .hf_itf = &native_flash_funcs, + .hf_base_addr = 0, + .hf_size = 1024 * 1024, + .hf_sector_cnt = FLASH_NUM_AREAS, + .hf_align = MYNEWT_VAL(MCU_FLASH_MIN_WRITE_SIZE), + .hf_erased_val = 0xff, +}; + +static void +flash_native_erase(uint32_t addr, uint32_t len) +{ + memset(file_loc + addr, 0xff, len); +} + +static void +flash_native_file_open(char *name) +{ + int created = 0; + char tmpl[] = "/tmp/native_flash.XXXXXX"; + + extern int ftruncate(int fd, off_t length); + + if (file != -1) { + close(file); + file = -1; + } + + if (name) { + file = open(name, O_RDWR); + if (file < 0) { + file = open(name, O_RDWR | O_CREAT, 0660); + assert(file > 0); + created = 1; + } + } else { + file = mkstemp(tmpl); + assert(file > 0); + created = 1; + } + + if (created) { + if (ftruncate(file, native_flash_dev.hf_size) < 0) { + assert(0); + } + } + + if (file_loc != NULL) { + munmap(file_loc, native_flash_dev.hf_size); + } + + file_loc = mmap(0, native_flash_dev.hf_size, + PROT_READ | PROT_WRITE, MAP_SHARED, file, 0); + assert(file_loc != MAP_FAILED); + if (created) { + flash_native_erase(0, native_flash_dev.hf_size); + } + + /* If using a temporary file, unlink it immediately. */ + if (name == NULL) { + remove(tmpl); + } +} + +static void +flash_native_ensure_file_open(void) +{ + if (file == 0) { + flash_native_file_open(NULL); + } +} + +static int +flash_native_write_internal(uint32_t address, const void *src, uint32_t length, + int allow_overwrite) +{ + static uint8_t buf[256]; + uint32_t cur; + uint32_t end; + int chunk_sz; + int rc; + int i; + + if (length == 0) { + return 0; + } + + end = address + length; + + flash_native_ensure_file_open(); + + cur = address; + while (cur < end) { + if (end - cur < sizeof buf) { + chunk_sz = end - cur; + } else { + chunk_sz = sizeof buf; + } + + /* Ensure data is not being overwritten. */ + if (!allow_overwrite) { + rc = native_flash_read(NULL, cur, buf, chunk_sz); + assert(rc == 0); + for (i = 0; i < chunk_sz; i++) { + assert(buf[i] == 0xff); + } + } + + cur += chunk_sz; + } + + memcpy((char *)file_loc + address, src, length); + + return 0; +} + +static int +native_flash_write(const struct hal_flash *dev, uint32_t address, + const void *src, uint32_t length) +{ + assert(address % native_flash_dev.hf_align == 0); + return flash_native_write_internal(address, src, length, 0); +} + +int +flash_native_memset(uint32_t offset, uint8_t c, uint32_t len) +{ + memset(file_loc + offset, c, len); + return 0; +} + +static int +native_flash_read(const struct hal_flash *dev, uint32_t address, void *dst, + uint32_t length) +{ + flash_native_ensure_file_open(); + memcpy(dst, (char *)file_loc + address, length); + + return 0; +} + +static int +find_area(uint32_t address) +{ + int i; + + for (i = 0; i < FLASH_NUM_AREAS; i++) { + if (native_flash_sectors[i] == address) { + return i; + } + } + + return -1; +} + +static int +flash_sector_len(int sector) +{ + uint32_t end; + + if (sector == FLASH_NUM_AREAS - 1) { + end = native_flash_dev.hf_size + native_flash_sectors[0]; + } else { + end = native_flash_sectors[sector + 1]; + } + return end - native_flash_sectors[sector]; +} + +static int +native_flash_erase_sector(const struct hal_flash *dev, uint32_t sector_address) +{ + int area_id; + uint32_t len; + + flash_native_ensure_file_open(); + + area_id = find_area(sector_address); + if (area_id == -1) { + return -1; + } + len = flash_sector_len(area_id); + flash_native_erase(sector_address, len); + return 0; +} + +static int +native_flash_sector_info(const struct hal_flash *dev, int idx, + uint32_t *address, uint32_t *size) +{ + assert(idx < FLASH_NUM_AREAS); + + *address = native_flash_sectors[idx]; + *size = flash_sector_len(idx); + return 0; +} + +static int +native_flash_init(const struct hal_flash *dev) +{ + //if (native_flash_file) { + flash_native_file_open(native_flash_file); + //} +#if MYNEWT_VAL(MCU_FLASH_STYLE_NORDIC) + int i; + + for (i = 0; i < FLASH_NUM_AREAS; i++) { + native_flash_sectors[i] = i * 2048; + } +#endif + return 0; +} diff --git a/babblesim/hw/mcu/nordic/nrf52_bsim/src/hal_hw_id.c b/babblesim/hw/mcu/nordic/nrf52_bsim/src/hal_hw_id.c new file mode 100644 index 0000000000..09e39801d1 --- /dev/null +++ b/babblesim/hw/mcu/nordic/nrf52_bsim/src/hal_hw_id.c @@ -0,0 +1,73 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include + +#include "hal/hal_bsp.h" + +#include "hal_native_priv.h" + +#ifndef min +#define min(a, b) ((a)<(b)?(a):(b)) +#endif + +static uint8_t hal_hw_id[HAL_BSP_MAX_ID_LEN]; +static uint8_t hal_hw_id_len; + +int +hal_bsp_hw_id_len(void) +{ + if (hal_hw_id_len != 0) { + return hal_hw_id_len; + } else { + return HAL_BSP_MAX_ID_LEN; + } +} + +/* + * This can be used as the unique hardware identifier for the platform, as + * it's supposed to be unique for this particular MCU. + */ +int +hal_bsp_hw_id(uint8_t *id, int max_len) +{ + if (hal_hw_id_len) { + if (max_len > hal_hw_id_len) { + max_len = hal_hw_id_len; + } + memcpy(id, hal_hw_id, max_len); + return max_len; + } + if (max_len > HAL_BSP_MAX_ID_LEN) { + max_len = HAL_BSP_MAX_ID_LEN; + } + memset(id, 0x42, max_len); + return max_len; +} + +void +hal_bsp_set_hw_id(const uint8_t *id, int len) +{ + if (len > HAL_BSP_MAX_ID_LEN) { + len = HAL_BSP_MAX_ID_LEN; + } + hal_hw_id_len = len; + memcpy(hal_hw_id, id, len); +} diff --git a/babblesim/hw/mcu/nordic/nrf52_bsim/src/hal_native_priv.h b/babblesim/hw/mcu/nordic/nrf52_bsim/src/hal_native_priv.h new file mode 100644 index 0000000000..1060053769 --- /dev/null +++ b/babblesim/hw/mcu/nordic/nrf52_bsim/src/hal_native_priv.h @@ -0,0 +1,27 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef __HAL_NATIVE_PRIV_H__ +#define __HAL_NATIVE_PRIV_H__ + +#include + +void hal_bsp_set_hw_id(const uint8_t *id, int len); + +#endif /* __HAL_NATIVE_PRIV_H__ */ diff --git a/babblesim/hw/mcu/nordic/nrf52_bsim/src/hal_os_tick.c b/babblesim/hw/mcu/nordic/nrf52_bsim/src/hal_os_tick.c new file mode 100644 index 0000000000..a2d7170ab7 --- /dev/null +++ b/babblesim/hw/mcu/nordic/nrf52_bsim/src/hal_os_tick.c @@ -0,0 +1,226 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include "os/mynewt.h" +#include "hal/hal_os_tick.h" +#include "nrf.h" +#include "mcu/cmsis_nvic.h" +#include "mcu/mcu_sim.h" +#include +#include +#include +#include +#include + +/* The OS scheduler requires a low-frequency timer. */ +#if MYNEWT_VAL(OS_SCHEDULING) && !MYNEWT_VAL(MCU_LFCLK_SOURCE) + #error The OS scheduler requires a low-frequency timer; configure MCU_LFCLK_SOURCE +#endif + +#define RTC_FREQ 32768 /* in Hz */ +#define OS_TICK_TIMER NRF_RTC1 +#define OS_TICK_IRQ RTC1_IRQn +#define OS_TICK_CMPREG 3 /* generate timer interrupt */ +#define RTC_COMPARE_INT_MASK(ccreg) (1UL << ((ccreg) + 16)) + +struct hal_os_tick +{ + int ticks_per_ostick; + os_time_t max_idle_ticks; + uint32_t lastocmp; +}; + +struct hal_os_tick g_hal_os_tick; + +/* + * Implement (x - y) where the range of both 'x' and 'y' is limited to 24-bits. + * + * For example: + * + * sub24(0, 0xffffff) = 1 + * sub24(0xffffff, 0xfffffe) = 1 + * sub24(0xffffff, 0) = -1 + * sub24(0x7fffff, 0) = 8388607 + * sub24(0x800000, 0) = -8388608 + */ +static inline int +sub24(uint32_t x, uint32_t y) +{ + int result; + + assert(x <= 0xffffff); + assert(y <= 0xffffff); + + result = x - y; + if (result & 0x800000) { + return (result | 0xff800000); + } else { + return (result & 0x007fffff); + } +} + +static inline uint32_t +nrf52_os_tick_counter(void) +{ + return nrf_rtc_counter_get(OS_TICK_TIMER); +} + +static inline void +nrf52_os_tick_set_ocmp(uint32_t ocmp) +{ + int delta; + uint32_t counter; + + OS_ASSERT_CRITICAL(); + while (1) { + ocmp &= 0xffffff; + nrf_rtc_cc_set(OS_TICK_TIMER, OS_TICK_CMPREG, ocmp); + counter = nrf52_os_tick_counter(); + /* + * From nRF52 Product specification + * + * - If Counter is 'N' writing (N) or (N + 1) to CC register + * may not trigger a compare event. + * + * - If Counter is 'N' writing (N + 2) to CC register is guaranteed + * to trigger a compare event at 'N + 2'. + */ + delta = sub24(ocmp, counter); + if (delta > 2) { + break; + } + ocmp += g_hal_os_tick.ticks_per_ostick; + } +} + +static void +nrf52_timer_handler(void) +{ + int delta; + int ticks; + os_sr_t sr; + uint32_t counter; + + os_trace_isr_enter(); + OS_ENTER_CRITICAL(sr); + + /* Calculate elapsed ticks and advance OS time. */ + + counter = nrf52_os_tick_counter(); + delta = sub24(counter, g_hal_os_tick.lastocmp); + ticks = delta / g_hal_os_tick.ticks_per_ostick; + os_time_advance(ticks); + + /* Clear timer interrupt */ + OS_TICK_TIMER->EVENTS_COMPARE[OS_TICK_CMPREG] = 0; + + /* Update the time associated with the most recent tick */ + g_hal_os_tick.lastocmp = (g_hal_os_tick.lastocmp + + (ticks * g_hal_os_tick.ticks_per_ostick)) & 0xffffff; + + /* Update the output compare to interrupt at the next tick */ + nrf52_os_tick_set_ocmp(g_hal_os_tick.lastocmp + g_hal_os_tick.ticks_per_ostick); + + OS_EXIT_CRITICAL(sr); + os_trace_isr_exit(); +} + +/* Wait For Interrupt */ +void +__WFI(void) +{ + while (hw_irq_ctrl_get_irq_status() == 0) { + tm_tick(); + } +} + +void +os_tick_idle(os_time_t ticks) +{ + uint32_t ocmp; + + OS_ASSERT_CRITICAL(); + + if (ticks > 0) { + /* + * Enter tickless regime during long idle durations. + */ + if (ticks > g_hal_os_tick.max_idle_ticks) { + ticks = g_hal_os_tick.max_idle_ticks; + } + ocmp = g_hal_os_tick.lastocmp + (ticks*g_hal_os_tick.ticks_per_ostick); + nrf52_os_tick_set_ocmp(ocmp); + } + + __WFI(); + + if (ticks > 0) { + /* + * Update OS time before anything else when coming out of + * the tickless regime. + */ + nrf52_timer_handler(); + } +} + +extern void nrf_rtc_regw_sideeffects(int i); + +void +os_tick_init(uint32_t os_ticks_per_sec, int prio) +{ + uint32_t sr; + + assert(RTC_FREQ % os_ticks_per_sec == 0); + + g_hal_os_tick.lastocmp = 0; + g_hal_os_tick.ticks_per_ostick = RTC_FREQ / os_ticks_per_sec; + + /* + * The maximum number of OS ticks allowed to elapse during idle is + * limited to 1/4th the number of timer ticks before the 24-bit counter + * rolls over. + */ + g_hal_os_tick.max_idle_ticks = (1UL << 22) / g_hal_os_tick.ticks_per_ostick; + + /* disable interrupts */ + OS_ENTER_CRITICAL(sr); + + /* Set isr in vector table and enable interrupt */ + NVIC_SetPriority(OS_TICK_IRQ, prio); + NVIC_SetVector(OS_TICK_IRQ, (uint32_t)nrf52_timer_handler); + NVIC_EnableIRQ(OS_TICK_IRQ); + + /* + * Program the OS_TICK_TIMER to operate at 32KHz and trigger an output + * compare interrupt at a rate of 'os_ticks_per_sec'. + */ + nrf_rtc_task_trigger(OS_TICK_TIMER, NRF_RTC_TASK_STOP); + nrf_rtc_task_trigger(OS_TICK_TIMER, NRF_RTC_TASK_CLEAR); + nrf_rtc_event_disable(OS_TICK_TIMER, 0xffffffff); + nrf_rtc_int_disable(OS_TICK_TIMER, 0xffffffff); + nrf_rtc_int_enable(OS_TICK_TIMER, RTC_COMPARE_INT_MASK(OS_TICK_CMPREG)); + + OS_TICK_TIMER->EVENTS_COMPARE[OS_TICK_CMPREG] = 0; + nrf_rtc_cc_set(OS_TICK_TIMER, OS_TICK_CMPREG, g_hal_os_tick.ticks_per_ostick); + + nrf_rtc_task_trigger(OS_TICK_TIMER, NRF_RTC_TASK_START); + + OS_EXIT_CRITICAL(sr); +} diff --git a/nimble/drivers/nrf5340/src/ble_phy_trace.c b/babblesim/hw/mcu/nordic/nrf52_bsim/src/hal_reset_cause.c similarity index 53% rename from nimble/drivers/nrf5340/src/ble_phy_trace.c rename to babblesim/hw/mcu/nordic/nrf52_bsim/src/hal_reset_cause.c index 6967c3f779..32182c1ecd 100644 --- a/nimble/drivers/nrf5340/src/ble_phy_trace.c +++ b/babblesim/hw/mcu/nordic/nrf52_bsim/src/hal_reset_cause.c @@ -17,28 +17,31 @@ * under the License. */ -#include -#include -#include +#include +#include "hal/hal_system.h" -#if MYNEWT_VAL(BLE_PHY_SYSVIEW) - -static os_trace_module_t g_ble_phy_trace_mod; -uint32_t ble_phy_trace_off; - -static void -ble_phy_trace_module_send_desc(void) +enum hal_reset_reason +hal_reset_cause(void) { - os_trace_module_desc(&g_ble_phy_trace_mod, "0 phy_set_tx cputime=%u usecs=%u"); - os_trace_module_desc(&g_ble_phy_trace_mod, "1 phy_set_rx cputime=%u usecs=%u"); - os_trace_module_desc(&g_ble_phy_trace_mod, "2 phy_disable"); -} + static enum hal_reset_reason reason; + uint32_t reg; -void -ble_phy_trace_init(void) -{ - ble_phy_trace_off = - os_trace_module_register(&g_ble_phy_trace_mod, "ble_phy", 3, - ble_phy_trace_module_send_desc); + if (reason) { + return reason; + } + reg = NRF_POWER->RESETREAS; + + if (reg & (POWER_RESETREAS_DOG_Msk | POWER_RESETREAS_LOCKUP_Msk)) { + reason = HAL_RESET_WATCHDOG; + } else if (reg & POWER_RESETREAS_SREQ_Msk) { + reason = HAL_RESET_SOFT; + } else if (reg & POWER_RESETREAS_RESETPIN_Msk) { + reason = HAL_RESET_PIN; + } else if (reg & POWER_RESETREAS_OFF_Msk) { + reason = HAL_RESET_SYS_OFF_INT; + } else { + reason = HAL_RESET_POR; /* could also be brownout */ + } + NRF_POWER->RESETREAS = reg; + return reason; } -#endif diff --git a/babblesim/hw/mcu/nordic/nrf52_bsim/src/hal_system.c b/babblesim/hw/mcu/nordic/nrf52_bsim/src/hal_system.c new file mode 100644 index 0000000000..4f46f34697 --- /dev/null +++ b/babblesim/hw/mcu/nordic/nrf52_bsim/src/hal_system.c @@ -0,0 +1,128 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "syscfg/syscfg.h" +#include "hal/hal_system.h" +#include "hal/hal_debug.h" +#include "nrf.h" +#include "cmsis.h" +#include "mcu/mcu_sim.h" +#include "hal/nrf_clock.h" + +/** + * Function called at startup. Called after BSS and .data initialized but + * prior to the _start function. + * + * NOTE: this function is called by both the bootloader and the application. + * If you add code here that you do not want executed in either case you need + * to conditionally compile it using the config variable BOOT_LOADER (will + * be set to 1 in case of bootloader build) + * + */ +void +hal_system_init(void) +{ +#if MYNEWT_VAL(MCU_DCDC_ENABLED) + NRF_POWER->DCDCEN = 1; +#endif +} + +void +hal_system_reset(void) +{ + +#if MYNEWT_VAL(HAL_SYSTEM_RESET_CB) + hal_system_reset_cb(); +#endif + + while (1) { + HAL_DEBUG_BREAK(); + NVIC_SystemReset(); + } +} + +int +hal_debugger_connected(void) +{ + return 0; +} + +/** + * hal system clock start + * + * Makes sure the LFCLK and/or HFCLK is started. + */ +void +hal_system_clock_start(void) +{ +#if MYNEWT_VAL(MCU_LFCLK_SOURCE) + uint32_t regmsk; + uint32_t regval; + uint32_t clksrc; + + regmsk = CLOCK_LFCLKSTAT_STATE_Msk | CLOCK_LFCLKSTAT_SRC_Msk; + regval = CLOCK_LFCLKSTAT_STATE_Running << CLOCK_LFCLKSTAT_STATE_Pos; + +#if MYNEWT_VAL_CHOICE(MCU_LFCLK_SOURCE, LFXO) + regval |= CLOCK_LFCLKSTAT_SRC_Xtal << CLOCK_LFCLKSTAT_SRC_Pos; + clksrc = CLOCK_LFCLKSRC_SRC_Xtal; +#elif MYNEWT_VAL_CHOICE(MCU_LFCLK_SOURCE, LFSYNTH) + regval |= CLOCK_LFCLKSTAT_SRC_Synth << CLOCK_LFCLKSTAT_SRC_Pos; + clksrc = CLOCK_LFCLKSRC_SRC_Synth; +#elif MYNEWT_VAL_CHOICE(MCU_LFCLK_SOURCE, LFRC) + regval |= CLOCK_LFCLKSTAT_SRC_RC << CLOCK_LFCLKSTAT_SRC_Pos; + clksrc = CLOCK_LFCLKSRC_SRC_RC; +#else + #error Unknown LFCLK source selected +#endif + +#if MYNEWT_VAL_CHOICE(MCU_LFCLK_SOURCE, LFSYNTH) + /* Must turn on HFLCK for synthesized 32768 crystal */ + nrf52_clock_hfxo_request(); +#else + /* Make sure HFCLK is stopped */ + nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_HFCLKSTOP); +#endif + + /* Check if this clock source is already running */ + if ((NRF_CLOCK_regs.LFCLKSTAT & regmsk) != regval) { + + nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_LFCLKSTOP); + NRF_CLOCK_regs.EVENTS_LFCLKSTARTED = 0; + NRF_CLOCK_regs.LFCLKSRC = clksrc; + nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_LFCLKSTART); + + /* Wait here till started! */ +// while (1) { +// if (NRF_CLOCK_regs.EVENTS_LFCLKSTARTED) { +// if ((NRF_CLOCK_regs.LFCLKSTAT & regmsk) == regval) { +// break; +// } +// } +// } + } +#endif +} + + +void* +NRF_RADIO_BASE_FUN(void) +{ + return NULL; +} diff --git a/babblesim/hw/mcu/nordic/nrf52_bsim/src/hal_timer.c b/babblesim/hw/mcu/nordic/nrf52_bsim/src/hal_timer.c new file mode 100644 index 0000000000..a847e9b68a --- /dev/null +++ b/babblesim/hw/mcu/nordic/nrf52_bsim/src/hal_timer.c @@ -0,0 +1,951 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#include +#include +#include "os/mynewt.h" +#include "mcu/cmsis_nvic.h" +#include "hal/hal_timer.h" +#include "nrf.h" +#include "mcu/nrf52_hal.h" +#include "mcu/nrf52_clock.h" +#include "hal/nrf_timer.h" + +/* IRQ prototype */ +typedef void (*hal_timer_irq_handler_t)(void); + +/* User CC 2 for reading counter, CC 3 for timer isr */ +#define NRF_TIMER_CC_READ (NRF_TIMER_CC_CHANNEL2) +#define NRF_TIMER_CC_INT (3) + +/* Output compare 2 used for RTC timers */ +#define NRF_RTC_TIMER_CC_INT (2) + +/* Maximum number of hal timers used */ +#define NRF52_HAL_TIMER_MAX (6) + +/* Maximum timer frequency */ +#define NRF52_MAX_TIMER_FREQ (16000000) + +struct nrf52_hal_timer { + uint8_t tmr_enabled; + uint8_t tmr_irq_num; + uint8_t tmr_rtc; + uint8_t tmr_pad; + uint32_t tmr_cntr; + uint32_t timer_isrs; + uint32_t tmr_freq; + void *tmr_reg; + TAILQ_HEAD(hal_timer_qhead, hal_timer) hal_timer_q; +}; + +#if MYNEWT_VAL(TIMER_0) +struct nrf52_hal_timer nrf52_hal_timer0; +#endif +#if MYNEWT_VAL(TIMER_1) +struct nrf52_hal_timer nrf52_hal_timer1; +#endif +#if MYNEWT_VAL(TIMER_2) +struct nrf52_hal_timer nrf52_hal_timer2; +#endif +#if MYNEWT_VAL(TIMER_3) +struct nrf52_hal_timer nrf52_hal_timer3; +#endif +#if MYNEWT_VAL(TIMER_4) +struct nrf52_hal_timer nrf52_hal_timer4; +#endif +#if MYNEWT_VAL(TIMER_5) +struct nrf52_hal_timer nrf52_hal_timer5; +#endif + +static const struct nrf52_hal_timer *nrf52_hal_timers[NRF52_HAL_TIMER_MAX] = { +#if MYNEWT_VAL(TIMER_0) + &nrf52_hal_timer0, +#else + NULL, +#endif +#if MYNEWT_VAL(TIMER_1) + &nrf52_hal_timer1, +#else + NULL, +#endif +#if MYNEWT_VAL(TIMER_2) + &nrf52_hal_timer2, +#else + NULL, +#endif +#if MYNEWT_VAL(TIMER_3) + &nrf52_hal_timer3, +#else + NULL, +#endif +#if MYNEWT_VAL(TIMER_4) + &nrf52_hal_timer4, +#else + NULL, +#endif +#if MYNEWT_VAL(TIMER_5) + &nrf52_hal_timer5 +#else + NULL +#endif +}; + +/* Resolve timer number into timer structure */ +#define NRF52_HAL_TIMER_RESOLVE(__n, __v) \ + if ((__n) >= NRF52_HAL_TIMER_MAX) { \ + rc = EINVAL; \ + goto err; \ + } \ + (__v) = (struct nrf52_hal_timer *) nrf52_hal_timers[(__n)]; \ + if ((__v) == NULL) { \ + rc = EINVAL; \ + goto err; \ + } + +/* Interrupt mask for interrupt enable/clear */ +#define NRF_TIMER_INT_MASK(x) ((1 << (uint32_t)(x)) << 16) + +static uint32_t +nrf_read_timer_cntr(NRF_TIMER_Type *hwtimer) +{ + uint32_t tcntr; + + /* Force a capture of the timer into 'cntr' capture channel; read it */ + nrf_timer_task_trigger(hwtimer, NRF_TIMER_TASK_CAPTURE2); + tcntr = hwtimer->CC[NRF_TIMER_CC_READ]; + + return tcntr; +} + +/** + * nrf timer set ocmp + * + * Set the OCMP used by the timer to the desired expiration tick + * + * NOTE: Must be called with interrupts disabled. + * + * @param timer Pointer to timer. + */ +static void +nrf_timer_set_ocmp(struct nrf52_hal_timer *bsptimer, uint32_t expiry) +{ + int32_t delta_t; + uint32_t temp; + uint32_t cntr; + NRF_TIMER_Type *hwtimer; + NRF_RTC_Type *rtctimer; + + if (bsptimer->tmr_rtc) { + rtctimer = (NRF_RTC_Type *)bsptimer->tmr_reg; + nrf_rtc_int_disable(rtctimer, NRF_TIMER_INT_MASK(NRF_RTC_TIMER_CC_INT)); + temp = bsptimer->tmr_cntr; + cntr = nrf_rtc_counter_get(rtctimer); + if (rtctimer->EVENTS_OVRFLW) { + temp += (1UL << 24); + cntr = nrf_rtc_counter_get(rtctimer); + } + temp |= cntr; + delta_t = (int32_t)(expiry - temp); + + /* + * The nRF52xxx documentation states that COMPARE event is guaranteed + * only if value written to CC register is at least 2 greater than the + * current counter value. We also need to account for possible extra + * tick during calculations so effectively any delta less than 3 needs + * to be handled differently. TICK event is used to have interrupt on + * each subsequent tick so we won't miss any and in case we detected + * mentioned extra tick during calculations, interrupt is triggered + * immediately. Delta 0 or less means we should always fire immediately. + */ + if (delta_t < 1) { + nrf_rtc_int_disable(rtctimer, RTC_INTENCLR_TICK_Msk); + NVIC_SetPendingIRQ(bsptimer->tmr_irq_num); + } else if (delta_t < 3 && 0) { + nrf_rtc_int_enable(rtctimer, RTC_INTENSET_TICK_Msk); + if (nrf_rtc_counter_get(rtctimer) != cntr) { + NVIC_SetPendingIRQ(bsptimer->tmr_irq_num); + } + } else { + nrf_rtc_int_disable(rtctimer, RTC_INTENCLR_TICK_Msk); + + if (delta_t < (1UL << 24)) { + nrf_rtc_cc_set(rtctimer, NRF_RTC_TIMER_CC_INT, expiry & 0x00ffffff); + } else { + /* CC too far ahead. Just make sure we set compare far ahead */ + nrf_rtc_cc_set(rtctimer, NRF_RTC_TIMER_CC_INT, cntr + (1UL << 23)); + } + nrf_rtc_int_enable(rtctimer, NRF_TIMER_INT_MASK(NRF_RTC_TIMER_CC_INT)); + } + } else { + hwtimer = bsptimer->tmr_reg; + + /* Disable ocmp interrupt and set new value */ + nrf_timer_int_disable(hwtimer, NRF_TIMER_INT_MASK(NRF_TIMER_CC_INT)); + + /* Set output compare register to timer expiration */ + nrf_timer_cc_set(hwtimer, NRF_TIMER_CC_INT, expiry); + + /* Clear interrupt flag */ + hwtimer->EVENTS_COMPARE[NRF_TIMER_CC_INT] = 0; + + /* Enable the output compare interrupt */ + nrf_timer_int_enable(hwtimer, NRF_TIMER_INT_MASK(NRF_TIMER_CC_INT)); + + /* Force interrupt to occur as we may have missed it */ + if ((int32_t)(nrf_read_timer_cntr(hwtimer) - expiry) >= 0) { + NVIC_SetPendingIRQ(bsptimer->tmr_irq_num); + } + } +} + +/* Disable output compare used for timer */ +static void +nrf_timer_disable_ocmp(NRF_TIMER_Type *hwtimer) +{ + nrf_timer_int_disable(hwtimer, NRF_TIMER_INT_MASK(NRF_TIMER_CC_INT)); +} + +static void +nrf_rtc_disable_ocmp(NRF_RTC_Type *rtctimer) +{ + nrf_rtc_int_disable(rtctimer, NRF_TIMER_INT_MASK(NRF_RTC_TIMER_CC_INT)); + nrf_rtc_int_disable(rtctimer, RTC_INTENCLR_TICK_Msk); +} + +static uint32_t +hal_timer_read_bsptimer(struct nrf52_hal_timer *bsptimer) +{ + uint32_t low32; + uint32_t ctx; + uint32_t tcntr; + NRF_RTC_Type *rtctimer; + + rtctimer = (NRF_RTC_Type *)bsptimer->tmr_reg; + __HAL_DISABLE_INTERRUPTS(ctx); + tcntr = bsptimer->tmr_cntr; + low32 = nrf_rtc_counter_get(rtctimer); + if (rtctimer->EVENTS_OVRFLW) { + tcntr += (1UL << 24); + bsptimer->tmr_cntr = tcntr; + low32 = nrf_rtc_counter_get(rtctimer); + rtctimer->EVENTS_OVRFLW = 0; + NVIC_SetPendingIRQ(bsptimer->tmr_irq_num); + } + tcntr |= low32; + __HAL_ENABLE_INTERRUPTS(ctx); + + return tcntr; +} + +#if (MYNEWT_VAL(TIMER_0) || MYNEWT_VAL(TIMER_1) || MYNEWT_VAL(TIMER_2) || \ + MYNEWT_VAL(TIMER_3) || MYNEWT_VAL(TIMER_4) || MYNEWT_VAL(TIMER_5)) +/** + * hal timer chk queue + * + * + * @param bsptimer + */ +static void +hal_timer_chk_queue(struct nrf52_hal_timer *bsptimer) +{ + uint32_t tcntr; + uint32_t ctx; + struct hal_timer *timer; + + /* disable interrupts */ + __HAL_DISABLE_INTERRUPTS(ctx); + while ((timer = TAILQ_FIRST(&bsptimer->hal_timer_q)) != NULL) { + if (bsptimer->tmr_rtc) { + tcntr = hal_timer_read_bsptimer(bsptimer); + } else { + tcntr = nrf_read_timer_cntr(bsptimer->tmr_reg); + } + if ((int32_t)(tcntr - timer->expiry) >= 0) { + TAILQ_REMOVE(&bsptimer->hal_timer_q, timer, link); + timer->link.tqe_prev = NULL; + timer->cb_func(timer->cb_arg); + } else { + break; + } + } + + /* Any timers left on queue? If so, we need to set OCMP */ + timer = TAILQ_FIRST(&bsptimer->hal_timer_q); + if (timer) { + nrf_timer_set_ocmp(bsptimer, timer->expiry); + } else { + if (bsptimer->tmr_rtc) { + nrf_rtc_disable_ocmp((NRF_RTC_Type *)bsptimer->tmr_reg); + } else { + nrf_timer_disable_ocmp(bsptimer->tmr_reg); + } + } + __HAL_ENABLE_INTERRUPTS(ctx); +} +#endif + +/** + * hal timer irq handler + * + * Generic HAL timer irq handler. + * + * @param tmr + */ +/** + * hal timer irq handler + * + * This is the global timer interrupt routine. + * + */ +#if (MYNEWT_VAL(TIMER_0) || MYNEWT_VAL(TIMER_1) || MYNEWT_VAL(TIMER_2) || \ + MYNEWT_VAL(TIMER_3) || MYNEWT_VAL(TIMER_4)) + +static void +hal_timer_irq_handler(struct nrf52_hal_timer *bsptimer) +{ + uint32_t compare; + NRF_TIMER_Type *hwtimer; + + os_trace_isr_enter(); + + /* Check interrupt source. If set, clear them */ + hwtimer = bsptimer->tmr_reg; + compare = hwtimer->EVENTS_COMPARE[NRF_TIMER_CC_INT]; + if (compare) { + hwtimer->EVENTS_COMPARE[NRF_TIMER_CC_INT] = 0; + } + + /* XXX: make these stats? */ + /* Count # of timer isrs */ + ++bsptimer->timer_isrs; + + /* + * NOTE: we dont check the 'compare' variable here due to how the timer + * is implemented on this chip. There is no way to force an output + * compare, so if we are late setting the output compare (i.e. the timer + * counter is already passed the output compare value), we use the NVIC + * to set a pending interrupt. This means that there will be no compare + * flag set, so all we do is check to see if the compare interrupt is + * enabled. + */ + if (hwtimer->INTENCLR & NRF_TIMER_INT_MASK(NRF_TIMER_CC_INT)) { + hal_timer_chk_queue(bsptimer); + /* XXX: Recommended by nordic to make sure interrupts are cleared */ + compare = hwtimer->EVENTS_COMPARE[NRF_TIMER_CC_INT]; + } + + os_trace_isr_exit(); +} +#endif + +#if MYNEWT_VAL(TIMER_5) +static void +hal_rtc_timer_irq_handler(struct nrf52_hal_timer *bsptimer) +{ + uint32_t overflow; + uint32_t compare; + uint32_t tick; + NRF_RTC_Type *rtctimer; + + os_trace_isr_enter(); + + /* Check interrupt source. If set, clear them */ + rtctimer = (NRF_RTC_Type *)bsptimer->tmr_reg; + compare = rtctimer->EVENTS_COMPARE[NRF_RTC_TIMER_CC_INT]; + if (compare) { + rtctimer->EVENTS_COMPARE[NRF_RTC_TIMER_CC_INT] = 0; + } + + tick = rtctimer->EVENTS_TICK; + if (tick) { + rtctimer->EVENTS_TICK = 0; + } + + overflow = rtctimer->EVENTS_OVRFLW; + if (overflow) { + rtctimer->EVENTS_OVRFLW = 0; + bsptimer->tmr_cntr += (1UL << 24); + } + + /* Count # of timer isrs */ + ++bsptimer->timer_isrs; + + /* + * NOTE: we dont check the 'compare' variable here due to how the timer + * is implemented on this chip. There is no way to force an output + * compare, so if we are late setting the output compare (i.e. the timer + * counter is already passed the output compare value), we use the NVIC + * to set a pending interrupt. This means that there will be no compare + * flag set, so all we do is check to see if the compare interrupt is + * enabled. + */ + hal_timer_chk_queue(bsptimer); + + /* Recommended by nordic to make sure interrupts are cleared */ + compare = rtctimer->EVENTS_COMPARE[NRF_RTC_TIMER_CC_INT]; + + os_trace_isr_exit(); +} +#endif + +#if MYNEWT_VAL(TIMER_0) +void +nrf52_timer0_irq_handler(void) +{ + hal_timer_irq_handler(&nrf52_hal_timer0); +} +#endif + +#if MYNEWT_VAL(TIMER_1) +void +nrf52_timer1_irq_handler(void) +{ + hal_timer_irq_handler(&nrf52_hal_timer1); +} +#endif + +#if MYNEWT_VAL(TIMER_2) +void +nrf52_timer2_irq_handler(void) +{ + hal_timer_irq_handler(&nrf52_hal_timer2); +} +#endif + +#if MYNEWT_VAL(TIMER_3) +void +nrf52_timer3_irq_handler(void) +{ + hal_timer_irq_handler(&nrf52_hal_timer3); +} +#endif + +#if MYNEWT_VAL(TIMER_4) +void +nrf52_timer4_irq_handler(void) +{ + hal_timer_irq_handler(&nrf52_hal_timer4); +} +#endif + +#if MYNEWT_VAL(TIMER_5) +void +nrf52_timer5_irq_handler(void) +{ + hal_rtc_timer_irq_handler(&nrf52_hal_timer5); +} +#endif + +/** + * hal timer init + * + * Initialize platform specific timer items + * + * @param timer_num Timer number to initialize + * @param cfg Pointer to platform specific configuration + * + * @return int 0: success; error code otherwise + */ +int +hal_timer_init(int timer_num, void *cfg) +{ + int rc; + uint8_t irq_num; + struct nrf52_hal_timer *bsptimer; + void *hwtimer; + hal_timer_irq_handler_t irq_isr; + + NRF52_HAL_TIMER_RESOLVE(timer_num, bsptimer); + + /* If timer is enabled do not allow init */ + if (bsptimer->tmr_enabled) { + rc = EINVAL; + goto err; + } + + switch (timer_num) { +#if MYNEWT_VAL(TIMER_0) + case 0: + irq_num = TIMER0_IRQn; + hwtimer = NRF_TIMER0; + irq_isr = nrf52_timer0_irq_handler; + break; +#endif +#if MYNEWT_VAL(TIMER_1) + case 1: + irq_num = TIMER1_IRQn; + hwtimer = NRF_TIMER1; + irq_isr = nrf52_timer1_irq_handler; + break; +#endif +#if MYNEWT_VAL(TIMER_2) + case 2: + irq_num = TIMER2_IRQn; + hwtimer = NRF_TIMER2; + irq_isr = nrf52_timer2_irq_handler; + break; +#endif +#if MYNEWT_VAL(TIMER_3) + case 3: + irq_num = TIMER3_IRQn; + hwtimer = NRF_TIMER3; + irq_isr = nrf52_timer3_irq_handler; + break; +#endif +#if MYNEWT_VAL(TIMER_4) + case 4: + irq_num = TIMER4_IRQn; + hwtimer = NRF_TIMER4; + irq_isr = nrf52_timer4_irq_handler; + break; +#endif +#if MYNEWT_VAL(TIMER_5) + case 5: + irq_num = RTC0_IRQn; + hwtimer = NRF_RTC0; + irq_isr = nrf52_timer5_irq_handler; + bsptimer->tmr_rtc = 1; + break; +#endif + default: + hwtimer = NULL; + break; + } + + if (hwtimer == NULL) { + rc = EINVAL; + goto err; + } + + bsptimer->tmr_reg = hwtimer; + bsptimer->tmr_irq_num = irq_num; + + /* Disable IRQ, set priority and set vector in table */ + NVIC_DisableIRQ(irq_num); + NVIC_SetPriority(irq_num, (1 << __NVIC_PRIO_BITS) - 1); + NVIC_SetVector(irq_num, (uint32_t)irq_isr); + + return 0; + +err: + return rc; +} + +/** + * hal timer config + * + * Configure a timer to run at the desired frequency. This starts the timer. + * + * @param timer_num + * @param freq_hz + * + * @return int + */ +int +hal_timer_config(int timer_num, uint32_t freq_hz) +{ + int rc; + uint8_t prescaler; + uint32_t ctx; + uint32_t div; + uint32_t min_delta; + uint32_t max_delta; + struct nrf52_hal_timer *bsptimer; + NRF_TIMER_Type *hwtimer; +#if MYNEWT_VAL(TIMER_5) + NRF_RTC_Type *rtctimer; +#endif + + NRF52_HAL_TIMER_RESOLVE(timer_num, bsptimer); + +#if MYNEWT_VAL(TIMER_5) + if (timer_num == 5) { + /* NOTE: we only allow the RTC frequency to be set at 32768 */ + if (bsptimer->tmr_enabled || (freq_hz != 32768) || + (bsptimer->tmr_reg == NULL)) { + rc = EINVAL; + goto err; + } + + bsptimer->tmr_freq = freq_hz; + bsptimer->tmr_enabled = 1; + + __HAL_DISABLE_INTERRUPTS(ctx); + + rtctimer = (NRF_RTC_Type *)bsptimer->tmr_reg; + + /* Stop the timer first */ + nrf_rtc_task_trigger(rtctimer, NRF_RTC_TASK_STOP); + nrf_rtc_task_trigger(rtctimer, NRF_RTC_TASK_CLEAR); + + /* Always no prescaler */ + rtctimer->PRESCALER = 0; + + /* Clear overflow events and set overflow interrupt */ + rtctimer->EVENTS_OVRFLW = 0; + nrf_rtc_int_enable(rtctimer, RTC_INTENSET_OVRFLW_Msk); + + /* Start the timer */ + nrf_rtc_task_trigger(rtctimer, NRF_RTC_TASK_START); + /* Set isr in vector table and enable interrupt */ + NVIC_EnableIRQ(bsptimer->tmr_irq_num); + + __HAL_ENABLE_INTERRUPTS(ctx); + return 0; + } +#endif + + /* Set timer to desired frequency */ + div = NRF52_MAX_TIMER_FREQ / freq_hz; + + /* + * Largest prescaler is 2^9 and must make sure frequency not too high. + * If hwtimer is NULL it means that the timer was not initialized prior + * to call. + */ + if (bsptimer->tmr_enabled || (div == 0) || (div > 512) || + (bsptimer->tmr_reg == NULL)) { + rc = EINVAL; + goto err; + } + + if (div == 1) { + prescaler = 0; + } else { + /* Find closest prescaler */ + for (prescaler = 1; prescaler < 10; ++prescaler) { + if (div <= (1 << prescaler)) { + min_delta = div - (1 << (prescaler - 1)); + max_delta = (1 << prescaler) - div; + if (min_delta < max_delta) { + prescaler -= 1; + } + break; + } + } + } + + /* Now set the actual frequency */ + bsptimer->tmr_freq = NRF52_MAX_TIMER_FREQ / (1 << prescaler); + bsptimer->tmr_enabled = 1; + + /* disable interrupts */ + __HAL_DISABLE_INTERRUPTS(ctx); + +#if MYNEWT_VAL_CHOICE(MCU_HFCLK_SOURCE, HFXO) + /* Make sure HFXO is started */ + nrf52_clock_hfxo_request(); +#endif + hwtimer = bsptimer->tmr_reg; + + /* Stop the timer first */ + nrf_timer_task_trigger(hwtimer, NRF_TIMER_TASK_STOP); + nrf_timer_task_trigger(hwtimer, NRF_TIMER_TASK_CLEAR); + + /* Put the timer in timer mode using 32 bits. */ + hwtimer->MODE = (hwtimer->MODE & ~TIMER_MODE_MODE_Msk) | + ((NRF_TIMER_MODE_TIMER << TIMER_MODE_MODE_Pos) & + TIMER_MODE_MODE_Msk); + hwtimer->BITMODE = TIMER_BITMODE_BITMODE_32Bit; + + /* Set the pre-scalar */ + hwtimer->PRESCALER = prescaler; + + /* Start the timer */ + nrf_timer_task_trigger(hwtimer, NRF_TIMER_TASK_START); + + NVIC_EnableIRQ(bsptimer->tmr_irq_num); + + __HAL_ENABLE_INTERRUPTS(ctx); + + return 0; + +err: + return rc; +} + +/** + * hal timer deinit + * + * De-initialize a HW timer. + * + * @param timer_num + * + * @return int + */ +int +hal_timer_deinit(int timer_num) +{ + int rc; + uint32_t ctx; + struct nrf52_hal_timer *bsptimer; + NRF_TIMER_Type *hwtimer; + NRF_RTC_Type *rtctimer; + + rc = 0; + NRF52_HAL_TIMER_RESOLVE(timer_num, bsptimer); + + __HAL_DISABLE_INTERRUPTS(ctx); + if (bsptimer->tmr_rtc) { + rtctimer = (NRF_RTC_Type *)bsptimer->tmr_reg; + nrf_rtc_int_disable(rtctimer, NRF_TIMER_INT_MASK(NRF_RTC_TIMER_CC_INT)); + nrf_rtc_task_trigger(rtctimer, NRF_RTC_TASK_STOP); + } else { + hwtimer = (NRF_TIMER_Type *)bsptimer->tmr_reg; + nrf_timer_int_disable(hwtimer, NRF_TIMER_INT_MASK(NRF_TIMER_CC_INT)); + hwtimer->TASKS_SHUTDOWN = 1; + } + bsptimer->tmr_enabled = 0; + bsptimer->tmr_reg = NULL; + +#if MYNEWT_VAL_CHOICE(MCU_HFCLK_SOURCE, HFXO) + if (timer_num != 5) { + nrf52_clock_hfxo_release(); + } +#endif + __HAL_ENABLE_INTERRUPTS(ctx); + +err: + return rc; +} + +/** + * hal timer get resolution + * + * Get the resolution of the timer. This is the timer period, in nanoseconds + * + * @param timer_num + * + * @return uint32_t The + */ +uint32_t +hal_timer_get_resolution(int timer_num) +{ + int rc; + uint32_t resolution; + struct nrf52_hal_timer *bsptimer; + + NRF52_HAL_TIMER_RESOLVE(timer_num, bsptimer); + + resolution = 1000000000 / bsptimer->tmr_freq; + return resolution; + +err: + rc = 0; + return rc; +} + +/** + * hal timer read + * + * Returns the timer counter. NOTE: if the timer is a 16-bit timer, only + * the lower 16 bits are valid. If the timer is a 64-bit timer, only the + * low 32-bits are returned. + * + * @return uint32_t The timer counter register. + */ +uint32_t +hal_timer_read(int timer_num) +{ + int rc; + uint32_t tcntr; + struct nrf52_hal_timer *bsptimer; + + NRF52_HAL_TIMER_RESOLVE(timer_num, bsptimer); + if (bsptimer->tmr_rtc) { + tcntr = hal_timer_read_bsptimer(bsptimer); + } else { + tcntr = nrf_read_timer_cntr(bsptimer->tmr_reg); + } + + return tcntr; + + /* Assert here since there is no invalid return code */ +err: + assert(0); + rc = 0; + return rc; +} + +/** + * hal timer delay + * + * Blocking delay for n ticks + * + * @param timer_num + * @param ticks + * + * @return int 0 on success; error code otherwise. + */ +int +hal_timer_delay(int timer_num, uint32_t ticks) +{ + uint32_t until; + + until = hal_timer_read(timer_num) + ticks; + while ((int32_t)(hal_timer_read(timer_num) - until) <= 0) { + /* Loop here till finished */ + } + + return 0; +} + +/** + * + * Initialize the HAL timer structure with the callback and the callback + * argument. Also initializes the HW specific timer pointer. + * + * @param cb_func + * + * @return int + */ +int +hal_timer_set_cb(int timer_num, struct hal_timer *timer, hal_timer_cb cb_func, + void *arg) +{ + int rc; + struct nrf52_hal_timer *bsptimer; + + NRF52_HAL_TIMER_RESOLVE(timer_num, bsptimer); + + timer->cb_func = cb_func; + timer->cb_arg = arg; + timer->link.tqe_prev = NULL; + timer->bsp_timer = bsptimer; + + rc = 0; + +err: + return rc; +} + +int +hal_timer_start(struct hal_timer *timer, uint32_t ticks) +{ + int rc; + uint32_t tick; + struct nrf52_hal_timer *bsptimer; + + /* Set the tick value at which the timer should expire */ + bsptimer = (struct nrf52_hal_timer *)timer->bsp_timer; + if (bsptimer->tmr_rtc) { + tick = hal_timer_read_bsptimer(bsptimer) + ticks; + } else { + tick = nrf_read_timer_cntr(bsptimer->tmr_reg) + ticks; + } + rc = hal_timer_start_at(timer, tick); + return rc; +} + +int +hal_timer_start_at(struct hal_timer *timer, uint32_t tick) +{ + uint32_t ctx; + struct hal_timer *entry; + struct nrf52_hal_timer *bsptimer; + + if ((timer == NULL) || (timer->link.tqe_prev != NULL) || + (timer->cb_func == NULL)) { + return EINVAL; + } + bsptimer = (struct nrf52_hal_timer *)timer->bsp_timer; + timer->expiry = tick; + + __HAL_DISABLE_INTERRUPTS(ctx); + + if (TAILQ_EMPTY(&bsptimer->hal_timer_q)) { + TAILQ_INSERT_HEAD(&bsptimer->hal_timer_q, timer, link); + } else { + TAILQ_FOREACH(entry, &bsptimer->hal_timer_q, link) { + if ((int32_t)(timer->expiry - entry->expiry) < 0) { + TAILQ_INSERT_BEFORE(entry, timer, link); + break; + } + } + if (!entry) { + TAILQ_INSERT_TAIL(&bsptimer->hal_timer_q, timer, link); + } + } + + /* If this is the head, we need to set new OCMP */ + if (timer == TAILQ_FIRST(&bsptimer->hal_timer_q)) { + nrf_timer_set_ocmp(bsptimer, timer->expiry); + } + + __HAL_ENABLE_INTERRUPTS(ctx); + + return 0; +} + +/** + * hal timer stop + * + * Stop a timer. + * + * @param timer + * + * @return int + */ +int +hal_timer_stop(struct hal_timer *timer) +{ + uint32_t ctx; + int reset_ocmp; + struct hal_timer *entry; + struct nrf52_hal_timer *bsptimer; + + if (timer == NULL) { + return EINVAL; + } + + bsptimer = (struct nrf52_hal_timer *)timer->bsp_timer; + + __HAL_DISABLE_INTERRUPTS(ctx); + + if (timer->link.tqe_prev != NULL) { + reset_ocmp = 0; + if (timer == TAILQ_FIRST(&bsptimer->hal_timer_q)) { + /* If first on queue, we will need to reset OCMP */ + entry = TAILQ_NEXT(timer, link); + reset_ocmp = 1; + } + TAILQ_REMOVE(&bsptimer->hal_timer_q, timer, link); + timer->link.tqe_prev = NULL; + if (reset_ocmp) { + if (entry) { + nrf_timer_set_ocmp((struct nrf52_hal_timer *)entry->bsp_timer, + entry->expiry); + } else { + if (bsptimer->tmr_rtc) { + nrf_rtc_disable_ocmp((NRF_RTC_Type *)bsptimer->tmr_reg); + } else { + nrf_timer_disable_ocmp(bsptimer->tmr_reg); + } + } + } + } + + __HAL_ENABLE_INTERRUPTS(ctx); + + return 0; +} diff --git a/babblesim/hw/mcu/nordic/nrf52_bsim/src/hal_uart.c b/babblesim/hw/mcu/nordic/nrf52_bsim/src/hal_uart.c new file mode 100644 index 0000000000..41ac9b1db4 --- /dev/null +++ b/babblesim/hw/mcu/nordic/nrf52_bsim/src/hal_uart.c @@ -0,0 +1,478 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "os/mynewt.h" +#include "hal/hal_uart.h" +#include "bsp/bsp.h" + +#ifdef MN_LINUX +#include +#endif +#ifdef MN_OSX +#include +#endif +#ifdef MN_FreeBSD +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mcu/mcu_sim.h" +#include "native_uart_cfg_priv.h" +#include "syscfg/syscfg.h" + +#define UART_CNT 2 + +#if MYNEWT_VAL(CONSOLE_UART_TX_BUF_SIZE) +#define UART_MAX_BYTES_PER_POLL MYNEWT_VAL(CONSOLE_UART_TX_BUF_SIZE) - 2 +#else +#define UART_MAX_BYTES_PER_POLL 64 +#endif +#define UART_POLLER_STACK_SZ OS_STACK_ALIGN(1024) + +struct uart { + int u_open; + int u_fd; + int u_tx_run; + int u_rx_char; + hal_uart_rx_char u_rx_func; + hal_uart_tx_char u_tx_func; + hal_uart_tx_done u_tx_done; + void *u_func_arg; +}; + +const char *native_uart_dev_strs[UART_CNT]; + +/* + * XXXX should try to use O_ASYNC/SIGIO for byte arrival notification, + * so we wouldn't need an OS for pseudo ttys. + */ +char *native_uart_log_file = NULL; +static int uart_log_fd = -1; + +static struct uart uarts[UART_CNT]; +static int uart_poller_running; +static struct os_task uart_poller_task; +static os_stack_t uart_poller_stack[UART_POLLER_STACK_SZ]; + +static void +uart_open_log(void) +{ + if (native_uart_log_file && uart_log_fd < 0) { + uart_log_fd = open(native_uart_log_file, O_WRONLY | O_CREAT | O_TRUNC, + 0666); + assert(uart_log_fd >= 0); + } +} + +static void +uart_log_data(struct uart *u, int istx, uint8_t data) +{ + static struct { + struct uart *uart; + int istx; + uint32_t time; + int chars_in_line; + } state = { + .uart = NULL, + .istx = 0 + }; + uint32_t now; + char tmpbuf[32]; + int len; + + if (uart_log_fd < 0) { + return; + } + now = os_time_get(); + if (state.uart) { + if (u != state.uart || now != state.time || istx != state.istx) { + /* + * End current printout. + */ + if (write(uart_log_fd, "\n", 1) != 1) { + assert(0); + } + state.uart = NULL; + } else { + if (state.chars_in_line == 8) { + if (write(uart_log_fd, "\n\t", 2) != 2) { + assert(0); + } + state.chars_in_line = 0; + } + len = snprintf(tmpbuf, sizeof(tmpbuf), "%c (%02x) ", + isalnum(data) ? data : '?', data); + if (write(uart_log_fd, tmpbuf, len) != len) { + assert(0); + } + state.chars_in_line++; + } + } + if (u && state.uart == NULL) { + len = snprintf(tmpbuf, sizeof(tmpbuf), "%u:uart%d %s\n\t%c (%02x) ", + now, u - uarts, istx ? "tx" : "rx", isalnum(data) ? data : '?', data); + if (write(uart_log_fd, tmpbuf, len) != len) { + assert(0); + } + state.chars_in_line = 1; + state.uart = u; + state.istx = istx; + state.time = now; + } +} + +static int +uart_transmit_char(struct uart *uart) +{ + int sr; + int rc; + char ch; + + OS_ENTER_CRITICAL(sr); + rc = uart->u_tx_func(uart->u_func_arg); + if (rc < 0) { + /* + * No more data to send. + */ + uart->u_tx_run = 0; + if (uart->u_tx_done) { + uart->u_tx_done(uart->u_func_arg); + } + OS_EXIT_CRITICAL(sr); + return 0; + } + ch = rc; + uart_log_data(uart, 1, ch); + OS_EXIT_CRITICAL(sr); + rc = write(uart->u_fd, &ch, 1); + if (rc <= 0) { + /* XXX EOF/error, what now? */ + return -1; + } + return 0; +} + +static void +uart_poller(void *arg) +{ + int i; + int rc; + int bytes; + int sr; + int didwork; + unsigned char ch; + struct uart *uart; + + while (1) { + for (i = 0; i < UART_CNT; i++) { + if (!uarts[i].u_open) { + continue; + } + uart = &uarts[i]; + + for (bytes = 0; bytes < UART_MAX_BYTES_PER_POLL; bytes++) { + didwork = 0; + if (uart->u_tx_run) { + uart_transmit_char(uart); + didwork = 1; + } + if (uart->u_rx_char < 0) { + rc = read(uart->u_fd, &ch, 1); + if (rc == 0) { + /* XXX EOF, what now? */ + assert(0); + } else if (rc > 0) { + uart->u_rx_char = ch; + } + } + if (uart->u_rx_char >= 0) { + OS_ENTER_CRITICAL(sr); + uart_log_data(uart, 0, uart->u_rx_char); + rc = uart->u_rx_func(uart->u_func_arg, uart->u_rx_char); + /* Delivered */ + if (rc >= 0) { + uart->u_rx_char = -1; + didwork = 1; + } + OS_EXIT_CRITICAL(sr); + } + if (!didwork) { + break; + } + } + } + uart_log_data(NULL, 0, 0); + os_time_delay(OS_TICKS_PER_SEC / 100); + } +} + +static void +set_nonblock(int fd) +{ + int flags; + + flags = fcntl(fd, F_GETFL); + if (flags == -1) { + const char msg[] = "fcntl(F_GETFL) fail"; + write(1, msg, sizeof(msg)); + return; + } + if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) { + const char msg[] = "fcntl(F_SETFL) fail"; + write(1, msg, sizeof(msg)); + return; + } +} + +static int +uart_pty_set_attr(int fd) +{ + struct termios tios; + + if (tcgetattr(fd, &tios)) { + const char msg[] = "tcgetattr() failed"; + write(1, msg, sizeof(msg)); + return -1; + } + + tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB); + tios.c_cflag |= CS8 | CREAD; + tios.c_iflag = IGNPAR; + tios.c_oflag = 0; + tios.c_lflag = 0; + if (tcsetattr(fd, TCSAFLUSH, &tios) < 0) { + const char msg[] = "tcsetattr() failed"; + write(1, msg, sizeof(msg)); + return -1; + } + return 0; +} + +static int +uart_pty(int port) +{ + int fd; + int loop_slave; + char pty_name[32]; + char msg[64]; + + if (openpty(&fd, &loop_slave, pty_name, NULL, NULL) < 0) { + const char msg[] = "openpty() failed"; + write(1, msg, sizeof(msg)); + return -1; + } + + if (uart_pty_set_attr(loop_slave)) { + goto err; + } + + snprintf(msg, sizeof(msg), "uart%d at %s\n", port, pty_name); + write(1, msg, strlen(msg)); + return fd; + err: + close(fd); + close(loop_slave); + return -1; +} + +/** + * Opens an external device terminal (/dev/cu.<...>). + */ +static int +uart_open_dev(int port, int32_t baudrate, uint8_t databits, + uint8_t stopbits, enum hal_uart_parity parity, + enum hal_uart_flow_ctl flow_ctl) +{ + const char *filename; + int fd; + int rc; + + filename = native_uart_dev_strs[port]; + assert(filename != NULL); + + fd = open(filename, O_RDWR); + if (fd < 0) { + return -1; + } + + rc = uart_dev_set_attr(fd, baudrate, databits, + stopbits, parity, flow_ctl); + if (rc != 0) { + close(fd); + return rc; + } + + dprintf(1, "uart%d at %s\n", port, filename); + + return fd; +} + +void +hal_uart_start_tx(int port) +{ + int sr; + + if (port >= UART_CNT || uarts[port].u_open == 0) { + return; + } + OS_ENTER_CRITICAL(sr); + uarts[port].u_tx_run = 1; + if (!os_started()) { + /* + * XXX this is a hack. + */ + uart_transmit_char(&uarts[port]); + } + OS_EXIT_CRITICAL(sr); +} + +void +hal_uart_start_rx(int port) +{ + /* nothing to do here */ +} + +void +hal_uart_blocking_tx(int port, uint8_t data) +{ + if (port >= UART_CNT || uarts[port].u_open == 0) { + return; + } + + /* XXX: Count statistics and add error checking here. */ + (void) write(uarts[port].u_fd, &data, sizeof(data)); +} + +int +hal_uart_init_cbs(int port, hal_uart_tx_char tx_func, hal_uart_tx_done tx_done, + hal_uart_rx_char rx_func, void *arg) +{ + struct uart *uart; + int rc; + + if (port >= UART_CNT) { + return -1; + } + + uart = &uarts[port]; + if (uart->u_open) { + return -1; + } + uart->u_tx_func = tx_func; + uart->u_tx_done = tx_done; + uart->u_rx_func = rx_func; + uart->u_func_arg = arg; + uart->u_rx_char = -1; + + if (!uart_poller_running) { + uart_poller_running = 1; + rc = os_task_init(&uart_poller_task, "uartpoll", uart_poller, NULL, + MYNEWT_VAL(MCU_UART_POLLER_PRIO), OS_WAIT_FOREVER, uart_poller_stack, + UART_POLLER_STACK_SZ); + assert(rc == 0); + } + return 0; +} + +int +hal_uart_config(int port, int32_t baudrate, uint8_t databits, uint8_t stopbits, + enum hal_uart_parity parity, enum hal_uart_flow_ctl flow_ctl) +{ + struct uart *uart; + + if (port >= UART_CNT) { + return -1; + } + + uart = &uarts[port]; + if (uart->u_open) { + return -1; + } + + if (native_uart_dev_strs[port] == NULL) { + uart->u_fd = uart_pty(port); + } else { + uart->u_fd = uart_open_dev(port, baudrate, databits, stopbits, + parity, flow_ctl); + } + + if (uart->u_fd < 0) { + return -1; + } + set_nonblock(uart->u_fd); + + + uart_open_log(); + uart->u_open = 1; + return 0; +} + +int +hal_uart_close(int port) +{ + struct uart *uart; + int rc; + + if (port >= UART_CNT) { + rc = -1; + goto err; + } + + uart = &uarts[port]; + if (!uart->u_open) { + rc = -1; + goto err; + } + + close(uart->u_fd); + + uart->u_open = 0; + return (0); + err: + return (rc); +} + +int +hal_uart_init(int port, void *arg) +{ + return (0); +} + +int +uart_set_dev(int port, const char *dev_str) +{ + if (port < 0 || port >= UART_CNT) { + return SYS_EINVAL; + } + + if (uarts[port].u_open) { + return SYS_EBUSY; + } + + native_uart_dev_strs[port] = dev_str; + + return 0; +} diff --git a/babblesim/hw/mcu/nordic/nrf52_bsim/src/hal_watchdog.c b/babblesim/hw/mcu/nordic/nrf52_bsim/src/hal_watchdog.c new file mode 100644 index 0000000000..d94c7e332a --- /dev/null +++ b/babblesim/hw/mcu/nordic/nrf52_bsim/src/hal_watchdog.c @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "hal/hal_watchdog.h" + +int +hal_watchdog_init(uint32_t expire_msecs) +{ + return (0); +} + +void +hal_watchdog_enable(void) +{ +} + +void +hal_watchdog_tickle(void) +{ +} diff --git a/babblesim/hw/mcu/nordic/nrf52_bsim/src/native_uart_cfg.c b/babblesim/hw/mcu/nordic/nrf52_bsim/src/native_uart_cfg.c new file mode 100644 index 0000000000..5e38ac7bf4 --- /dev/null +++ b/babblesim/hw/mcu/nordic/nrf52_bsim/src/native_uart_cfg.c @@ -0,0 +1,248 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#include +#include +#include + +/* B0 defined in bits/termios.h collides with nrfx/mdk/nrf52.h */ +#undef B0 + +#include "os/mynewt.h" +#include "native_uart_cfg_priv.h" + +/* uint64 is used here to accommodate speed_t, whatever that is. */ +static const uint64_t uart_baud_table[][2] = { +#ifdef B50 + { 50, B50 }, +#endif +#ifdef B75 + { 75, B75 }, +#endif +#ifdef B110 + { 110, B110 }, +#endif +#ifdef B134 + { 134, B134 }, +#endif +#ifdef B150 + { 150, B150 }, +#endif +#ifdef B200 + { 200, B200 }, +#endif +#ifdef B300 + { 300, B300 }, +#endif +#ifdef B600 + { 600, B600 }, +#endif +#ifdef B1200 + { 1200, B1200 }, +#endif +#ifdef B1800 + { 1800, B1800 }, +#endif +#ifdef B2400 + { 2400, B2400 }, +#endif +#ifdef B4800 + { 4800, B4800 }, +#endif +#ifdef B9600 + { 9600, B9600 }, +#endif +#ifdef B19200 + { 19200, B19200 }, +#endif +#ifdef B38400 + { 38400, B38400 }, +#endif +#ifdef B57600 + { 57600, B57600 }, +#endif +#ifdef B115200 + { 115200, B115200 }, +#endif +#ifdef B230400 + { 230400, B230400 }, +#endif +#ifdef B460800 + { 460800, B460800 }, +#endif +#ifdef B500000 + { 500000, B500000 }, +#endif +#ifdef B576000 + { 576000, B576000 }, +#endif +#ifdef B921600 + { 921600, B921600 }, +#endif +#ifdef B1000000 + { 1000000, B1000000 }, +#endif +#ifdef B1152000 + { 1152000, B1152000 }, +#endif +#ifdef B1500000 + { 1500000, B1500000 }, +#endif +#ifdef B2000000 + { 2000000, B2000000 }, +#endif +#ifdef B2500000 + { 2500000, B2500000 }, +#endif +#ifdef B3000000 + { 3000000, B3000000 }, +#endif +#ifdef B3500000 + { 3500000, B3500000 }, +#endif +#ifdef B3710000 + { 3710000, B3710000 }, +#endif +#ifdef B4000000 + { 4000000, B4000000 }, +#endif +}; +#define UART_BAUD_TABLE_SZ (sizeof uart_baud_table / sizeof uart_baud_table[0]) + +/** + * Returns 0 on failure. + */ +speed_t +uart_baud_to_speed(int_least32_t baud) +{ + int i; + + for (i = 0; i < UART_BAUD_TABLE_SZ; i++) { + if (uart_baud_table[i][0] == baud) { + return uart_baud_table[i][1]; + } + } + + return 0; +} + +/** + * Configures an external device terminal (/dev/cu.<...>). + */ +int +uart_dev_set_attr(int fd, int32_t baudrate, uint8_t databits, + uint8_t stopbits, enum hal_uart_parity parity, + enum hal_uart_flow_ctl flow_ctl) +{ + struct termios tty; + speed_t speed; + int rc; + + assert(fd >= 0); + + memset(&tty, 0, sizeof(tty)); + cfmakeraw(&tty); + + speed = uart_baud_to_speed(baudrate); + if (speed == 0) { + fprintf(stderr, "invalid baud rate: %d\n", (int)baudrate); + assert(0); + } + + tty.c_cflag |= (speed | CLOCAL | CREAD); + + /* Set flow control. */ + switch (flow_ctl) { + case HAL_UART_FLOW_CTL_NONE: + tty.c_cflag &= ~CRTSCTS; + break; + + case HAL_UART_FLOW_CTL_RTS_CTS: + tty.c_cflag |= CRTSCTS; + break; + + default: + fprintf(stderr, "invalid flow control setting: %d\n", flow_ctl); + return -1; + } + + errno = 0; + rc = cfsetospeed(&tty, speed); + if (rc != 0) { + fprintf(stderr, "cfsetospeed failed; %d (%s) baudrate=%d\n", + errno, strerror(errno), (int)baudrate); + return -1; + } + + errno = 0; + rc = cfsetispeed(&tty, speed); + if (rc != 0) { + fprintf(stderr, "cfsetispeed failed; %d (%s) baudrate=%d\n", + errno, strerror(errno), (int)baudrate); + return -1; + } + + switch (databits) { + case 7: + tty.c_cflag |= CS7; + + switch (parity) { + case HAL_UART_PARITY_ODD: + tty.c_cflag |= PARENB; + tty.c_cflag |= PARODD; + tty.c_cflag &= ~CSTOPB; + tty.c_cflag &= ~CSIZE; + break; + + case HAL_UART_PARITY_EVEN: + tty.c_cflag |= PARENB; + tty.c_cflag &= ~PARODD; + tty.c_cflag &= ~CSTOPB; + tty.c_cflag &= ~CSIZE; + break; + + default: + return SYS_EINVAL; + } + + case 8: + if (parity != HAL_UART_PARITY_NONE) { + return SYS_EINVAL; + } + tty.c_cflag |= CS8; + tty.c_cflag &= ~PARENB; + tty.c_cflag &= ~CSTOPB; + tty.c_cflag &= ~CSIZE; + break; + + default: + return SYS_EINVAL; + } + + rc = tcsetattr(fd, TCSANOW, &tty); + if (rc != 0) { + fprintf(stderr, "tcsetattr failed; %d (%s)\n", errno, strerror(errno)); + return -1; + } + + return 0; +} diff --git a/babblesim/hw/mcu/nordic/nrf52_bsim/src/native_uart_cfg_priv.h b/babblesim/hw/mcu/nordic/nrf52_bsim/src/native_uart_cfg_priv.h new file mode 100644 index 0000000000..786a68addf --- /dev/null +++ b/babblesim/hw/mcu/nordic/nrf52_bsim/src/native_uart_cfg_priv.h @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_NATIVE_UART_CFG_PRIV_ +#define H_NATIVE_UART_CFG_PRIV_ + +#include +#include "hal/hal_uart.h" + +speed_t uart_baud_to_speed(int_least32_t baud); +int uart_dev_set_attr(int fd, int32_t baudrate, uint8_t databits, + uint8_t stopbits, enum hal_uart_parity parity, + enum hal_uart_flow_ctl flow_ctl); + +#endif diff --git a/babblesim/hw/mcu/nordic/nrf52_bsim/src/nrf52_clock.c b/babblesim/hw/mcu/nordic/nrf52_bsim/src/nrf52_clock.c new file mode 100644 index 0000000000..25ccc7fdd3 --- /dev/null +++ b/babblesim/hw/mcu/nordic/nrf52_bsim/src/nrf52_clock.c @@ -0,0 +1,103 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +#include +#include +#include +#include +#include "mcu/nrf52_hal.h" +#include "nrfx.h" +#include "syscfg/syscfg.h" +#include "os/os.h" + +static uint8_t nrf52_clock_hfxo_refcnt; + +/** + * Request HFXO clock be turned on. Note that each request must have a + * corresponding release. + * + * @return int 0: hfxo was already on. 1: hfxo was turned on. + */ +int +nrf52_clock_hfxo_request(void) +{ + int started; + uint32_t ctx; + +#if MYNEWT_VAL_CHOICE(MCU_HFCLK_SOURCE, HFINT) + /* Cannot enable/disable hfxo if it is not present */ + assert(0); +#endif + + started = 0; + __HAL_DISABLE_INTERRUPTS(ctx); + assert(nrf52_clock_hfxo_refcnt < 0xff); + if (nrf52_clock_hfxo_refcnt == 0) { + /* Check the current STATE and SRC of HFCLK */ + if ((NRF_CLOCK->HFCLKSTAT & + (CLOCK_HFCLKSTAT_SRC_Msk | CLOCK_HFCLKSTAT_STATE_Msk)) != + (CLOCK_HFCLKSTAT_SRC_Xtal << CLOCK_HFCLKSTAT_SRC_Pos | + CLOCK_HFCLKSTAT_STATE_Running << CLOCK_HFCLKSTAT_STATE_Pos)) { + NRF_CLOCK->EVENTS_HFCLKSTARTED = 0; + nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_HFCLKSTART); + while (!NRF_CLOCK->EVENTS_HFCLKSTARTED) { +#if BABBLESIM + tm_tick(); +#endif + } + } + started = 1; + } + ++nrf52_clock_hfxo_refcnt; + __HAL_ENABLE_INTERRUPTS(ctx); + + return started; +} + +/** + * Release the HFXO. This means that the caller no longer needs the HFXO to be + * turned on. Each call to release should have been preceeded by a corresponding + * call to request the HFXO + * + * + * @return int 0: HFXO not stopped by this call (others using it) 1: HFXO + * stopped. + */ +int +nrf52_clock_hfxo_release(void) +{ + int stopped; + uint32_t ctx; + +#if MYNEWT_VAL_CHOICE(MCU_HFCLK_SOURCE, HFINT) + /* Cannot enable/disable hfxo if it is not present */ + assert(0); +#endif + + stopped = 0; + __HAL_DISABLE_INTERRUPTS(ctx); + assert(nrf52_clock_hfxo_refcnt != 0); + --nrf52_clock_hfxo_refcnt; + if (nrf52_clock_hfxo_refcnt == 0) { + nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_HFCLKSTOP); + stopped = 1; + } + __HAL_ENABLE_INTERRUPTS(ctx); + + return stopped; +} diff --git a/babblesim/hw/mcu/nordic/nrf52_bsim/src/system_nrf52.c b/babblesim/hw/mcu/nordic/nrf52_bsim/src/system_nrf52.c new file mode 100644 index 0000000000..00224cdc06 --- /dev/null +++ b/babblesim/hw/mcu/nordic/nrf52_bsim/src/system_nrf52.c @@ -0,0 +1,37 @@ +/* Copyright (c) 2012 ARM LIMITED + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of ARM nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "mcu/cmsis_nvic.h" +#include "nrf.h" + + +void SystemInit(void) +{ +} diff --git a/babblesim/hw/mcu/nordic/nrf52_bsim/syscfg.yml b/babblesim/hw/mcu/nordic/nrf52_bsim/syscfg.yml new file mode 100644 index 0000000000..d6b6695904 --- /dev/null +++ b/babblesim/hw/mcu/nordic/nrf52_bsim/syscfg.yml @@ -0,0 +1,526 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +syscfg.defs: + MCU_TARGET: + description: > + Specifies target MCU, shall be set by BSP. + value: + restrictions: + - $notnull + choices: + - nRF52810 + - nRF52811 + - nRF52832 + - nRF52840 + + MCU_FLASH_MIN_WRITE_SIZE: + description: > + Specifies the required alignment for internal flash writes. + Used internally by the newt tool. + value: 1 + + MCU_DCDC_ENABLED: + description: > + Specifies whether or not to enable DC/DC regulator. This requires + external circuitry so is defined to be zero by default and + expected to be overridden by the BSP. + value: 0 + + MCU_HFCLK_SOURCE: + description: > + Selected source for high frequency clock (HFCLK). + Selecting HFXO will still mostly use the HFINT but will switch to HFXO when requested (BLE, certain timers, etc...) + Selecting HFINT should only be used in the case where an external 32MHz crystal oscillator is not present. + value: HFXO + choices: + - HFXO + - HFINT + restrictions: + - '(MCU_HFCLK_SOURCE == "HFXO") || (MCU_LFCLK_SOURCE != "LFSYNTH")' + + MCU_LFCLK_SOURCE: + description: > + Selected source for low frequency clock (LFCLK). + value: + choices: + - LFRC # 32.768 kHz RC oscillator + - LFXO # 32.768 kHz crystal oscillator + - LFSYNTH # 32.768 kHz synthesized from HFCLK + + MCU_I2C_RECOVERY_DELAY_USEC: + description: > + Time to wait for activity on SCL line after triggering start task + before restarting TWI controller. This is to recover from state + where controller is unresponsive due to glitch on I2C bus. + Note: Default value seems to work fine, but may need to be tuned. + value: 100 + + MCU_BUS_DRIVER_I2C_USE_TWIM: + description: > + Enables usage of i2c_nrf52_twim bus driver for I2C. + If disabled, standard i2c_hal driver is used. + value: 0 + + MCU_GPIO_USE_PORT_EVENT: + description: > + When enabled, hal_gpio will use GPIOTE PORT event instead of PIN + events for interrupts. This mode may be less accurate (i.e. pulse + length needs to be longer in order to be detected) but it reduces + power consumption since it does not require HFCLK to be running. + Refer to nRF52xxx Product Specification document for more details. + value: 0 + + MCU_DEBUG_IGNORE_BKPT: + description: > + When enabled, asm(bkpt) will be ignored. If not set, it will hit + the breakpoint wherever it gets called, For example, reset and crash + value: 0 + + +# MCU peripherals definitions + I2C_0: + description: 'Enable nRF52xxx I2C (TWI) 0' + value: 0 + restrictions: + - '!(SPI_0_MASTER && ((MCU_TARGET == "nrf52832") || (MCU_TARGET == "nrf52840")))' + - '!(SPI_0_SLAVE && ((MCU_TARGET == "nrf52832") || (MCU_TARGET == "nrf52840")))' + - '!(SPI_1_MASTER && (MCU_TARGET == "nrf52811"))' + - '!(SPI_1_SLAVE && (MCU_TARGET == "nrf52811"))' + I2C_0_PIN_SCL: + description: 'SCL pin for I2C_0' + value: '' + I2C_0_PIN_SDA: + description: 'SDA pin for I2C_0' + value: '' + I2C_0_FREQ_KHZ: + description: 'Frequency [kHz] for I2C_0' + value: 100 + + I2C_1: + description: 'Enable nRF52xxx I2C (TWI) 1' + value: 0 + restrictions: + - "!SPI_1_MASTER" + - "!SPI_1_SLAVE" + I2C_1_PIN_SCL: + description: 'SCL pin for I2C_1' + value: '' + I2C_1_PIN_SDA: + description: 'SDA pin for I2C_1' + value: '' + I2C_1_FREQ_KHZ: + description: 'Frequency [kHz] for I2C_1' + value: 100 + + SPI_0_MASTER: + description: 'Enable nRF52xxx SPI Master 0' + value: 0 + restrictions: + - "!SPI_0_SLAVE" + - '!(I2C_0 && ((MCU_TARGET == "nrf52832") || (MCU_TARGET == "nrf52840")))' + SPI_0_MASTER_PIN_SCK: + description: 'SCK pin for SPI_0_MASTER' + value: '' + SPI_0_MASTER_PIN_MOSI: + description: 'MOSI pin for SPI_0_MASTER' + value: '' + SPI_0_MASTER_PIN_MISO: + description: 'MISO pin for SPI_0_MASTER' + value: '' + + SPI_0_SLAVE: + description: 'Enable nRF52xxx SPI Slave 0' + value: 0 + restrictions: + - "!SPI_0_MASTER" + - '!(I2C_0 && ((MCU_TARGET == "nrf52832") || (MCU_TARGET == "nrf52840")))' + SPI_0_SLAVE_PIN_SCK: + description: 'SCK pin for SPI_0_SLAVE' + value: '' + SPI_0_SLAVE_PIN_MOSI: + description: 'MOSI pin for SPI_0_SLAVE' + value: '' + SPI_0_SLAVE_PIN_MISO: + description: 'MISO pin for SPI_0_SLAVE' + value: '' + SPI_0_SLAVE_PIN_SS: + description: 'SS pin for SPI_0_SLAVE' + value: '' + + SPI_1_MASTER: + description: 'Enable nRF52xxx SPI Master 1' + value: 0 + restrictions: + - "!SPI_1_SLAVE" + - '!(I2C_1 && ((MCU_TARGET == "nrf52832") || (MCU_TARGET == "nrf52840")))' + - '!(I2C_0 && ((MCU_TARGET == "nrf52811")))' + SPI_1_MASTER_PIN_SCK: + description: 'SCK pin for SPI_1_MASTER' + value: '' + SPI_1_MASTER_PIN_MOSI: + description: 'MOSI pin for SPI_1_MASTER' + value: '' + SPI_1_MASTER_PIN_MISO: + description: 'MISO pin for SPI_1_MASTER' + value: '' + + SPI_1_SLAVE: + description: 'Enable nRF52xxx SPI Slave 1' + value: 0 + restrictions: + - "!SPI_1_MASTER" + - '!(I2C_1 && ((MCU_TARGET == "nrf52832") || (MCU_TARGET == "nrf52840")))' + - '!(I2C_0 && ((MCU_TARGET == "nrf52811")))' + SPI_1_SLAVE_PIN_SCK: + description: 'SCK pin for SPI_1_SLAVE' + value: '' + SPI_1_SLAVE_PIN_MOSI: + description: 'MOSI pin for SPI_1_SLAVE' + value: '' + SPI_1_SLAVE_PIN_MISO: + description: 'MISO pin for SPI_1_SLAVE' + value: '' + SPI_1_SLAVE_PIN_SS: + description: 'SS pin for SPI_1_SLAVE' + value: '' + + SPI_2_MASTER: + description: 'Enable nRF52xxx SPI Master 2' + value: 0 + restrictions: + - "!SPI_2_SLAVE" + SPI_2_MASTER_PIN_SCK: + description: 'SCK pin for SPI_2_MASTER' + value: '' + SPI_2_MASTER_PIN_MOSI: + description: 'MOSI pin for SPI_2_MASTER' + value: '' + SPI_2_MASTER_PIN_MISO: + description: 'MISO pin for SPI_2_MASTER' + value: '' + + SPI_2_SLAVE: + description: 'Enable nRF52xxx SPI Slave 2' + value: 0 + restrictions: + - "!SPI_2_MASTER" + SPI_2_SLAVE_PIN_SCK: + description: 'SCK pin for SPI_2_SLAVE' + value: '' + SPI_2_SLAVE_PIN_MOSI: + description: 'MOSI pin for SPI_2_SLAVE' + value: '' + SPI_2_SLAVE_PIN_MISO: + description: 'MISO pin for SPI_2_SLAVE' + value: '' + SPI_2_SLAVE_PIN_SS: + description: 'SS pin for SPI_2_SLAVE' + value: '' + + SPI_3_MASTER: + description: 'Enable nRF52xxx SPI Master 3' + value: 0 + restrictions: + - 'MCU_TARGET == "nRF52840" || !SPI_3_MASTER' + SPI_3_MASTER_PIN_SCK: + description: 'SCK pin for SPI_3_MASTER' + value: '' + SPI_3_MASTER_PIN_MOSI: + description: 'MOSI pin for SPI_3_MASTER' + value: '' + SPI_3_MASTER_PIN_MISO: + description: 'MISO pin for SPI_3_MASTER' + value: '' + + ADC_0: + description: 'Enable nRF52xxx ADC 0' + value: 0 + + ADC_0_REFMV_0: + description: 'reference mV in AREF0 if used' + value: 0 + + PWM_0: + description: 'Enable nRF52xxx PWM 0' + value: 0 + PWM_1: + description: 'Enable nRF52xxx PWM 1' + value: 0 + PWM_2: + description: 'Enable nRF52xxx PWM 2' + value: 0 + PWM_3: + description: 'Enable nRF52xxx PWM 3' + value: 0 + restrictions: + - 'MCU_TARGET == "nRF52840" || !PWM_3' + + TRNG: + description: 'Enable nRF52xxx TRNG' + value: 0 + + CRYPTO: + description: 'Enable nRF52xxx CRYPTO' + value: 0 + + UART_0: + description: 'Enable nRF52xxx UART0' + value: 1 + UART_0_PIN_TX: + description: 'TX pin for UART0' + value: '' + UART_0_PIN_RX: + description: 'RX pin for UART0' + value: '' + UART_0_PIN_RTS: + description: 'RTS pin for UART0' + value: -1 + UART_0_PIN_CTS: + description: 'CTS pin for UART0' + value: -1 + + UART_1: + description: 'Enable nRF52xxx UART1' + value: 0 + restrictions: + - 'MCU_TARGET == "nRF52840" || !UART_1' + UART_1_PIN_TX: + description: 'TX pin for UART1' + value: '' + UART_1_PIN_RX: + description: 'RX pin for UART1' + value: '' + UART_1_PIN_RTS: + description: 'RTS pin for UART1' + value: -1 + UART_1_PIN_CTS: + description: 'CTS pin for UART1' + value: -1 + + TEMP: + description: 'Enable nRF52xxx internal temperature mesurement' + value: 0 + + TIMER_0: + description: 'Enable nRF52xxx Timer 0' + value: 1 + TIMER_1: + description: 'Enable nRF52xxx Timer 1' + value: 0 + TIMER_2: + description: 'Enable nRF52xxx Timer 2' + value: 0 + TIMER_3: + description: 'Enable nRF52xxx Timer 3' + value: 0 + TIMER_4: + description: 'Enable nRF52xxx Timer 4' + value: 0 + TIMER_5: + description: 'Enable nRF52xxx RTC 0' + value: 0 + + QSPI_ENABLE: + description: 'NRF52 QSPI' + value: 0 + + QSPI_READOC: + description: > + QSPI Command to use + 0 - 0x09 Fast Read + 1 - 0x3B Fast Read Dual Output + 2 - 0xBB Fast Read Dual I/O + 3 - 0x6B Fast Read Quad Output + 4 - 0xEB Fast Read Quad I/O + value: 0 + QSPI_WRITEOC: + description: > + QSPI Command to use + 0 - 0x02 Page program + 1 - 0xA2 Page program Dual Data + 2 - 0x32 Page program Quad Data + 3 - 0x38 Page program Quad I/O + value: 0 + QSPI_ADDRMODE: + description: 'Address lentgh 0=24 bits, 1=32 bits' + value: 0 + QSPI_DPMCONFIG: + description: 'Deep power mode enable' + value: 0 + QSPI_SCK_DELAY: + description: > + Minimum amount of time that the CSN pin must stay high + before it can go low again. Value is specified in number of 16 + MHz periods (62.5 ns). + value: 0 + QSPI_SCK_FREQ: + description: '32MHz clock divider (0-31). Clock = 32MHz / (1+divider)' + value: 0 + QSPI_SPI_MODE: + description: 'SPI 0=Mode0 or 1=Mode3' + value: 0 + + QSPI_FLASH_SECTOR_SIZE: + description: 'QSPI sector size. In most cases it should be 4096.' + value: 0 + QSPI_FLASH_PAGE_SIZE: + description: > + QSPI page size. Writes can only be performed to one page at a time. + In most cases it should be 256. + value: 0 + + QSPI_FLASH_SECTOR_COUNT: + description: 'QSPI sector count' + value: -1 + QSPI_PIN_CS: + description: 'CS pin for QSPI' + value: -1 + QSPI_PIN_SCK: + description: 'SCK pin for QSPI' + value: -1 + QSPI_PIN_DIO0: + description: 'DIO0 pin for QSPI' + value: -1 + QSPI_PIN_DIO1: + description: 'DIO1 pin for QSPI' + value: -1 + QSPI_PIN_DIO2: + description: 'DIO2 pin for QSPI' + value: -1 + QSPI_PIN_DIO3: + description: 'DIO3 pin for QSPI' + value: -1 + + NFC_PINS_AS_GPIO: + description: 'Use NFC pins as GPIOs instead of NFC functionality' + value: 1 + + GPIO_AS_PIN_RESET: + description: 'Enable pin reset' + value: 0 + +# Deprecated settings + + MCU_NRF52832: + description: Use MCU_TARGET instead + value: 0 + restrictions: + - "!MCU_NRF52840" + deprecated: 1 + MCU_NRF52840: + description: Use MCU_TARGET instead + value: 0 + restrictions: + - "!MCU_NRF52832" + deprecated: 1 + + XTAL_32768: + description: Use MCU_LFCLK_SOURCE instead + value: 0 + restrictions: + - "!XTAL_RC" + - "!XTAL_32768_SYNTH" + deprecated: 1 + XTAL_RC: + description: Use MCU_LFCLK_SOURCE instead + value: 0 + restrictions: + - "!XTAL_32768" + - "!XTAL_32768_SYNTH" + deprecated: 1 + XTAL_32768_SYNTH: + description: Use MCU_LFCLK_SOURCE instead + value: 0 + restrictions: + - "!XTAL_32768" + - "!XTAL_RC" + deprecated: 1 + + MCU_NATIVE_USE_SIGNALS: + description: > + Whether to use POSIX signals to implement context switches. Valid + values are as follows: + 1: More correctness; less stability. The OS tick timer will + cause a high-priority task to preempt a low-priority task. + This causes stability issues because a task can be preempted + while it is in the middle of a system call, potentially + causing deadlock or memory corruption. + + 0: Less correctness; more stability. The OS tick timer only + runs while the idle task is active. Therefore, a sleeping + high-priority task will not preempt a low-priority task due + to a timing event (e.g., delay or callout expired). + However, this version of sim does not suffer from the + stability issues that affect the "signals" implementation. + + Unit tests should use 1. Long-running sim processes should use 0. + + value: 1 + MCU_NATIVE: + description: > + Set to indicate that we are using native mcu. + value: 1 + MCU_FLASH_STYLE_ST: + description: Emulated flash layout is similar to one in STM32. + value: 0 + restrictions: + - "!MCU_FLASH_STYLE_NORDIC" + MCU_FLASH_STYLE_NORDIC: + description: > + Emulated flash layout is similar to one in NRF51/2 and SAMD21. + value: 1 + restrictions: + - "!MCU_FLASH_STYLE_ST" + MCU_UART_POLLER_PRIO: + description: 'Priority of native UART poller task.' + type: task_priority + value: 1 + MCU_TIMER_POLLER_PRIO: + description: 'Priority of native HAL timer task.' + type: task_priority + value: 0 + +syscfg.vals: + OS_TICKS_PER_SEC: 128 + +syscfg.vals.MCU_NRF52832: + MCU_TARGET: nRF52832 +syscfg.vals.MCU_NRF52840: + MCU_TARGET: nRF52840 + +syscfg.vals.XTAL_32768: + MCU_LFCLK_SOURCE: LFXO +syscfg.vals.XTAL_RC: + MCU_LFCLK_SOURCE: LFRC +syscfg.vals.XTAL_32768_SYNTH: + MCU_LFCLK_SOURCE: LFSYNTH + +syscfg.restrictions: + - "!I2C_0 || (I2C_0_PIN_SCL && I2C_0_PIN_SDA)" + - "!I2C_1 || (I2C_1_PIN_SCL && I2C_1_PIN_SDA)" + - "!SPI_0_MASTER || (SPI_0_MASTER_PIN_SCK && SPI_0_MASTER_PIN_MOSI && SPI_0_MASTER_PIN_MISO)" + - "!SPI_1_MASTER || (SPI_1_MASTER_PIN_SCK && SPI_1_MASTER_PIN_MOSI && SPI_1_MASTER_PIN_MISO)" + - "!SPI_2_MASTER || (SPI_2_MASTER_PIN_SCK && SPI_2_MASTER_PIN_MOSI && SPI_2_MASTER_PIN_MISO)" + - "!SPI_3_MASTER || (SPI_3_MASTER_PIN_SCK && SPI_3_MASTER_PIN_MOSI && SPI_3_MASTER_PIN_MISO)" + - "!SPI_0_SLAVE || (SPI_0_SLAVE_PIN_SCK && SPI_0_SLAVE_PIN_MOSI && SPI_0_SLAVE_PIN_MISO && SPI_0_SLAVE_PIN_SS)" + - "!SPI_1_SLAVE || (SPI_1_SLAVE_PIN_SCK && SPI_1_SLAVE_PIN_MOSI && SPI_1_SLAVE_PIN_MISO && SPI_1_SLAVE_PIN_SS)" + - "!SPI_2_SLAVE || (SPI_2_SLAVE_PIN_SCK && SPI_2_SLAVE_PIN_MOSI && SPI_2_SLAVE_PIN_MISO && SPI_2_SLAVE_PIN_SS)" + - "!UART_0 || (UART_0_PIN_TX && UART_0_PIN_RX)" + - "!UART_1 || (UART_1_PIN_TX && UART_1_PIN_RX)" + - "(OS_TICKS_PER_SEC == 128 || OS_TICKS_PER_SEC == 256 || OS_TICKS_PER_SEC == 512 || OS_TICKS_PER_SEC == 1024)" diff --git a/babblesim/sdk/.gitignore b/babblesim/sdk/.gitignore new file mode 100644 index 0000000000..b269fe6291 --- /dev/null +++ b/babblesim/sdk/.gitignore @@ -0,0 +1,3 @@ +components +nrfx +src \ No newline at end of file diff --git a/babblesim/sdk/pkg.yml b/babblesim/sdk/pkg.yml new file mode 100644 index 0000000000..a542a3044e --- /dev/null +++ b/babblesim/sdk/pkg.yml @@ -0,0 +1,47 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +pkg.name: babblesim/sdk +pkg.type: sdk +pkg.description: External files required to build BabbleSim +pkg.author: "Apache Mynewt " +pkg.homepage: "https://mynewt.apache.org/" + +pkg.cflags: -std=gnu99 + +pkg.include_dirs: + - components/ext_NRF52_hw_models/src/nrfx_config + - components/ext_NRF52_hw_models/src/nrfx/nrfx_replacements + - components/ext_NRF52_hw_models/src/nrfx/mdk_replacements + - components/ext_NRF52_hw_models/src/HW_models + - components/libUtilv1/src + - components/libPhyComv1/src + - components/libRandv2/src + - components/ext_libCryptov1/src + - nrfx + - nrfx/drivers + - nrfx/hal + - nrfx/mdk + +pkg.pre_build_cmds: + scripts/link_babblesim.sh: 1 + scripts/link_nrfx.sh: 2 + +pkg.lflags: + - -ldl diff --git a/babblesim/sdk/scripts/link_babblesim.sh b/babblesim/sdk/scripts/link_babblesim.sh new file mode 100755 index 0000000000..1c069eb34a --- /dev/null +++ b/babblesim/sdk/scripts/link_babblesim.sh @@ -0,0 +1,47 @@ +#!/bin/bash +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +if [ -z ${BSIM_COMPONENTS_PATH+x} ]; then + echo "This board requires the BabbleSim simulator. Please set" \ + "the environment variable BSIM_COMPONENTS_PATH to point to its components" \ + "folder. More information can be found in" \ + "https://babblesim.github.io/folder_structure_and_env.html" 1>&2 + exit 1 +fi + +if [ -z ${BSIM_OUT_PATH+x} ]; then + echo "This board requires the BabbleSim simulator. Please set" \ + "the environment variable BSIM_OUT_PATH to point to the folder where the" \ + "simulator is compiled to. More information can be found in" \ + "https://babblesim.github.io/folder_structure_and_env.html" 1>&2 + exit 1 +fi + +ln -sfn "${BSIM_COMPONENTS_PATH}" ./components + +mkdir -p ./src/ +cp "${BSIM_OUT_PATH}"/lib/*.32.a ./src/ + +# XXX: Workaround for bad linking by newt. Sometimes newt will link +# nrf weak functions from nrf_hal_originals.o instead of their BabbleSim +# replacements inside libNRF52_hw_models.32.a. But as long as the other +# weak functions, that do not have their replacements, are not used, +# we can just remove the file from the .a library here. +ar d ./src/libNRF52_hw_models.32.a nrf_hal_originals.o diff --git a/babblesim/sdk/scripts/link_nrfx.sh b/babblesim/sdk/scripts/link_nrfx.sh new file mode 100755 index 0000000000..6bc894e29c --- /dev/null +++ b/babblesim/sdk/scripts/link_nrfx.sh @@ -0,0 +1,21 @@ +#!/bin/bash +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +ln -sfn ${NRFX_BASE} ./nrfx diff --git a/babblesim/targets/blecent/pkg.yml b/babblesim/targets/blecent/pkg.yml new file mode 100644 index 0000000000..451821938c --- /dev/null +++ b/babblesim/targets/blecent/pkg.yml @@ -0,0 +1,23 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +pkg.name: babblesim/targets/blecent +pkg.type: target +pkg.descrption: Sample target for running blecent on BabbleSim +pkg.author: "Apache Mynewt " +pkg.homepage: "https://mynewt.apache.org/" diff --git a/babblesim/targets/blecent/syscfg.yml b/babblesim/targets/blecent/syscfg.yml new file mode 100644 index 0000000000..eb7d46edb5 --- /dev/null +++ b/babblesim/targets/blecent/syscfg.yml @@ -0,0 +1,20 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +syscfg.vals: + BLE_LL_PUBLIC_DEV_ADDR: 0xbabb1e000002 diff --git a/babblesim/targets/blecent/target.yml b/babblesim/targets/blecent/target.yml new file mode 100644 index 0000000000..b4e69674a2 --- /dev/null +++ b/babblesim/targets/blecent/target.yml @@ -0,0 +1,21 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +target.app: "@apache-mynewt-nimble/apps/blecent" +target.bsp: "@apache-mynewt-nimble/babblesim/hw/bsp/nrf52_bsim" +target.build_profile: debug diff --git a/babblesim/targets/blehci/pkg.yml b/babblesim/targets/blehci/pkg.yml new file mode 100644 index 0000000000..c8cdf78c2d --- /dev/null +++ b/babblesim/targets/blehci/pkg.yml @@ -0,0 +1,23 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +pkg.name: babblesim/targets/blehci +pkg.type: target +pkg.descrption: Sample target for running blehci on BabbleSim +pkg.author: "Apache Mynewt " +pkg.homepage: "https://mynewt.apache.org/" diff --git a/babblesim/targets/blehci/syscfg.yml b/babblesim/targets/blehci/syscfg.yml new file mode 100644 index 0000000000..14a909e913 --- /dev/null +++ b/babblesim/targets/blehci/syscfg.yml @@ -0,0 +1,21 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +syscfg.vals: + BLE_LL_PUBLIC_DEV_ADDR: 0xbabb1e000001 + BLE_HCI_TRANSPORT_HS: uart diff --git a/babblesim/targets/blehci/target.yml b/babblesim/targets/blehci/target.yml new file mode 100644 index 0000000000..23953eb8a1 --- /dev/null +++ b/babblesim/targets/blehci/target.yml @@ -0,0 +1,21 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +target.app: "@apache-mynewt-nimble/apps/blehci" +target.bsp: "@apache-mynewt-nimble/babblesim/hw/bsp/nrf52_bsim" +target.build_profile: debug diff --git a/babblesim/targets/bleprph/pkg.yml b/babblesim/targets/bleprph/pkg.yml new file mode 100644 index 0000000000..e8209bd317 --- /dev/null +++ b/babblesim/targets/bleprph/pkg.yml @@ -0,0 +1,23 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +pkg.name: babblesim/targets/bleprph +pkg.type: target +pkg.descrption: Sample target for running bleprph on BabbleSim +pkg.author: "Apache Mynewt " +pkg.homepage: "https://mynewt.apache.org/" diff --git a/babblesim/targets/bleprph/syscfg.yml b/babblesim/targets/bleprph/syscfg.yml new file mode 100644 index 0000000000..279d94a2c6 --- /dev/null +++ b/babblesim/targets/bleprph/syscfg.yml @@ -0,0 +1,20 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +syscfg.vals: + BLE_LL_PUBLIC_DEV_ADDR: 0xbabb1e000003 diff --git a/babblesim/targets/bleprph/target.yml b/babblesim/targets/bleprph/target.yml new file mode 100644 index 0000000000..e7a0854313 --- /dev/null +++ b/babblesim/targets/bleprph/target.yml @@ -0,0 +1,21 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +target.app: "@apache-mynewt-nimble/apps/bleprph" +target.bsp: "@apache-mynewt-nimble/babblesim/hw/bsp/nrf52_bsim" +target.build_profile: debug diff --git a/babblesim/targets/btshell/pkg.yml b/babblesim/targets/btshell/pkg.yml new file mode 100644 index 0000000000..cc0b4bc2ff --- /dev/null +++ b/babblesim/targets/btshell/pkg.yml @@ -0,0 +1,23 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +pkg.name: babblesim/targets/btshell +pkg.type: target +pkg.descrption: Sample target for running btshell on BabbleSim +pkg.author: "Apache Mynewt " +pkg.homepage: "https://mynewt.apache.org/" diff --git a/babblesim/targets/btshell/syscfg.yml b/babblesim/targets/btshell/syscfg.yml new file mode 100644 index 0000000000..152a6652b7 --- /dev/null +++ b/babblesim/targets/btshell/syscfg.yml @@ -0,0 +1,20 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +syscfg.vals: + BLE_LL_PUBLIC_DEV_ADDR: 0xbabb1e000004 diff --git a/babblesim/targets/btshell/target.yml b/babblesim/targets/btshell/target.yml new file mode 100644 index 0000000000..3545e2d8c0 --- /dev/null +++ b/babblesim/targets/btshell/target.yml @@ -0,0 +1,21 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +target.app: "@apache-mynewt-nimble/apps/btshell" +target.bsp: "@apache-mynewt-nimble/babblesim/hw/bsp/nrf52_bsim" +target.build_profile: debug diff --git a/babblesim/targets/edtthci/pkg.yml b/babblesim/targets/edtthci/pkg.yml new file mode 100644 index 0000000000..a08f47b86c --- /dev/null +++ b/babblesim/targets/edtthci/pkg.yml @@ -0,0 +1,24 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +pkg.name: babblesim/targets/edtthci +pkg.type: target +pkg.description: +pkg.author: +pkg.homepage: diff --git a/babblesim/targets/edtthci/syscfg.yml b/babblesim/targets/edtthci/syscfg.yml new file mode 100644 index 0000000000..6b32ddc653 --- /dev/null +++ b/babblesim/targets/edtthci/syscfg.yml @@ -0,0 +1,56 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +syscfg.vals: + # EDTT requires 0x123456789ABC address for the first device + # and 0x456789ABCDEF for the second one + BLE_LL_PUBLIC_DEV_ADDR: 0x123456789ABC # d=1 + # BLE_LL_PUBLIC_DEV_ADDR: 0x456789ABCDEF # d=2 + + EDTT_HCI_LOG_FILE: ("hci_logs") + EDTT_HCI_LOGS: 1 + + BLE_LL_HCI_VS_EVENT_ON_ASSERT: 0 + BLE_LL_CFG_FEAT_LE_ENCRYPTION: 1 + BLE_LL_CFG_FEAT_CONN_PARAM_REQ: 1 + BLE_LL_CFG_FEAT_SLAVE_INIT_FEAT_XCHG: 1 + BLE_LL_CFG_FEAT_LE_PING: 1 + BLE_LL_CFG_FEAT_DATA_LEN_EXT: 1 + BLE_LL_CFG_FEAT_LL_PRIVACY: 1 + BLE_LL_CFG_FEAT_LE_CSA2: 1 +# BLE_LL_CFG_FEAT_LE_CODED_PHY: 1 # not modeled in bsim + BLE_LL_CFG_FEAT_LL_EXT_ADV: 1 + BLE_LL_CFG_FEAT_LL_PERIODIC_ADV: 1 + BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER: 1 + BLE_LL_CFG_FEAT_CTRL_TO_HOST_FLOW_CONTROL: 1 + BLE_LL_CFG_FEAT_LL_SCA_UPDATE: 1 + + BLE_PHY_2M: 1 + + BLE_ROLE_CENTRAL: 1 + BLE_ROLE_PERIPHERAL: 1 + BLE_ROLE_BROADCASTER: 1 + BLE_ROLE_OBSERVER: 1 + + BLE_VERSION: 52 + BLE_LL_ROLE_CENTRAL: 1 + BLE_LL_ROLE_PERIPHERAL: 1 + BLE_LL_ROLE_BROADCASTER: 1 + BLE_LL_ROLE_OBSERVER: 1 + BLE_HW_WHITELIST_ENABLE: 1 diff --git a/babblesim/targets/edtthci/target.yml b/babblesim/targets/edtthci/target.yml new file mode 100644 index 0000000000..3990ba4e70 --- /dev/null +++ b/babblesim/targets/edtthci/target.yml @@ -0,0 +1,22 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +target.app: "@apache-mynewt-nimble/babblesim/edtt/hci_test" +target.bsp: "@apache-mynewt-nimble/babblesim/hw/bsp/nrf52_bsim" +target.build_profile: debug diff --git a/docs/README.rst b/docs/README.rst index ef2871c636..a05534a578 100644 --- a/docs/README.rst +++ b/docs/README.rst @@ -1,5 +1,5 @@ NimBLE Bluetooth Stack Documentation -################################# +#################################### This folder holds the documentation for the NimBLE Bluetooth stack from the `Apache Mynewt`_ project. It is built using `Sphinx`_. @@ -19,8 +19,8 @@ Previewing Changes ========================== In order to preview any changes you make you must first install a Sphinx -toolchain as described at https://github.com/apache/mynewt-documentation#id3. - Then: +toolchain as described at https://github.com/apache/mynewt-documentation. +Then: .. code-block:: bash diff --git a/docs/ble_hs/ble_hs_id.rst b/docs/ble_hs/ble_hs_id.rst index dbb47c9411..6e257e10a8 100644 --- a/docs/ble_hs/ble_hs_id.rst +++ b/docs/ble_hs/ble_hs_id.rst @@ -43,3 +43,10 @@ Header .. code-block:: cpp #include "host/ble_hs.h" + +API +~~~ + +.. doxygengroup:: bt_host_id + :content-only: + :members: diff --git a/docs/ble_hs/ble_hs_return_codes.rst b/docs/ble_hs/ble_hs_return_codes.rst index c69cc4f8d4..5cce93d60e 100644 --- a/docs/ble_hs/ble_hs_return_codes.rst +++ b/docs/ble_hs/ble_hs_return_codes.rst @@ -121,317 +121,335 @@ Return codes - Core The precise meaning of each of these error codes depends on the function that returns it. The API reference for a particular function indicates the conditions under which each of these codes are returned. -+---------+------------------------------+---------------------------------------------------------------------------------------------+ -| Value | Name | Condition | -+=========+==============================+=============================================================================================+ -| 0x00 | *N/A* | Success | -+---------+------------------------------+---------------------------------------------------------------------------------------------+ -| 0x01 | BLE\_HS\_EAGAIN | Temporary failure; try again. | -+---------+------------------------------+---------------------------------------------------------------------------------------------+ -| 0x02 | BLE\_HS\_EALREADY | Operation already in progress or completed. | -+---------+------------------------------+---------------------------------------------------------------------------------------------+ -| 0x03 | BLE\_HS\_EINVAL | One or more arguments are invalid. | -+---------+------------------------------+---------------------------------------------------------------------------------------------+ -| 0x04 | BLE\_HS\_EMSGSIZE | The provided buffer is too small. | -+---------+------------------------------+---------------------------------------------------------------------------------------------+ -| 0x05 | BLE\_HS\_ENOENT | No entry matching the specified criteria. | -+---------+------------------------------+---------------------------------------------------------------------------------------------+ -| 0x06 | BLE\_HS\_ENOMEM | Operation failed due to resource exhaustion. | -+---------+------------------------------+---------------------------------------------------------------------------------------------+ -| 0x07 | BLE\_HS\_ENOTCONN | No open connection with the specified handle. | -+---------+------------------------------+---------------------------------------------------------------------------------------------+ -| 0x08 | BLE\_HS\_ENOTSUP | Operation disabled at compile time. | -+---------+------------------------------+---------------------------------------------------------------------------------------------+ -| 0x09 | BLE\_HS\_EAPP | Application callback behaved unexpectedly. | -+---------+------------------------------+---------------------------------------------------------------------------------------------+ -| 0x0a | BLE\_HS\_EBADDATA | Command from peer is invalid. | -+---------+------------------------------+---------------------------------------------------------------------------------------------+ -| 0x0b | BLE\_HS\_EOS | Mynewt OS error. | -+---------+------------------------------+---------------------------------------------------------------------------------------------+ -| 0x0c | BLE\_HS\_ECONTROLLER | Event from controller is invalid. | -+---------+------------------------------+---------------------------------------------------------------------------------------------+ -| 0x0d | BLE\_HS\_ETIMEOUT | Operation timed out. | -+---------+------------------------------+---------------------------------------------------------------------------------------------+ -| 0x0e | BLE\_HS\_EDONE | Operation completed successfully. | -+---------+------------------------------+---------------------------------------------------------------------------------------------+ -| 0x0f | BLE\_HS\_EBUSY | Operation cannot be performed until procedure completes. | -+---------+------------------------------+---------------------------------------------------------------------------------------------+ -| 0x10 | BLE\_HS\_EREJECT | Peer rejected a connection parameter update request. | -+---------+------------------------------+---------------------------------------------------------------------------------------------+ -| 0x11 | BLE\_HS\_EUNKNOWN | Unexpected failure; catch all. | -+---------+------------------------------+---------------------------------------------------------------------------------------------+ -| 0x12 | BLE\_HS\_EROLE | Operation requires different role (e.g., central vs. peripheral). | -+---------+------------------------------+---------------------------------------------------------------------------------------------+ -| 0x13 | BLE\_HS\_ETIMEOUT\_HCI | HCI request timed out; controller unresponsive. | -+---------+------------------------------+---------------------------------------------------------------------------------------------+ -| 0x14 | BLE\_HS\_ENOMEM\_EVT | Controller failed to send event due to memory exhaustion (combined host-controller only). | -+---------+------------------------------+---------------------------------------------------------------------------------------------+ -| 0x15 | BLE\_HS\_ENOADDR | Operation requires an identity address but none configured. | -+---------+------------------------------+---------------------------------------------------------------------------------------------+ -| 0x16 | BLE\_HS\_ENOTSYNCED | Attempt to use the host before it is synced with controller. | -+---------+------------------------------+---------------------------------------------------------------------------------------------+ -| 0x17 | BLE\_HS\_EAUTHEN | Insufficient authentication. | -+---------+------------------------------+---------------------------------------------------------------------------------------------+ -| 0x18 | BLE\_HS\_EAUTHOR | Insufficient authorization. | -+---------+------------------------------+---------------------------------------------------------------------------------------------+ -| 0x19 | BLE\_HS\_EENCRYPT | Insufficient encryption level. | -+---------+------------------------------+---------------------------------------------------------------------------------------------+ -| 0x1a | BLE\_HS\_EENCRYPT\_KEY\_SZ | Insufficient key size. | -+---------+------------------------------+---------------------------------------------------------------------------------------------+ -| 0x1b | BLE\_HS\_ESTORE\_CAP | Storage at capacity. | -+---------+------------------------------+---------------------------------------------------------------------------------------------+ -| 0x1c | BLE\_HS\_ESTORE\_FAIL | Storage IO error. | -+---------+------------------------------+---------------------------------------------------------------------------------------------+ +.. table:: Return codes - Core + :widths: 10 30 60 + + +---------+------------------------------+---------------------------------------------------------------------------------------------+ + | Value | Name | Condition | + +=========+==============================+=============================================================================================+ + | 0x00 | *N/A* | Success | + +---------+------------------------------+---------------------------------------------------------------------------------------------+ + | 0x01 | BLE\_HS\_EAGAIN | Temporary failure; try again. | + +---------+------------------------------+---------------------------------------------------------------------------------------------+ + | 0x02 | BLE\_HS\_EALREADY | Operation already in progress or completed. | + +---------+------------------------------+---------------------------------------------------------------------------------------------+ + | 0x03 | BLE\_HS\_EINVAL | One or more arguments are invalid. | + +---------+------------------------------+---------------------------------------------------------------------------------------------+ + | 0x04 | BLE\_HS\_EMSGSIZE | The provided buffer is too small. | + +---------+------------------------------+---------------------------------------------------------------------------------------------+ + | 0x05 | BLE\_HS\_ENOENT | No entry matching the specified criteria. | + +---------+------------------------------+---------------------------------------------------------------------------------------------+ + | 0x06 | BLE\_HS\_ENOMEM | Operation failed due to resource exhaustion. | + +---------+------------------------------+---------------------------------------------------------------------------------------------+ + | 0x07 | BLE\_HS\_ENOTCONN | No open connection with the specified handle. | + +---------+------------------------------+---------------------------------------------------------------------------------------------+ + | 0x08 | BLE\_HS\_ENOTSUP | Operation disabled at compile time. | + +---------+------------------------------+---------------------------------------------------------------------------------------------+ + | 0x09 | BLE\_HS\_EAPP | Application callback behaved unexpectedly. | + +---------+------------------------------+---------------------------------------------------------------------------------------------+ + | 0x0a | BLE\_HS\_EBADDATA | Command from peer is invalid. | + +---------+------------------------------+---------------------------------------------------------------------------------------------+ + | 0x0b | BLE\_HS\_EOS | Mynewt OS error. | + +---------+------------------------------+---------------------------------------------------------------------------------------------+ + | 0x0c | BLE\_HS\_ECONTROLLER | Event from controller is invalid. | + +---------+------------------------------+---------------------------------------------------------------------------------------------+ + | 0x0d | BLE\_HS\_ETIMEOUT | Operation timed out. | + +---------+------------------------------+---------------------------------------------------------------------------------------------+ + | 0x0e | BLE\_HS\_EDONE | Operation completed successfully. | + +---------+------------------------------+---------------------------------------------------------------------------------------------+ + | 0x0f | BLE\_HS\_EBUSY | Operation cannot be performed until procedure completes. | + +---------+------------------------------+---------------------------------------------------------------------------------------------+ + | 0x10 | BLE\_HS\_EREJECT | Peer rejected a connection parameter update request. | + +---------+------------------------------+---------------------------------------------------------------------------------------------+ + | 0x11 | BLE\_HS\_EUNKNOWN | Unexpected failure; catch all. | + +---------+------------------------------+---------------------------------------------------------------------------------------------+ + | 0x12 | BLE\_HS\_EROLE | Operation requires different role (e.g., central vs. peripheral). | + +---------+------------------------------+---------------------------------------------------------------------------------------------+ + | 0x13 | BLE\_HS\_ETIMEOUT\_HCI | HCI request timed out; controller unresponsive. | + +---------+------------------------------+---------------------------------------------------------------------------------------------+ + | 0x14 | BLE\_HS\_ENOMEM\_EVT | Controller failed to send event due to memory exhaustion (combined host-controller only). | + +---------+------------------------------+---------------------------------------------------------------------------------------------+ + | 0x15 | BLE\_HS\_ENOADDR | Operation requires an identity address but none configured. | + +---------+------------------------------+---------------------------------------------------------------------------------------------+ + | 0x16 | BLE\_HS\_ENOTSYNCED | Attempt to use the host before it is synced with controller. | + +---------+------------------------------+---------------------------------------------------------------------------------------------+ + | 0x17 | BLE\_HS\_EAUTHEN | Insufficient authentication. | + +---------+------------------------------+---------------------------------------------------------------------------------------------+ + | 0x18 | BLE\_HS\_EAUTHOR | Insufficient authorization. | + +---------+------------------------------+---------------------------------------------------------------------------------------------+ + | 0x19 | BLE\_HS\_EENCRYPT | Insufficient encryption level. | + +---------+------------------------------+---------------------------------------------------------------------------------------------+ + | 0x1a | BLE\_HS\_EENCRYPT\_KEY\_SZ | Insufficient key size. | + +---------+------------------------------+---------------------------------------------------------------------------------------------+ + | 0x1b | BLE\_HS\_ESTORE\_CAP | Storage at capacity. | + +---------+------------------------------+---------------------------------------------------------------------------------------------+ + | 0x1c | BLE\_HS\_ESTORE\_FAIL | Storage IO error. | + +---------+------------------------------+---------------------------------------------------------------------------------------------+ Return codes - ATT ^^^^^^^^^^^^^^^^^^ -+----------------+----------------+--------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ -| NimBLE Value | Formal Value | Name | Condition | -+================+================+============================================+===========================================================================================================================================+ -| 0x0101 | 0x01 | BLE\_ATT\_ERR\_INVALID\_HANDLE | The attribute handle given was not valid on this server. | -+----------------+----------------+--------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ -| 0x0102 | 0x02 | BLE\_ATT\_ERR\_READ\_NOT\_PERMITTED | The attribute cannot be read. | -+----------------+----------------+--------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ -| 0x0103 | 0x03 | BLE\_ATT\_ERR\_WRITE\_NOT\_PERMITTED | The attribute cannot be written. | -+----------------+----------------+--------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ -| 0x0104 | 0x04 | BLE\_ATT\_ERR\_INVALID\_PDU | The attribute PDU was invalid. | -+----------------+----------------+--------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ -| 0x0105 | 0x05 | BLE\_ATT\_ERR\_INSUFFICIENT\_AUTHEN | The attribute requires authentication before it can be read or written. | -+----------------+----------------+--------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ -| 0x0106 | 0x06 | BLE\_ATT\_ERR\_REQ\_NOT\_SUPPORTED | Attribute server does not support the request received from the client. | -+----------------+----------------+--------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ -| 0x0107 | 0x07 | BLE\_ATT\_ERR\_INVALID\_OFFSET | Offset specified was past the end of the attribute. | -+----------------+----------------+--------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ -| 0x0108 | 0x08 | BLE\_ATT\_ERR\_INSUFFICIENT\_AUTHOR | The attribute requires authorization before it can be read or written. | -+----------------+----------------+--------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ -| 0x0109 | 0x09 | BLE\_ATT\_ERR\_PREPARE\_QUEUE\_FULL | Too many prepare writes have been queued. | -+----------------+----------------+--------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ -| 0x010a | 0x0a | BLE\_ATT\_ERR\_ATTR\_NOT\_FOUND | No attribute found within the given attribute handle range. | -+----------------+----------------+--------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ -| 0x010b | 0x0b | BLE\_ATT\_ERR\_ATTR\_NOT\_LONG | The attribute cannot be read or written using the Read Blob Request. | -+----------------+----------------+--------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ -| 0x010c | 0x0c | BLE\_ATT\_ERR\_INSUFFICIENT\_KEY\_SZ | The Encryption Key Size used for encrypting this link is insufficient. | -+----------------+----------------+--------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ -| 0x010d | 0x0d | BLE\_ATT\_ERR\_INVALID\_ATTR\_VALUE\_LEN | The attribute value length is invalid for the operation. | -+----------------+----------------+--------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ -| 0x010e | 0x0e | BLE\_ATT\_ERR\_UNLIKELY | The attribute request that was requested has encountered an error that was unlikely, and therefore could not be completed as requested. | -+----------------+----------------+--------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ -| 0x010f | 0x0f | BLE\_ATT\_ERR\_INSUFFICIENT\_ENC | The attribute requires encryption before it can be read or written. | -+----------------+----------------+--------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ -| 0x0110 | 0x10 | BLE\_ATT\_ERR\_UNSUPPORTED\_GROUP | The attribute type is not a supported grouping attribute as defined by a higher layer specification. | -+----------------+----------------+--------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ -| 0x0111 | 0x11 | BLE\_ATT\_ERR\_INSUFFICIENT\_RES | Insufficient Resources to complete the request. | -+----------------+----------------+--------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ +.. table:: Return codes - ATT + :widths: 11 10 45 34 + + +----------------+----------------+--------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | NimBLE Value | Formal Value | Name | Condition | + +================+================+============================================+===========================================================================================================================================+ + | 0x0101 | 0x01 | BLE\_ATT\_ERR\_INVALID\_HANDLE | The attribute handle given was not valid on this server. | + +----------------+----------------+--------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | 0x0102 | 0x02 | BLE\_ATT\_ERR\_READ\_NOT\_PERMITTED | The attribute cannot be read. | + +----------------+----------------+--------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | 0x0103 | 0x03 | BLE\_ATT\_ERR\_WRITE\_NOT\_PERMITTED | The attribute cannot be written. | + +----------------+----------------+--------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | 0x0104 | 0x04 | BLE\_ATT\_ERR\_INVALID\_PDU | The attribute PDU was invalid. | + +----------------+----------------+--------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | 0x0105 | 0x05 | BLE\_ATT\_ERR\_INSUFFICIENT\_AUTHEN | The attribute requires authentication before it can be read or written. | + +----------------+----------------+--------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | 0x0106 | 0x06 | BLE\_ATT\_ERR\_REQ\_NOT\_SUPPORTED | Attribute server does not support the request received from the client. | + +----------------+----------------+--------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | 0x0107 | 0x07 | BLE\_ATT\_ERR\_INVALID\_OFFSET | Offset specified was past the end of the attribute. | + +----------------+----------------+--------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | 0x0108 | 0x08 | BLE\_ATT\_ERR\_INSUFFICIENT\_AUTHOR | The attribute requires authorization before it can be read or written. | + +----------------+----------------+--------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | 0x0109 | 0x09 | BLE\_ATT\_ERR\_PREPARE\_QUEUE\_FULL | Too many prepare writes have been queued. | + +----------------+----------------+--------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | 0x010a | 0x0a | BLE\_ATT\_ERR\_ATTR\_NOT\_FOUND | No attribute found within the given attribute handle range. | + +----------------+----------------+--------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | 0x010b | 0x0b | BLE\_ATT\_ERR\_ATTR\_NOT\_LONG | The attribute cannot be read or written using the Read Blob Request. | + +----------------+----------------+--------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | 0x010c | 0x0c | BLE\_ATT\_ERR\_INSUFFICIENT\_KEY\_SZ | The Encryption Key Size used for encrypting this link is insufficient. | + +----------------+----------------+--------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | 0x010d | 0x0d | BLE\_ATT\_ERR\_INVALID\_ATTR\_VALUE\_LEN | The attribute value length is invalid for the operation. | + +----------------+----------------+--------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | 0x010e | 0x0e | BLE\_ATT\_ERR\_UNLIKELY | The attribute request that was requested has encountered an error that was unlikely, and therefore could not be completed as requested. | + +----------------+----------------+--------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | 0x010f | 0x0f | BLE\_ATT\_ERR\_INSUFFICIENT\_ENC | The attribute requires encryption before it can be read or written. | + +----------------+----------------+--------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | 0x0110 | 0x10 | BLE\_ATT\_ERR\_UNSUPPORTED\_GROUP | The attribute type is not a supported grouping attribute as defined by a higher layer specification. | + +----------------+----------------+--------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | 0x0111 | 0x11 | BLE\_ATT\_ERR\_INSUFFICIENT\_RES | Insufficient Resources to complete the request. | + +----------------+----------------+--------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ Return codes - HCI ^^^^^^^^^^^^^^^^^^ -+----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ -| NimBLE Value | Formal Value | Name | Condition | -+================+================+====================================+================================================================================+ -| 0x0201 | 0x01 | BLE\_ERR\_UNKNOWN\_HCI\_CMD | Unknown HCI Command | -+----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ -| 0x0202 | 0x02 | BLE\_ERR\_UNK\_CONN\_ID | Unknown Connection Identifier | -+----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ -| 0x0203 | 0x03 | BLE\_ERR\_HW\_FAIL | Hardware Failure | -+----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ -| 0x0204 | 0x04 | BLE\_ERR\_PAGE\_TMO | Page Timeout | -+----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ -| 0x0205 | 0x05 | BLE\_ERR\_AUTH\_FAIL | Authentication Failure | -+----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ -| 0x0206 | 0x06 | BLE\_ERR\_PINKEY\_MISSING | PIN or Key Missing | -+----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ -| 0x0207 | 0x07 | BLE\_ERR\_MEM\_CAPACITY | Memory Capacity Exceeded | -+----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ -| 0x0208 | 0x08 | BLE\_ERR\_CONN\_SPVN\_TMO | Connection Timeout | -+----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ -| 0x0209 | 0x09 | BLE\_ERR\_CONN\_LIMIT | Connection Limit Exceeded | -+----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ -| 0x020a | 0x0a | BLE\_ERR\_SYNCH\_CONN\_LIMIT | Synchronous Connection Limit To A Device Exceeded | -+----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ -| 0x020b | 0x0b | BLE\_ERR\_ACL\_CONN\_EXISTS | ACL Connection Already Exists | -+----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ -| 0x020c | 0x0c | BLE\_ERR\_CMD\_DISALLOWED | Command Disallowed | -+----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ -| 0x020d | 0x0d | BLE\_ERR\_CONN\_REJ\_RESOURCES | Connection Rejected due to Limited Resources | -+----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ -| 0x020e | 0x0e | BLE\_ERR\_CONN\_REJ\_SECURITY | Connection Rejected Due To Security Reasons | -+----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ -| 0x020f | 0x0f | BLE\_ERR\_CONN\_REJ\_BD\_ADDR | Connection Rejected due to Unacceptable BD\_ADDR | -+----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ -| 0x0210 | 0x10 | BLE\_ERR\_CONN\_ACCEPT\_TMO | Connection Accept Timeout Exceeded | -+----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ -| 0x0211 | 0x11 | BLE\_ERR\_UNSUPPORTED | Unsupported Feature or Parameter Value | -+----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ -| 0x0212 | 0x12 | BLE\_ERR\_INV\_HCI\_CMD\_PARMS | Invalid HCI Command Parameters | -+----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ -| 0x0213 | 0x13 | BLE\_ERR\_REM\_USER\_CONN\_TERM | Remote User Terminated Connection | -+----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ -| 0x0214 | 0x14 | BLE\_ERR\_RD\_CONN\_TERM\_RESRCS | Remote Device Terminated Connection due to Low Resources | -+----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ -| 0x0215 | 0x15 | BLE\_ERR\_RD\_CONN\_TERM\_PWROFF | Remote Device Terminated Connection due to Power Off | -+----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ -| 0x0216 | 0x16 | BLE\_ERR\_CONN\_TERM\_LOCAL | Connection Terminated By Local Host | -+----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ -| 0x0217 | 0x17 | BLE\_ERR\_REPEATED\_ATTEMPTS | Repeated Attempts | -+----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ -| 0x0218 | 0x18 | BLE\_ERR\_NO\_PAIRING | Pairing Not Allowed | -+----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ -| 0x0219 | 0x19 | BLE\_ERR\_UNK\_LMP | Unknown LMP PDU | -+----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ -| 0x021a | 0x1a | BLE\_ERR\_UNSUPP\_REM\_FEATURE | Unsupported Remote Feature / Unsupported LMP Feature | -+----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ -| 0x021b | 0x1b | BLE\_ERR\_SCO\_OFFSET | SCO Offset Rejected | -+----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ -| 0x021c | 0x1c | BLE\_ERR\_SCO\_ITVL | SCO Interval Rejected | -+----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ -| 0x021d | 0x1d | BLE\_ERR\_SCO\_AIR\_MODE | SCO Air Mode Rejected | -+----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ -| 0x021e | 0x1e | BLE\_ERR\_INV\_LMP\_LL\_PARM | Invalid LMP Parameters / Invalid LL Parameters | -+----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ -| 0x021f | 0x1f | BLE\_ERR\_UNSPECIFIED | Unspecified Error | -+----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ -| 0x0220 | 0x20 | BLE\_ERR\_UNSUPP\_LMP\_LL\_PARM | Unsupported LMP Parameter Value / Unsupported LL Parameter Value | -+----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ -| 0x0221 | 0x21 | BLE\_ERR\_NO\_ROLE\_CHANGE | Role Change Not Allowed | -+----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ -| 0x0222 | 0x22 | BLE\_ERR\_LMP\_LL\_RSP\_TMO | LMP Response Timeout / LL Response Timeout | -+----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ -| 0x0223 | 0x23 | BLE\_ERR\_LMP\_COLLISION | LMP Error Transaction Collision | -+----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ -| 0x0224 | 0x24 | BLE\_ERR\_LMP\_PDU | LMP PDU Not Allowed | -+----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ -| 0x0225 | 0x25 | BLE\_ERR\_ENCRYPTION\_MODE | Encryption Mode Not Acceptable | -+----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ -| 0x0226 | 0x26 | BLE\_ERR\_LINK\_KEY\_CHANGE | Link Key cannot be Changed | -+----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ -| 0x0227 | 0x27 | BLE\_ERR\_UNSUPP\_QOS | Requested QoS Not Supported | -+----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ -| 0x0228 | 0x28 | BLE\_ERR\_INSTANT\_PASSED | Instant Passed | -+----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ -| 0x0229 | 0x29 | BLE\_ERR\_UNIT\_KEY\_PAIRING | Pairing With Unit Key Not Supported | -+----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ -| 0x022a | 0x2a | BLE\_ERR\_DIFF\_TRANS\_COLL | Different Transaction Collision | -+----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ -| 0x022c | 0x2c | BLE\_ERR\_QOS\_PARM | QoS Unacceptable Parameter | -+----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ -| 0x022d | 0x2d | BLE\_ERR\_QOS\_REJECTED | QoS Rejected | -+----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ -| 0x022e | 0x2e | BLE\_ERR\_CHAN\_CLASS | Channel Classification Not Supported | -+----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ -| 0x022f | 0x2f | BLE\_ERR\_INSUFFICIENT\_SEC | Insufficient Security | -+----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ -| 0x0230 | 0x30 | BLE\_ERR\_PARM\_OUT\_OF\_RANGE | Parameter Out Of Mandatory Range | -+----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ -| 0x0232 | 0x32 | BLE\_ERR\_PENDING\_ROLE\_SW | Role Switch Pending | -+----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ -| 0x0234 | 0x34 | BLE\_ERR\_RESERVED\_SLOT | Reserved Slot Violation | -+----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ -| 0x0235 | 0x35 | BLE\_ERR\_ROLE\_SW\_FAIL | Role Switch Failed | -+----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ -| 0x0236 | 0x36 | BLE\_ERR\_INQ\_RSP\_TOO\_BIG | Extended Inquiry Response Too Large | -+----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ -| 0x0237 | 0x37 | BLE\_ERR\_SEC\_SIMPLE\_PAIR | Secure Simple Pairing Not Supported By Host | -+----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ -| 0x0238 | 0x38 | BLE\_ERR\_HOST\_BUSY\_PAIR | Host Busy - Pairing | -+----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ -| 0x0239 | 0x39 | BLE\_ERR\_CONN\_REJ\_CHANNEL | Connection Rejected due to No Suitable Channel Found | -+----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ -| 0x023a | 0x3a | BLE\_ERR\_CTLR\_BUSY | Controller Busy | -+----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ -| 0x023b | 0x3b | BLE\_ERR\_CONN\_PARMS | Unacceptable Connection Parameters | -+----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ -| 0x023c | 0x3c | BLE\_ERR\_DIR\_ADV\_TMO | Directed Advertising Timeout | -+----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ -| 0x023d | 0x3d | BLE\_ERR\_CONN\_TERM\_MIC | Connection Terminated due to MIC Failure | -+----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ -| 0x023e | 0x3e | BLE\_ERR\_CONN\_ESTABLISHMENT | Connection Failed to be Established | -+----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ -| 0x023f | 0x3f | BLE\_ERR\_MAC\_CONN\_FAIL | MAC Connection Failed | -+----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ -| 0x0240 | 0x40 | BLE\_ERR\_COARSE\_CLK\_ADJ | Coarse Clock Adjustment Rejected but Will Try to Adjust Using Clock Dragging | -+----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ +.. table:: Return codes - HCI + :widths: 11 10 39 40 + + +----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ + | NimBLE Value | Formal Value | Name | Condition | + +================+================+====================================+================================================================================+ + | 0x0201 | 0x01 | BLE\_ERR\_UNKNOWN\_HCI\_CMD | Unknown HCI Command | + +----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ + | 0x0202 | 0x02 | BLE\_ERR\_UNK\_CONN\_ID | Unknown Connection Identifier | + +----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ + | 0x0203 | 0x03 | BLE\_ERR\_HW\_FAIL | Hardware Failure | + +----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ + | 0x0204 | 0x04 | BLE\_ERR\_PAGE\_TMO | Page Timeout | + +----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ + | 0x0205 | 0x05 | BLE\_ERR\_AUTH\_FAIL | Authentication Failure | + +----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ + | 0x0206 | 0x06 | BLE\_ERR\_PINKEY\_MISSING | PIN or Key Missing | + +----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ + | 0x0207 | 0x07 | BLE\_ERR\_MEM\_CAPACITY | Memory Capacity Exceeded | + +----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ + | 0x0208 | 0x08 | BLE\_ERR\_CONN\_SPVN\_TMO | Connection Timeout | + +----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ + | 0x0209 | 0x09 | BLE\_ERR\_CONN\_LIMIT | Connection Limit Exceeded | + +----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ + | 0x020a | 0x0a | BLE\_ERR\_SYNCH\_CONN\_LIMIT | Synchronous Connection Limit To A Device Exceeded | + +----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ + | 0x020b | 0x0b | BLE\_ERR\_ACL\_CONN\_EXISTS | ACL Connection Already Exists | + +----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ + | 0x020c | 0x0c | BLE\_ERR\_CMD\_DISALLOWED | Command Disallowed | + +----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ + | 0x020d | 0x0d | BLE\_ERR\_CONN\_REJ\_RESOURCES | Connection Rejected due to Limited Resources | + +----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ + | 0x020e | 0x0e | BLE\_ERR\_CONN\_REJ\_SECURITY | Connection Rejected Due To Security Reasons | + +----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ + | 0x020f | 0x0f | BLE\_ERR\_CONN\_REJ\_BD\_ADDR | Connection Rejected due to Unacceptable BD\_ADDR | + +----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ + | 0x0210 | 0x10 | BLE\_ERR\_CONN\_ACCEPT\_TMO | Connection Accept Timeout Exceeded | + +----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ + | 0x0211 | 0x11 | BLE\_ERR\_UNSUPPORTED | Unsupported Feature or Parameter Value | + +----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ + | 0x0212 | 0x12 | BLE\_ERR\_INV\_HCI\_CMD\_PARMS | Invalid HCI Command Parameters | + +----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ + | 0x0213 | 0x13 | BLE\_ERR\_REM\_USER\_CONN\_TERM | Remote User Terminated Connection | + +----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ + | 0x0214 | 0x14 | BLE\_ERR\_RD\_CONN\_TERM\_RESRCS | Remote Device Terminated Connection due to Low Resources | + +----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ + | 0x0215 | 0x15 | BLE\_ERR\_RD\_CONN\_TERM\_PWROFF | Remote Device Terminated Connection due to Power Off | + +----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ + | 0x0216 | 0x16 | BLE\_ERR\_CONN\_TERM\_LOCAL | Connection Terminated By Local Host | + +----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ + | 0x0217 | 0x17 | BLE\_ERR\_REPEATED\_ATTEMPTS | Repeated Attempts | + +----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ + | 0x0218 | 0x18 | BLE\_ERR\_NO\_PAIRING | Pairing Not Allowed | + +----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ + | 0x0219 | 0x19 | BLE\_ERR\_UNK\_LMP | Unknown LMP PDU | + +----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ + | 0x021a | 0x1a | BLE\_ERR\_UNSUPP\_REM\_FEATURE | Unsupported Remote Feature / Unsupported LMP Feature | + +----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ + | 0x021b | 0x1b | BLE\_ERR\_SCO\_OFFSET | SCO Offset Rejected | + +----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ + | 0x021c | 0x1c | BLE\_ERR\_SCO\_ITVL | SCO Interval Rejected | + +----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ + | 0x021d | 0x1d | BLE\_ERR\_SCO\_AIR\_MODE | SCO Air Mode Rejected | + +----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ + | 0x021e | 0x1e | BLE\_ERR\_INV\_LMP\_LL\_PARM | Invalid LMP Parameters / Invalid LL Parameters | + +----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ + | 0x021f | 0x1f | BLE\_ERR\_UNSPECIFIED | Unspecified Error | + +----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ + | 0x0220 | 0x20 | BLE\_ERR\_UNSUPP\_LMP\_LL\_PARM | Unsupported LMP Parameter Value / Unsupported LL Parameter Value | + +----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ + | 0x0221 | 0x21 | BLE\_ERR\_NO\_ROLE\_CHANGE | Role Change Not Allowed | + +----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ + | 0x0222 | 0x22 | BLE\_ERR\_LMP\_LL\_RSP\_TMO | LMP Response Timeout / LL Response Timeout | + +----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ + | 0x0223 | 0x23 | BLE\_ERR\_LMP\_COLLISION | LMP Error Transaction Collision | + +----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ + | 0x0224 | 0x24 | BLE\_ERR\_LMP\_PDU | LMP PDU Not Allowed | + +----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ + | 0x0225 | 0x25 | BLE\_ERR\_ENCRYPTION\_MODE | Encryption Mode Not Acceptable | + +----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ + | 0x0226 | 0x26 | BLE\_ERR\_LINK\_KEY\_CHANGE | Link Key cannot be Changed | + +----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ + | 0x0227 | 0x27 | BLE\_ERR\_UNSUPP\_QOS | Requested QoS Not Supported | + +----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ + | 0x0228 | 0x28 | BLE\_ERR\_INSTANT\_PASSED | Instant Passed | + +----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ + | 0x0229 | 0x29 | BLE\_ERR\_UNIT\_KEY\_PAIRING | Pairing With Unit Key Not Supported | + +----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ + | 0x022a | 0x2a | BLE\_ERR\_DIFF\_TRANS\_COLL | Different Transaction Collision | + +----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ + | 0x022c | 0x2c | BLE\_ERR\_QOS\_PARM | QoS Unacceptable Parameter | + +----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ + | 0x022d | 0x2d | BLE\_ERR\_QOS\_REJECTED | QoS Rejected | + +----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ + | 0x022e | 0x2e | BLE\_ERR\_CHAN\_CLASS | Channel Classification Not Supported | + +----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ + | 0x022f | 0x2f | BLE\_ERR\_INSUFFICIENT\_SEC | Insufficient Security | + +----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ + | 0x0230 | 0x30 | BLE\_ERR\_PARM\_OUT\_OF\_RANGE | Parameter Out Of Mandatory Range | + +----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ + | 0x0232 | 0x32 | BLE\_ERR\_PENDING\_ROLE\_SW | Role Switch Pending | + +----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ + | 0x0234 | 0x34 | BLE\_ERR\_RESERVED\_SLOT | Reserved Slot Violation | + +----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ + | 0x0235 | 0x35 | BLE\_ERR\_ROLE\_SW\_FAIL | Role Switch Failed | + +----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ + | 0x0236 | 0x36 | BLE\_ERR\_INQ\_RSP\_TOO\_BIG | Extended Inquiry Response Too Large | + +----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ + | 0x0237 | 0x37 | BLE\_ERR\_SEC\_SIMPLE\_PAIR | Secure Simple Pairing Not Supported By Host | + +----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ + | 0x0238 | 0x38 | BLE\_ERR\_HOST\_BUSY\_PAIR | Host Busy - Pairing | + +----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ + | 0x0239 | 0x39 | BLE\_ERR\_CONN\_REJ\_CHANNEL | Connection Rejected due to No Suitable Channel Found | + +----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ + | 0x023a | 0x3a | BLE\_ERR\_CTLR\_BUSY | Controller Busy | + +----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ + | 0x023b | 0x3b | BLE\_ERR\_CONN\_PARMS | Unacceptable Connection Parameters | + +----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ + | 0x023c | 0x3c | BLE\_ERR\_DIR\_ADV\_TMO | Directed Advertising Timeout | + +----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ + | 0x023d | 0x3d | BLE\_ERR\_CONN\_TERM\_MIC | Connection Terminated due to MIC Failure | + +----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ + | 0x023e | 0x3e | BLE\_ERR\_CONN\_ESTABLISHMENT | Connection Failed to be Established | + +----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ + | 0x023f | 0x3f | BLE\_ERR\_MAC\_CONN\_FAIL | MAC Connection Failed | + +----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ + | 0x0240 | 0x40 | BLE\_ERR\_COARSE\_CLK\_ADJ | Coarse Clock Adjustment Rejected but Will Try to Adjust Using Clock Dragging | + +----------------+----------------+------------------------------------+--------------------------------------------------------------------------------+ Return codes - L2CAP ^^^^^^^^^^^^^^^^^^^^ -+----------------+----------------+----------------------------------------------+------------------------------------------------------+ -| NimBLE Value | Formal Value | Name | Condition | -+================+================+==============================================+======================================================+ -| 0x0300 | 0x00 | BLE\_L2CAP\_SIG\_ERR\_CMD\_NOT\_UNDERSTOOD | Invalid or unsupported incoming L2CAP sig command. | -+----------------+----------------+----------------------------------------------+------------------------------------------------------+ -| 0x0301 | 0x01 | BLE\_L2CAP\_SIG\_ERR\_MTU\_EXCEEDED | Incoming packet too large. | -+----------------+----------------+----------------------------------------------+------------------------------------------------------+ -| 0x0302 | 0x02 | BLE\_L2CAP\_SIG\_ERR\_INVALID\_CID | No channel with specified ID. | -+----------------+----------------+----------------------------------------------+------------------------------------------------------+ +.. table:: Return codes - L2CAP + :widths: 11 10 50 29 + + +----------------+----------------+----------------------------------------------+------------------------------------------------------+ + | NimBLE Value | Formal Value | Name | Condition | + +================+================+==============================================+======================================================+ + | 0x0300 | 0x00 | BLE\_L2CAP\_SIG\_ERR\_CMD\_NOT\_UNDERSTOOD | Invalid or unsupported incoming L2CAP sig command. | + +----------------+----------------+----------------------------------------------+------------------------------------------------------+ + | 0x0301 | 0x01 | BLE\_L2CAP\_SIG\_ERR\_MTU\_EXCEEDED | Incoming packet too large. | + +----------------+----------------+----------------------------------------------+------------------------------------------------------+ + | 0x0302 | 0x02 | BLE\_L2CAP\_SIG\_ERR\_INVALID\_CID | No channel with specified ID. | + +----------------+----------------+----------------------------------------------+------------------------------------------------------+ Return codes - Security manager (us) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -+----------------+----------------+-----------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ -| NimBLE Value | Formal Value | Name | Condition | -+================+================+===================================+===========================================================================================================================================+ -| 0x0401 | 0x01 | BLE\_SM\_ERR\_PASSKEY | The user input of passkey failed, for example, the user cancelled the operation. | -+----------------+----------------+-----------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ -| 0x0402 | 0x02 | BLE\_SM\_ERR\_OOB | The OOB data is not available. | -+----------------+----------------+-----------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ -| 0x0403 | 0x03 | BLE\_SM\_ERR\_AUTHREQ | The pairing procedure cannot be performed as authentication requirements cannot be met due to IO capabilities of one or both devices. | -+----------------+----------------+-----------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ -| 0x0404 | 0x04 | BLE\_SM\_ERR\_CONFIRM\_MISMATCH | The confirm value does not match the calculated compare value. | -+----------------+----------------+-----------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ -| 0x0405 | 0x05 | BLE\_SM\_ERR\_PAIR\_NOT\_SUPP | Pairing is not supported by the device. | -+----------------+----------------+-----------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ -| 0x0406 | 0x06 | BLE\_SM\_ERR\_ENC\_KEY\_SZ | The resultant encryption key size is insufficient for the security requirements of this device. | -+----------------+----------------+-----------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ -| 0x0407 | 0x07 | BLE\_SM\_ERR\_CMD\_NOT\_SUPP | The SMP command received is not supported on this device. | -+----------------+----------------+-----------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ -| 0x0408 | 0x08 | BLE\_SM\_ERR\_UNSPECIFIED | Pairing failed due to an unspecified reason. | -+----------------+----------------+-----------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ -| 0x0409 | 0x09 | BLE\_SM\_ERR\_REPEATED | Pairing or authentication procedure is disallowed because too little time has elapsed since last pairing request or security request. | -+----------------+----------------+-----------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ -| 0x040a | 0x0a | BLE\_SM\_ERR\_INVAL | The Invalid Parameters error code indicates that the command length is invalid or that a parameter is outside of the specified range. | -+----------------+----------------+-----------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ -| 0x040b | 0x0b | BLE\_SM\_ERR\_DHKEY | Indicates to the remote device that the DHKey Check value received doesn’t match the one calculated by the local device. | -+----------------+----------------+-----------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ -| 0x040c | 0x0c | BLE\_SM\_ERR\_NUMCMP | Indicates that the confirm values in the numeric comparison protocol do not match. | -+----------------+----------------+-----------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ -| 0x040d | 0x0d | BLE\_SM\_ERR\_ALREADY | Indicates that the pairing over the LE transport failed due to a Pairing Request sent over the BR/EDR transport in process. | -+----------------+----------------+-----------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ -| 0x040e | 0x0e | BLE\_SM\_ERR\_CROSS\_TRANS | Indicates that the BR/EDR Link Key generated on the BR/EDR transport cannot be used to derive and distribute keys for the LE transport. | -+----------------+----------------+-----------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ +.. table:: Return codes - Security manager (us) + :widths: 11 10 39 40 + + +----------------+----------------+-----------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | NimBLE Value | Formal Value | Name | Condition | + +================+================+===================================+===========================================================================================================================================+ + | 0x0401 | 0x01 | BLE\_SM\_ERR\_PASSKEY | The user input of passkey failed, for example, the user cancelled the operation. | + +----------------+----------------+-----------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | 0x0402 | 0x02 | BLE\_SM\_ERR\_OOB | The OOB data is not available. | + +----------------+----------------+-----------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | 0x0403 | 0x03 | BLE\_SM\_ERR\_AUTHREQ | The pairing procedure cannot be performed as authentication requirements cannot be met due to IO capabilities of one or both devices. | + +----------------+----------------+-----------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | 0x0404 | 0x04 | BLE\_SM\_ERR\_CONFIRM\_MISMATCH | The confirm value does not match the calculated compare value. | + +----------------+----------------+-----------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | 0x0405 | 0x05 | BLE\_SM\_ERR\_PAIR\_NOT\_SUPP | Pairing is not supported by the device. | + +----------------+----------------+-----------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | 0x0406 | 0x06 | BLE\_SM\_ERR\_ENC\_KEY\_SZ | The resultant encryption key size is insufficient for the security requirements of this device. | + +----------------+----------------+-----------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | 0x0407 | 0x07 | BLE\_SM\_ERR\_CMD\_NOT\_SUPP | The SMP command received is not supported on this device. | + +----------------+----------------+-----------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | 0x0408 | 0x08 | BLE\_SM\_ERR\_UNSPECIFIED | Pairing failed due to an unspecified reason. | + +----------------+----------------+-----------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | 0x0409 | 0x09 | BLE\_SM\_ERR\_REPEATED | Pairing or authentication procedure is disallowed because too little time has elapsed since last pairing request or security request. | + +----------------+----------------+-----------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | 0x040a | 0x0a | BLE\_SM\_ERR\_INVAL | The Invalid Parameters error code indicates that the command length is invalid or that a parameter is outside of the specified range. | + +----------------+----------------+-----------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | 0x040b | 0x0b | BLE\_SM\_ERR\_DHKEY | Indicates to the remote device that the DHKey Check value received doesn’t match the one calculated by the local device. | + +----------------+----------------+-----------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | 0x040c | 0x0c | BLE\_SM\_ERR\_NUMCMP | Indicates that the confirm values in the numeric comparison protocol do not match. | + +----------------+----------------+-----------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | 0x040d | 0x0d | BLE\_SM\_ERR\_ALREADY | Indicates that the pairing over the LE transport failed due to a Pairing Request sent over the BR/EDR transport in process. | + +----------------+----------------+-----------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | 0x040e | 0x0e | BLE\_SM\_ERR\_CROSS\_TRANS | Indicates that the BR/EDR Link Key generated on the BR/EDR transport cannot be used to derive and distribute keys for the LE transport. | + +----------------+----------------+-----------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ Return codes - Security manager (peer) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -+----------------+----------------+-----------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ -| NimBLE Value | Formal Value | Name | Condition | -+================+================+===================================+===========================================================================================================================================+ -| 0x0501 | 0x01 | BLE\_SM\_ERR\_PASSKEY | The user input of passkey failed, for example, the user cancelled the operation. | -+----------------+----------------+-----------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ -| 0x0502 | 0x02 | BLE\_SM\_ERR\_OOB | The OOB data is not available. | -+----------------+----------------+-----------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ -| 0x0503 | 0x03 | BLE\_SM\_ERR\_AUTHREQ | The pairing procedure cannot be performed as authentication requirements cannot be met due to IO capabilities of one or both devices. | -+----------------+----------------+-----------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ -| 0x0504 | 0x04 | BLE\_SM\_ERR\_CONFIRM\_MISMATCH | The confirm value does not match the calculated compare value. | -+----------------+----------------+-----------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ -| 0x0505 | 0x05 | BLE\_SM\_ERR\_PAIR\_NOT\_SUPP | Pairing is not supported by the device. | -+----------------+----------------+-----------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ -| 0x0506 | 0x06 | BLE\_SM\_ERR\_ENC\_KEY\_SZ | The resultant encryption key size is insufficient for the security requirements of this device. | -+----------------+----------------+-----------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ -| 0x0507 | 0x07 | BLE\_SM\_ERR\_CMD\_NOT\_SUPP | The SMP command received is not supported on this device. | -+----------------+----------------+-----------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ -| 0x0508 | 0x08 | BLE\_SM\_ERR\_UNSPECIFIED | Pairing failed due to an unspecified reason. | -+----------------+----------------+-----------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ -| 0x0509 | 0x09 | BLE\_SM\_ERR\_REPEATED | Pairing or authentication procedure is disallowed because too little time has elapsed since last pairing request or security request. | -+----------------+----------------+-----------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ -| 0x050a | 0x0a | BLE\_SM\_ERR\_INVAL | The Invalid Parameters error code indicates that the command length is invalid or that a parameter is outside of the specified range. | -+----------------+----------------+-----------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ -| 0x050b | 0x0b | BLE\_SM\_ERR\_DHKEY | Indicates to the remote device that the DHKey Check value received doesn’t match the one calculated by the local device. | -+----------------+----------------+-----------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ -| 0x050c | 0x0c | BLE\_SM\_ERR\_NUMCMP | Indicates that the confirm values in the numeric comparison protocol do not match. | -+----------------+----------------+-----------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ -| 0x050d | 0x0d | BLE\_SM\_ERR\_ALREADY | Indicates that the pairing over the LE transport failed due to a Pairing Request sent over the BR/EDR transport in process. | -+----------------+----------------+-----------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ -| 0x050e | 0x0e | BLE\_SM\_ERR\_CROSS\_TRANS | Indicates that the BR/EDR Link Key generated on the BR/EDR transport cannot be used to derive and distribute keys for the LE transport. | -+----------------+----------------+-----------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ +.. table:: Return codes - Security manager (peer) + :widths: 11 10 39 40 + + +----------------+----------------+-----------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | NimBLE Value | Formal Value | Name | Condition | + +================+================+===================================+===========================================================================================================================================+ + | 0x0501 | 0x01 | BLE\_SM\_ERR\_PASSKEY | The user input of passkey failed, for example, the user cancelled the operation. | + +----------------+----------------+-----------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | 0x0502 | 0x02 | BLE\_SM\_ERR\_OOB | The OOB data is not available. | + +----------------+----------------+-----------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | 0x0503 | 0x03 | BLE\_SM\_ERR\_AUTHREQ | The pairing procedure cannot be performed as authentication requirements cannot be met due to IO capabilities of one or both devices. | + +----------------+----------------+-----------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | 0x0504 | 0x04 | BLE\_SM\_ERR\_CONFIRM\_MISMATCH | The confirm value does not match the calculated compare value. | + +----------------+----------------+-----------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | 0x0505 | 0x05 | BLE\_SM\_ERR\_PAIR\_NOT\_SUPP | Pairing is not supported by the device. | + +----------------+----------------+-----------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | 0x0506 | 0x06 | BLE\_SM\_ERR\_ENC\_KEY\_SZ | The resultant encryption key size is insufficient for the security requirements of this device. | + +----------------+----------------+-----------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | 0x0507 | 0x07 | BLE\_SM\_ERR\_CMD\_NOT\_SUPP | The SMP command received is not supported on this device. | + +----------------+----------------+-----------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | 0x0508 | 0x08 | BLE\_SM\_ERR\_UNSPECIFIED | Pairing failed due to an unspecified reason. | + +----------------+----------------+-----------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | 0x0509 | 0x09 | BLE\_SM\_ERR\_REPEATED | Pairing or authentication procedure is disallowed because too little time has elapsed since last pairing request or security request. | + +----------------+----------------+-----------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | 0x050a | 0x0a | BLE\_SM\_ERR\_INVAL | The Invalid Parameters error code indicates that the command length is invalid or that a parameter is outside of the specified range. | + +----------------+----------------+-----------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | 0x050b | 0x0b | BLE\_SM\_ERR\_DHKEY | Indicates to the remote device that the DHKey Check value received doesn’t match the one calculated by the local device. | + +----------------+----------------+-----------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | 0x050c | 0x0c | BLE\_SM\_ERR\_NUMCMP | Indicates that the confirm values in the numeric comparison protocol do not match. | + +----------------+----------------+-----------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | 0x050d | 0x0d | BLE\_SM\_ERR\_ALREADY | Indicates that the pairing over the LE transport failed due to a Pairing Request sent over the BR/EDR transport in process. | + +----------------+----------------+-----------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ + | 0x050e | 0x0e | BLE\_SM\_ERR\_CROSS\_TRANS | Indicates that the BR/EDR Link Key generated on the BR/EDR transport cannot be used to derive and distribute keys for the LE transport. | + +----------------+----------------+-----------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+ diff --git a/docs/ble_setup/ble_addr.rst b/docs/ble_setup/ble_addr.rst index 0a67a5f774..bfd49923b8 100644 --- a/docs/ble_setup/ble_addr.rst +++ b/docs/ble_setup/ble_addr.rst @@ -52,12 +52,12 @@ Method 3: Configure a random address at runtime Random addresses get configured through the NimBLE host. The following two functions are used in random address configuration: -- :doc:`ble_hs_id_gen_rnd <../ble_hs/ble_hs_id/functions/ble_hs_id_gen_rnd>`: +- :c:func:`ble_hs_id_gen_rnd`: Generates a new random address. -- :doc:`ble_hs_id_set_rnd <../ble_hs/ble_hs_id/functions/ble_hs_id_set_rnd>`: +- :c:func:`ble_hs_id_set_rnd`: Sets the device's random address. -For an example of how this is done, see the :doc:`<../../../os/tutorials/ibeacon>`. +For an example of how this is done, see the :doc:`../../../tutorials/ble/ibeacon`. *Note:* A NimBLE device can be configured with multiple addresses; at most one of each address type. diff --git a/docs/ble_setup/ble_sync_cb.rst b/docs/ble_setup/ble_sync_cb.rst index b14a3582a4..a01d51475e 100644 --- a/docs/ble_setup/ble_sync_cb.rst +++ b/docs/ble_setup/ble_sync_cb.rst @@ -65,7 +65,7 @@ reset callbacks. } int - main(void) + mynewt_main(int argc, char **argv) { /* Initialize all packages. */ sysinit(); diff --git a/docs/btshell/btshell_GAP.rst b/docs/btshell/btshell_GAP.rst index ce6475554d..149c4c02c2 100644 --- a/docs/btshell/btshell_GAP.rst +++ b/docs/btshell/btshell_GAP.rst @@ -34,627 +34,646 @@ modes and procedures are defined for use over an LE physical transport: Available commands ~~~~~~~~~~~~~~~~~~ -Parameters default values are marked red. - Configuration ------------- -+---------------------+-----------------+----------------------------+---------------------------------------------------------------------------------------------------------+ -| **Command** | **Parmeters** | \*\* Possible values\*\* | **Description** | -+=====================+=================+============================+=========================================================================================================+ -| **set** | | | Set configuration options | -+---------------------+-----------------+----------------------------+---------------------------------------------------------------------------------------------------------+ -| | addr | XX:XX:XX:XX:XX:XX | Local device address | -+---------------------+-----------------+----------------------------+---------------------------------------------------------------------------------------------------------+ -| | addr\_type | ``public`` | Local device address type | -+---------------------+-----------------+----------------------------+---------------------------------------------------------------------------------------------------------+ -| | | random | Use random address for scan requests | -+---------------------+-----------------+----------------------------+---------------------------------------------------------------------------------------------------------+ -| | mtu | [23-UINT16\_MAX] | GATT Maximum Transmission Unit (MTU) | -+---------------------+-----------------+----------------------------+---------------------------------------------------------------------------------------------------------+ -| | irk | XX:XX:XX... | Local Identity Resolving Key (16 byte | -+---------------------+-----------------+----------------------------+---------------------------------------------------------------------------------------------------------+ -| **set-priv-mode** | | | Set privacy mode for device | -+---------------------+-----------------+----------------------------+---------------------------------------------------------------------------------------------------------+ -| | addr | XX:XX:XX:XX:XX:XX | Remote device address | -+---------------------+-----------------+----------------------------+---------------------------------------------------------------------------------------------------------+ -| | addr\_type | ``public`` | Remote device public address type | -+---------------------+-----------------+----------------------------+---------------------------------------------------------------------------------------------------------+ -| | | random | Remote device random address type | -+---------------------+-----------------+----------------------------+---------------------------------------------------------------------------------------------------------+ -| | mode | [``0``-1] | 0 - use network privacy, 1 - use device privacy | -+---------------------+-----------------+----------------------------+---------------------------------------------------------------------------------------------------------+ -| **white-list** | | | Add devices to white list (this command accepts multiple instances of addr and addr\_type parameters) | -+---------------------+-----------------+----------------------------+---------------------------------------------------------------------------------------------------------+ -| | addr | XX:XX:XX:XX:XX:XX | Remote device address | -+---------------------+-----------------+----------------------------+---------------------------------------------------------------------------------------------------------+ -| | addr\_type | ``public`` | Remote device public address type | -+---------------------+-----------------+----------------------------+---------------------------------------------------------------------------------------------------------+ -| | | random | Remote device random address type | -+---------------------+-----------------+----------------------------+---------------------------------------------------------------------------------------------------------+ +.. table:: Configuration + :widths: 20 15 25 40 + + +---------------------+-----------------+----------------------------+---------------------------------------------------------------------------------------------------------+ + | **Command** | **Parameters** | **Possible values** | **Description** | + +=====================+=================+============================+=========================================================================================================+ + | **set** | | | Set configuration options | + +---------------------+-----------------+----------------------------+---------------------------------------------------------------------------------------------------------+ + | | addr | XX:XX:XX:XX:XX:XX | Local device address | + +---------------------+-----------------+----------------------------+---------------------------------------------------------------------------------------------------------+ + | | addr\_type | ``public`` | Local device address type | + +---------------------+-----------------+----------------------------+---------------------------------------------------------------------------------------------------------+ + | | | random | Use random address for scan requests | + +---------------------+-----------------+----------------------------+---------------------------------------------------------------------------------------------------------+ + | | mtu | [23-UINT16\_MAX] | GATT Maximum Transmission Unit (MTU) | + +---------------------+-----------------+----------------------------+---------------------------------------------------------------------------------------------------------+ + | | irk | XX:XX:XX... | Local Identity Resolving Key (16 byte | + +---------------------+-----------------+----------------------------+---------------------------------------------------------------------------------------------------------+ + | **set-priv-mode** | | | Set privacy mode for device | + +---------------------+-----------------+----------------------------+---------------------------------------------------------------------------------------------------------+ + | | addr | XX:XX:XX:XX:XX:XX | Remote device address | + +---------------------+-----------------+----------------------------+---------------------------------------------------------------------------------------------------------+ + | | addr\_type | ``public`` | Remote device public address type | + +---------------------+-----------------+----------------------------+---------------------------------------------------------------------------------------------------------+ + | | | random | Remote device random address type | + +---------------------+-----------------+----------------------------+---------------------------------------------------------------------------------------------------------+ + | | mode | [``0``-1] | 0 - use network privacy, 1 - use device privacy | + +---------------------+-----------------+----------------------------+---------------------------------------------------------------------------------------------------------+ + | **white-list** | | | Add devices to white list (this command accepts multiple instances of addr and addr\_type parameters) | + +---------------------+-----------------+----------------------------+---------------------------------------------------------------------------------------------------------+ + | | addr | XX:XX:XX:XX:XX:XX | Remote device address | + +---------------------+-----------------+----------------------------+---------------------------------------------------------------------------------------------------------+ + | | addr\_type | ``public`` | Remote device public address type | + +---------------------+-----------------+----------------------------+---------------------------------------------------------------------------------------------------------+ + | | | random | Remote device random address type | + +---------------------+-----------------+----------------------------+---------------------------------------------------------------------------------------------------------+ Device discovery and connection ------------------------------- -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| **Command** | **Parmeters** | \*\* Possible values\*\* | **Description** | -+==========================+================================+============================+============================================================================================================+ -| **scan** | | | Discover remote devices | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | cancel | | cancel ongoing scan procedure | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | extended | ``none`` | Start legacy scan | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | | 1M | Start extended scan on 1M PHY | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | | coded | Start extended scan on Coded PHY | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | | both | Start extended scan on both PHYs | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | duration | [1-``INT32_MAX``], | Duration of scan in milliseconds | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | limited | [``0``-1] | Use limited discovery procedure | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | passive | [``0``-1] | Use passive scan | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | interval | [``0``-UINT16\_MAX] | Scan interval, if 0 use stack's default | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | window | [``0``-UINT16\_MAX] | Scan window, if 0 use stack's default | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | filter | ``no_wl`` | Scan filter policy - Accept all advertising packets | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | | use\_wl | Accept only advertising packets from devices on White List | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | | no\_wl\_inita | Accept all advertising packets (including directed RPA) | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | | use\_wl\_inita | Accept only advertising packets from devices on White List (including directed RPA) | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | nodups | [``0``-1] | Disable duplicates filtering | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | own\_addr\_type | ``public`` | Use public address for scan requests | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | | random | Use random address for scan requests | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | | rpa\_pub | Use RPA address for scan requests (fallback to public if no IRK) | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | | rpa\_rnd | Use RPA address for scan requests (fallback to random if no IRK) | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | extended\_duration | [``0``-UINT16\_MAX] | Duration of extended scan in 10 milliseconds | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | extended\_period | [``0``-UINT16\_MAX] | Periodic scan interval in 1.28 seconds (0 disabled) | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | longrange\_interval | [``0``-UINT16\_MAX] | Scan interval for Coded Scan , if 0 use stack's default | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | longrange\_window | [``0``-UINT16\_MAX] | Scan window for Coded Scan , if 0 use stack's default | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | longrange\_passive | [``0``-1] | Use passive scan for Coded Scan | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| **connect** | | | Initiate connection to remote device | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | cancel | | Cancel ongoing connection procedure | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | extended | ``none`` | Use legacy connection procedure | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | | 1M | Extended connect using 1M PHY scan parameters | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | | coded | Extended connect using Coded PHY scan parameters | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | | both | Extended connect using 1M and Coded PHYs scan parameters | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | | all | Extended connect using 1M and Coded PHYs scan parameters (Provide also connection parameters for 2M PHY) | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | peer\_addr\_type | ``public`` | Remote device public address type | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | | random | Remote device random address type | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | | public\_id | Remote device public address type (Identity) | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | | random\_id | Remote device random address type (Identity) | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | peer\_addr | XX:XX:XX:XX:XX:XX | Remote device address | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | own\_addr\_type | ``public`` | Use public address for scan requests | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | | random | Use random address for scan requests | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | | rpa\_pub | Use RPA address for scan requests (fallback to public if no IRK) | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | | rpa\_rnd | Use RPA address for scan requests (fallback to random if no IRK) | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | duration | [``0``-INT32\_MAX] | Connection attempt duration, if 0 use stack's default | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | scan\_interval | [0-UINT16\_MAX] | Scan interval, default: 0x0010 | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | scan\_window | [0-UINT16\_MAX] | Scan window, default: 0x0010 | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | interval\_min | [0-UINT16\_MAX] | Minimum connection interval, default: 30 | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | interval\_max | [0-UINT16\_MAX] | Maximum connection interval, default: 50 | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | latency | [UINT16] | Connection latency, default: 0 | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | timeout | [UINT16] | Connection timeout, default: 0x0100 | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | min\_conn\_event\_len | [UINT16] | Minimum length of connection event, default: 0x0010 | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | max\_conn\_event\_len | [UINT16] | Maximum length of connection event, default: 0x0300 | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | coded\_scan\_interval | [0-UINT16\_MAX] | Coded PHY Scan interval, default: 0x0010 | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | coded\_scan\_window | [0-UINT16\_MAX] | Coded PHY Scan window, default: 0x0010 | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | coded\_interval\_min | [0-UINT16\_MAX] | Coded PHY Minimum connection interval, default: 30 | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | coded\_interval\_max | [0-UINT16\_MAX] | Coded PHY Maximum connection interval, default: 50 | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | coded\_latency | [UINT16] | Coded PHY Connection latency, default: 0 | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | coded\_timeout | [UINT16] | Coded PHY Connection timeout, default: 0x0100 | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | coded\_min\_conn\_event\_len | [UINT16] | Coded PHY Minimum length of connection event, default: 0x0010 | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | coded\_max\_conn\_event\_len | [UINT16] | Coded PHY Maximum length of connection event, default: 0x0300 | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | 2M\_scan\_interval | [0-UINT16\_MAX] | 2M PHY Scan interval, default: 0x0010 | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | 2M\_scan\_window | [0-UINT16\_MAX] | 2M PHY Scan window, default: 0x0010 | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | 2M\_interval\_min | [0-UINT16\_MAX] | 2M PHY Minimum connection interval, default: 30 | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | 2M\_interval\_max | [0-UINT16\_MAX] | 2M PHY Maximum connection interval, default: 50 | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | 2M\_latency | [UINT16] | 2M PHY Connection latency, default: 0 | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | 2M\_timeout | [UINT16] | 2M PHY Connection timeout, default: 0x0100 | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | 2M\_min\_conn\_event\_len | [UINT16] | 2M PHY Minimum length of connection event, default: 0x0010 | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | 2M\_max\_conn\_event\_len | [UINT16] | 2M PHY Maximum length of connection event, default: 0x0300 | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| **disconnect** | | | Disconnect exisiting connection | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | conn | [UINT16] | Connection handle | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | reason | [UINT8] | Disconnect reason | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| **show-addr** | | | Show local public and random identity addresses | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| **show-conn** | | | Show current connections | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| **conn-rssi** | | | Obtain RSSI of specified connection | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | conn | [UINT16] | Connection handle | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| **conn-update-params** | | | Update parameters of specified connection | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | conn | [UINT16] | Connection handle | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | interval\_min | [0-UINT16\_MAX] | Minimum connection interval, default: 30 | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | interval\_max | [0-UINT16\_MAX] | Maximum connection interval, default: 50 | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | latency | [UINT16] | Connection latency, default: 0 | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | timeout | [UINT16] | Connection timeout, default: 0x0100 | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | min\_conn\_event\_len | [UINT16] | Minimum length of connection event, default: 0x0010 | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | max\_conn\_event\_len | [UINT16] | Maximum length of connection event, default: 0x0300 | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| **conn-datalen** | | | Set DLE parmaeters for connection | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | conn | [UINT16] | Connection handle | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | octets | [UINT16] | Maximum transmission packet size | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | time | [UINT16] | Maximum transmission packet time | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| **phy-set** | | | Set prefered PHYs used for connection | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | conn | [UINT16] | Connection handle | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | tx\_phys\_mask | [UINT8] | Prefered PHYs on TX is mask of following bits0x00 - no preference0x01 - 1M, 0x02 - 2M, 0x04 - Coded | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | rx\_phys\_mask | [UINT8] | Prefered PHYs on RX is mask of following bits0x00 - no preference0x01 - 1M, 0x02 - 2M, 0x04 - Coded | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | phy\_opts | [UINT16] | Options for Coded PHY 0 - any coding, 1 - prefer S2, 2 - prefer S8 | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| **phy-set-default** | | | Set default prefered PHYs used for new connection | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | tx\_phys\_mask | [UINT8] | Prefered PHYs on TX is mask of following bits0x00 - no preference0x01 - 1M, 0x02 - 2M, 0x04 - Coded | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | rx\_phys\_mask | [UINT8] | Prefered PHYs on RX is mask of following bits0x00 - no preference0x01 - 1M, 0x02 - 2M, 0x04 - Coded | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| **phy-read** | | | Read connection current PHY | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | conn | [UINT16] | Connection handle | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| **l2cap-update** | | | Update connection parameters | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | interval\_min | [0-UINT16\_MAX] | Minimum connection interval, default: 30 | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | interval\_max | [0-UINT16\_MAX] | Maximum connection interval, default: 50 | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | latency | [UINT16] | Connection latency, default: 0 | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ -| | timeout | [UINT16] | Connection timeout, default: 0x0100 | -+--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ +.. table:: Device discovery and connection + :widths: 15 25 20 40 + + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | **Command** | **Parameters** | **Possible values** | **Description** | + +==========================+================================+============================+============================================================================================================+ + | **scan** | | | Discover remote devices | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | cancel | | cancel ongoing scan procedure | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | extended | ``none`` | Start legacy scan | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | | 1M | Start extended scan on 1M PHY | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | | coded | Start extended scan on Coded PHY | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | | both | Start extended scan on both PHYs | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | duration | [1-``INT32_MAX``], | Duration of scan in milliseconds | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | limited | [``0``-1] | Use limited discovery procedure | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | passive | [``0``-1] | Use passive scan | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | interval | [``0``-UINT16\_MAX] | Scan interval, if 0 use stack's default | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | window | [``0``-UINT16\_MAX] | Scan window, if 0 use stack's default | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | filter | ``no_wl`` | Scan filter policy - Accept all advertising packets | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | | use\_wl | Accept only advertising packets from devices on White List | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | | no\_wl\_inita | Accept all advertising packets (including directed RPA) | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | | use\_wl\_inita | Accept only advertising packets from devices on White List (including directed RPA) | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | nodups | [``0``-1] | Disable duplicates filtering | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | own\_addr\_type | ``public`` | Use public address for scan requests | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | | random | Use random address for scan requests | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | | rpa\_pub | Use RPA address for scan requests (fallback to public if no IRK) | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | | rpa\_rnd | Use RPA address for scan requests (fallback to random if no IRK) | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | extended\_duration | [``0``-UINT16\_MAX] | Duration of extended scan in 10 milliseconds | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | extended\_period | [``0``-UINT16\_MAX] | Periodic scan interval in 1.28 seconds (0 disabled) | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | longrange\_interval | [``0``-UINT16\_MAX] | Scan interval for Coded Scan , if 0 use stack's default | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | longrange\_window | [``0``-UINT16\_MAX] | Scan window for Coded Scan , if 0 use stack's default | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | longrange\_passive | [``0``-1] | Use passive scan for Coded Scan | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | **connect** | | | Initiate connection to remote device | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | cancel | | Cancel ongoing connection procedure | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | extended | ``none`` | Use legacy connection procedure | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | | 1M | Extended connect using 1M PHY scan parameters | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | | coded | Extended connect using Coded PHY scan parameters | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | | both | Extended connect using 1M and Coded PHYs scan parameters | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | | all | Extended connect using 1M and Coded PHYs scan parameters (Provide also connection parameters for 2M PHY) | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | peer\_addr\_type | ``public`` | Remote device public address type | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | | random | Remote device random address type | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | | public\_id | Remote device public address type (Identity) | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | | random\_id | Remote device random address type (Identity) | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | peer\_addr | XX:XX:XX:XX:XX:XX | Remote device address | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | own\_addr\_type | ``public`` | Use public address for scan requests | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | | random | Use random address for scan requests | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | | rpa\_pub | Use RPA address for scan requests (fallback to public if no IRK) | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | | rpa\_rnd | Use RPA address for scan requests (fallback to random if no IRK) | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | duration | [``0``-INT32\_MAX] | Connection attempt duration, if 0 use stack's default | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | scan\_interval | [0-UINT16\_MAX] | Scan interval, default: 0x0010 | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | scan\_window | [0-UINT16\_MAX] | Scan window, default: 0x0010 | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | interval\_min | [0-UINT16\_MAX] | Minimum connection interval, default: 30 | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | interval\_max | [0-UINT16\_MAX] | Maximum connection interval, default: 50 | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | latency | [UINT16] | Connection latency, default: 0 | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | timeout | [UINT16] | Connection timeout, default: 0x0100 | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | min\_conn\_event\_len | [UINT16] | Minimum length of connection event, default: 0x0010 | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | max\_conn\_event\_len | [UINT16] | Maximum length of connection event, default: 0x0300 | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | coded\_scan\_interval | [0-UINT16\_MAX] | Coded PHY Scan interval, default: 0x0010 | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | coded\_scan\_window | [0-UINT16\_MAX] | Coded PHY Scan window, default: 0x0010 | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | coded\_interval\_min | [0-UINT16\_MAX] | Coded PHY Minimum connection interval, default: 30 | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | coded\_interval\_max | [0-UINT16\_MAX] | Coded PHY Maximum connection interval, default: 50 | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | coded\_latency | [UINT16] | Coded PHY Connection latency, default: 0 | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | coded\_timeout | [UINT16] | Coded PHY Connection timeout, default: 0x0100 | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | coded\_min\_conn\_event\_len | [UINT16] | Coded PHY Minimum length of connection event, default: 0x0010 | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | coded\_max\_conn\_event\_len | [UINT16] | Coded PHY Maximum length of connection event, default: 0x0300 | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | 2M\_scan\_interval | [0-UINT16\_MAX] | 2M PHY Scan interval, default: 0x0010 | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | 2M\_scan\_window | [0-UINT16\_MAX] | 2M PHY Scan window, default: 0x0010 | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | 2M\_interval\_min | [0-UINT16\_MAX] | 2M PHY Minimum connection interval, default: 30 | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | 2M\_interval\_max | [0-UINT16\_MAX] | 2M PHY Maximum connection interval, default: 50 | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | 2M\_latency | [UINT16] | 2M PHY Connection latency, default: 0 | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | 2M\_timeout | [UINT16] | 2M PHY Connection timeout, default: 0x0100 | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | 2M\_min\_conn\_event\_len | [UINT16] | 2M PHY Minimum length of connection event, default: 0x0010 | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | 2M\_max\_conn\_event\_len | [UINT16] | 2M PHY Maximum length of connection event, default: 0x0300 | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | **disconnect** | | | Disconnect exisiting connection | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | conn | [UINT16] | Connection handle | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | reason | [UINT8] | Disconnect reason | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | **show-addr** | | | Show local public and random identity addresses | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | **show-conn** | | | Show current connections | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | **conn-rssi** | | | Obtain RSSI of specified connection | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | conn | [UINT16] | Connection handle | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | **conn-update-params** | | | Update parameters of specified connection | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | conn | [UINT16] | Connection handle | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | interval\_min | [0-UINT16\_MAX] | Minimum connection interval, default: 30 | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | interval\_max | [0-UINT16\_MAX] | Maximum connection interval, default: 50 | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | latency | [UINT16] | Connection latency, default: 0 | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | timeout | [UINT16] | Connection timeout, default: 0x0100 | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | min\_conn\_event\_len | [UINT16] | Minimum length of connection event, default: 0x0010 | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | max\_conn\_event\_len | [UINT16] | Maximum length of connection event, default: 0x0300 | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | **conn-datalen** | | | Set DLE parmaeters for connection | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | conn | [UINT16] | Connection handle | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | octets | [UINT16] | Maximum transmission packet size | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | time | [UINT16] | Maximum transmission packet time | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | **phy-set** | | | Set prefered PHYs used for connection | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | conn | [UINT16] | Connection handle | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | tx\_phys\_mask | [UINT8] | Prefered PHYs on TX is mask of following bits0x00 - no preference0x01 - 1M, 0x02 - 2M, 0x04 - Coded | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | rx\_phys\_mask | [UINT8] | Prefered PHYs on RX is mask of following bits0x00 - no preference0x01 - 1M, 0x02 - 2M, 0x04 - Coded | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | phy\_opts | [UINT16] | Options for Coded PHY 0 - any coding, 1 - prefer S2, 2 - prefer S8 | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | **phy-set-default** | | | Set default prefered PHYs used for new connection | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | tx\_phys\_mask | [UINT8] | Prefered PHYs on TX is mask of following bits0x00 - no preference0x01 - 1M, 0x02 - 2M, 0x04 - Coded | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | rx\_phys\_mask | [UINT8] | Prefered PHYs on RX is mask of following bits0x00 - no preference0x01 - 1M, 0x02 - 2M, 0x04 - Coded | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | **phy-read** | | | Read connection current PHY | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | conn | [UINT16] | Connection handle | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | **l2cap-update** | | | Update connection parameters | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | interval\_min | [0-UINT16\_MAX] | Minimum connection interval, default: 30 | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | interval\_max | [0-UINT16\_MAX] | Maximum connection interval, default: 50 | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | latency | [UINT16] | Connection latency, default: 0 | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ + | | timeout | [UINT16] | Connection timeout, default: 0x0100 | + +--------------------------+--------------------------------+----------------------------+------------------------------------------------------------------------------------------------------------+ Security -------- -+---------------------------+--------------------+----------------------------+----------------------------------------------------------------------------------------------------------------------------+ -| **Command** | **Parmeters** | \*\* Possible values\*\* | **Description** | -+===========================+====================+============================+============================================================================================================================+ -| **security-set-data** | | | Set security configuration | -+---------------------------+--------------------+----------------------------+----------------------------------------------------------------------------------------------------------------------------+ -| | oob-flag | [``0``-1] | Set Out-Of-Band (OOB) flag in Security Manager | -+---------------------------+--------------------+----------------------------+----------------------------------------------------------------------------------------------------------------------------+ -| | mitm-flag | [``0``-1] | Set Man-In-The-Middle (MITM) flag in Security Manager | -+---------------------------+--------------------+----------------------------+----------------------------------------------------------------------------------------------------------------------------+ -| | io\_capabilities | 0 | Set Input-Output Capabilities to "DisplayOnly" | -+---------------------------+--------------------+----------------------------+----------------------------------------------------------------------------------------------------------------------------+ -| | | 1 | Set Input-Output Capabilities to "DisplayYesNo" | -+---------------------------+--------------------+----------------------------+----------------------------------------------------------------------------------------------------------------------------+ -| | | 2 | Set Input-Output Capabilities to "KeyboardOnly" | -+---------------------------+--------------------+----------------------------+----------------------------------------------------------------------------------------------------------------------------+ -| | | 3 | Set Input-Output Capabilities to "NoInputNoOutput" | -+---------------------------+--------------------+----------------------------+----------------------------------------------------------------------------------------------------------------------------+ -| | | 4 | Set Input-Output Capabilities to "KeyboardDisplay" | -+---------------------------+--------------------+----------------------------+----------------------------------------------------------------------------------------------------------------------------+ -| | our\_key\_dist | [UINT8] | Set Local Keys Distribution, this is a bit field of possible values: LTK (0x01), IRK (0x02), CSRK (0x04), LTK\_SC(0x08) | -+---------------------------+--------------------+----------------------------+----------------------------------------------------------------------------------------------------------------------------+ -| | their\_key\_dist | [UINT8] | Set Remote Keys Distribution, this is a bit field of possible values: LTK (0x01), IRK (0x02), CSRK (0x04), LTK\_SC(0x08) | -+---------------------------+--------------------+----------------------------+----------------------------------------------------------------------------------------------------------------------------+ -| | bonding-flag | [``0``-1] | Set Bonding flag in Security Manager | -+---------------------------+--------------------+----------------------------+----------------------------------------------------------------------------------------------------------------------------+ -| | sc-flag | [``0``-1] | Set Secure Connections flag in Security Manager | -+---------------------------+--------------------+----------------------------+----------------------------------------------------------------------------------------------------------------------------+ -| **security-pair** | | | Start pairing procedure | -+---------------------------+--------------------+----------------------------+----------------------------------------------------------------------------------------------------------------------------+ -| | conn | [UINT16] | Connection handle | -+---------------------------+--------------------+----------------------------+----------------------------------------------------------------------------------------------------------------------------+ -| **security-encryption** | | | Start encryption procedure | -+---------------------------+--------------------+----------------------------+----------------------------------------------------------------------------------------------------------------------------+ -| | conn | [UINT16] | Connection handle | -+---------------------------+--------------------+----------------------------+----------------------------------------------------------------------------------------------------------------------------+ -| | ediv | [UINT16] | EDIV for LTK to use (use storage if not provided) | -+---------------------------+--------------------+----------------------------+----------------------------------------------------------------------------------------------------------------------------+ -| | rand | [UINT64] | Rand for LTK | -+---------------------------+--------------------+----------------------------+----------------------------------------------------------------------------------------------------------------------------+ -| | ltk | XX:XX:XX... | LTK (16 bytes) | -+---------------------------+--------------------+----------------------------+----------------------------------------------------------------------------------------------------------------------------+ -| **security-start** | | | Start security procedure (This starts either pairing or encryption depending if keys are stored) | -+---------------------------+--------------------+----------------------------+----------------------------------------------------------------------------------------------------------------------------+ -| | conn | [UINT16] | Connection handle | -+---------------------------+--------------------+----------------------------+----------------------------------------------------------------------------------------------------------------------------+ -| **auth-passkey** | | | Reply to Passkey request | -+---------------------------+--------------------+----------------------------+----------------------------------------------------------------------------------------------------------------------------+ -| | conn | [UINT16] | Connection handle | -+---------------------------+--------------------+----------------------------+----------------------------------------------------------------------------------------------------------------------------+ -| | action | [UINT16] | Action to reply (as received in event) | -+---------------------------+--------------------+----------------------------+----------------------------------------------------------------------------------------------------------------------------+ -| | key | [0-999999] | Passkey to reply (Input or Display action) | -+---------------------------+--------------------+----------------------------+----------------------------------------------------------------------------------------------------------------------------+ -| | oob | XX:XX:XX:... | Out-Of-Band secret (16 bytes) (OOB action) | -+---------------------------+--------------------+----------------------------+----------------------------------------------------------------------------------------------------------------------------+ -| | yesno | Yy-Ny | Confirm passkey (for Passkey Confirm action) | -+---------------------------+--------------------+----------------------------+----------------------------------------------------------------------------------------------------------------------------+ +.. table:: Security + :widths: 15 15 15 55 + + +---------------------------+--------------------+----------------------------+----------------------------------------------------------------------------------------------------------------------------+ + | **Command** | **Parameters** | **Possible values** | **Description** | + +===========================+====================+============================+============================================================================================================================+ + | **security-set-data** | | | Set security configuration | + +---------------------------+--------------------+----------------------------+----------------------------------------------------------------------------------------------------------------------------+ + | | oob-flag | [``0``-1] | Set Out-Of-Band (OOB) flag in Security Manager | + +---------------------------+--------------------+----------------------------+----------------------------------------------------------------------------------------------------------------------------+ + | | mitm-flag | [``0``-1] | Set Man-In-The-Middle (MITM) flag in Security Manager | + +---------------------------+--------------------+----------------------------+----------------------------------------------------------------------------------------------------------------------------+ + | | io\_capabilities | 0 | Set Input-Output Capabilities to "DisplayOnly" | + +---------------------------+--------------------+----------------------------+----------------------------------------------------------------------------------------------------------------------------+ + | | | 1 | Set Input-Output Capabilities to "DisplayYesNo" | + +---------------------------+--------------------+----------------------------+----------------------------------------------------------------------------------------------------------------------------+ + | | | 2 | Set Input-Output Capabilities to "KeyboardOnly" | + +---------------------------+--------------------+----------------------------+----------------------------------------------------------------------------------------------------------------------------+ + | | | 3 | Set Input-Output Capabilities to "NoInputNoOutput" | + +---------------------------+--------------------+----------------------------+----------------------------------------------------------------------------------------------------------------------------+ + | | | 4 | Set Input-Output Capabilities to "KeyboardDisplay" | + +---------------------------+--------------------+----------------------------+----------------------------------------------------------------------------------------------------------------------------+ + | | our\_key\_dist | [UINT8] | Set Local Keys Distribution, this is a bit field of possible values: LTK (0x01), IRK (0x02), CSRK (0x04), LTK\_SC(0x08) | + +---------------------------+--------------------+----------------------------+----------------------------------------------------------------------------------------------------------------------------+ + | | their\_key\_dist | [UINT8] | Set Remote Keys Distribution, this is a bit field of possible values: LTK (0x01), IRK (0x02), CSRK (0x04), LTK\_SC(0x08) | + +---------------------------+--------------------+----------------------------+----------------------------------------------------------------------------------------------------------------------------+ + | | bonding-flag | [``0``-1] | Set Bonding flag in Security Manager | + +---------------------------+--------------------+----------------------------+----------------------------------------------------------------------------------------------------------------------------+ + | | sc-flag | [``0``-1] | Set Secure Connections flag in Security Manager | + +---------------------------+--------------------+----------------------------+----------------------------------------------------------------------------------------------------------------------------+ + | **security-pair** | | | Start pairing procedure | + +---------------------------+--------------------+----------------------------+----------------------------------------------------------------------------------------------------------------------------+ + | | conn | [UINT16] | Connection handle | + +---------------------------+--------------------+----------------------------+----------------------------------------------------------------------------------------------------------------------------+ + | **security-encryption** | | | Start encryption procedure | + +---------------------------+--------------------+----------------------------+----------------------------------------------------------------------------------------------------------------------------+ + | | conn | [UINT16] | Connection handle | + +---------------------------+--------------------+----------------------------+----------------------------------------------------------------------------------------------------------------------------+ + | | ediv | [UINT16] | EDIV for LTK to use (use storage if not provided) | + +---------------------------+--------------------+----------------------------+----------------------------------------------------------------------------------------------------------------------------+ + | | rand | [UINT64] | Rand for LTK | + +---------------------------+--------------------+----------------------------+----------------------------------------------------------------------------------------------------------------------------+ + | | ltk | XX:XX:XX... | LTK (16 bytes) | + +---------------------------+--------------------+----------------------------+----------------------------------------------------------------------------------------------------------------------------+ + | **security-start** | | | Start security procedure (This starts either pairing or encryption depending if keys are stored) | + +---------------------------+--------------------+----------------------------+----------------------------------------------------------------------------------------------------------------------------+ + | | conn | [UINT16] | Connection handle | + +---------------------------+--------------------+----------------------------+----------------------------------------------------------------------------------------------------------------------------+ + | **auth-passkey** | | | Reply to Passkey request | + +---------------------------+--------------------+----------------------------+----------------------------------------------------------------------------------------------------------------------------+ + | | conn | [UINT16] | Connection handle | + +---------------------------+--------------------+----------------------------+----------------------------------------------------------------------------------------------------------------------------+ + | | action | [UINT16] | Action to reply (as received in event) | + +---------------------------+--------------------+----------------------------+----------------------------------------------------------------------------------------------------------------------------+ + | | key | [0-999999] | Passkey to reply (Input or Display action) | + +---------------------------+--------------------+----------------------------+----------------------------------------------------------------------------------------------------------------------------+ + | | oob | XX:XX:XX:... | Out-Of-Band secret (16 bytes) (OOB action) | + +---------------------------+--------------------+----------------------------+----------------------------------------------------------------------------------------------------------------------------+ + | | yesno | Yy-Ny | Confirm passkey (for Passkey Confirm action) | + +---------------------------+--------------------+----------------------------+----------------------------------------------------------------------------------------------------------------------------+ Advertising with Extended Advertising enabled --------------------------------------------- -+------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| **Command** | **Parmeters** | \*\* Possible values\*\* | **Description** | -+==============================+==========================+============================+=====================================================================================+ -| **advertise-configure** | | | Configure new advertising instance | -+------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | instance | [``0``-UINT8\_MAX] | Advertising instance | -+------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | connectable | [``0``-1] | Use connectable advertising | -+------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | scannable | [``0``-1] | Use scannable advertising | -+------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | peer\_addr\_type | ``public`` | Remote device public address type | -+------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | | random | Remote device random address type | -+------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | | public\_id | Remote device public address type (Identity) | -+------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | | random\_id | Remote device random address type (Identity) | -+------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | peer\_addr | XX:XX:XX:XX:XX:XX | Remote device address - if provided perform directed advertising | -+------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | own\_addr\_type | ``public`` | Use public address for scan requests | -+------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | | random | Use random address for scan requests | -+------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | | rpa\_pub | Use RPA address for scan requests (fallback to public if no IRK) | -+------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | | rpa\_rnd | Use RPA address for scan requests (fallback to random if no IRK) | -+------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | channel\_map | [``0``-UINT8\_MAX} | Primary advertising channels map. If 0 use all channels. | -+------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | filter | ``none`` | Advertising filter policy - no filtering, no whitelist used | -+------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | | scan | process all connection requests but only scans from white list | -+------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | | conn | process all scan request but only connection requests from white list | -+------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | | both | ignore all scan and connection requests unless in white list | -+------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | interval\_min | [``0``-UINT32\_MAX] | Minimum advertising interval in 0.625 miliseconds If 0 use stack default. | -+------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | interval\_max | [``0``-UINT32\_MAX] | Maximum advertising interval in 0.625 miliseconds If 0 use stack default. | -+------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | rx\_power | [-127 - ``127``] | Advertising TX power in dBm | -+------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | primary\_phy | ``1M`` | Use 1M PHY on primary advertising channels | -+------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | | ``coded`` | Use Coded PHY on primary advertising channels | -+------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | secondary\_phy | ``1M`` | Use 1M PHY on secondary advertising channels | -+------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | | ``coded`` | Use coded PHY on primary advertising channels | -+------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | | ``2M`` | Use 2M PHY on primary advertising channels | -+------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | sid | [``0``-16] | Adsertising instance SID | -+------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | high\_duty | [``0``-1] | Use high\_duty advertising | -+------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | anonymous | [``0``-1] | Use anonymous advertising | -+------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | legacy | [``0``-1] | Use legacy PDUs for advertising | -+------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | include\_tx\_power | [``0``-1] | Include TX power information in advertising PDUs | -+------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | scan\_req\_notif | [``0``-1] | Enable SCAN\_REQ notifications | -+------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| **advertise-set-addr** | | | Configure *random* adress for instance | -+------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | instance | [``0``-UINT8\_MAX] | Advertising instance | -+------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | addr | XX:XX:XX:XX:XX:XX | Random address | -+------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| **advertise-set-adv-data** | | | Configure advertising instance ADV\_DATA. This allow to configure following TLVs: | -+------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| **advertise-set-scan-rsp** | | | Configure advertising instance SCAN\_RSP. This allow to configure following TLVs: | -+------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | instance | [``0``-UINT8\_MAX] | Advertising instance | -+------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | flags | [``0``-UINT8\_MAX] | Flags value | -+------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | uuid16 | [UINT16] | 16-bit UUID value (can be passed multiple times) | -+------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | uuid16\_is\_complete | [``0``-1] | I 16-bit UUID list is complete | -+------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | uuid32 | [UINT32] | 32-bit UUID value (can be passed multiple times) | -+------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | uuid32\_is\_complete | [``0``-1] | I 32-bit UUID list is complete | -+------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | uuid128 | XX:XX:XX:... | 128-bit UUID value (16 bytes) (can be passed multiple times) | -+------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | uuid128\_is\_complete | [``0``-1] | I 128-bit UUID list is complete | -+------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | tx\_power\_level | [-127 - 127] | TX Power level to include | -+------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | appearance | [UINT16] | Appearance | -+------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | name | string | Name | -+------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | advertising\_interval | [UINT16] | Advertising interval | -+------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | service\_data\_uuid32 | XX:XX:XX:... | 32-bit UUID service data | -+------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | service\_data\_uuid128 | XX:XX:XX:... | 128-bit UUID service data | -+------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | uri | XX:XX:XX:... | URI | -+------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | msg\_data | XX:XX:XX:... | Manufacturer data | -+------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | eddystone\_url | string | Eddystone with specified URL | -+------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| **advertise-start** | | | Start advertising with configured instance | -+------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | instance | [``0``-UINT8\_MAX] | Advertising instance | -+------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | duration | [``0``-UINT16\_MAX] | Advertising duration in 10ms units. 0 - forver | -+------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | max\_events | [``0``-UINT8\_MAX] | Maximum number of advertising events. 0 - no limit | -+------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| **advertise-stop** | | | Stop advertising | -+------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | instance | [``0``-UINT8\_MAX] | Advertising instance | -+------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| **advertise-remove** | | | Remove configured advertising instance | -+------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | instance | [``0``-UINT8\_MAX] | Advertising instance | -+------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ +.. table:: Advertising with Extended Advertising enabled + :widths: 15 20 20 45 + + +------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | **Command** | **Parameters** | **Possible values** | **Description** | + +==============================+==========================+============================+=====================================================================================+ + | **advertise-configure** | | | Configure new advertising instance | + +------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | instance | [``0``-UINT8\_MAX] | Advertising instance | + +------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | connectable | [``0``-1] | Use connectable advertising | + +------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | scannable | [``0``-1] | Use scannable advertising | + +------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | peer\_addr\_type | ``public`` | Remote device public address type | + +------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | | random | Remote device random address type | + +------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | | public\_id | Remote device public address type (Identity) | + +------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | | random\_id | Remote device random address type (Identity) | + +------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | peer\_addr | XX:XX:XX:XX:XX:XX | Remote device address - if provided perform directed advertising | + +------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | own\_addr\_type | ``public`` | Use public address for scan requests | + +------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | | random | Use random address for scan requests | + +------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | | rpa\_pub | Use RPA address for scan requests (fallback to public if no IRK) | + +------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | | rpa\_rnd | Use RPA address for scan requests (fallback to random if no IRK) | + +------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | channel\_map | [``0``-UINT8\_MAX} | Primary advertising channels map. If 0 use all channels. | + +------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | filter | ``none`` | Advertising filter policy - no filtering, no whitelist used | + +------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | | scan | process all connection requests but only scans from white list | + +------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | | conn | process all scan request but only connection requests from white list | + +------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | | both | ignore all scan and connection requests unless in white list | + +------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | interval\_min | [``0``-UINT32\_MAX] | Minimum advertising interval in 0.625 miliseconds If 0 use stack default. | + +------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | interval\_max | [``0``-UINT32\_MAX] | Maximum advertising interval in 0.625 miliseconds If 0 use stack default. | + +------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | rx\_power | [-127 - ``127``] | Advertising TX power in dBm | + +------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | primary\_phy | ``1M`` | Use 1M PHY on primary advertising channels | + +------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | | ``coded`` | Use Coded PHY on primary advertising channels | + +------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | secondary\_phy | ``1M`` | Use 1M PHY on secondary advertising channels | + +------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | | ``coded`` | Use coded PHY on primary advertising channels | + +------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | | ``2M`` | Use 2M PHY on primary advertising channels | + +------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | sid | [``0``-16] | Adsertising instance SID | + +------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | high\_duty | [``0``-1] | Use high\_duty advertising | + +------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | anonymous | [``0``-1] | Use anonymous advertising | + +------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | legacy | [``0``-1] | Use legacy PDUs for advertising | + +------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | include\_tx\_power | [``0``-1] | Include TX power information in advertising PDUs | + +------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | scan\_req\_notif | [``0``-1] | Enable SCAN\_REQ notifications | + +------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | **advertise-set-addr** | | | Configure *random* address for instance | + +------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | instance | [``0``-UINT8\_MAX] | Advertising instance | + +------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | addr | XX:XX:XX:XX:XX:XX | Random address | + +------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | **advertise-set-adv-data** | | | Configure advertising instance ADV\_DATA. This allow to configure following TLVs: | + +------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | **advertise-set-scan-rsp** | | | Configure advertising instance SCAN\_RSP. This allow to configure following TLVs: | + +------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | instance | [``0``-UINT8\_MAX] | Advertising instance | + +------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | flags | [``0``-UINT8\_MAX] | Flags value | + +------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | uuid16 | [UINT16] | 16-bit UUID value (can be passed multiple times) | + +------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | uuid16\_is\_complete | [``0``-1] | I 16-bit UUID list is complete | + +------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | uuid32 | [UINT32] | 32-bit UUID value (can be passed multiple times) | + +------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | uuid32\_is\_complete | [``0``-1] | I 32-bit UUID list is complete | + +------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | uuid128 | XX:XX:XX:... | 128-bit UUID value (16 bytes) (can be passed multiple times) | + +------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | uuid128\_is\_complete | [``0``-1] | I 128-bit UUID list is complete | + +------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | tx\_power\_level | [-127 - 127] | TX Power level to include | + +------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | appearance | [UINT16] | Appearance | + +------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | name | string | Name | + +------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | advertising\_interval | [UINT16] | Advertising interval | + +------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | service\_data\_uuid32 | XX:XX:XX:... | 32-bit UUID service data | + +------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | service\_data\_uuid128 | XX:XX:XX:... | 128-bit UUID service data | + +------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | uri | XX:XX:XX:... | URI | + +------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | msg\_data | XX:XX:XX:... | Manufacturer data | + +------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | eddystone\_url | string | Eddystone with specified URL | + +------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | **advertise-start** | | | Start advertising with configured instance | + +------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | instance | [``0``-UINT8\_MAX] | Advertising instance | + +------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | duration | [``0``-UINT16\_MAX] | Advertising duration in 10ms units. 0 - forver | + +------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | max\_events | [``0``-UINT8\_MAX] | Maximum number of advertising events. 0 - no limit | + +------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | **advertise-stop** | | | Stop advertising | + +------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | instance | [``0``-UINT8\_MAX] | Advertising instance | + +------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | **advertise-remove** | | | Remove configured advertising instance | + +------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | instance | [``0``-UINT8\_MAX] | Advertising instance | + +------------------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ Legacy Advertising with Extended Advertising disabled ----------------------------------------------------- -+--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| **Command** | **Parmeters** | \*\* Possible values\*\* | **Description** | -+====================+==========================+============================+=====================================================================================+ -| **advertise** | | | Enable advertising | -+--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | stop | | Stop enabled advertising | -+--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | conn | ``und`` | Connectable mode: undirected | -+--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | | non | non-connectable | -+--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | | dir | directed | -+--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | discov | ``gen`` | Discoverable mode: general discoverable | -+--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | | ltd | limited discoverable | -+--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | | non | non-discoverable | -+--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | scannable | [``0``-1] | Use scannable advertising | -+--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | peer\_addr\_type | ``public`` | Remote device public address type | -+--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | | random | Remote device random address type | -+--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | | public\_id | Remote device public address type (Identity) | -+--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | | random\_id | Remote device random address type (Identity) | -+--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | peer\_addr | XX:XX:XX:XX:XX:XX | Remote device address - if provided perform directed advertising | -+--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | own\_addr\_type | ``public`` | Use public address for scan requests | -+--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | | random | Use random address for scan requests | -+--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | | rpa\_pub | Use RPA address for scan requests (fallback to public if no IRK) | -+--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | | rpa\_rnd | Use RPA address for scan requests (fallback to random if no IRK) | -+--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | channel\_map | [``0``-UINT8\_MAX} | Primary advertising channels map. If 0 use all channels. | -+--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | filter | ``none`` | Advertising filter policy - no filtering, no whitelist used | -+--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | | scan | process all connection requests but only scans from white list | -+--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | | conn | process all scan request but only connection requests from white list | -+--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | | both | ignore all scan and connection requests unless in white list | -+--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | interval\_min | [``0``-UINT32\_MAX] | Minimum advertising interval in 0.625 miliseconds If 0 use stack default. | -+--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | interval\_max | [``0``-UINT32\_MAX] | Maximum advertising interval in 0.625 miliseconds If 0 use stack default. | -+--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | high\_duty | [``0``-1] | Use high\_duty advertising | -+--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | duration | [``1``-INT32\_MAX] | Advertising duration in ms | -+--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| **set-adv-data** | | | Configure advertising instance ADV\_DATA. This allow to configure following TLVs: | -+--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| **set-scan-rsp** | | | Configure advertising instance SCAN\_RSP. This allow to configure following TLVs: | -+--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | flags | [``0``-UINT8\_MAX] | Flags value | -+--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | uuid16 | [UINT16] | 16-bit UUID value (can be passed multiple times) | -+--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | uuid16\_is\_complete | [``0``-1] | I 16-bit UUID list is complete | -+--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | uuid32 | [UINT32] | 32-bit UUID value (can be passed multiple times) | -+--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | uuid32\_is\_complete | [``0``-1] | I 32-bit UUID list is complete | -+--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | uuid128 | XX:XX:XX:... | 128-bit UUID value (16 bytes) (can be passed multiple times) | -+--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | uuid128\_is\_complete | [``0``-1] | I 128-bit UUID list is complete | -+--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | tx\_power\_level | [-127 - 127] | TX Power level to include | -+--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | appearance | [UINT16] | Appearance | -+--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | name | string | Name | -+--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | advertising\_interval | [UINT16] | Advertising interval | -+--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | service\_data\_uuid32 | XX:XX:XX:... | 32-bit UUID service data | -+--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | service\_data\_uuid128 | XX:XX:XX:... | 128-bit UUID service data | -+--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | uri | XX:XX:XX:... | URI | -+--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | msg\_data | XX:XX:XX:... | Manufacturer data | -+--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ -| | eddystone\_url | string | Eddystone with specified URL | -+--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ +.. table:: Legacy Advertising with Extended Advertising disabled + :widths: 15 20 20 45 + + +--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | **Command** | **Parameters** | **Possible values** | **Description** | + +====================+==========================+============================+=====================================================================================+ + | **advertise** | | | Enable advertising | + +--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | stop | | Stop enabled advertising | + +--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | conn | ``und`` | Connectable mode: undirected | + +--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | | non | non-connectable | + +--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | | dir | directed | + +--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | discov | ``gen`` | Discoverable mode: general discoverable | + +--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | | ltd | limited discoverable | + +--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | | non | non-discoverable | + +--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | scannable | [``0``-1] | Use scannable advertising | + +--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | peer\_addr\_type | ``public`` | Remote device public address type | + +--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | | random | Remote device random address type | + +--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | | public\_id | Remote device public address type (Identity) | + +--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | | random\_id | Remote device random address type (Identity) | + +--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | peer\_addr | XX:XX:XX:XX:XX:XX | Remote device address - if provided perform directed advertising | + +--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | own\_addr\_type | ``public`` | Use public address for scan requests | + +--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | | random | Use random address for scan requests | + +--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | | rpa\_pub | Use RPA address for scan requests (fallback to public if no IRK) | + +--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | | rpa\_rnd | Use RPA address for scan requests (fallback to random if no IRK) | + +--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | channel\_map | [``0``-UINT8\_MAX} | Primary advertising channels map. If 0 use all channels. | + +--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | filter | ``none`` | Advertising filter policy - no filtering, no whitelist used | + +--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | | scan | process all connection requests but only scans from white list | + +--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | | conn | process all scan request but only connection requests from white list | + +--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | | both | ignore all scan and connection requests unless in white list | + +--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | interval\_min | [``0``-UINT32\_MAX] | Minimum advertising interval in 0.625 miliseconds If 0 use stack default. | + +--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | interval\_max | [``0``-UINT32\_MAX] | Maximum advertising interval in 0.625 miliseconds If 0 use stack default. | + +--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | high\_duty | [``0``-1] | Use high\_duty advertising | + +--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | duration | [``1``-INT32\_MAX] | Advertising duration in ms | + +--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | **set-adv-data** | | | Configure advertising instance ADV\_DATA. This allow to configure following TLVs: | + +--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | **set-scan-rsp** | | | Configure advertising instance SCAN\_RSP. This allow to configure following TLVs: | + +--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | flags | [``0``-UINT8\_MAX] | Flags value | + +--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | uuid16 | [UINT16] | 16-bit UUID value (can be passed multiple times) | + +--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | uuid16\_is\_complete | [``0``-1] | I 16-bit UUID list is complete | + +--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | uuid32 | [UINT32] | 32-bit UUID value (can be passed multiple times) | + +--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | uuid32\_is\_complete | [``0``-1] | I 32-bit UUID list is complete | + +--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | uuid128 | XX:XX:XX:... | 128-bit UUID value (16 bytes) (can be passed multiple times) | + +--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | uuid128\_is\_complete | [``0``-1] | I 128-bit UUID list is complete | + +--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | tx\_power\_level | [-127 - 127] | TX Power level to include | + +--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | appearance | [UINT16] | Appearance | + +--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | name | string | Name | + +--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | advertising\_interval | [UINT16] | Advertising interval | + +--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | service\_data\_uuid32 | XX:XX:XX:... | 32-bit UUID service data | + +--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | service\_data\_uuid128 | XX:XX:XX:... | 128-bit UUID service data | + +--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | uri | XX:XX:XX:... | URI | + +--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | msg\_data | XX:XX:XX:... | Manufacturer data | + +--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ + | | eddystone\_url | string | Eddystone with specified URL | + +--------------------+--------------------------+----------------------------+-------------------------------------------------------------------------------------+ L2CAP Connection Oriented Channels ---------------------------------- -+---------------------------+-----------------+----------------------------+----------------------------------------------------+ -| **Command** | **Parmeters** | \*\* Possible values\*\* | **Description** | -+===========================+=================+============================+====================================================+ -| **l2cap-create-server** | | | Create L2CAP server | -+---------------------------+-----------------+----------------------------+----------------------------------------------------+ -| | psm | [UINT16] | PSM | -+---------------------------+-----------------+----------------------------+----------------------------------------------------+ -| **l2cap-connect** | | | Connect to remote L2CAP server | -+---------------------------+-----------------+----------------------------+----------------------------------------------------+ -| | conn | [UINT16] | Connection handle | -+---------------------------+-----------------+----------------------------+----------------------------------------------------+ -| | psm | [UINT16] | PSM | -+---------------------------+-----------------+----------------------------+----------------------------------------------------+ -| **l2cap-disconnect** | | | Disconnec from L2CAP server | -+---------------------------+-----------------+----------------------------+----------------------------------------------------+ -| | conn | [UINT16] | Connection handle | -+---------------------------+-----------------+----------------------------+----------------------------------------------------+ -| | idx | [UINT16] | L2CAP connection oriented channel identifier | -+---------------------------+-----------------+----------------------------+----------------------------------------------------+ -| **l2cap-send** | | | Send data over connected L2CAP channel | -+---------------------------+-----------------+----------------------------+----------------------------------------------------+ -| | conn | [UINT16] | Connection handle | -+---------------------------+-----------------+----------------------------+----------------------------------------------------+ -| | idx | [UINT16] | L2CAP connection oriented channel identifier | -+---------------------------+-----------------+----------------------------+----------------------------------------------------+ -| | bytes | [UINT16] | Number of bytes to send (hardcoded data pattern) | -+---------------------------+-----------------+----------------------------+----------------------------------------------------+ -| **l2cap-show-coc** | | | Show connected L2CAP channels | -+---------------------------+-----------------+----------------------------+----------------------------------------------------+ +.. table:: L2CAP Connection Oriented Channels + :widths: 25 15 15 45 + + +---------------------------+-----------------+----------------------------+----------------------------------------------------+ + | **Command** | **Parameters** | **Possible values** | **Description** | + +===========================+=================+============================+====================================================+ + | **l2cap-create-server** | | | Create L2CAP server | + +---------------------------+-----------------+----------------------------+----------------------------------------------------+ + | | psm | [UINT16] | PSM | + +---------------------------+-----------------+----------------------------+----------------------------------------------------+ + | **l2cap-connect** | | | Connect to remote L2CAP server | + +---------------------------+-----------------+----------------------------+----------------------------------------------------+ + | | conn | [UINT16] | Connection handle | + +---------------------------+-----------------+----------------------------+----------------------------------------------------+ + | | psm | [UINT16] | PSM | + +---------------------------+-----------------+----------------------------+----------------------------------------------------+ + | **l2cap-disconnect** | | | Disconnec from L2CAP server | + +---------------------------+-----------------+----------------------------+----------------------------------------------------+ + | | conn | [UINT16] | Connection handle | + +---------------------------+-----------------+----------------------------+----------------------------------------------------+ + | | idx | [UINT16] | L2CAP connection oriented channel identifier | + +---------------------------+-----------------+----------------------------+----------------------------------------------------+ + | **l2cap-send** | | | Send data over connected L2CAP channel | + +---------------------------+-----------------+----------------------------+----------------------------------------------------+ + | | conn | [UINT16] | Connection handle | + +---------------------------+-----------------+----------------------------+----------------------------------------------------+ + | | idx | [UINT16] | L2CAP connection oriented channel identifier | + +---------------------------+-----------------+----------------------------+----------------------------------------------------+ + | | bytes | [UINT16] | Number of bytes to send (hardcoded data pattern) | + +---------------------------+-----------------+----------------------------+----------------------------------------------------+ + | **l2cap-show-coc** | | | Show connected L2CAP channels | + +---------------------------+-----------------+----------------------------+----------------------------------------------------+ Keys storage ------------ -+---------------------+-----------------+----------------------------+----------------------------------------------------+ -| **Command** | **Parmeters** | \*\* Possible values\*\* | **Description** | -+=====================+=================+============================+====================================================+ -| **keystore-add** | | | Add keys to storage | -+---------------------+-----------------+----------------------------+----------------------------------------------------+ -| | type | msec | Master Key | -+---------------------+-----------------+----------------------------+----------------------------------------------------+ -| | | ssec | Slave Key | -+---------------------+-----------------+----------------------------+----------------------------------------------------+ -| | | cccd | Client Characteristic Configuration Descriptor | -+---------------------+-----------------+----------------------------+----------------------------------------------------+ -| | addr | XX:XX:XX:XX:XX:XX | Device address | -+---------------------+-----------------+----------------------------+----------------------------------------------------+ -| | addr\_type | ``public`` | Device address type | -+---------------------+-----------------+----------------------------+----------------------------------------------------+ -| | | random | Use random address for scan requests | -+---------------------+-----------------+----------------------------+----------------------------------------------------+ -| | ediv | [UINT16] | EDIV for LTK to add | -+---------------------+-----------------+----------------------------+----------------------------------------------------+ -| | rand | [UINT64] | Rand for LTK | -+---------------------+-----------------+----------------------------+----------------------------------------------------+ -| | ltk | XX:XX:XX... | LTK (16 bytes) | -+---------------------+-----------------+----------------------------+----------------------------------------------------+ -| | irk | XX:XX:XX... | Identity Resolving Key (16 bytes) | -+---------------------+-----------------+----------------------------+----------------------------------------------------+ -| | csrk | XX:XX:XX... | Connection Signature Resolving Key (16 bytes) | -+---------------------+-----------------+----------------------------+----------------------------------------------------+ -| **keystore-del** | | | Delete keys from storage | -+---------------------+-----------------+----------------------------+----------------------------------------------------+ -| | type | msec | Master Key | -+---------------------+-----------------+----------------------------+----------------------------------------------------+ -| | | ssec | Slave Key | -+---------------------+-----------------+----------------------------+----------------------------------------------------+ -| | | cccd | Client Characteristic Configuration Descriptor | -+---------------------+-----------------+----------------------------+----------------------------------------------------+ -| | addr | XX:XX:XX:XX:XX:XX | Device address | -+---------------------+-----------------+----------------------------+----------------------------------------------------+ -| | addr\_type | ``public`` | Device address type | -+---------------------+-----------------+----------------------------+----------------------------------------------------+ -| | | random | Use random address for scan requests | -+---------------------+-----------------+----------------------------+----------------------------------------------------+ -| | ediv | [UINT16] | EDIV for LTK to remove | -+---------------------+-----------------+----------------------------+----------------------------------------------------+ -| | rand | [UINT64] | Rand for LTK | -+---------------------+-----------------+----------------------------+----------------------------------------------------+ -| **keystore-show** | | | Show stored keys | -+---------------------+-----------------+----------------------------+----------------------------------------------------+ -| | type | msec | Master Keys | -+---------------------+-----------------+----------------------------+----------------------------------------------------+ -| | | ssec | Slave Keys | -+---------------------+-----------------+----------------------------+----------------------------------------------------+ -| | | cccd | Client Characteristic Configuration Descriptor s | -+---------------------+-----------------+----------------------------+----------------------------------------------------+ +.. table:: Keys storage + :widths: 20 15 20 45 + + +---------------------+-----------------+----------------------------+----------------------------------------------------+ + | **Command** | **Parameters** | **Possible values** | **Description** | + +=====================+=================+============================+====================================================+ + | **keystore-add** | | | Add keys to storage | + +---------------------+-----------------+----------------------------+----------------------------------------------------+ + | | type | msec | Master Key | + +---------------------+-----------------+----------------------------+----------------------------------------------------+ + | | | ssec | Slave Key | + +---------------------+-----------------+----------------------------+----------------------------------------------------+ + | | | cccd | Client Characteristic Configuration Descriptor | + +---------------------+-----------------+----------------------------+----------------------------------------------------+ + | | addr | XX:XX:XX:XX:XX:XX | Device address | + +---------------------+-----------------+----------------------------+----------------------------------------------------+ + | | addr\_type | ``public`` | Device address type | + +---------------------+-----------------+----------------------------+----------------------------------------------------+ + | | | random | Use random address for scan requests | + +---------------------+-----------------+----------------------------+----------------------------------------------------+ + | | ediv | [UINT16] | EDIV for LTK to add | + +---------------------+-----------------+----------------------------+----------------------------------------------------+ + | | rand | [UINT64] | Rand for LTK | + +---------------------+-----------------+----------------------------+----------------------------------------------------+ + | | ltk | XX:XX:XX... | LTK (16 bytes) | + +---------------------+-----------------+----------------------------+----------------------------------------------------+ + | | irk | XX:XX:XX... | Identity Resolving Key (16 bytes) | + +---------------------+-----------------+----------------------------+----------------------------------------------------+ + | | csrk | XX:XX:XX... | Connection Signature Resolving Key (16 bytes) | + +---------------------+-----------------+----------------------------+----------------------------------------------------+ + | **keystore-del** | | | Delete keys from storage | + +---------------------+-----------------+----------------------------+----------------------------------------------------+ + | | type | msec | Master Key | + +---------------------+-----------------+----------------------------+----------------------------------------------------+ + | | | ssec | Slave Key | + +---------------------+-----------------+----------------------------+----------------------------------------------------+ + | | | cccd | Client Characteristic Configuration Descriptor | + +---------------------+-----------------+----------------------------+----------------------------------------------------+ + | | addr | XX:XX:XX:XX:XX:XX | Device address | + +---------------------+-----------------+----------------------------+----------------------------------------------------+ + | | addr\_type | ``public`` | Device address type | + +---------------------+-----------------+----------------------------+----------------------------------------------------+ + | | | random | Use random address for scan requests | + +---------------------+-----------------+----------------------------+----------------------------------------------------+ + | | ediv | [UINT16] | EDIV for LTK to remove | + +---------------------+-----------------+----------------------------+----------------------------------------------------+ + | | rand | [UINT64] | Rand for LTK | + +---------------------+-----------------+----------------------------+----------------------------------------------------+ + | **keystore-show** | | | Show stored keys | + +---------------------+-----------------+----------------------------+----------------------------------------------------+ + | | type | msec | Master Keys | + +---------------------+-----------------+----------------------------+----------------------------------------------------+ + | | | ssec | Slave Keys | + +---------------------+-----------------+----------------------------+----------------------------------------------------+ + | | | cccd | Client Characteristic Configuration Descriptors | + +---------------------+-----------------+----------------------------+----------------------------------------------------+ diff --git a/docs/btshell/btshell_GATT.rst b/docs/btshell/btshell_GATT.rst index 0fe465fe5b..5468e49c4f 100644 --- a/docs/btshell/btshell_GATT.rst +++ b/docs/btshell/btshell_GATT.rst @@ -1,108 +1,109 @@ GATT feature API for btshell ============================ -GATT(GENERIC ATTRIBUTE PROFILE) describes a service framework using the Attribute Protocol for discovering services, +Generic Attribute Profile (GATT) describes a service framework using the Attribute Protocol for discovering services, and for reading and writing characteristic values on a peer device. There are 11 features defined in the GATT Profile, and each of the features is mapped to procedures and sub-procedures: Available commands ~~~~~~~~~~~~~~~~~~ -Parameters default values (if applicable) are marked red. - Configuration ------------- -+------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ -| **Command** | **Parmeters** | \*\* Possible values\*\* | **Description** | -+====================================+=================+============================+===========================================================+ -| **gatt-discover-characteristic** | | | Discover GATT characteristics | -+------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ -| | conn | [UINT16] | Connection handle | -+------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ -| | uuid | [UINT16] | Characteristic UUID | -+------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ -| | start | [UINT16] | Discovery start handle | -+------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ -| | end | [UINT16] | Discovery end handle | -+------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ -| **gatt-discover-descriptor** | | | Discover GATT descriptors | -+------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ -| | conn | [UINT16] | Connection handle | -+------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ -| | start | [UINT16] | Discovery start handle | -+------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ -| | end | [UINT16] | Discovery end handle | -+------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ -| **gatt-discover-service** | | | Discover services | -+------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ -| | conn | [UINT16] | Connection handle | -+------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ -| | uuid16 | [UINT16] | Service UUID | -+------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ -| **gatt-discover-full** | | | Discover services, characteristic and descriptors | -+------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ -| | conn | [UINT16] | Connection handle | -+------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ -| **gatt-find-included-services** | | | Find included services | -+------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ -| | conn | [UINT16] | Connection handle | -+------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ -| | start | [UINT16] | Discovery start handle | -+------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ -| | end | [UINT16] | Discovery end handle | -+------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ -| **gatt-exchange-mtu** | | | Initiate ATT MTU exchange procedure | -+------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ -| | conn | [UINT16] | Connection handle | -+------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ -| **gatt-read** | | | Read attribute | -+------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ -| | conn | [UINT16] | Connection handle | -+------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ -| | long | [``0``-1] | Long read | -+------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ -| | attr | [UINT16] | Attribute handle | -+------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ -| | offset | [UINT16] | Long read offset value | -+------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ -| | uuid | [UINT16] | Characteristic UUID | -+------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ -| | start | [UINT16] | Discovery start handle | -+------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ -| | end | [UINT16] | Discovery end handle | -+------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ -| **gatt-notify** | | | Send notification or indication to all subscribed peers | -+------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ -| | attr | [UINT16] | Attribute handle | -+------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ -| **gatt-service-changed** | | | Send Services Changed notification | -+------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ -| | start | [UINT16] | Start handle | -+------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ -| | end | [UINT16] | End handle | -+------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ -| **gatt-service-visibility** | | | Set service visibility | -+------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ -| | handle | [UINT16] | Service handle | -+------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ -| | visibility | [``0``-1] | Service visibility | -+------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ -| **gatt-show** | | | Show remote devices discovered databases structure | -+------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ -| **gatt-show-local** | | | Show local database structure | -+------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ -| **gatt-write** | | | Write attribute | -+------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ -| | conn | [UINT16] | Connection handle | -+------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ -| | no\_rsp | [``0``-1] | Use Write Without Response | -+------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ -| | long | [``0``-1] | Use Long Write procedure | -+------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ -| | attr | [UINT16] | Attribute handle | -+------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ -| | offset | [UINT16] | Long write offset value | -+------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ -| | value | XX:XX:XX... | Data to write | -+------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ +.. table:: Configuration + :widths: 20 15 20 45 + + +------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ + | **Command** | **Parmeters** | **Possible values** | **Description** | + +====================================+=================+============================+===========================================================+ + | **gatt-discover-characteristic** | | | Discover GATT characteristics | + +------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ + | | conn | [UINT16] | Connection handle | + +------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ + | | uuid | [UINT16] | Characteristic UUID | + +------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ + | | start | [UINT16] | Discovery start handle | + +------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ + | | end | [UINT16] | Discovery end handle | + +------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ + | **gatt-discover-descriptor** | | | Discover GATT descriptors | + +------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ + | | conn | [UINT16] | Connection handle | + +------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ + | | start | [UINT16] | Discovery start handle | + +------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ + | | end | [UINT16] | Discovery end handle | + +------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ + | **gatt-discover-service** | | | Discover services | + +------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ + | | conn | [UINT16] | Connection handle | + +------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ + | | uuid16 | [UINT16] | Service UUID | + +------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ + | **gatt-discover-full** | | | Discover services, characteristic and descriptors | + +------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ + | | conn | [UINT16] | Connection handle | + +------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ + | **gatt-find-included-services** | | | Find included services | + +------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ + | | conn | [UINT16] | Connection handle | + +------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ + | | start | [UINT16] | Discovery start handle | + +------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ + | | end | [UINT16] | Discovery end handle | + +------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ + | **gatt-exchange-mtu** | | | Initiate ATT MTU exchange procedure | + +------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ + | | conn | [UINT16] | Connection handle | + +------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ + | **gatt-read** | | | Read attribute | + +------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ + | | conn | [UINT16] | Connection handle | + +------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ + | | long | [``0``-1] | Long read | + +------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ + | | attr | [UINT16] | Attribute handle | + +------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ + | | offset | [UINT16] | Long read offset value | + +------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ + | | uuid | [UINT16] | Characteristic UUID | + +------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ + | | start | [UINT16] | Discovery start handle | + +------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ + | | end | [UINT16] | Discovery end handle | + +------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ + | **gatt-notify** | | | Send notification or indication to all subscribed peers | + +------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ + | | attr | [UINT16] | Attribute handle | + +------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ + | **gatt-service-changed** | | | Send Services Changed notification | + +------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ + | | start | [UINT16] | Start handle | + +------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ + | | end | [UINT16] | End handle | + +------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ + | **gatt-service-visibility** | | | Set service visibility | + +------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ + | | handle | [UINT16] | Service handle | + +------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ + | | visibility | [``0``-1] | Service visibility | + +------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ + | **gatt-show** | | | Show remote devices discovered databases structure | + +------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ + | **gatt-show-local** | | | Show local database structure | + +------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ + | **gatt-write** | | | Write attribute | + +------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ + | | conn | [UINT16] | Connection handle | + +------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ + | | no\_rsp | [``0``-1] | Use Write Without Response | + +------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ + | | long | [``0``-1] | Use Long Write procedure | + +------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ + | | attr | [UINT16] | Attribute handle | + +------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ + | | offset | [UINT16] | Long write offset value | + +------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ + | | value | XX:XX:XX... | Data to write | + +------------------------------------+-----------------+----------------------------+-----------------------------------------------------------+ diff --git a/docs/btshell/btshell_advdata.rst b/docs/btshell/btshell_advdata.rst index eabfcb3b84..b533cb069b 100644 --- a/docs/btshell/btshell_advdata.rst +++ b/docs/btshell/btshell_advdata.rst @@ -6,42 +6,46 @@ formats used for Extended Inquiry Response (EIR), Advertising Data (AD), and OOB to the Bluetooth Core Specification, CSSv6, available for download `here `__. -+---------------------------+-----------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------+ -| **Name** | **Definition** | **Details** | **btshell Notes** | -+===========================+=====================================================+===========================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================+==============================================+ -| flags | Indicates basic information about the advertiser. | Flags used over the LE physical channel are: \* Limited Discoverable Mode \* General Discoverable Mode \* BR/EDR Not Supported \* Simultaneous LE and BR/EDR to Same Device Capable (Controller) \* Simultaneous LE and BR/EDR to Same Device Capable (Host) | NimBLE will auto-calculate if set to 0. | -+---------------------------+-----------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------+ -| uuid16 | 16-bit Bluetooth Service UUIDs | Indicates the Service UUID list is incomplete i.e. more 16-bit Service UUIDs available. 16 bit UUIDs shall only be used if they are assigned by the Bluetooth SIG. | Set repeatedly for multiple service UUIDs. | -+---------------------------+-----------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------+ -| uuid16\_is\_complete | 16-bit Bluetooth Service UUIDs | Indicates the Service UUID list is complete. 16 bit UUIDs shall only be used if they are assigned by the Bluetooth SIG. | | -+---------------------------+-----------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------+ -| uuid32 | 32-bit Bluetooth Service UUIDs | Indicates the Service UUID list is incomplete i.e. more 32-bit Service UUIDs available. 32 bit UUIDs shall only be used if they are assigned by the Bluetooth SIG. | Set repeatedly for multiple service UUIDs. | -+---------------------------+-----------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------+ -| uuid32\_is\_complete | 32-bit Bluetooth Service UUIDs | Indicates the Service UUID list is complete. 32 bit UUIDs shall only be used if they are assigned by the Bluetooth SIG. | | -+---------------------------+-----------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------+ -| uuid128 | Global 128-bit Service UUIDs | More 128-bit Service UUIDs available. | Set repeatedly for multiple service UUIDs. | -+---------------------------+-----------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------+ -| uuid128\_is\_complete | Global 128-bit Service UUIDs | Complete list of 128-bit Service UUIDs | | -+---------------------------+-----------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------+ -| tx\_power\_level | TX Power Level | Indicates the transmitted power level of the packet containing the data type. The TX Power Level data type may be used to calculate path loss on a received packet using the following equation: pathloss = Tx Power Level – RSSI where “RSSI” is the received signal strength, in dBm, of the packet received. | NimBLE will auto-calculate if set to -128. | -+---------------------------+-----------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------+ -| slave\_interval\_range | Slave Connection Interval Range | Contains the Peripheral’s preferred connection interval range, for all logical connections. Size: 4 Octets . The first 2 octets defines the minimum value for the connection interval in the following manner: connIntervalmin = Conn\_Interval\_Min \* 1.25 ms Conn\_Interval\_Min range: 0x0006 to 0x0C80 Value of 0xFFFF indicates no specific minimum. The other 2 octets defines the maximum value for the connection interval in the following manner: connIntervalmax = Conn\_Interval\_Max \* 1.25 ms Conn\_Interval\_Max range: 0x0006 to 0x0C80 Conn\_Interval\_Max shall be equal to or greater than the Conn\_Interval\_Min. Value of 0xFFFF indicates no specific maximum. | | -+---------------------------+-----------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------+ -| service\_data\_uuid16 | Service Data - 16 bit UUID | Size: 2 or more octets The first 2 octets contain the 16 bit Service UUID followed by additional service data | | -+---------------------------+-----------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------+ -| public\_target\_address | Public Target Address | Defines the address of one or more intended recipients of an advertisement when one or more devices were bonded using a public address. This data type shall exist only once. It may be sent in either the Advertising or Scan Response data, but not both. | | -+---------------------------+-----------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------+ -| appearance | Appearance | Defines the external appearance of the device. The Appearance data type shall exist only once. It may be sent in either the Advertising or Scan Response data, but not both. | | -+---------------------------+-----------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------+ -| advertising\_interval | Advertising Interval | Contains the advInterval value as defined in the Core specification, Volume 6, Part B, Section 4.4.2.2. | | -+---------------------------+-----------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------+ -| service\_data\_uuid32 | Service Data - 32 bit UUID | Size: 4 or more octets The first 4 octets contain the 32 bit Service UUID followed by additional service data | | -+---------------------------+-----------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------+ -| service\_data\_uuid128 | Service Data - 128 bit UUID | Size: 16 or more octets The first 16 octets contain the 128 bit Service UUID followed by additional service data | | -+---------------------------+-----------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------+ -| uri | Uniform Resource Identifier (URI) | Scheme name string and URI as a UTF-8 string | | -+---------------------------+-----------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------+ -| mfg\_data | Manufacturer Specific data | Size: 2 or more octets The first 2 octets contain the Company Identifier Code followed by additional manufacturer specific data | | -+---------------------------+-----------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------+ -| eddystone\_url | | | | -+---------------------------+-----------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------+ +.. table:: Advertisement Data Fields + :class: longtable + :widths: 20 20 45 15 + + +---------------------------+-----------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------+ + | **Name** | **Definition** | **Details** | **btshell Notes** | + +===========================+=====================================================+===========================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================+==============================================+ + | flags | Indicates basic information about the advertiser. | Flags used over the LE physical channel are: \* Limited Discoverable Mode \* General Discoverable Mode \* BR/EDR Not Supported \* Simultaneous LE and BR/EDR to Same Device Capable (Controller) \* Simultaneous LE and BR/EDR to Same Device Capable (Host) | NimBLE will auto-calculate if set to 0. | + +---------------------------+-----------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------+ + | uuid16 | 16-bit Bluetooth Service UUIDs | Indicates the Service UUID list is incomplete i.e. more 16-bit Service UUIDs available. 16 bit UUIDs shall only be used if they are assigned by the Bluetooth SIG. | Set repeatedly for multiple service UUIDs. | + +---------------------------+-----------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------+ + | uuid16\_is\_complete | 16-bit Bluetooth Service UUIDs | Indicates the Service UUID list is complete. 16 bit UUIDs shall only be used if they are assigned by the Bluetooth SIG. | | + +---------------------------+-----------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------+ + | uuid32 | 32-bit Bluetooth Service UUIDs | Indicates the Service UUID list is incomplete i.e. more 32-bit Service UUIDs available. 32 bit UUIDs shall only be used if they are assigned by the Bluetooth SIG. | Set repeatedly for multiple service UUIDs. | + +---------------------------+-----------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------+ + | uuid32\_is\_complete | 32-bit Bluetooth Service UUIDs | Indicates the Service UUID list is complete. 32 bit UUIDs shall only be used if they are assigned by the Bluetooth SIG. | | + +---------------------------+-----------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------+ + | uuid128 | Global 128-bit Service UUIDs | More 128-bit Service UUIDs available. | Set repeatedly for multiple service UUIDs. | + +---------------------------+-----------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------+ + | uuid128\_is\_complete | Global 128-bit Service UUIDs | Complete list of 128-bit Service UUIDs | | + +---------------------------+-----------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------+ + | tx\_power\_level | TX Power Level | Indicates the transmitted power level of the packet containing the data type. The TX Power Level data type may be used to calculate path loss on a received packet using the following equation: pathloss = Tx Power Level – RSSI where “RSSI” is the received signal strength, in dBm, of the packet received. | NimBLE will auto-calculate if set to -128. | + +---------------------------+-----------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------+ + | slave\_interval\_range | Slave Connection Interval Range | Contains the Peripheral’s preferred connection interval range, for all logical connections. Size: 4 Octets . The first 2 octets defines the minimum value for the connection interval in the following manner: connIntervalmin = Conn\_Interval\_Min \* 1.25 ms Conn\_Interval\_Min range: 0x0006 to 0x0C80 Value of 0xFFFF indicates no specific minimum. The other 2 octets defines the maximum value for the connection interval in the following manner: connIntervalmax = Conn\_Interval\_Max \* 1.25 ms Conn\_Interval\_Max range: 0x0006 to 0x0C80 Conn\_Interval\_Max shall be equal to or greater than the Conn\_Interval\_Min. Value of 0xFFFF indicates no specific maximum. | | + +---------------------------+-----------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------+ + | service\_data\_uuid16 | Service Data - 16 bit UUID | Size: 2 or more octets The first 2 octets contain the 16 bit Service UUID followed by additional service data | | + +---------------------------+-----------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------+ + | public\_target\_address | Public Target Address | Defines the address of one or more intended recipients of an advertisement when one or more devices were bonded using a public address. This data type shall exist only once. It may be sent in either the Advertising or Scan Response data, but not both. | | + +---------------------------+-----------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------+ + | appearance | Appearance | Defines the external appearance of the device. The Appearance data type shall exist only once. It may be sent in either the Advertising or Scan Response data, but not both. | | + +---------------------------+-----------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------+ + | advertising\_interval | Advertising Interval | Contains the advInterval value as defined in the Core specification, Volume 6, Part B, Section 4.4.2.2. | | + +---------------------------+-----------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------+ + | service\_data\_uuid32 | Service Data - 32 bit UUID | Size: 4 or more octets The first 4 octets contain the 32 bit Service UUID followed by additional service data | | + +---------------------------+-----------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------+ + | service\_data\_uuid128 | Service Data - 128 bit UUID | Size: 16 or more octets The first 16 octets contain the 128 bit Service UUID followed by additional service data | | + +---------------------------+-----------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------+ + | uri | Uniform Resource Identifier (URI) | Scheme name string and URI as a UTF-8 string | | + +---------------------------+-----------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------+ + | mfg\_data | Manufacturer Specific data | Size: 2 or more octets The first 2 octets contain the Company Identifier Code followed by additional manufacturer specific data | | + +---------------------------+-----------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------+ + | eddystone\_url | | | | + +---------------------------+-----------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------------------------------+ diff --git a/docs/btshell/btshell_api.rst b/docs/btshell/btshell_api.rst index 49605bf41c..28a1021c51 100644 --- a/docs/btshell/btshell_api.rst +++ b/docs/btshell/btshell_api.rst @@ -48,11 +48,11 @@ For example: set addr_type=public addr=01:02:03:04:05:06 set addr_type=random addr=c1:aa:bb:cc:dd:ee -The address configuration can be viewed with the ``gatt-show-addr`` command, as follows: +The address configuration can be viewed with the ``show-addr`` command, as follows: :: - gatt-show-addr + show-addr public_id_addr=01:02:03:04:05:06 random_id_addr=c1:aa:bb:cc:dd:ee Initiate a direct connection to a device diff --git a/docs/index.rst b/docs/index.rst index b41b1b283e..b07f1f88d0 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -46,7 +46,7 @@ ideal wireless technology for the Internet of Things (IoT). - LE Secure Connections featuring FIPS-compliant algorithms. - LE Data Length Extension for higher throughput - **Coming Soon**: Assigning an Internet Protocol (IP) address - (complaint with the IPv6 or 6LoWPAN standard) to a Bluetooth device + (compliant with the IPv6 or 6LoWPAN standard) to a Bluetooth device through Internet Protocol Support Profile (IPSP) The Bluetooth 5 is backward compatible with previous Bluetooth version diff --git a/docs/mesh/index.rst b/docs/mesh/index.rst index 6ad75363f0..bab9d883ae 100644 --- a/docs/mesh/index.rst +++ b/docs/mesh/index.rst @@ -84,6 +84,7 @@ Lightness Server Model. .. figure:: mesh_lightning_model.jpg :alt: Light Lightness Server model (source: Mesh Model Specification 1.0) + :width: 450 Mesh Node features supported by Apache Mynewt ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/ext/liblc3/pkg.yml b/ext/liblc3/pkg.yml new file mode 100644 index 0000000000..9a19fd3cf5 --- /dev/null +++ b/ext/liblc3/pkg.yml @@ -0,0 +1,50 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +pkg.name: ext/liblc3 +pkg.description: LC3 Codec library +pkg.author: "Apache Mynewt " +pkg.homepage: "http://mynewt.apache.org/" +pkg.keywords: + - lc3 + +pkg.type: sdk + +pkg.cflags: -O3 -std=c11 -ffast-math -Wno-array-bounds +pkg.lflags: -lm + +pkg.ign_dirs: + - "@liblc3/test" + - "@liblc3/zephyr" + - "@liblc3/fuzz" + - "@liblc3/tables" + - "@liblc3/tools" + +pkg.src_dirs: + - "@liblc3/src" + +pkg.include_dirs: + - "@liblc3/include" + +repository.liblc3: + type: github + vers: v1.0.4-commit + branch: main + user: google + repo: liblc3 diff --git a/ext/libsamplerate/pkg.yml b/ext/libsamplerate/pkg.yml new file mode 100644 index 0000000000..94a950261d --- /dev/null +++ b/ext/libsamplerate/pkg.yml @@ -0,0 +1,46 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +pkg.name: ext/libsamplerate +pkg.description: samplerate library +pkg.author: "Apache Mynewt " +pkg.homepage: "http://mynewt.apache.org/" +pkg.keywords: + - samplerate + +pkg.type: sdk + +pkg.cflags: -O3 -DHAVE_STDBOOL_H -fsingle-precision-constant -DHAVE_CONFIG_H -DNDEBUG -DLIBSAMPLERATE_SINGLE_PRECISION +pkg.lflags: -lm + +app.cflags: + - -DLIBSAMPLERATE_SINGLE_PRECISION + +pkg.src_dirs: + - "@libsamplerate/src" + +pkg.include_dirs: + - "@libsamplerate/include" + +repository.libsamplerate: + type: github + vers: 0.2.2-commit + branch: release-0.2.2 + user: libsndfile + repo: libsamplerate diff --git a/ext/libsamplerate/src/config.h b/ext/libsamplerate/src/config.h new file mode 100644 index 0000000000..dca00b2b89 --- /dev/null +++ b/ext/libsamplerate/src/config.h @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_LIBSAMPLERATE_CONFIG_ +#define H_LIBSAMPLERATE_CONFIG_ + +#include "syscfg/syscfg.h" + +#if MYNEWT_VAL(LIBSAMPLERATE_ENABLE_SINC_BEST_CONVERTER) +#define ENABLE_SINC_BEST_CONVERTER 1 +#endif + +#if MYNEWT_VAL(LIBSAMPLERATE_ENABLE_SINC_MEDIUM_CONVERTER) +#define ENABLE_SINC_MEDIUM_CONVERTER 1 +#endif + +#if MYNEWT_VAL(LIBSAMPLERATE_ENABLE_SINC_FAST_CONVERTER) +#define ENABLE_SINC_FAST_CONVERTER 1 +#endif + +#define PACKAGE "libsamplerate" +#define VERSION "0.2.2" + +#endif /* H_LIBSAMPLERATE_CONFIG_ */ diff --git a/ext/libsamplerate/syscfg.yml b/ext/libsamplerate/syscfg.yml new file mode 100644 index 0000000000..730d84d1d1 --- /dev/null +++ b/ext/libsamplerate/syscfg.yml @@ -0,0 +1,27 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +syscfg.defs: + LIBSAMPLERATE_ENABLE_SINC_BEST_CONVERTER: + description: Enable SINC best converter + value: 1 + LIBSAMPLERATE_ENABLE_SINC_MEDIUM_CONVERTER: + description: Enable SINC medium converter + value: 1 + LIBSAMPLERATE_ENABLE_SINC_FAST_CONVERTER: + description: Enable SINC fastest converter + value: 1 diff --git a/nimble/controller/include/controller/ble_fem.h b/nimble/controller/include/controller/ble_fem.h new file mode 100644 index 0000000000..bd0b93e13a --- /dev/null +++ b/nimble/controller/include/controller/ble_fem.h @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_BLE_FEM_ +#define H_BLE_FEM_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "syscfg/syscfg.h" + +#if MYNEWT_VAL(BLE_FEM_PA) +void ble_fem_pa_init(void); +void ble_fem_pa_enable(void); +void ble_fem_pa_disable(void); +#if MYNEWT_VAL(BLE_FEM_PA_GAIN_TUNABLE) +/* Configures FEM to selected TX power and returns expected PHY TX power */ +int ble_fem_pa_tx_power_set(int tx_power); + +/* returns rounded FEM TX power */ +int ble_fem_pa_tx_power_round(int tx_power); +#endif +#endif + +#if MYNEWT_VAL(BLE_FEM_LNA) +void ble_fem_lna_init(void); +void ble_fem_lna_enable(void); +void ble_fem_lna_disable(void); + +#if MYNEWT_VAL(BLE_FEM_LNA_GAIN_TUNABLE) +/* Return current value of FEM LNA RX gain (in dBm) */ +int ble_fem_lna_rx_gain(void); +#endif + +#endif + +#if MYNEWT_VAL(BLE_FEM_ANTENNA) +/* 0 sets default antenna, any other value is FEM specific */ +int ble_fem_antenna(uint8_t antenna); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* H_BLE_FEM_ */ diff --git a/nimble/controller/include/controller/ble_hw.h b/nimble/controller/include/controller/ble_hw.h index cf2930761a..394c3a173c 100644 --- a/nimble/controller/include/controller/ble_hw.h +++ b/nimble/controller/include/controller/ble_hw.h @@ -94,12 +94,6 @@ void ble_hw_resolv_list_rmv(int index); /* Returns the size of the whitelist in HW */ uint8_t ble_hw_resolv_list_size(void); -/* Enable the resolving list */ -void ble_hw_resolv_list_enable(void); - -/* Disables resolving list devices */ -void ble_hw_resolv_list_disable(void); - /* Returns index of resolved address; -1 if not resolved */ int ble_hw_resolv_list_match(void); diff --git a/nimble/controller/include/controller/ble_ll.h b/nimble/controller/include/controller/ble_ll.h index 24d7db3003..ab75edcba3 100644 --- a/nimble/controller/include/controller/ble_ll.h +++ b/nimble/controller/include/controller/ble_ll.h @@ -21,7 +21,6 @@ #define H_BLE_LL_ #include "stats/stats.h" -#include "os/os_cputime.h" #include "nimble/nimble_opt.h" #include "nimble/nimble_npl.h" #include "controller/ble_phy.h" @@ -30,39 +29,30 @@ #include "controller/ble_ll_ctrl.h" #include "hal/hal_system.h" #endif +#ifdef RIOT_VERSION +#include "hal/hal_timer.h" +#endif #ifdef __cplusplus extern "C" { #endif -#if MYNEWT_VAL(OS_CPUTIME_FREQ) != 32768 -#error 32.768kHz clock required -#endif - -#if defined(MYNEWT) && MYNEWT_VAL(BLE_LL_VND_EVENT_ON_ASSERT) +#if defined(MYNEWT) && MYNEWT_VAL(BLE_LL_HCI_VS_EVENT_ON_ASSERT) #ifdef NDEBUG #define BLE_LL_ASSERT(cond) (void(0)) #else +void ble_ll_assert(const char *file, unsigned line) __attribute((noreturn)); +#define BLE_LL_FILE (__builtin_strrchr(__FILE__, '/') ? \ + __builtin_strrchr (__FILE__, '/') + 1 : __FILE__) #define BLE_LL_ASSERT(cond) \ if (!(cond)) { \ - if (hal_debugger_connected()) { \ - assert(0);\ - } else {\ - ble_ll_hci_ev_send_vendor_err(__FILE__, __LINE__); \ - while(1) {}\ - }\ + ble_ll_assert(BLE_LL_FILE, __LINE__); \ } #endif #else #define BLE_LL_ASSERT(cond) assert(cond) #endif -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY) || MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) -#define BLE_LL_BT5_PHY_SUPPORTED (1) -#else -#define BLE_LL_BT5_PHY_SUPPORTED (0) -#endif - /* Controller revision. */ #define BLE_LL_SUB_VERS_NR (0x0000) @@ -95,6 +85,8 @@ extern "C" { /* Packet queue header definition */ STAILQ_HEAD(ble_ll_pkt_q, os_mbuf_pkthdr); +#define BLE_LL_CHAN_MAP_LEN (5) + /* * Global Link Layer data object. There is only one Link Layer data object * per controller although there may be many instances of the link layer state @@ -108,11 +100,22 @@ struct ble_ll_obj /* Current Link Layer state */ uint8_t ll_state; + /* Global channel map */ + uint8_t chan_map[BLE_LL_CHAN_MAP_LEN]; + uint8_t chan_map_used; + +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) || MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) /* Number of ACL data packets supported */ uint8_t ll_num_acl_pkts; /* ACL data packet size */ uint16_t ll_acl_pkt_size; +#endif + +#if MYNEWT_VAL(BLE_LL_ISO) + uint8_t ll_num_iso_pkts; + uint16_t ll_iso_pkt_size; +#endif /* Preferred PHY's */ uint8_t ll_pref_tx_phys; @@ -121,22 +124,23 @@ struct ble_ll_obj /* Task event queue */ struct ble_npl_eventq ll_evq; - /* Wait for response timer */ - struct hal_timer ll_wfr_timer; - /* Packet receive queue (and event). Holds received packets from PHY */ struct ble_npl_event ll_rx_pkt_ev; struct ble_ll_pkt_q ll_rx_pkt_q; /* Packet transmit queue */ +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) || MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) struct ble_npl_event ll_tx_pkt_ev; +#endif struct ble_ll_pkt_q ll_tx_pkt_q; +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) || MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) /* Data buffer overflow event */ struct ble_npl_event ll_dbuf_overflow_ev; /* Number of completed packets event */ struct ble_npl_event ll_comp_pkt_ev; +#endif /* HW error callout */ struct ble_npl_callout ll_hw_err_timer; @@ -169,6 +173,7 @@ STATS_SECT_START(ble_ll_stats) STATS_SECT_ENTRY(rx_connect_reqs) STATS_SECT_ENTRY(rx_scan_ind) STATS_SECT_ENTRY(rx_aux_connect_rsp) + STATS_SECT_ENTRY(rx_pdu_on_scan_disabled) STATS_SECT_ENTRY(adv_txg) STATS_SECT_ENTRY(adv_late_starts) STATS_SECT_ENTRY(adv_resched_pdu_fail) @@ -214,50 +219,77 @@ extern STATS_SECT_DECL(ble_ll_stats) ble_ll_stats; /* States */ #define BLE_LL_STATE_STANDBY (0) +#if MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) #define BLE_LL_STATE_ADV (1) +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) #define BLE_LL_STATE_SCANNING (2) -#define BLE_LL_STATE_INITIATING (3) +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) #define BLE_LL_STATE_CONNECTION (4) +#endif +#if MYNEWT_VAL(BLE_LL_DTM) #define BLE_LL_STATE_DTM (5) +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) && MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) #define BLE_LL_STATE_SYNC (6) +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) && MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) +#define BLE_LL_STATE_SCAN_AUX (7) +#endif +#if MYNEWT_VAL(BLE_LL_EXT) +#define BLE_LL_STATE_EXTERNAL (8) +#endif +#if MYNEWT_VAL(BLE_LL_ISO_BROADCASTER) +#define BLE_LL_STATE_BIG (9) +#endif /* LL Features */ -#define BLE_LL_FEAT_LE_ENCRYPTION (0x0000000001) -#define BLE_LL_FEAT_CONN_PARM_REQ (0x0000000002) -#define BLE_LL_FEAT_EXTENDED_REJ (0x0000000004) -#define BLE_LL_FEAT_SLAVE_INIT (0x0000000008) -#define BLE_LL_FEAT_LE_PING (0x0000000010) -#define BLE_LL_FEAT_DATA_LEN_EXT (0x0000000020) -#define BLE_LL_FEAT_LL_PRIVACY (0x0000000040) -#define BLE_LL_FEAT_EXT_SCAN_FILT (0x0000000080) -#define BLE_LL_FEAT_LE_2M_PHY (0x0000000100) -#define BLE_LL_FEAT_STABLE_MOD_ID_TX (0x0000000200) -#define BLE_LL_FEAT_STABLE_MOD_ID_RX (0x0000000400) -#define BLE_LL_FEAT_LE_CODED_PHY (0x0000000800) -#define BLE_LL_FEAT_EXT_ADV (0x0000001000) -#define BLE_LL_FEAT_PERIODIC_ADV (0x0000002000) -#define BLE_LL_FEAT_CSA2 (0x0000004000) -#define BLE_LL_FEAT_LE_POWER_CLASS_1 (0x0000008000) -#define BLE_LL_FEAT_MIN_USED_CHAN (0x0000010000) -#define BLE_LL_FEAT_CTE_REQ (0x0000020000) -#define BLE_LL_FEAT_CTE_RSP (0x0000040000) -#define BLE_LL_FEAT_CTE_TX (0x0000080000) -#define BLE_LL_FEAT_CTE_RX (0x0000100000) -#define BLE_LL_FEAT_CTE_AOD (0x0000200000) -#define BLE_LL_FEAT_CTE_AOA (0x0000400000) -#define BLE_LL_FEAT_CTE_RECV (0x0000800000) -#define BLE_LL_FEAT_SYNC_TRANS_SEND (0x0001000000) -#define BLE_LL_FEAT_SYNC_TRANS_RECV (0x0002000000) -#define BLE_LL_FEAT_SCA_UPDATE (0x0004000000) -#define BLE_LL_FEAT_REM_PKEY (0x0008000000) -#define BLE_LL_FEAT_CIS_MASTER (0x0010000000) -#define BLE_LL_FEAT_CIS_SLAVE (0x0020000000) -#define BLE_LL_FEAT_ISO_BROADCASTER (0x0040000000) -#define BLE_LL_FEAT_SYNC_RECV (0x0080000000) -#define BLE_LL_FEAT_ISO_HOST_SUPPORT (0x0100000000) -#define BLE_LL_FEAT_POWER_CTRL_REQ (0x0200000000) -#define BLE_LL_FEAT_POWER_CHANGE_IND (0x0400000000) -#define BLE_LL_FEAT_PATH_LOSS_MON (0x0800000000) +#define BLE_LL_FEAT_LE_ENCRYPTION (0x0000000000001) +#define BLE_LL_FEAT_CONN_PARM_REQ (0x0000000000002) +#define BLE_LL_FEAT_EXTENDED_REJ (0x0000000000004) +#define BLE_LL_FEAT_PERIPH_INIT (0x0000000000008) +#define BLE_LL_FEAT_LE_PING (0x0000000000010) +#define BLE_LL_FEAT_DATA_LEN_EXT (0x0000000000020) +#define BLE_LL_FEAT_LL_PRIVACY (0x0000000000040) +#define BLE_LL_FEAT_EXT_SCAN_FILT (0x0000000000080) +#define BLE_LL_FEAT_LE_2M_PHY (0x0000000000100) +#define BLE_LL_FEAT_STABLE_MOD_ID_TX (0x0000000000200) +#define BLE_LL_FEAT_STABLE_MOD_ID_RX (0x0000000000400) +#define BLE_LL_FEAT_LE_CODED_PHY (0x0000000000800) +#define BLE_LL_FEAT_EXT_ADV (0x0000000001000) +#define BLE_LL_FEAT_PERIODIC_ADV (0x0000000002000) +#define BLE_LL_FEAT_CSA2 (0x0000000004000) +#define BLE_LL_FEAT_LE_POWER_CLASS_1 (0x0000000008000) +#define BLE_LL_FEAT_MIN_USED_CHAN (0x0000000010000) +#define BLE_LL_FEAT_CTE_REQ (0x0000000020000) +#define BLE_LL_FEAT_CTE_RSP (0x0000000040000) +#define BLE_LL_FEAT_CTE_TX (0x0000000080000) +#define BLE_LL_FEAT_CTE_RX (0x0000000100000) +#define BLE_LL_FEAT_CTE_AOD (0x0000000200000) +#define BLE_LL_FEAT_CTE_AOA (0x0000000400000) +#define BLE_LL_FEAT_CTE_RECV (0x0000000800000) +#define BLE_LL_FEAT_SYNC_TRANS_SEND (0x0000001000000) +#define BLE_LL_FEAT_SYNC_TRANS_RECV (0x0000002000000) +#define BLE_LL_FEAT_SCA_UPDATE (0x0000004000000) +#define BLE_LL_FEAT_REM_PKEY (0x0000008000000) +#define BLE_LL_FEAT_CIS_CENTRAL (0x0000010000000) +#define BLE_LL_FEAT_CIS_PERIPH (0x0000020000000) +#define BLE_LL_FEAT_ISO_BROADCASTER (0x0000040000000) +#define BLE_LL_FEAT_SYNC_RECV (0x0000080000000) +#define BLE_LL_FEAT_CIS_HOST (0x0000100000000) +#define BLE_LL_FEAT_POWER_CTRL_REQ (0x0000200000000) +#define BLE_LL_FEAT_POWER_CHANGE_IND (0x0000400000000) +#define BLE_LL_FEAT_PATH_LOSS_MON (0x0000800000000) +#define BLE_LL_FEAT_PERIODIC_ADV_ADI (0x0001000000000) +#define BLE_LL_FEAT_CONN_SUBRATING (0x0002000000000) +#define BLE_LL_FEAT_CONN_SUBRATING_HOST (0x0004000000000) +#define BLE_LL_FEAT_CHANNEL_CLASS (0x0008000000000) +#define BLE_LL_FEAT_ADV_CODING_SEL (0x0010000000000) +#define BLE_LL_FEAT_ADV_CODING_SEL_HOST (0x0020000000000) +#define BLE_LL_FEAT_CS (0x0400000000000) +#define BLE_LL_FEAT_CS_HOST_SUPPORT (0x0800000000000) +#define BLE_LL_FEAT_CS_PCT_QUALITY_IND (0x1000000000000) /* This is initial mask, so if feature exchange will not happen, * but host will want to use this procedure, we will try. If not @@ -268,11 +300,17 @@ extern STATS_SECT_DECL(ble_ll_stats) ble_ll_stats; #define BLE_LL_CONN_CLEAR_FEATURE(connsm, feature) (connsm->conn_features &= ~(feature)) /* All the features which can be controlled by the Host */ -#define BLE_LL_HOST_CONTROLLED_FEATURES (BLE_LL_FEAT_ISO_HOST_SUPPORT) +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE) | \ + MYNEWT_VAL(BLE_LL_ADV_CODING_SELECTION) +#define BLE_LL_HOST_CONTROLLED_FEATURES (1) +#else +#define BLE_LL_HOST_CONTROLLED_FEATURES (0) +#endif /* LL timing */ #define BLE_LL_IFS (150) /* usecs */ #define BLE_LL_MAFS (300) /* usecs */ +#define BLE_LL_MSS (150) /* usecs */ /* * BLE LL device address. Note that element 0 of the array is the LSB and @@ -307,6 +345,27 @@ struct ble_dev_addr #define BLE_LL_MAX_PDU_LEN ((BLE_LL_PDU_HDR_LEN) + (BLE_LL_MAX_PAYLOAD_LEN)) #define BLE_LL_CRCINIT_ADV (0x555555) +#define BLE_LL_CONN_HANDLE(t, h) ((((t) << 8) & BLE_LL_CONN_HANDLE_TYPE_MASK) | \ + ((h) & BLE_LL_CONN_HANDLE_IDX_MASK)) +#define BLE_LL_CONN_HANDLE_TYPE_MASK (0x0700) +#define BLE_LL_CONN_HANDLE_IDX_MASK (0x00ff) +#define BLE_LL_CONN_HANDLE_TYPE(conn_h) (((conn_h) & BLE_LL_CONN_HANDLE_TYPE_MASK) >> 8) +#define BLE_LL_CONN_HANDLE_IDX(conn_h) ((conn_h) & BLE_LL_CONN_HANDLE_IDX_MASK) + +#define BLE_LL_CONN_HANDLE_TYPE_ACL (0x00) +#define BLE_LL_CONN_HANDLE_TYPE_CIS (0x01) +#define BLE_LL_CONN_HANDLE_TYPE_BIS (0x02) +#define BLE_LL_CONN_HANDLE_TYPE_BIS_SYNC (0x03) + +#define BLE_LL_CONN_HANDLE_IS_ACL(ch) \ + (BLE_LL_CONN_HANDLE_TYPE(ch) == BLE_LL_CONN_HANDLE_TYPE_ACL) +#define BLE_LL_CONN_HANDLE_IS_CIS(ch) \ + (BLE_LL_CONN_HANDLE_TYPE(ch) == BLE_LL_CONN_HANDLE_TYPE_CIS) +#define BLE_LL_CONN_HANDLE_IS_BIS(ch) \ + (BLE_LL_CONN_HANDLE_TYPE(ch) == BLE_LL_CONN_HANDLE_TYPE_BIS) +#define BLE_LL_CONN_HANDLE_IS_BIS_SYNC(ch) \ + (BLE_LL_CONN_HANDLE_TYPE(ch) == BLE_LL_CONN_HANDLE_TYPE_BIS_SYNC) + /* Access address for advertising channels */ #define BLE_ACCESS_ADDR_ADV (0x8E89BED6) @@ -354,6 +413,7 @@ struct ble_dev_addr #define BLE_LL_EXT_ADV_FLAGS_SIZE (1) #define BLE_LL_EXT_ADV_ADVA_SIZE (6) #define BLE_LL_EXT_ADV_TARGETA_SIZE (6) +#define BLE_LL_EXT_ADV_CTE_INFO_SIZE (1) #define BLE_LL_EXT_ADV_DATA_INFO_SIZE (2) #define BLE_LL_EXT_ADV_AUX_PTR_SIZE (3) #define BLE_LL_EXT_ADV_SYNC_INFO_SIZE (18) @@ -446,6 +506,7 @@ struct ble_dev_addr /* ACAD data types */ #define BLE_LL_ACAD_CHANNEL_MAP_UPDATE_IND 0x28 +#define BLE_LL_ACAD_BIGINFO 0x2C struct ble_ll_acad_channel_map_update_ind { uint8_t map[5]; @@ -453,14 +514,9 @@ struct ble_ll_acad_channel_map_update_ind { } __attribute__((packed)); /*--- External API ---*/ -/* Initialize the Link Layer */ -void ble_ll_init(void); - /* Reset the Link Layer */ int ble_ll_reset(void); -int ble_ll_is_valid_public_addr(const uint8_t *addr); - /* 'Boolean' function returning true if address is a valid random address */ int ble_ll_is_valid_random_addr(const uint8_t *addr); @@ -471,10 +527,6 @@ int ble_ll_is_valid_random_addr(const uint8_t *addr); int ble_ll_is_valid_own_addr_type(uint8_t own_addr_type, const uint8_t *random_addr); -/* Calculate the amount of time in microseconds a PDU with payload length of - * 'payload_len' will take to transmit on a PHY 'phy_mode'. */ -uint32_t ble_ll_pdu_tx_time_get(uint16_t payload_len, int phy_mode); - /* Calculate maximum octets of PDU payload which can be transmitted during * 'usecs' on a PHY 'phy_mode'. */ uint16_t ble_ll_pdu_max_tx_octets_get(uint32_t usecs, int phy_mode); @@ -542,8 +594,11 @@ void ble_ll_state_set(uint8_t ll_state); /* Get the link layer state */ uint8_t ble_ll_state_get(void); -/* Send an event to LL task */ -void ble_ll_event_send(struct ble_npl_event *ev); +/* Add an event to LL task */ +void ble_ll_event_add(struct ble_npl_event *ev); + +/* Remove an event from LL task */ +void ble_ll_event_remove(struct ble_npl_event *ev); /* Hand received pdu's to LL task */ void ble_ll_rx_pdu_in(struct os_mbuf *rxpdu); @@ -572,10 +627,6 @@ int ble_ll_set_host_feat(const uint8_t *cmdbuf, uint8_t len); /* Read set of states supported by the Link Layer */ uint64_t ble_ll_read_supp_states(void); -/* Check if octets and time are valid. Returns 0 if not valid */ -int ble_ll_chk_txrx_octets(uint16_t octets); -int ble_ll_chk_txrx_time(uint16_t time); - /* Random numbers */ int ble_ll_rand_init(void); void ble_ll_rand_sample(uint8_t rnum); @@ -593,13 +644,6 @@ ble_ll_get_addr_type(uint8_t txrxflag) return BLE_HCI_ADV_OWN_ADDR_PUBLIC; } -/* Convert usecs to ticks and round up to nearest tick */ -static inline uint32_t -ble_ll_usecs_to_ticks_round_up(uint32_t usecs) -{ - return os_cputime_usecs_to_ticks(usecs + 30); -} - #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) /* LTK 0x4C68384139F574D836BCF34E9DFB01BF */ extern const uint8_t g_bletest_LTK[]; diff --git a/nimble/controller/include/controller/ble_ll_adv.h b/nimble/controller/include/controller/ble_ll_adv.h index 4afaadd002..6290c9f456 100644 --- a/nimble/controller/include/controller/ble_ll_adv.h +++ b/nimble/controller/include/controller/ble_ll_adv.h @@ -168,7 +168,7 @@ int ble_ll_adv_can_chg_whitelist(void); * Called when an advertising event has been removed from the scheduler * without being run. */ -void ble_ll_adv_event_rmvd_from_sched(struct ble_ll_adv_sm *advsm); +void ble_ll_adv_preempted(struct ble_ll_adv_sm *advsm); /* * Called when a periodic event has been removed from the scheduler @@ -199,6 +199,28 @@ int ble_ll_adv_periodic_enable(const uint8_t *cmdbuf, uint8_t len); int ble_ll_adv_periodic_set_info_transfer(const uint8_t *cmdbuf, uint8_t len, uint8_t *rspbuf, uint8_t *rsplen); +/* Get advertising instance with periodic advertising configured */ +struct ble_ll_adv_sm *ble_ll_adv_sync_get(uint8_t handle); +int ble_ll_adv_padv_event_start_get(struct ble_ll_adv_sm *advsm, + uint32_t *event_start, + uint8_t *event_start_rem_us); + +#if MYNEWT_VAL(BLE_LL_ISO_BROADCASTER) +struct ble_ll_iso_big; + +/* Add BIG to periodic advertising instance */ +int ble_ll_adv_sync_big_add(struct ble_ll_adv_sm *advsm, + struct ble_ll_iso_big *big); +/* Remove BIG from periodic advertising instance */ +int ble_ll_adv_sync_big_remove(struct ble_ll_adv_sm *advsm, + struct ble_ll_iso_big *big); +#endif /* BLE_LL_ISO_BROADCASTER */ + +#if MYNEWT_VAL(BLE_VERSION) >= 54 +int ble_ll_adv_ext_set_param_v2(const uint8_t *cmdbuf, uint8_t len, + uint8_t *rspbuf, uint8_t *rsplen); +#endif + /* Called to notify adv code about RPA rotation */ void ble_ll_adv_rpa_timeout(void); diff --git a/nimble/controller/include/controller/ble_ll_conn.h b/nimble/controller/include/controller/ble_ll_conn.h index d7db6878a1..90f013fbe1 100644 --- a/nimble/controller/include/controller/ble_ll_conn.h +++ b/nimble/controller/include/controller/ble_ll_conn.h @@ -24,6 +24,7 @@ #include "nimble/ble.h" #include "nimble/hci_common.h" #include "nimble/nimble_npl.h" +#include "controller/ble_ll.h" #include "controller/ble_ll_sched.h" #include "controller/ble_ll_ctrl.h" #include "controller/ble_phy.h" @@ -34,27 +35,19 @@ extern "C" { /* Roles */ #define BLE_LL_CONN_ROLE_NONE (0) -#define BLE_LL_CONN_ROLE_MASTER (1) -#define BLE_LL_CONN_ROLE_SLAVE (2) + +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) +#define BLE_LL_CONN_ROLE_CENTRAL (1) +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) +#define BLE_LL_CONN_ROLE_PERIPHERAL (2) +#endif /* Connection states */ #define BLE_LL_CONN_STATE_IDLE (0) #define BLE_LL_CONN_STATE_CREATED (1) #define BLE_LL_CONN_STATE_ESTABLISHED (2) -/* Channel map size */ -#define BLE_LL_CONN_CHMAP_LEN (5) - -/* Definitions for source clock accuracy */ -#define BLE_MASTER_SCA_251_500_PPM (0) -#define BLE_MASTER_SCA_151_250_PPM (1) -#define BLE_MASTER_SCA_101_150_PPM (2) -#define BLE_MASTER_SCA_76_100_PPM (3) -#define BLE_MASTER_SCA_51_75_PPM (4) -#define BLE_MASTER_SCA_31_50_PPM (5) -#define BLE_MASTER_SCA_21_30_PPM (6) -#define BLE_MASTER_SCA_0_20_PPM (7) - /* Definition for RSSI when the RSSI is unknown */ #define BLE_LL_CONN_UNKNOWN_RSSI (127) @@ -105,41 +98,47 @@ struct ble_ll_conn_enc_data #endif /* Connection state machine flags. */ -union ble_ll_conn_sm_flags { - struct { - uint32_t pkt_rxd:1; - uint32_t terminate_ind_txd:1; - uint32_t terminate_ind_rxd:1; - uint32_t terminate_ind_rxd_acked:1; - uint32_t allow_slave_latency:1; - uint32_t slave_set_last_anchor:1; - uint32_t awaiting_host_reply:1; - uint32_t terminate_started:1; - uint32_t conn_update_sched:1; - uint32_t host_expects_upd_event:1; - uint32_t version_ind_sent:1; - uint32_t rxd_version_ind:1; - uint32_t chanmap_update_scheduled:1; - uint32_t conn_empty_pdu_txd:1; - uint32_t last_txd_md:1; - uint32_t conn_req_txd:1; - uint32_t send_ltk_req:1; - uint32_t encrypted:1; - uint32_t encrypt_chg_sent:1; - uint32_t le_ping_supp:1; - uint32_t csa2_supp:1; - uint32_t host_phy_update: 1; - uint32_t phy_update_sched: 1; - uint32_t ctrlr_phy_update: 1; - uint32_t phy_update_event: 1; - uint32_t peer_phy_update: 1; /* XXX:combine with ctrlr udpate bit? */ - uint32_t aux_conn_req: 1; - uint32_t rxd_features:1; - uint32_t pending_hci_rd_features:1; - uint32_t pending_initiate_dle:1; - } cfbit; - uint32_t conn_flags; -} __attribute__((packed)); +struct ble_ll_conn_sm_flags { + uint32_t pkt_rxd : 1; + uint32_t last_txd_md : 1; + uint32_t empty_pdu_txd : 1; + uint32_t periph_use_latency : 1; + uint32_t periph_set_last_anchor : 1; + uint32_t csa2 : 1; + uint32_t encrypted : 1; + uint32_t encrypt_ltk_req : 1; + uint32_t encrypt_event_sent : 1; + uint32_t encrypt_paused : 1; + uint32_t pending_encrypt_restart : 1; + uint32_t version_ind_txd : 1; + uint32_t version_ind_rxd : 1; + uint32_t features_rxd : 1; + uint32_t features_host_req : 1; + uint32_t terminate_started : 1; + uint32_t terminate_ind_txd : 1; + uint32_t terminate_ind_rxd : 1; + uint32_t terminate_ind_rxd_acked : 1; + uint32_t conn_update_sched : 1; + uint32_t conn_update_use_cp : 1; + uint32_t conn_update_host_initd : 1; + uint32_t conn_update_host_w4reply : 1; + uint32_t conn_update_host_w4event : 1; + uint32_t chanmap_update_sched : 1; + uint32_t phy_update_sched : 1; + uint32_t phy_update_self_initiated : 1; + uint32_t phy_update_peer_initiated : 1; + uint32_t phy_update_host_initiated : 1; + uint32_t phy_update_host_w4event : 1; + uint32_t le_ping_supp : 1; +#if MYNEWT_VAL(BLE_LL_CONN_INIT_AUTO_DLE) + uint32_t pending_initiate_dle : 1; +#endif +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE) + uint8_t subrate_trans : 1; + uint8_t subrate_ind_txd : 1; + uint8_t subrate_host_req : 1; +#endif +}; /** * Structure used for PHY data inside a connection. @@ -167,11 +166,11 @@ struct ble_ll_conn_phy_data uint32_t cur_rx_phy: 2; uint32_t new_tx_phy: 2; uint32_t new_rx_phy: 2; - uint32_t host_pref_tx_phys_mask: 3; - uint32_t host_pref_rx_phys_mask: 3; - uint32_t req_pref_tx_phys_mask: 3; - uint32_t req_pref_rx_phys_mask: 3; - uint32_t phy_options: 2; + uint32_t pref_mask_tx: 3; + uint32_t pref_mask_rx: 3; + uint32_t pref_mask_tx_req: 3; + uint32_t pref_mask_rx_req: 3; + uint32_t pref_opts: 2; } __attribute__((packed)); #define CONN_CUR_TX_PHY_MASK(csm) (1 << ((csm)->phy_data.cur_tx_phy - 1)) @@ -188,33 +187,27 @@ struct hci_conn_update uint16_t max_ce_len; }; -struct hci_ext_conn_params -{ - uint16_t scan_itvl; - uint16_t scan_window; - uint16_t conn_itvl_min; - uint16_t conn_itvl_max; - uint16_t conn_latency; - uint16_t supervision_timeout; - uint16_t min_ce_len; - uint16_t max_ce_len; +struct ble_ll_conn_subrate_params { + uint16_t subrate_factor; + uint16_t subrate_base_event; + uint16_t periph_latency; + uint16_t cont_num; + uint16_t supervision_tmo; }; -struct hci_ext_create_conn -{ - uint8_t filter_policy; - uint8_t own_addr_type; - uint8_t peer_addr_type; - uint8_t peer_addr[BLE_DEV_ADDR_LEN]; - uint8_t init_phy_mask; - struct hci_ext_conn_params params[3]; +struct ble_ll_conn_subrate_req_params { + uint16_t subrate_min; + uint16_t subrate_max; + uint16_t max_latency; + uint16_t cont_num; + uint16_t supervision_tmo; }; /* Connection state machine */ struct ble_ll_conn_sm { /* Connection state machine flags */ - union ble_ll_conn_sm_flags csmflags; + struct ble_ll_conn_sm_flags flags; /* Current connection handle, state and role */ uint16_t conn_handle; @@ -224,9 +217,6 @@ struct ble_ll_conn_sm /* RSSI */ int8_t conn_rssi; - /* For privacy */ - int8_t rpa_index; - /* Connection data length management */ uint8_t max_tx_octets; uint8_t max_rx_octets; @@ -240,30 +230,27 @@ struct ble_ll_conn_sm uint16_t rem_max_rx_time; uint16_t eff_max_tx_time; uint16_t eff_max_rx_time; - uint8_t max_tx_octets_phy_mode[BLE_PHY_NUM_MODE]; + uint16_t ota_max_rx_time; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) uint16_t host_req_max_tx_time; + uint16_t host_req_max_rx_time; #endif -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) +#if MYNEWT_VAL(BLE_LL_PHY) struct ble_ll_conn_phy_data phy_data; uint16_t phy_instant; uint8_t phy_tx_transition; #endif /* Used to calculate data channel index for connection */ - uint8_t chanmap[BLE_LL_CONN_CHMAP_LEN]; - uint8_t req_chanmap[BLE_LL_CONN_CHMAP_LEN]; + uint8_t chan_map[BLE_LL_CHAN_MAP_LEN]; + uint8_t req_chanmap[BLE_LL_CHAN_MAP_LEN]; uint16_t chanmap_instant; uint16_t channel_id; /* TODO could be union with hop and last chan used */ uint8_t hop_inc; uint8_t data_chan_index; uint8_t last_unmapped_chan; - uint8_t num_used_chans; - -#if MYNEWT_VAL(BLE_LL_STRICT_CONN_SCHEDULING) - uint8_t period_occ_mask; /* mask: period 0 = 0x01, period 3 = 0x08 */ -#endif + uint8_t chan_map_used; /* Ack/Flow Control */ uint8_t tx_seqnum; /* note: can be 1 bit */ @@ -280,7 +267,7 @@ struct ble_ll_conn_sm /* connection event mgmt */ uint8_t reject_reason; uint8_t host_reply_opcode; - uint8_t master_sca; + uint8_t central_sca; uint8_t tx_win_size; uint8_t cur_ctrl_proc; uint8_t disconnect_reason; @@ -304,20 +291,38 @@ struct ble_ll_conn_sm /* Connection timing */ uint16_t conn_itvl; - uint16_t slave_latency; uint16_t supervision_tmo; - uint16_t min_ce_len; - uint16_t max_ce_len; + uint32_t max_ce_len_ticks; uint16_t tx_win_off; uint32_t anchor_point; uint8_t anchor_point_usecs; /* XXX: can this be uint8_t ?*/ uint8_t conn_itvl_usecs; uint32_t conn_itvl_ticks; uint32_t last_anchor_point; /* Slave only */ - uint32_t slave_cur_tx_win_usecs; - uint32_t slave_cur_window_widening; + uint32_t periph_cur_tx_win_usecs; + uint32_t periph_cur_window_widening; uint32_t last_rxd_pdu_cputime; /* Used exclusively for supervision timer */ + uint16_t periph_latency; +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE) + uint16_t acc_subrate_min; + uint16_t acc_subrate_max; + uint16_t acc_max_latency; + uint16_t acc_cont_num; + uint16_t acc_supervision_tmo; + + uint16_t subrate_base_event; + uint16_t subrate_factor; + uint16_t cont_num; + uint16_t cont_num_left; + uint8_t has_nonempty_pdu; + + union { + struct ble_ll_conn_subrate_params subrate_trans; + struct ble_ll_conn_subrate_req_params subrate_req; + }; +#endif + /* * Used to mark that identity address was used as InitA */ @@ -327,6 +332,9 @@ struct ble_ll_conn_sm uint8_t own_addr_type; uint8_t peer_addr_type; uint8_t peer_addr[BLE_DEV_ADDR_LEN]; +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + uint8_t peer_addr_resolved; +#endif /* * XXX: TODO. Could save memory. Have single event at LL and put these @@ -338,6 +346,8 @@ struct ble_ll_conn_sm /* Packet transmit queue */ struct os_mbuf *cur_tx_pdu; STAILQ_HEAD(conn_txq_head, os_mbuf_pkthdr) conn_txq; + uint8_t conn_txq_num_data_pkt; + uint8_t conn_txq_num_zero_pkt; /* List entry for active/free connection pools */ union { @@ -374,57 +384,123 @@ struct ble_ll_conn_sm /* For connection update procedure */ struct ble_ll_conn_upd_req conn_update_req; + uint16_t conn_update_anchor_offset_req; /* XXX: for now, just store them all */ struct ble_ll_conn_params conn_cp; - struct ble_ll_scan_sm *scansm; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - struct hci_ext_create_conn initial_params; -#endif - #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER) uint8_t sync_transfer_mode; uint16_t sync_transfer_skip; uint32_t sync_transfer_sync_timeout; #endif -}; -/* Flags */ -#define CONN_F_UPDATE_SCHED(csm) ((csm)->csmflags.cfbit.conn_update_sched) -#define CONN_F_EMPTY_PDU_TXD(csm) ((csm)->csmflags.cfbit.conn_empty_pdu_txd) -#define CONN_F_LAST_TXD_MD(csm) ((csm)->csmflags.cfbit.last_txd_md) -#define CONN_F_CONN_REQ_TXD(csm) ((csm)->csmflags.cfbit.conn_req_txd) -#define CONN_F_ENCRYPTED(csm) ((csm)->csmflags.cfbit.encrypted) -#define CONN_F_ENC_CHANGE_SENT(csm) ((csm)->csmflags.cfbit.encrypt_chg_sent) -#define CONN_F_LE_PING_SUPP(csm) ((csm)->csmflags.cfbit.le_ping_supp) -#define CONN_F_TERMINATE_STARTED(csm) ((csm)->csmflags.cfbit.terminate_started) -#define CONN_F_CSA2_SUPP(csm) ((csm)->csmflags.cfbit.csa2_supp) -#define CONN_F_HOST_PHY_UPDATE(csm) ((csm)->csmflags.cfbit.host_phy_update) -#define CONN_F_PHY_UPDATE_SCHED(csm) ((csm)->csmflags.cfbit.phy_update_sched) -#define CONN_F_CTRLR_PHY_UPDATE(csm) ((csm)->csmflags.cfbit.ctrlr_phy_update) -#define CONN_F_PHY_UPDATE_EVENT(csm) ((csm)->csmflags.cfbit.phy_update_event) -#define CONN_F_PEER_PHY_UPDATE(csm) ((csm)->csmflags.cfbit.peer_phy_update) -#define CONN_F_AUX_CONN_REQ(csm) ((csm)->csmflags.cfbit.aux_conn_req) +#if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) + SLIST_ENTRY(ble_ll_conn_sm) css_sle; + uint16_t css_slot_idx; + uint16_t css_slot_idx_pending; + uint8_t css_period_idx; +#endif +}; /* Role */ -#define CONN_IS_MASTER(csm) (csm->conn_role == BLE_LL_CONN_ROLE_MASTER) -#define CONN_IS_SLAVE(csm) (csm->conn_role == BLE_LL_CONN_ROLE_SLAVE) +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) +#define CONN_IS_CENTRAL(csm) (csm->conn_role == BLE_LL_CONN_ROLE_CENTRAL) +#else +#define CONN_IS_CENTRAL(csm) (false) +#endif + +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) +#define CONN_IS_PERIPHERAL(csm) (csm->conn_role == BLE_LL_CONN_ROLE_PERIPHERAL) +#else +#define CONN_IS_PERIPHERAL(csm) (false) +#endif + +static inline int +ble_ll_conn_rem_feature_check(struct ble_ll_conn_sm *connsm, uint64_t feature) +{ + uint8_t byte_idx; + + /* 8 lsb are conn features */ + feature >>= 8; + + byte_idx = __builtin_ctzll(feature) / 8; + return connsm->remote_features[byte_idx] & (feature >> (byte_idx * 8)); +} -/* - * Given a handle, returns an active connection state machine (or NULL if the - * handle does not exist - * - */ -struct ble_ll_conn_sm *ble_ll_conn_find_active_conn(uint16_t handle); + +static inline void +ble_ll_conn_rem_feature_add(struct ble_ll_conn_sm *connsm, uint64_t feature) +{ + uint8_t byte_idx; + + /* 8 lsb are conn features */ + feature >>= 8; + + byte_idx = __builtin_ctzll(feature) / 8; + connsm->remote_features[byte_idx] |= (feature >> (byte_idx * 8)); +} + + +struct ble_ll_conn_sm *ble_ll_conn_find_by_handle(uint16_t handle); +struct ble_ll_conn_sm *ble_ll_conn_find_by_peer_addr(const uint8_t* addr, + uint8_t addr_type); + +/* Perform channel map update on all connections (applies to central role) */ +void ble_ll_conn_chan_map_update(void); /* required for unit testing */ uint8_t ble_ll_conn_calc_dci(struct ble_ll_conn_sm *conn, uint16_t latency); -/* used to get anchor point for connection event specified */ -void ble_ll_conn_get_anchor(struct ble_ll_conn_sm *connsm, uint16_t conn_event, +/* get current event counter and anchor point */ +void ble_ll_conn_anchor_get(struct ble_ll_conn_sm *connsm, uint16_t *event_cntr, uint32_t *anchor, uint8_t *anchor_usecs); +/* get anchor point for specified connection event */ +void ble_ll_conn_anchor_event_cntr_get(struct ble_ll_conn_sm *connsm, + uint16_t event_cntr, uint32_t *anchor, + uint8_t *anchor_usecs); + +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) +int ble_ll_conn_move_anchor(struct ble_ll_conn_sm *connsm, uint16_t offset); +#endif + +struct ble_ll_scan_addr_data; +struct ble_ll_scan_pdu_data; + +uint8_t ble_ll_conn_tx_connect_ind_pducb(uint8_t *dptr, void *pducb_arg, + uint8_t *hdr_byte); +void ble_ll_conn_prepare_connect_ind(struct ble_ll_conn_sm *connsm, + struct ble_ll_scan_pdu_data *pdu_data, + struct ble_ll_scan_addr_data *addrd, + uint8_t channel); + +/* Send CONNECT_IND/AUX_CONNECT_REQ */ +int ble_ll_conn_send_connect_req(struct os_mbuf *rxpdu, + struct ble_ll_scan_addr_data *addrd, + uint8_t ext); +/* Cancel connection after AUX_CONNECT_REQ was sent */ +void ble_ll_conn_send_connect_req_cancel(void); +/* Signal connection created via CONNECT_IND */ +void ble_ll_conn_created_on_legacy(struct os_mbuf *rxpdu, + struct ble_ll_scan_addr_data *addrd, + uint8_t *targeta); +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) +/* Signal connection created via AUX_CONNECT_REQ */ +void ble_ll_conn_created_on_aux(struct os_mbuf *rxpdu, + struct ble_ll_scan_addr_data *addrd, + uint8_t *targeta); +#endif + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE) +int ble_ll_conn_subrate_req_hci(struct ble_ll_conn_sm *connsm, + struct ble_ll_conn_subrate_req_params *srp); +int ble_ll_conn_subrate_req_llcp(struct ble_ll_conn_sm *connsm, + struct ble_ll_conn_subrate_req_params *srp); +void ble_ll_conn_subrate_set(struct ble_ll_conn_sm *connsm, + struct ble_ll_conn_subrate_params *sp); +#endif + #ifdef __cplusplus } #endif diff --git a/nimble/controller/include/controller/ble_ll_crypto.h b/nimble/controller/include/controller/ble_ll_crypto.h new file mode 100644 index 0000000000..4514b0b107 --- /dev/null +++ b/nimble/controller/include/controller/ble_ll_crypto.h @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_BLE_LL_CRYPTO_ +#define H_BLE_LL_CRYPTO_ + +#ifdef __cplusplus +extern "C" { +#endif + +int +ble_ll_crypto_cmac(const uint8_t *key, const uint8_t *in, int len, + uint8_t *out); + +static inline int +ble_ll_crypto_h6(const uint8_t *w, const uint8_t *key_id, uint8_t *out) +{ + return ble_ll_crypto_cmac(w, key_id, 4, out); +} + +static inline int +ble_ll_crypto_h7(const uint8_t *salt, const uint8_t *w, uint8_t *out) +{ + return ble_ll_crypto_cmac(salt, w, 16, out); +} + +int ble_ll_crypto_h8(const uint8_t *k, const uint8_t *s, const uint8_t *key_id, + uint8_t *out); + +#ifdef __cplusplus +} +#endif + +#endif /* H_BLE_LL_CRYPTO_ */ diff --git a/nimble/controller/include/controller/ble_ll_cs.h b/nimble/controller/include/controller/ble_ll_cs.h new file mode 100644 index 0000000000..fb7cb4a59b --- /dev/null +++ b/nimble/controller/include/controller/ble_ll_cs.h @@ -0,0 +1,51 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* All Channel Sounding APIs are experimental and subject to change at any time */ + +#ifndef H_BLE_LL_CS +#define H_BLE_LL_CS + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* HCI handlers */ +int ble_ll_cs_hci_rd_loc_supp_cap(uint8_t *rspbuf, uint8_t *rsplen); +int ble_ll_cs_hci_rd_rem_supp_cap(const uint8_t *cmdbuf, uint8_t cmdlen); +int ble_ll_cs_hci_wr_cached_rem_supp_cap(const uint8_t *cmdbuf, uint8_t cmdlen, uint8_t *rspbuf, uint8_t *rsplen); +int ble_ll_cs_hci_sec_enable(const uint8_t *cmdbuf, uint8_t cmdlen); +int ble_ll_cs_hci_set_def_settings(const uint8_t *cmdbuf, uint8_t cmdlen, uint8_t *rspbuf, uint8_t *rsplen); +int ble_ll_cs_hci_rd_rem_fae(const uint8_t *cmdbuf, uint8_t cmdlen); +int ble_ll_cs_hci_wr_cached_rem_fae(const uint8_t *cmdbuf, uint8_t cmdlen, uint8_t *rspbuf, uint8_t *rsplen); +int ble_ll_cs_hci_create_config(const uint8_t *cmdbuf, uint8_t cmdlen); +int ble_ll_cs_hci_remove_config(const uint8_t *cmdbuf, uint8_t cmdlen); +int ble_ll_cs_hci_set_chan_class(const uint8_t *cmdbuf, uint8_t cmdlen); +int ble_ll_cs_hci_set_proc_params(const uint8_t *cmdbuf, uint8_t cmdlen, uint8_t *rspbuf, uint8_t *rsplen); +int ble_ll_cs_hci_proc_enable(const uint8_t *cmdbuf, uint8_t cmdlen); +int ble_ll_cs_hci_test(const uint8_t *cmdbuf, uint8_t cmdlen, uint8_t *rspbuf, uint8_t *rsplen); +int ble_ll_cs_hci_test_end(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/nimble/controller/include/controller/ble_ll_ctrl.h b/nimble/controller/include/controller/ble_ll_ctrl.h index 15a45b2a08..918cc977b8 100644 --- a/nimble/controller/include/controller/ble_ll_ctrl.h +++ b/nimble/controller/include/controller/ble_ll_ctrl.h @@ -41,7 +41,9 @@ extern "C" { #define BLE_LL_CTRL_PROC_PHY_UPDATE (9) #define BLE_LL_CTRL_PROC_SCA_UPDATE (10) #define BLE_LL_CTRL_PROC_CIS_CREATE (11) -#define BLE_LL_CTRL_PROC_NUM (12) +#define BLE_LL_CTRL_PROC_SUBRATE_REQ (12) +#define BLE_LL_CTRL_PROC_SUBRATE_UPDATE (13) +#define BLE_LL_CTRL_PROC_NUM (14) #define BLE_LL_CTRL_PROC_IDLE (255) /* Checks if a particular control procedure is running */ @@ -70,7 +72,7 @@ extern "C" { #define BLE_LL_CTRL_PAUSE_ENC_RSP (0x0B) #define BLE_LL_CTRL_VERSION_IND (0x0C) #define BLE_LL_CTRL_REJECT_IND (0x0D) -#define BLE_LL_CTRL_SLAVE_FEATURE_REQ (0x0E) +#define BLE_LL_CTRL_PERIPH_FEATURE_REQ (0x0E) #define BLE_LL_CTRL_CONN_PARM_REQ (0x0F) #define BLE_LL_CTRL_CONN_PARM_RSP (0x10) #define BLE_LL_CTRL_REJECT_IND_EXT (0x11) @@ -91,9 +93,16 @@ extern "C" { #define BLE_LL_CTRL_CIS_RSP (0x20) #define BLE_LL_CTRL_CIS_IND (0x21) #define BLE_LL_CTRL_CIS_TERMINATE_IND (0x22) +#define BLE_LL_CTRL_POWER_CONTROL_REQ (0x23) +#define BLE_LL_CTRL_POWER_CONTROL_RSP (0x24) +#define BLE_LL_CTRL_POWER_CHANGE_IND (0x25) +#define BLE_LL_CTRL_SUBRATE_REQ (0x26) +#define BLE_LL_CTRL_SUBRATE_IND (0x27) +#define BLE_LL_CTRL_CHAN_REPORTING_IND (0x28) +#define BLE_LL_CTRL_CHAN_STATUS_IND (0x29) /* Maximum opcode value */ -#define BLE_LL_CTRL_OPCODES (BLE_LL_CTRL_CIS_TERMINATE_IND + 1) +#define BLE_LL_CTRL_OPCODES (BLE_LL_CTRL_CHAN_STATUS_IND + 1) extern const uint8_t g_ble_ll_ctrl_pkt_lengths[BLE_LL_CTRL_OPCODES]; @@ -198,7 +207,7 @@ struct ble_ll_version_ind * LL control slave feature req * -> 8 bytes of data containing features supported by device. */ -#define BLE_LL_CTRL_SLAVE_FEATURE_REQ_LEN (8) +#define BLE_LL_CTRL_PERIPH_FEATURE_REQ_LEN (8) /* LL control connection param req and connection param rsp */ struct ble_ll_conn_params @@ -275,6 +284,14 @@ struct ble_ll_len_req #define BLE_LL_CTRL_CIS_IND_LEN (15) #define BLE_LL_CTRL_CIS_TERMINATE_LEN (3) +#define BLE_LL_CTRL_POWER_CONTROL_REQ_LEN (3) +#define BLE_LL_CTRL_POWER_CONTROL_RSP_LEN (4) +#define BLE_LL_CTRL_POWER_CHANGE_IND_LEN (4) +#define BLE_LL_CTRL_SUBRATE_REQ_LEN (10) +#define BLE_LL_CTRL_SUBRATE_IND_LEN (10) +#define BLE_LL_CTRL_CHAN_REPORTING_IND_LEN (3) +#define BLE_LL_CTRL_CHAN_STATUS_IND_LEN (10) + /* API */ struct ble_ll_conn_sm; void ble_ll_ctrl_proc_start(struct ble_ll_conn_sm *connsm, int ctrl_proc); @@ -289,8 +306,10 @@ uint8_t ble_ll_ctrl_conn_param_reply(struct ble_ll_conn_sm *connsm, int ble_ll_ctrl_reject_ind_send(struct ble_ll_conn_sm *connsm, uint8_t rej_opcode, uint8_t err); int ble_ll_ctrl_start_enc_send(struct ble_ll_conn_sm *connsm); -int ble_ll_ctrl_enc_allowed_pdu_rx(struct os_mbuf *rxpdu); +int ble_ll_ctrl_enc_allowed_pdu_rx(struct ble_ll_conn_sm *connsm, + struct os_mbuf *rxpdu); int ble_ll_ctrl_enc_allowed_pdu_tx(struct os_mbuf_pkthdr *pkthdr); +int ble_ll_ctrl_tx_start(struct ble_ll_conn_sm *connsm, struct os_mbuf *txpdu); int ble_ll_ctrl_tx_done(struct os_mbuf *txpdu, struct ble_ll_conn_sm *connsm); int ble_ll_ctrl_is_start_enc_rsp(struct os_mbuf *txpdu); @@ -314,8 +333,11 @@ void ble_ll_hci_ev_send_adv_set_terminated(uint8_t status, uint8_t adv_handle, int ble_ll_hci_ev_phy_update(struct ble_ll_conn_sm *connsm, uint8_t status); void ble_ll_calc_session_key(struct ble_ll_conn_sm *connsm); void ble_ll_ctrl_phy_update_proc_complete(struct ble_ll_conn_sm *connsm); -void ble_ll_ctrl_initiate_dle(struct ble_ll_conn_sm *connsm); -void ble_ll_hci_ev_send_vendor_err(const char *file, uint32_t line); +void ble_ll_ctrl_initiate_dle(struct ble_ll_conn_sm *connsm, bool initial); +void ble_ll_hci_ev_send_vs_assert(const char *file, uint32_t line); +void ble_ll_hci_ev_send_vs_printf(uint8_t id, const char *fmt, ...); +void ble_ll_hci_ev_send_vs_llcp_trace(uint8_t type, uint16_t handle, uint16_t count, + void *pdu, size_t length); uint8_t ble_ll_ctrl_phy_tx_transition_get(uint8_t phy_mask); uint8_t ble_ll_ctrl_phy_from_phy_mask(uint8_t phy_mask); @@ -325,6 +347,15 @@ void ble_ll_hci_ev_sca_update(struct ble_ll_conn_sm *connsm, uint8_t status, uint8_t peer_sca); #endif +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE) +void ble_ll_hci_ev_subrate_change(struct ble_ll_conn_sm *connsm, uint8_t status); +#endif + +#if MYNEWT_VAL(BLE_LL_HCI_VS_CONN_STRICT_SCHED) +void ble_ll_hci_ev_send_vs_css_slot_changed(uint16_t conn_handle, + uint16_t slot_idx); +#endif + #ifdef __cplusplus } #endif diff --git a/nimble/controller/include/controller/ble_ll_ext.h b/nimble/controller/include/controller/ble_ll_ext.h new file mode 100644 index 0000000000..5b3bb3767f --- /dev/null +++ b/nimble/controller/include/controller/ble_ll_ext.h @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_BLE_LL_EXT_ +#define H_BLE_LL_EXT_ + +#ifdef __cplusplus +extern "C" { +#endif + +#if MYNEWT_VAL(BLE_LL_EXT) + +/* Quickstart guide: + * - create scheduling item with sched_type set to BLE_LL_SCHED_EXTERNAL + * - use sched_ext_type to differentiate between different types of custom items + * - insert into scheduler using ble_ll_sched_insert() + * - set LL state to BLE_LL_STATE_EXTERNAL when item is being executed + * - set LL state back to BLE_LL_STATE_IDLE when item is done + */ + +struct ble_ll_sched_item; + +/* Called when LL package is initialized (before ll_task is started) */ +void ble_ll_ext_init(void); +/* Called when LL is reset (i.e. HCI_Reset) */ +void ble_ll_ext_reset(void); +/* Called when LL is in "external" state and PHY starts to receive a PDU */ +int ble_ll_ext_rx_isr_start(uint8_t pdu_type, struct ble_mbuf_hdr *rxhdr); +/* Called when LL is in "external" state and PHY finished to receive a PDU */ +int ble_ll_ext_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr); +/* Called when PDU received in "external" state reaches LL */ +void ble_ll_ext_rx_pkt_in(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *rxhdr); +/* Called when LL is in "external" state and was preempted */ +void ble_ll_ext_halt(void); +/* Called when LL is in "external" state and PHY failed to receive a PDU */ +void ble_ll_ext_wfr_timer_exp(void); +/* Called when an "external" scheduling item was removed from scheduler queue */ +void ble_ll_ext_sched_removed(struct ble_ll_sched_item *sch); + +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* H_BLE_LL_EXT_ */ diff --git a/nimble/controller/include/controller/ble_ll_hci.h b/nimble/controller/include/controller/ble_ll_hci.h index 6a9e48e537..6fef1f7b16 100644 --- a/nimble/controller/include/controller/ble_ll_hci.h +++ b/nimble/controller/include/controller/ble_ll_hci.h @@ -25,13 +25,10 @@ extern "C" { #endif #include "nimble/hci_common.h" - -/* For supported commands */ -#define BLE_LL_SUPP_CMD_LEN (45) -extern const uint8_t g_ble_ll_supp_cmds[BLE_LL_SUPP_CMD_LEN]; +#include "nimble/transport.h" /* The largest event the controller will send. */ -#define BLE_LL_MAX_EVT_LEN MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE) +#define BLE_LL_MAX_EVT_LEN MYNEWT_VAL(BLE_TRANSPORT_EVT_SIZE) /* * This determines the number of outstanding commands allowed from the @@ -41,11 +38,29 @@ extern const uint8_t g_ble_ll_supp_cmds[BLE_LL_SUPP_CMD_LEN]; */ #define BLE_LL_CFG_NUM_HCI_CMD_PKTS (1) -typedef void (*ble_ll_hci_post_cmd_complete_cb)(void); +typedef void (*ble_ll_hci_post_cmd_complete_cb)(void *user_data); + +#if MYNEWT_VAL(BLE_LL_HCI_VS) +typedef int (* ble_ll_hci_vs_cb_t)(uint16_t ocf, + const uint8_t *cmdbuf, uint8_t cmdlen, + uint8_t *rspbuf, uint8_t *rsplen); + +#define BLE_LL_HCI_VS_CMD(_ocf, _cb) { .ocf = (_ocf), .cb = (_cb) } + +struct ble_ll_hci_vs_cmd { + uint16_t ocf; + ble_ll_hci_vs_cb_t cb; + SLIST_ENTRY(ble_ll_hci_vs_cmd) link; +}; +#endif /* Initialize LL HCI */ void ble_ll_hci_init(void); +int ble_ll_hci_cmd_rx(uint8_t *cmdbuf); +int ble_ll_hci_acl_rx(struct os_mbuf *om); +int ble_ll_hci_iso_rx(struct os_mbuf *om); + /* Used to determine if the LE event is enabled/disabled */ bool ble_ll_hci_is_le_event_enabled(unsigned int subev); @@ -65,8 +80,17 @@ int ble_ll_hci_chk_phy_masks(uint8_t all_phys, uint8_t tx_phys, uint8_t rx_phys, /* Returns true if Extended Advertising HCI commands are in use */ bool ble_ll_hci_adv_mode_ext(void); -/* Get TX power compensation rounded to integer dB */ -int8_t ble_ll_get_tx_pwr_compensation(void); +/* Check if max octets/time are within allowed range */ +int ble_ll_hci_check_dle(uint16_t max_octets, uint16_t max_time); + +void ble_ll_hci_supp_cmd_get(uint8_t *buf); + +/* Used to set post HCI command hook */ +void ble_ll_hci_post_cmd_cb_set(ble_ll_hci_post_cmd_complete_cb cb, void *user_data); + +#if MYNEWT_VAL(BLE_LL_HCI_VS) +void ble_ll_hci_vs_register(struct ble_ll_hci_vs_cmd *cmds, uint32_t num_cmds); +#endif #ifdef __cplusplus } diff --git a/nimble/controller/include/controller/ble_ll_iso.h b/nimble/controller/include/controller/ble_ll_iso.h index 2944b07476..8d6cbde562 100644 --- a/nimble/controller/include/controller/ble_ll_iso.h +++ b/nimble/controller/include/controller/ble_ll_iso.h @@ -21,16 +21,53 @@ #define H_BLE_LL_ISO #include +#include #ifdef __cplusplus extern "C" { #endif -int ble_ll_iso_read_tx_sync(const uint8_t *cmdbuf, uint8_t len); +struct ble_ll_iso_data_path { + uint8_t data_path_id; + uint8_t enabled : 1; +}; +struct ble_ll_iso_test_mode { + struct { + uint32_t rand; + uint8_t payload_type; + uint8_t enabled : 1; + } transmit; +}; +struct ble_ll_iso_conn { + /* Connection handle */ + uint16_t handle; + + /* Maximum SDU size */ + uint16_t max_sdu; + + /* ISO Data Path */ + struct ble_ll_iso_data_path data_path; + + /* ISO Test Mode */ + struct ble_ll_iso_test_mode test_mode; + + /* ISOAL Multiplexer */ + struct ble_ll_isoal_mux mux; + + /* HCI SDU Fragment */ + struct os_mbuf *frag; + + /* Number of Completed Packets */ + uint16_t num_completed_pkt; + + STAILQ_ENTRY(ble_ll_iso_conn) iso_conn_q_next; +}; + +/* HCI command handlers */ +int ble_ll_iso_read_tx_sync(const uint8_t *cmdbuf, uint8_t len, uint8_t *rspbuf, uint8_t *rsplen); int ble_ll_iso_set_cig_param(const uint8_t *cmdbuf, uint8_t len, uint8_t *rspbuf, uint8_t *rsplen); int ble_ll_iso_set_cig_param_test(const uint8_t *cmdbuf, uint8_t len, uint8_t *rspbuf, uint8_t *rsplen); int ble_ll_iso_create_cis(const uint8_t *cmdbuf, uint8_t len); -int ble_ll_iso_disconnect_cmd(const struct ble_hci_lc_disconnect_cp *cmd); int ble_ll_iso_remove_cig(const uint8_t *cmdbuf, uint8_t len, uint8_t *rspbuf, uint8_t *rsplen); int ble_ll_iso_accept_cis_req(const uint8_t *cmdbuf, uint8_t len); int ble_ll_iso_reject_cis_req(const uint8_t *cmdbuf, uint8_t len); @@ -39,12 +76,39 @@ int ble_ll_iso_create_big_test(const uint8_t *cmdbuf, uint8_t len); int ble_ll_iso_terminate_big(const uint8_t *cmdbuf, uint8_t len); int ble_ll_iso_big_create_sync(const uint8_t *cmdbuf, uint8_t len); int ble_ll_iso_big_terminate_sync(const uint8_t *cmdbuf, uint8_t len); -int ble_ll_iso_setup_iso_data_path(const uint8_t *cmdbuf, uint8_t len); -int ble_ll_iso_remove_iso_data_path(const uint8_t *cmdbuf, uint8_t len); -int ble_ll_iso_transmit_test(const uint8_t *cmdbuf, uint8_t len); +int ble_ll_iso_setup_iso_data_path(const uint8_t *cmdbuf, uint8_t len, uint8_t *rspbuf, uint8_t *rsplen); +int ble_ll_iso_remove_iso_data_path(const uint8_t *cmdbuf, uint8_t len, uint8_t *rspbuf, uint8_t *rsplen); +int ble_ll_iso_transmit_test(const uint8_t *cmdbuf, uint8_t len, uint8_t *rspbuf, uint8_t *rsplen); int ble_ll_iso_receive_test(const uint8_t *cmdbuf, uint8_t len); int ble_ll_iso_read_counters_test(const uint8_t *cmdbuf, uint8_t len); -int ble_ll_iso_end_test(const uint8_t *cmdbuf, uint8_t len); +int ble_ll_iso_end_test(const uint8_t *cmdbuf, uint8_t len, uint8_t *rspbuf, uint8_t *rsplen); + +void ble_ll_iso_init(void); +void ble_ll_iso_reset(void); + +/* ISO Data handler */ +int ble_ll_iso_data_in(struct os_mbuf *om); + +int ble_ll_iso_pdu_get(struct ble_ll_iso_conn *conn, uint8_t idx, uint32_t pkt_counter, uint8_t *llid, void *dptr); + +struct ble_ll_iso_conn_init_param { + uint32_t iso_interval_us; + uint32_t sdu_interval_us; + uint16_t conn_handle; + uint16_t max_sdu; + uint8_t max_pdu; + uint8_t framing; + uint8_t pte; + uint8_t bn; +}; + +void ble_ll_iso_conn_init(struct ble_ll_iso_conn *conn, struct ble_ll_iso_conn_init_param *param); +void ble_ll_iso_conn_free(struct ble_ll_iso_conn *conn); + +int ble_ll_iso_conn_event_start(struct ble_ll_iso_conn *conn, uint32_t timestamp); +int ble_ll_iso_conn_event_done(struct ble_ll_iso_conn *conn); + +struct ble_ll_iso_conn *ble_ll_iso_conn_find_by_handle(uint16_t conn_handle); #ifdef __cplusplus } diff --git a/nimble/drivers/nrf5340/include/ble/xcvr.h b/nimble/controller/include/controller/ble_ll_iso_big.h similarity index 52% rename from nimble/drivers/nrf5340/include/ble/xcvr.h rename to nimble/controller/include/controller/ble_ll_iso_big.h index df6ef700d3..8576fc5494 100644 --- a/nimble/drivers/nrf5340/include/ble/xcvr.h +++ b/nimble/controller/include/controller/ble_ll_iso_big.h @@ -17,34 +17,38 @@ * under the License. */ -#ifndef H_BLE_XCVR_ -#define H_BLE_XCVR_ +#ifndef H_BLE_LL_ISO_BIG_ +#define H_BLE_LL_ISO_BIG_ #ifdef __cplusplus extern "C" { #endif -#define XCVR_RX_RADIO_RAMPUP_USECS (40) -#define XCVR_TX_RADIO_RAMPUP_USECS (40) +#if MYNEWT_VAL(BLE_LL_ISO_BROADCASTER) -/* - * NOTE: we have to account for the RTC output compare issue. We want it to be - * 5 ticks. - */ -#define XCVR_PROC_DELAY_USECS (153) -#define XCVR_RX_START_DELAY_USECS (XCVR_RX_RADIO_RAMPUP_USECS) -#define XCVR_TX_START_DELAY_USECS (XCVR_TX_RADIO_RAMPUP_USECS) -#define XCVR_TX_SCHED_DELAY_USECS (XCVR_TX_START_DELAY_USECS + XCVR_PROC_DELAY_USECS) -#define XCVR_RX_SCHED_DELAY_USECS (XCVR_RX_START_DELAY_USECS + XCVR_PROC_DELAY_USECS) +struct ble_ll_iso_big; +struct ble_ll_iso_bis; -/* - * Define HW whitelist size. This is the total possible whitelist size; - * not necessarily the size that will be used (may be smaller) - */ -#define BLE_HW_WHITE_LIST_SIZE (8) +int ble_ll_iso_big_biginfo_copy(struct ble_ll_iso_big *big, uint8_t *dptr, + uint32_t base_ticks, uint8_t base_rem_us); +int ble_ll_iso_big_biginfo_len(struct ble_ll_iso_big *big); + +void ble_ll_iso_big_chan_map_update(void); + +void ble_ll_iso_big_halt(void); + +int ble_ll_iso_big_hci_create(const uint8_t *cmdbuf, uint8_t len); +int ble_ll_iso_big_hci_create_test(const uint8_t *cmdbuf, uint8_t len); +int ble_ll_iso_big_hci_terminate(const uint8_t *cmdbuf, uint8_t len); +void ble_ll_iso_big_hci_evt_complete(void); + +void ble_ll_iso_big_init(void); +void ble_ll_iso_big_reset(void); + +#endif /* BLE_LL_ISO_BROADCASTER */ #ifdef __cplusplus } #endif -#endif /* H_BLE_XCVR_ */ +#endif /* H_BLE_LL_ISO_BIG_ */ diff --git a/nimble/controller/include/controller/ble_ll_isoal.h b/nimble/controller/include/controller/ble_ll_isoal.h new file mode 100644 index 0000000000..a590a0f6e7 --- /dev/null +++ b/nimble/controller/include/controller/ble_ll_isoal.h @@ -0,0 +1,98 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_BLE_LL_ISOAL_ +#define H_BLE_LL_ISOAL_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct ble_ll_isoal_mux { +#if MYNEWT_VAL(BLE_LL_ISOAL_MUX_PREFILL) + uint8_t active; +#endif + + /* Max PDU length */ + uint8_t max_pdu; + /* Number of expected SDUs per ISO interval */ + uint8_t sdu_per_interval; + /* Number of expected PDUs per SDU */ + uint8_t pdu_per_sdu; + /* Number of SDUs required to fill complete BIG/CIG event (i.e. with pt) */ + uint8_t sdu_per_event; + /* Number of SDUs available for current event */ + uint8_t sdu_in_event; + + /* Burst Number */ + uint8_t bn; + + STAILQ_HEAD(, os_mbuf_pkthdr) sdu_q; + uint16_t sdu_q_len; + + uint32_t sdu_counter; + + uint32_t event_tx_timestamp; + uint32_t last_tx_timestamp; + uint16_t last_tx_packet_seq_num; + + /* The head SDU Segment is the Continuation of an SDU */ + uint8_t sc : 1; + uint8_t framed : 1; + uint8_t framing_mode : 1; +}; + +#define BLE_LL_ISOAL_SEGHDR(sc, cmplt, len) \ + ((uint16_t)((sc) & 0x01) | (((cmplt) & 0x01) << 1) | ((len) & 0xff) << 8) + +#define BLE_LL_ISOAL_SEGHDR_SC(word) ((word) & 0x01) +#define BLE_LL_ISOAL_SEGHDR_CMPLT(word) ((word >> 1) & 0x01) +#define BLE_LL_ISOAL_SEGHDR_LEN(word) ((word >> 8) & 0xff) + +#define BLE_LL_ISOAL_MUX_IS_FRAMED(framing) \ + ((framing) == BLE_HCI_ISO_FRAMING_FRAMED_SEGMENTABLE || \ + (framing) == BLE_HCI_ISO_FRAMING_FRAMED_UNSEGMENTED) + +void ble_ll_isoal_mux_init(struct ble_ll_isoal_mux *mux, uint8_t max_pdu, + uint32_t iso_interval_us, uint32_t sdu_interval_us, + uint8_t bn, uint8_t pte, bool framed, + uint8_t framing_mode); +void ble_ll_isoal_mux_free(struct ble_ll_isoal_mux *mux); + +int ble_ll_isoal_mux_event_start(struct ble_ll_isoal_mux *mux, + uint32_t timestamp); +int ble_ll_isoal_mux_event_done(struct ble_ll_isoal_mux *mux); + +int ble_ll_isoal_mux_pdu_get(struct ble_ll_isoal_mux *mux, uint8_t idx, + uint8_t *llid, void *dptr); + +void ble_ll_isoal_mux_sdu_enqueue(struct ble_ll_isoal_mux *mux, + struct os_mbuf *om); + +void ble_ll_isoal_init(void); +void ble_ll_isoal_reset(void); + +#ifdef __cplusplus +} +#endif + +#endif /* H_BLE_LL_ISOAL_ */ diff --git a/nimble/controller/include/controller/ble_ll_pdu.h b/nimble/controller/include/controller/ble_ll_pdu.h new file mode 100644 index 0000000000..b18db94482 --- /dev/null +++ b/nimble/controller/include/controller/ble_ll_pdu.h @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_BLE_LL_PDU_ +#define H_BLE_LL_PDU_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Header mask for keystream generation */ +#define BLE_LL_PDU_HEADERMASK_DATA (0xe3) +#define BLE_LL_PDU_HEADERMASK_BIS (0xc3) +#define BLE_LL_PDU_HEADERMASK_CIS (0xa3) + +#define BLE_LL_PDU_PREAMBLE_1M_LEN (1) +#define BLE_LL_PDU_PREAMBLE_2M_LEN (2) +#define BLE_LL_PDU_AA_LEN (4) +#define BLE_LL_PDU_HEADER_LEN (2) +#define BLE_LL_PDU_CRC_LEN (3) + +uint32_t ble_ll_pdu_syncword_us(uint8_t phy_mode); +uint32_t ble_ll_pdu_us(uint8_t payload_len, uint8_t phy_mode); + +#ifdef __cplusplus +} +#endif + +#endif /* H_BLE_LL_PDU_ */ diff --git a/nimble/controller/include/controller/ble_ll_resolv.h b/nimble/controller/include/controller/ble_ll_resolv.h index 228e0a3703..ff28e783ce 100644 --- a/nimble/controller/include/controller/ble_ll_resolv.h +++ b/nimble/controller/include/controller/ble_ll_resolv.h @@ -72,6 +72,12 @@ int ble_ll_resolv_local_addr_rd(const uint8_t *cmdbuf, uint8_t len, struct ble_ll_resolv_entry * ble_ll_resolv_list_find(const uint8_t *addr, uint8_t addr_type); +static inline int8_t +ble_ll_resolv_get_idx(struct ble_ll_resolv_entry *rl) +{ + return rl - g_ble_ll_resolv_list; +} + /* Returns true if address resolution is enabled */ uint8_t ble_ll_resolv_enabled(void); @@ -109,6 +115,17 @@ int ble_ll_resolv_peer_rpa_any(const uint8_t *rpa); /* Initialize resolv*/ void ble_ll_resolv_init(void); +#if MYNEWT_VAL(BLE_LL_HCI_VS_LOCAL_IRK) +int ble_ll_resolv_local_irk_set(uint8_t own_addr_type, const uint8_t *irk); +int ble_ll_resolv_local_rpa_get(uint8_t own_addr_type, uint8_t *rpa); +#else +static inline int +ble_ll_resolv_local_rpa_get(uint8_t own_addr_type, uint8_t *rpa) +{ + return -1; +} +#endif + #ifdef __cplusplus } #endif diff --git a/nimble/controller/include/controller/ble_ll_rfmgmt.h b/nimble/controller/include/controller/ble_ll_rfmgmt.h index 37b81a88be..1aa1c4bb4a 100644 --- a/nimble/controller/include/controller/ble_ll_rfmgmt.h +++ b/nimble/controller/include/controller/ble_ll_rfmgmt.h @@ -24,6 +24,8 @@ extern "C" { #endif +#include "controller/ble_ll_tmr.h" + void ble_ll_rfmgmt_init(void); #if MYNEWT_VAL(BLE_LL_RFMGMT_ENABLE_TIME) > 0 @@ -51,7 +53,7 @@ static inline void ble_ll_rfmgmt_reset(void) { } static inline void ble_ll_rfmgmt_scan_changed(bool e, uint32_t n) { } static inline void ble_ll_rfmgmt_sched_changed(struct ble_ll_sched_item *f) { } static inline void ble_ll_rfmgmt_release(void) { } -static inline uint32_t ble_ll_rfmgmt_enable_now(void) { return 0; } +static inline uint32_t ble_ll_rfmgmt_enable_now(void) { return ble_ll_tmr_get(); } static inline bool ble_ll_rfmgmt_is_enabled(void) { return true; } #endif diff --git a/nimble/controller/include/controller/ble_ll_scan.h b/nimble/controller/include/controller/ble_ll_scan.h index 9bbd4d6900..47c7437414 100644 --- a/nimble/controller/include/controller/ble_ll_scan.h +++ b/nimble/controller/include/controller/ble_ll_scan.h @@ -21,7 +21,7 @@ #define H_BLE_LL_SCAN_ #include "controller/ble_ll_sched.h" -#include "hal/hal_timer.h" +#include "controller/ble_ll_tmr.h" #include "syscfg/syscfg.h" #include "nimble/nimble_npl.h" @@ -80,67 +80,15 @@ struct ble_ll_scan_timing { uint32_t start_time; }; -struct ble_ll_scan_params +struct ble_ll_scan_phy { uint8_t phy; - uint8_t own_addr_type; - uint8_t scan_filt_policy; uint8_t configured; uint8_t scan_type; uint8_t scan_chan; struct ble_ll_scan_timing timing; }; -#define BLE_LL_AUX_HAS_ADVA 0x01 -#define BLE_LL_AUX_HAS_TARGETA 0x02 -#define BLE_LL_AUX_HAS_ADI 0x04 -#define BLE_LL_AUX_IS_MATCHED 0x08 -#define BLE_LL_AUX_IS_TARGETA_RESOLVED 0x10 - -#define BLE_LL_AUX_FLAG_HCI_SENT_ANY 0x02 -#define BLE_LL_AUX_FLAG_HCI_SENT_COMPLETED 0x04 -#define BLE_LL_AUX_FLAG_HCI_SENT_TRUNCATED 0x08 -#define BLE_LL_AUX_FLAG_SCAN_COMPLETE 0x10 -#define BLE_LL_AUX_FLAG_SCAN_ERROR 0x20 -#define BLE_LL_AUX_FLAG_AUX_ADV_RECEIVED 0x40 -#define BLE_LL_AUX_FLAG_AUX_CHAIN_RECEIVED 0x80 - -struct ble_ll_aux_data { - uint8_t flags; - - /* - * Since aux_data can be accessed from ISR and LL, we have separate copies - * of flags to make sure that ISR does not modify flags while LL uses them. - * ISR updates 'flags_isr' and LL adds these to 'flags_ll' which it then - * uses for further processing allowing to update 'flags_isr' if another - * scan for given 'aux_data' is scheduled. Note that flags must not be unset - * while aux_data is valid. - */ - uint8_t flags_isr; - uint8_t flags_ll; - - uint8_t ref_cnt; - uint8_t chan; - uint8_t aux_phy; - uint8_t aux_primary_phy; - uint8_t mode; - uint8_t scanning; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - int8_t rpa_index; -#endif - uint16_t adi; - uint32_t offset; - uint8_t offset_units; - uint8_t adva[6]; - uint8_t adva_type; - uint8_t targeta[6]; - uint8_t targeta_type; - uint16_t evt_type; - struct ble_ll_sched_item sch; - struct ble_hci_ev *evt; - struct ble_npl_event ev; -}; - struct ble_ll_scan_pdu_data { uint8_t hdr_byte; /* ScanA for SCAN_REQ and InitA for CONNECT_IND */ @@ -151,16 +99,40 @@ struct ble_ll_scan_pdu_data { uint8_t adva[BLE_DEV_ADDR_LEN]; }; +struct ble_ll_scan_vs_config { + uint8_t ignore_legacy : 1; + uint8_t ignore_ext : 1; + uint8_t rssi_filter : 1; + + int8_t rssi_threshold; +}; + +struct ble_ll_scan_addr_data { + uint8_t *adva; + uint8_t *targeta; + uint8_t *adv_addr; + uint8_t adva_type : 1; + uint8_t targeta_type : 1; + uint8_t adv_addr_type : 1; +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + uint8_t adva_resolved : 1; + uint8_t targeta_resolved : 1; + int8_t rpa_index; +#endif +}; + struct ble_ll_scan_sm { uint8_t scan_enabled; + uint8_t own_addr_type; + uint8_t scan_filt_policy; uint8_t scan_filt_dups; uint8_t scan_rsp_pending; uint8_t scan_rsp_cons_fails; uint8_t scan_rsp_cons_ok; uint8_t scan_peer_rpa[BLE_DEV_ADDR_LEN]; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) +#if MYNEWT_VAL(BLE_LL_SCAN_ACTIVE_SCAN_NRPA) ble_npl_time_t scan_nrpa_timer; uint8_t scan_nrpa[BLE_DEV_ADDR_LEN]; #endif @@ -171,7 +143,7 @@ struct ble_ll_scan_sm uint16_t backoff_count; uint32_t scan_win_start_time; struct ble_npl_event scan_sched_ev; - struct hal_timer scan_timer; + struct ble_ll_tmr scan_timer; struct ble_npl_event scan_interrupted_ev; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) @@ -183,28 +155,38 @@ struct ble_ll_scan_sm #endif uint8_t restart_timer_needed; - struct ble_ll_aux_data *cur_aux_data; - struct ble_ll_scan_params *scanp; - struct ble_ll_scan_params *scanp_next; - struct ble_ll_scan_params scanp_phys[BLE_LL_SCAN_PHY_NUMBER]; + struct ble_ll_scan_phy *scanp; + struct ble_ll_scan_phy *scanp_next; + struct ble_ll_scan_phy scan_phys[BLE_LL_SCAN_PHY_NUMBER]; + +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + /* Connection sm for initiator scan */ + struct ble_ll_conn_sm *connsm; +#endif + +#if MYNEWT_VAL(BLE_LL_HCI_VS_SET_SCAN_CFG) + struct ble_ll_scan_vs_config vs_config; +#endif }; /* Scan types */ #define BLE_SCAN_TYPE_PASSIVE (BLE_HCI_SCAN_TYPE_PASSIVE) #define BLE_SCAN_TYPE_ACTIVE (BLE_HCI_SCAN_TYPE_ACTIVE) +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) #define BLE_SCAN_TYPE_INITIATE (2) +#endif /*---- HCI ----*/ /* Set scanning parameters */ -int ble_ll_scan_set_scan_params(const uint8_t *cmdbuf, uint8_t len); +int ble_ll_scan_hci_set_params(const uint8_t *cmdbuf, uint8_t len); /* Turn scanning on/off */ -int ble_ll_hci_scan_set_enable(const uint8_t *cmdbuf, uint8_t len); -int ble_ll_hci_ext_scan_set_enable(const uint8_t *cmdbuf, uint8_t len); +int ble_ll_scan_hci_set_enable(const uint8_t *cmdbuf, uint8_t len); +int ble_ll_scan_hci_set_ext_enable(const uint8_t *cmdbuf, uint8_t len); #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -int ble_ll_set_ext_scan_params(const uint8_t *cmdbuf, uint8_t len); +int ble_ll_scan_hci_set_ext_params(const uint8_t *cmdbuf, uint8_t len); #endif /*--- Controller Internal API ---*/ @@ -230,13 +212,12 @@ int ble_ll_scan_can_chg_whitelist(void); /* Boolean function returning true if scanning enabled */ int ble_ll_scan_enabled(void); -/* Boolean function returns true if whitelist is enabled for scanning */ -int ble_ll_scan_whitelist_enabled(void); - /* Initialize the scanner when we start initiating */ -struct hci_create_conn; -int ble_ll_scan_initiator_start(struct hci_create_conn *hcc, - struct ble_ll_scan_sm **sm); +struct ble_ll_conn_create_scan; +struct ble_ll_conn_create_params; +int +ble_ll_scan_initiator_start(struct ble_ll_conn_sm *connsm, uint8_t ext, + struct ble_ll_conn_create_scan *cc_scan); /* Returns storage for PDU data (for SCAN_REQ or CONNECT_IND) */ struct ble_ll_scan_pdu_data *ble_ll_scan_get_pdu_data(void); @@ -254,7 +235,11 @@ uint8_t *ble_ll_scan_get_local_rpa(void); void ble_ll_scan_sm_stop(int chk_disable); /* Resume scanning */ +#if MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) void ble_ll_scan_chk_resume(void); +#else +static inline void ble_ll_scan_chk_resume(void) { }; +#endif /* Called when wait for response timer expires in scanning mode */ void ble_ll_scan_wfr_timer_exp(void); @@ -262,30 +247,39 @@ void ble_ll_scan_wfr_timer_exp(void); /* Called when scan could be interrupted */ void ble_ll_scan_interrupted(struct ble_ll_scan_sm *scansm); -int ble_ll_scan_adv_decode_addr(uint8_t pdu_type, uint8_t *rxbuf, - struct ble_mbuf_hdr *ble_hdr, - uint8_t **addr, uint8_t *addr_type, - uint8_t **inita, uint8_t *init_addr_type, - int *ext_mode); - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -int ble_ll_scan_update_aux_data(struct ble_mbuf_hdr *ble_hdr, uint8_t *rxbuf, - bool *adva_present); - -/* Initialize the extended scanner when we start initiating */ -struct hci_ext_create_conn; -int ble_ll_scan_ext_initiator_start(struct hci_ext_create_conn *hcc, - struct ble_ll_scan_sm **sm); - -/* Called to parse extended advertising*/ -struct ble_ll_aux_data *ble_ll_scan_aux_data_ref(struct ble_ll_aux_data *aux_scan); -void ble_ll_scan_aux_data_unref(struct ble_ll_aux_data *aux_scan); -void ble_ll_scan_end_adv_evt(struct ble_ll_aux_data *aux_data); -#endif - /* Called to halt currently running scan */ void ble_ll_scan_halt(void); +uint8_t ble_ll_scan_get_own_addr_type(void); +uint8_t ble_ll_scan_get_filt_policy(void); +uint8_t ble_ll_scan_get_filt_dups(void); +uint8_t ble_ll_scan_backoff_kick(void); +void ble_ll_scan_backoff_update(int success); + +int ble_ll_scan_dup_check_ext(uint8_t addr_type, uint8_t *addr, bool has_aux, + uint16_t adi); +int ble_ll_scan_dup_update_ext(uint8_t addr_type, uint8_t *addr, bool has_aux, + uint16_t adi); +int ble_ll_scan_have_rxd_scan_rsp(uint8_t *addr, uint8_t txadd, uint8_t ext_adv, + uint16_t adi); +void ble_ll_scan_add_scan_rsp_adv(uint8_t *addr, uint8_t txadd, uint8_t ext_adv, + uint16_t adi); + +struct ble_ll_scan_sm *ble_ll_scan_sm_get(void); + +void ble_ll_scan_make_req_pdu(struct ble_ll_scan_sm *scansm, uint8_t *pdu, + uint8_t *hdr_byte, uint8_t adva_type, + const uint8_t *adva, int rpa_index); + +int +ble_ll_scan_rx_filter(uint8_t own_addr_type, uint8_t scan_filt_policy, + struct ble_ll_scan_addr_data *addrd, uint8_t *scan_ok); +int ble_ll_scan_rx_check_init(struct ble_ll_scan_addr_data *addrd); + +#if MYNEWT_VAL(BLE_LL_HCI_VS_SET_SCAN_CFG) +int ble_ll_scan_set_vs_config(uint32_t flags, int8_t rssi_threshold); +#endif + #ifdef __cplusplus } #endif diff --git a/nimble/controller/include/controller/ble_ll_scan_aux.h b/nimble/controller/include/controller/ble_ll_scan_aux.h new file mode 100644 index 0000000000..b1d6c9caf5 --- /dev/null +++ b/nimble/controller/include/controller/ble_ll_scan_aux.h @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_BLE_LL_SCAN_AUX_ +#define H_BLE_LL_SCAN_AUX_ + +#ifdef __cplusplus +extern "C" { +#endif + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) + +struct ble_ll_scan_aux_data; + +void ble_ll_scan_aux_init(void); +int ble_ll_scan_aux_sched(struct ble_ll_scan_aux_data *aux, uint32_t pdu_ticks, + uint8_t pdu_rem_us, uint32_t aux_ptr); +int ble_ll_scan_aux_rx_isr_start(uint8_t pdu_type, struct ble_mbuf_hdr *rxhdr); +int ble_ll_scan_aux_rx_isr_end(struct os_mbuf *rxpdu, uint8_t crcok); +void ble_ll_scan_aux_rx_pkt_in(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *rxhdr); + +void ble_ll_scan_aux_break(struct ble_ll_scan_aux_data *aux); +void ble_ll_scan_aux_wfr_timer_exp(void); +void ble_ll_scan_aux_halt(void); +void ble_ll_scan_aux_sched_remove(struct ble_ll_sched_item *sch); + +int ble_ll_scan_aux_rx_isr_end_on_ext(struct ble_ll_scan_sm *scansm, + struct os_mbuf *rxpdu); +void ble_ll_scan_aux_pkt_in_on_ext(struct os_mbuf *rxpdu, + struct ble_mbuf_hdr *rxhdr); + +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* H_BLE_LL_SCAN_AUX_ */ diff --git a/nimble/controller/include/controller/ble_ll_sched.h b/nimble/controller/include/controller/ble_ll_sched.h index a614cf0905..5daa647fab 100644 --- a/nimble/controller/include/controller/ble_ll_sched.h +++ b/nimble/controller/include/controller/ble_ll_sched.h @@ -25,8 +25,7 @@ extern "C" { #endif /* Time per BLE scheduler slot */ -#define BLE_LL_SCHED_USECS_PER_SLOT (1250) -#define BLE_LL_SCHED_32KHZ_TICKS_PER_SLOT (41) /* 1 tick = 30.517 usecs */ +#define BLE_LL_SCHED_USECS_PER_SLOT (1250) /* * Worst case time needed for scheduled advertising item. This is the longest @@ -67,10 +66,14 @@ extern uint8_t g_ble_ll_sched_offset_ticks; #define BLE_LL_SCHED_TYPE_ADV (1) #define BLE_LL_SCHED_TYPE_SCAN (2) #define BLE_LL_SCHED_TYPE_CONN (3) -#define BLE_LL_SCHED_TYPE_AUX_SCAN (4) #define BLE_LL_SCHED_TYPE_DTM (5) #define BLE_LL_SCHED_TYPE_PERIODIC (6) #define BLE_LL_SCHED_TYPE_SYNC (7) +#define BLE_LL_SCHED_TYPE_SCAN_AUX (8) +#define BLE_LL_SCHED_TYPE_BIG (9) +#if MYNEWT_VAL(BLE_LL_EXT) +#define BLE_LL_SCHED_TYPE_EXTERNAL (255) +#endif /* Return values for schedule callback. */ #define BLE_LL_SCHED_STATE_RUNNING (0) @@ -80,39 +83,10 @@ extern uint8_t g_ble_ll_sched_offset_ticks; struct ble_ll_sched_item; typedef int (*sched_cb_func)(struct ble_ll_sched_item *sch); typedef void (*sched_remove_cb_func)(struct ble_ll_sched_item *sch); -/* - * Strict connection scheduling (for the master) is different than how - * connections are normally scheduled. With strict connection scheduling we - * introduce the concept of a "period". A period is a collection of slots. Each - * slot is 1.25 msecs in length. The number of slots in a period is determined - * by the syscfg value BLE_LL_CONN_INIT_SLOTS. A collection of periods is called - * an epoch. The length of an epoch is determined by the number of connections - * (BLE_MAX_CONNECTIONS plus BLE_LL_ADD_STRICT_SCHED_PERIODS). Connections - * will be scheduled at period boundaries. Any scanning/initiating/advertising - * will be done in unused periods, if possible. - */ -#if MYNEWT_VAL(BLE_LL_STRICT_CONN_SCHEDULING) -#define BLE_LL_SCHED_PERIODS (MYNEWT_VAL(BLE_MAX_CONNECTIONS) + \ - MYNEWT_VAL(BLE_LL_ADD_STRICT_SCHED_PERIODS)) -struct ble_ll_sched_obj -{ - uint8_t sch_num_occ_periods; - uint32_t sch_occ_period_mask; - uint32_t sch_ticks_per_period; - uint32_t sch_ticks_per_epoch; - uint32_t sch_epoch_start; -}; - -extern struct ble_ll_sched_obj g_ble_ll_sched_data; +typedef int (* ble_ll_sched_preempt_cb_t)(struct ble_ll_sched_item *sch, + struct ble_ll_sched_item *item); -/* - * XXX: TODO: - * -> How do we know epoch start is up to date? Not wrapped? - * -> for now, only do this with no more than 32 connections. - * -> Do not let initiating occur if no empty sched slots - */ -#endif /* * Schedule item @@ -125,6 +99,9 @@ extern struct ble_ll_sched_obj g_ble_ll_sched_data; struct ble_ll_sched_item { uint8_t sched_type; +#if MYNEWT_VAL(BLE_LL_EXT) + uint8_t sched_ext_type; +#endif uint8_t enqueued; uint8_t remainder; uint32_t start_time; @@ -137,6 +114,10 @@ struct ble_ll_sched_item /* Initialize the scheduler */ int ble_ll_sched_init(void); +int ble_ll_sched_insert(struct ble_ll_sched_item *sch, uint32_t max_delay, + ble_ll_sched_preempt_cb_t preempt_cb); +void ble_ll_sched_restart(void); + /* Remove item(s) from schedule */ int ble_ll_sched_rmv_elem(struct ble_ll_sched_item *sch); @@ -144,11 +125,11 @@ void ble_ll_sched_rmv_elem_type(uint8_t type, sched_remove_cb_func remove_cb); /* Schedule a new master connection */ struct ble_ll_conn_sm; -int ble_ll_sched_master_new(struct ble_ll_conn_sm *connsm, - struct ble_mbuf_hdr *ble_hdr, uint8_t pyld_len); +int ble_ll_sched_conn_central_new(struct ble_ll_conn_sm *connsm, + struct ble_mbuf_hdr *ble_hdr, uint8_t pyld_len); /* Schedule a new slave connection */ -int ble_ll_sched_slave_new(struct ble_ll_conn_sm *connsm); +int ble_ll_sched_conn_periph_new(struct ble_ll_conn_sm *connsm); struct ble_ll_adv_sm; typedef void ble_ll_sched_adv_new_cb(struct ble_ll_adv_sm *advsm, @@ -159,19 +140,13 @@ int ble_ll_sched_adv_new(struct ble_ll_sched_item *sch, ble_ll_sched_adv_new_cb cb, void *arg); /* Schedule periodic advertising event */ -int ble_ll_sched_periodic_adv(struct ble_ll_sched_item *sch, uint32_t *start, - bool after_overlap); +int ble_ll_sched_periodic_adv(struct ble_ll_sched_item *sch, bool first_event); -int ble_ll_sched_sync_reschedule(struct ble_ll_sched_item *sch, - uint32_t anchor_point, - uint8_t anchor_point_usecs, - uint32_t window_widening, int8_t phy_mode); -int ble_ll_sched_sync(struct ble_ll_sched_item *sch, - uint32_t beg_cputime, uint32_t rem_usecs, uint32_t offset, - int8_t phy_mode); +int ble_ll_sched_sync_reschedule(struct ble_ll_sched_item *sch, uint32_t ww_us); +int ble_ll_sched_sync(struct ble_ll_sched_item *sch); /* Reschedule an advertising event */ -int ble_ll_sched_adv_reschedule(struct ble_ll_sched_item *sch, uint32_t *start, +int ble_ll_sched_adv_reschedule(struct ble_ll_sched_item *sch, uint32_t max_delay_ticks); /* Reschedule and advertising pdu */ @@ -193,13 +168,7 @@ int ble_ll_sched_conn_reschedule(struct ble_ll_conn_sm * connsm); int ble_ll_sched_next_time(uint32_t *next_event_time); #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -struct ble_ll_scan_sm; -struct ble_ll_aux_data; -int ble_ll_sched_aux_scan(struct ble_mbuf_hdr *ble_hdr, - struct ble_ll_scan_sm *scansm, - struct ble_ll_aux_data *aux_scan); - -int ble_ll_sched_scan_req_over_aux_ptr(uint32_t chan, uint8_t phy_mode); +int ble_ll_sched_scan_aux(struct ble_ll_sched_item *sch); #endif /* Stop the scheduler */ @@ -209,6 +178,50 @@ void ble_ll_sched_stop(void); int ble_ll_sched_dtm(struct ble_ll_sched_item *sch); #endif +#if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) +#if !MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED_FIXED) +void ble_ll_sched_css_set_params(uint32_t slot_us, uint32_t period_slots); +#endif +void ble_ll_sched_css_set_enabled(uint8_t enabled); +void ble_ll_sched_css_update_anchor(struct ble_ll_conn_sm *connsm); +void ble_ll_sched_css_set_conn_anchor(struct ble_ll_conn_sm *connsm); +#if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED_FIXED) +static inline bool +ble_ll_sched_css_is_enabled(void) +{ + return true; +} + +static inline uint32_t +ble_ll_sched_css_get_slot_us(void) +{ + return MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED_SLOT_US); +} + +static inline uint32_t +ble_ll_sched_css_get_period_slots(void) +{ + return MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED_PERIOD_SLOTS); +} + +static inline uint32_t +ble_ll_sched_css_get_conn_interval_us(void) +{ + return ble_ll_sched_css_get_period_slots() * + ble_ll_sched_css_get_slot_us() / 1250; +} +#else +bool ble_ll_sched_css_is_enabled(void); +uint32_t ble_ll_sched_css_get_slot_us(void); +uint32_t ble_ll_sched_css_get_period_slots(void); +uint32_t ble_ll_sched_css_get_conn_interval_us(void); +#endif +#endif + +#if MYNEWT_VAL(BLE_LL_ISO_BROADCASTER) +int ble_ll_sched_iso_big(struct ble_ll_sched_item *sch, int first, int fixed); +#endif /* BLE_LL_ISO_BROADCASTER */ + #ifdef __cplusplus } #endif diff --git a/nimble/controller/include/controller/ble_ll_sync.h b/nimble/controller/include/controller/ble_ll_sync.h index 712af6dffc..5d7ef7a864 100644 --- a/nimble/controller/include/controller/ble_ll_sync.h +++ b/nimble/controller/include/controller/ble_ll_sync.h @@ -30,10 +30,11 @@ extern "C" { #endif +struct ble_ll_scan_addr_data; struct ble_ll_sync_sm; int ble_ll_sync_create(const uint8_t *cmdbuf, uint8_t len); -int ble_ll_sync_cancel(ble_ll_hci_post_cmd_complete_cb *post_cmd_cb); +int ble_ll_sync_cancel(void); int ble_ll_sync_terminate(const uint8_t *cmdbuf, uint8_t len); int ble_ll_sync_list_add(const uint8_t *cmdbuf, uint8_t len); int ble_ll_sync_list_remove(const uint8_t *cmdbuf, uint8_t len); @@ -44,12 +45,11 @@ int ble_ll_sync_transfer(const uint8_t *cmdbuf, uint8_t len, uint8_t *rspbuf, uint8_t *rsplen); void ble_ll_sync_periodic_ind(struct ble_ll_conn_sm *connsm, - const uint8_t *sync_ind, bool reports_disabled, + const uint8_t *sync_ind, uint8_t mode, uint16_t max_skip, uint32_t sync_timeout); void ble_ll_sync_transfer_disconnected(struct ble_ll_conn_sm *connsm); -void ble_ll_sync_info_event(const uint8_t *addr, uint8_t addr_type, - int rpa_index, uint8_t sid, +void ble_ll_sync_info_event(struct ble_ll_scan_addr_data *addrd, uint8_t sid, struct ble_mbuf_hdr *rxhdr, const uint8_t *syncinfo); diff --git a/nimble/controller/include/controller/ble_ll_tmr.h b/nimble/controller/include/controller/ble_ll_tmr.h new file mode 100644 index 0000000000..bf62503824 --- /dev/null +++ b/nimble/controller/include/controller/ble_ll_tmr.h @@ -0,0 +1,177 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_BLE_LL_TMR_ +#define H_BLE_LL_TMR_ + +#include "os/os_cputime.h" +#include "controller/ble_ll.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define USECS_PER_TICK ((1000000 + MYNEWT_VAL(OS_CPUTIME_FREQ) - 1) / \ + MYNEWT_VAL(OS_CPUTIME_FREQ)) + +#define LL_TMR_LT(_t1, _t2) ((int32_t)((_t1) - (_t2)) < 0) +#define LL_TMR_GT(_t1, _t2) ((int32_t)((_t1) - (_t2)) > 0) +#define LL_TMR_GEQ(_t1, _t2) ((int32_t)((_t1) - (_t2)) >= 0) +#define LL_TMR_LEQ(_t1, _t2) ((int32_t)((_t1) - (_t2)) <= 0) + +typedef void (ble_ll_tmr_cb)(void *arg); + +struct ble_ll_tmr { + struct hal_timer t; +}; + +static inline uint32_t +ble_ll_tmr_get(void) +{ + return os_cputime_get32(); +} + +static inline uint32_t +ble_ll_tmr_t2u(uint32_t ticks) +{ +#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 31250 + return ticks * 32; +#endif + + return os_cputime_ticks_to_usecs(ticks); +} + +static inline uint32_t +ble_ll_tmr_u2t(uint32_t usecs) +{ +#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 31250 + return usecs / 32; +#endif +#if MYNEWT_VAL(OS_CPUTIME_FREQ) == 32768 +#if __ARM_FEATURE_IDIV + if (usecs < 131072) { + return (usecs * 32768) / 1000000; + } else { + return ((uint64_t)usecs * 32768) / 1000000; + } +#else + if (usecs <= 31249) { + return (usecs * 137439) / 4194304; + } +#endif +#endif + + return os_cputime_usecs_to_ticks(usecs); +} + +static inline uint32_t +ble_ll_tmr_u2t_up(uint32_t usecs) +{ + return ble_ll_tmr_u2t(usecs + (USECS_PER_TICK - 1)); +} + +static inline uint32_t +ble_ll_tmr_u2t_r(uint32_t usecs, uint8_t *rem_us) +{ + uint32_t ticks; + + ticks = ble_ll_tmr_u2t(usecs); + *rem_us = usecs - ble_ll_tmr_t2u(ticks); + if (*rem_us == USECS_PER_TICK) { + *rem_us = 0; + ticks++; + } + + return ticks; +} + +static inline void +ble_ll_tmr_add(uint32_t *ticks, uint8_t *rem_us, uint32_t usecs) +{ + uint32_t t_ticks; + uint8_t t_rem_us; + + t_ticks = ble_ll_tmr_u2t_r(usecs, &t_rem_us); + + *ticks += t_ticks; + *rem_us += t_rem_us; + if (*rem_us >= USECS_PER_TICK) { + *rem_us -= USECS_PER_TICK; + *ticks += 1; + } +} + +static inline void +ble_ll_tmr_add_u(uint32_t *ticks, uint8_t *rem_us, uint8_t usecs) +{ + BLE_LL_ASSERT(usecs < USECS_PER_TICK); + + *rem_us += usecs; + if (*rem_us >= USECS_PER_TICK) { + *rem_us -= USECS_PER_TICK; + *ticks += 1; + } +} + +static inline void +ble_ll_tmr_sub(uint32_t *ticks, uint8_t *rem_us, uint32_t usecs) +{ + uint32_t t_ticks; + uint8_t t_rem_us; + + if (usecs <= *rem_us) { + *rem_us -= usecs; + return; + } + + usecs -= *rem_us; + *rem_us = 0; + + t_ticks = ble_ll_tmr_u2t_r(usecs, &t_rem_us); + if (t_rem_us) { + t_ticks += 1; + *rem_us = USECS_PER_TICK - t_rem_us; + } + + *ticks -= t_ticks; +} + +static inline void +ble_ll_tmr_init(struct ble_ll_tmr *tmr, ble_ll_tmr_cb *cb, void *arg) +{ + os_cputime_timer_init(&tmr->t, cb, arg); +} + +static inline void +ble_ll_tmr_start(struct ble_ll_tmr *tmr, uint32_t tgt) +{ + os_cputime_timer_start(&tmr->t, tgt); +} + +static inline void +ble_ll_tmr_stop(struct ble_ll_tmr *tmr) +{ + os_cputime_timer_stop(&tmr->t); +} + +#ifdef __cplusplus +} +#endif + +#endif /* H_BLE_LL_TMR_ */ \ No newline at end of file diff --git a/nimble/controller/include/controller/ble_ll_utils.h b/nimble/controller/include/controller/ble_ll_utils.h index 248309009b..291872bfb8 100644 --- a/nimble/controller/include/controller/ble_ll_utils.h +++ b/nimble/controller/include/controller/ble_ll_utils.h @@ -19,11 +19,32 @@ #include -uint32_t ble_ll_utils_calc_access_addr(void); -uint8_t ble_ll_utils_remapped_channel(uint8_t remap_index, const uint8_t *chanmap); -uint8_t ble_ll_utils_calc_dci_csa2(uint16_t event_cntr, uint16_t channel_id, - uint8_t num_used_chans, const uint8_t *chanmap); -uint8_t ble_ll_utils_calc_num_used_chans(const uint8_t *chanmap); +#define INT16_GT(_a, _b) ((int16_t)((_a) - (_b)) > 0) +#define INT16_LT(_a, _b) ((int16_t)((_a) - (_b)) < 0) +#define INT16_LTE(_a, _b) ((int16_t)((_a) - (_b)) <= 0) + +#define MIN(_a, _b) ((_a) < (_b) ? (_a) : (_b)) +#define MAX(_a, _b) ((_a) > (_b) ? (_a) : (_b)) +#define CLAMP(_n, _min, _max) (MAX(_min, MIN(_n, _max))) +#define IN_RANGE(_n, _min, _max) (((_n) >= (_min)) && ((_n) <= (_max))) + +int ble_ll_utils_verify_aa(uint32_t aa); +uint32_t ble_ll_utils_calc_aa(void); +uint32_t ble_ll_utils_calc_seed_aa(void); +uint32_t ble_ll_utils_calc_big_aa(uint32_t seed_aa, uint32_t n); + +uint8_t ble_ll_utils_chan_map_remap(const uint8_t *chan_map, uint8_t remap_index); +uint8_t ble_ll_utils_chan_map_used_get(const uint8_t *chan_map); + +uint8_t ble_ll_utils_dci_csa2(uint16_t counter, uint16_t chan_id, + uint8_t num_used_chans, const uint8_t *chan_map); +uint16_t ble_ll_utils_dci_iso_event(uint16_t counter, uint16_t chan_id, + uint16_t *prn_sub_lu, uint8_t chan_map_used, + const uint8_t *chan_map, uint16_t *remap_idx); +uint16_t ble_ll_utils_dci_iso_subevent(uint16_t chan_id, uint16_t *prn_sub_lu, + uint8_t chan_map_used, const uint8_t *chan_map, + uint16_t *remap_idx); + uint32_t ble_ll_utils_calc_window_widening(uint32_t anchor_point, uint32_t last_anchor_point, - uint8_t master_sca); + uint8_t central_sca); diff --git a/nimble/controller/include/controller/ble_phy.h b/nimble/controller/include/controller/ble_phy.h index cd8350d657..fe70044234 100644 --- a/nimble/controller/include/controller/ble_phy.h +++ b/nimble/controller/include/controller/ble_phy.h @@ -65,6 +65,7 @@ struct os_mbuf; #define BLE_PHY_TRANSITION_NONE (0) #define BLE_PHY_TRANSITION_RX_TX (1) #define BLE_PHY_TRANSITION_TX_RX (2) +#define BLE_PHY_TRANSITION_TX_TX (3) /* PHY error codes */ #define BLE_PHY_ERR_RADIO_STATE (1) @@ -83,11 +84,18 @@ typedef void (*ble_phy_tx_end_func)(void *arg); /* Initialize the PHY */ int ble_phy_init(void); -/* Reset the PHY */ -int ble_phy_reset(void); - /* Set the PHY channel */ int ble_phy_setchan(uint8_t chan, uint32_t access_addr, uint32_t crcinit); +uint8_t ble_phy_chan_get(void); + +#if MYNEWT_VAL(BLE_PHY_VARIABLE_TIFS) +/* Set T_ifs time for next transition */ +void ble_phy_tifs_set(uint16_t tifs); +#endif + +/* Set T_ifs for tx-tx transitions. Anchor is 0 for start of previous PDU, + * non-zero for end of PDU */ +void ble_phy_tifs_txtx_set(uint16_t usecs, uint8_t anchor); /* Set transmit start time */ int ble_phy_tx_set_start_time(uint32_t cputime, uint8_t rem_usecs); @@ -104,23 +112,17 @@ typedef uint8_t (*ble_phy_tx_pducb_t)(uint8_t *dptr, void *pducb_arg, /* Place the PHY into transmit mode */ int ble_phy_tx(ble_phy_tx_pducb_t pducb, void *pducb_arg, uint8_t end_trans); -/* Place the PHY into receive mode */ -int ble_phy_rx(void); - /* Copies the received PHY buffer into the allocated pdu */ void ble_phy_rxpdu_copy(uint8_t *dptr, struct os_mbuf *rxpdu); /* Set the transmit power */ -int ble_phy_txpwr_set(int dbm); +int ble_phy_tx_power_set(int dbm); /* Get highest allowed power from range */ -int ble_phy_txpower_round(int dbm); +int ble_phy_tx_power_round(int dbm); /* Get the transmit power */ -int ble_phy_txpwr_get(void); - -/* Set RX path power compensation value rounded to integer dB */ -void ble_phy_set_rx_pwr_compensation(int8_t compensation); +int ble_phy_tx_power_get(void); /* Disable the PHY */ void ble_phy_disable(void); @@ -163,15 +165,16 @@ uint8_t ble_phy_max_data_pdu_pyld(void); uint32_t ble_phy_access_addr_get(void); /* Enable encryption */ -void ble_phy_encrypt_enable(uint64_t pkt_counter, uint8_t *iv, uint8_t *key, - uint8_t is_master); - +void ble_phy_encrypt_enable(const uint8_t *key); +/* Set mask for PDU header (see Core 5.3, Vol 6, Part E, 2.2) */ +void ble_phy_encrypt_header_mask_set(uint8_t mask); +/* Set encryption IV */ +void ble_phy_encrypt_iv_set(const uint8_t *iv); +/* Set encryption packet counter and direction bit */ +void ble_phy_encrypt_counter_set(uint64_t counter, uint8_t dir_bit); /* Disable encryption */ void ble_phy_encrypt_disable(void); -/* Set the packet counters and dir used by LE encyption */ -void ble_phy_encrypt_set_pkt_cntr(uint64_t pkt_counter, int dir); - /* Enable phy resolving list */ void ble_phy_resolv_list_enable(void); @@ -202,15 +205,15 @@ void ble_phy_resolv_list_disable(void); #define BLE_PHY_MASK_2M (BLE_HCI_LE_PHY_2M_PREF_MASK) #define BLE_PHY_MASK_CODED (BLE_HCI_LE_PHY_CODED_PREF_MASK) +/* PHY indices (for a zero-based array) */ +#define BLE_PHY_IDX_1M (0) +#define BLE_PHY_IDX_2M (1) +#define BLE_PHY_IDX_CODED (2) + #if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY) || MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY)) -uint32_t ble_phy_mode_pdu_start_off(int phy); void ble_phy_mode_set(uint8_t tx_phy_mode, uint8_t rx_phy_mode); -#else -#define ble_phy_mode_pdu_start_off(phy) (40) - #endif -int ble_phy_get_cur_phy(void); static inline int ble_ll_phy_to_phy_mode(int phy, int phy_options) { int phy_mode; @@ -235,6 +238,9 @@ static inline int ble_ll_phy_to_phy_mode(int phy, int phy_options) #if MYNEWT_VAL(BLE_LL_DTM) void ble_phy_enable_dtm(void); void ble_phy_disable_dtm(void); +#if MYNEWT_VAL(BLE_LL_DTM_EXTENSIONS) +int ble_phy_dtm_carrier(uint8_t rf_channel); +#endif #endif #ifdef __cplusplus diff --git a/nimble/controller/pkg.yml b/nimble/controller/pkg.yml index 96c636798b..2f22e3ebf5 100644 --- a/nimble/controller/pkg.yml +++ b/nimble/controller/pkg.yml @@ -29,10 +29,20 @@ pkg.req_apis: - ble_driver - ble_transport - stats +pkg.req_apis.BLE_FEM_PA: + - ble_fem_pa +pkg.req_apis.BLE_FEM_LNA: + - ble_fem_lna +pkg.req_apis.BLE_FEM_ANTENNA: + - ble_fem_antenna pkg.deps: - "@apache-mynewt-core/kernel/os" + - "@apache-mynewt-core/crypto/tinycrypt" - nimble + - nimble/transport pkg.init: - ble_ll_init: 'MYNEWT_VAL(BLE_LL_SYSINIT_STAGE)' + ble_ll_init: + - $before:ble_transport_hs_init + - $before:ble_transport_ll_init diff --git a/nimble/controller/src/ble_ll.c b/nimble/controller/src/ble_ll.c index cf83b79c38..a0d6dbbc03 100644 --- a/nimble/controller/src/ble_ll.c +++ b/nimble/controller/src/ble_ll.c @@ -24,31 +24,50 @@ #include "sysinit/sysinit.h" #include "syscfg/syscfg.h" #include "os/os.h" -#include "os/os_cputime.h" #include "stats/stats.h" #include "nimble/ble.h" #include "nimble/nimble_opt.h" #include "nimble/hci_common.h" -#include "nimble/ble_hci_trans.h" +#include "nimble/transport.h" +#include "controller/ble_ll_utils.h" #include "controller/ble_hw.h" #include "controller/ble_phy.h" #include "controller/ble_phy_trace.h" #include "controller/ble_ll.h" +#include "controller/ble_ll_pdu.h" #include "controller/ble_ll_adv.h" #include "controller/ble_ll_sched.h" #include "controller/ble_ll_scan.h" +#include "controller/ble_ll_scan_aux.h" #include "controller/ble_ll_hci.h" #include "controller/ble_ll_whitelist.h" #include "controller/ble_ll_resolv.h" #include "controller/ble_ll_rfmgmt.h" #include "controller/ble_ll_trace.h" #include "controller/ble_ll_sync.h" +#include "controller/ble_fem.h" +#if MYNEWT_VAL(BLE_LL_ISO) +#include "controller/ble_ll_iso.h" +#endif +#if MYNEWT_VAL(BLE_LL_ISO_BROADCASTER) +#include "controller/ble_ll_iso_big.h" +#endif +#if MYNEWT_VAL(BLE_LL_EXT) +#include "controller/ble_ll_ext.h" +#endif #include "ble_ll_conn_priv.h" +#include "ble_ll_hci_priv.h" +#include "ble_ll_priv.h" +#include "hal/hal_system.h" #if MYNEWT_VAL(BLE_LL_DTM) #include "ble_ll_dtm_priv.h" #endif +#if MYNEWT_VAL(BLE_LL_EXT) +#include +#endif + /* XXX: * * 1) use the sanity task! @@ -61,49 +80,185 @@ * right thing to do. */ +/* This is TX power on PHY (or FEM PA if enabled) */ +int8_t g_ble_ll_tx_power; +static int8_t g_ble_ll_tx_power_phy_current; +int8_t g_ble_ll_tx_power_compensation; +int8_t g_ble_ll_rx_power_compensation; + +#if BLE_LL_HOST_CONTROLLED_FEATURES +static const uint64_t g_ble_ll_host_controlled_features = +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE) + BLE_LL_FEAT_CONN_SUBRATING_HOST | +#endif +#if MYNEWT_VAL(BLE_LL_ADV_CODING_SELECTION) + BLE_LL_FEAT_ADV_CODING_SEL_HOST | +#endif + 0; +#endif + /* Supported states */ -#define BLE_LL_S_NCA (0x00000000001) -#define BLE_LL_S_SA (0x00000000002) -#define BLE_LL_S_CA (0x00000000004) -#define BLE_LL_S_HDCA (0x00000000008) -#define BLE_LL_S_PS (0x00000000010) -#define BLE_LL_S_AS (0x00000000020) -#define BLE_LL_S_INIT (0x00000000040) -#define BLE_LL_S_SLAVE (0x00000000080) -#define BLE_LL_S_NCA_PS (0x00000000100) -#define BLE_LL_S_SA_PS (0x00000000200) -#define BLE_LL_S_CA_PS (0x00000000400) -#define BLE_LL_S_HDCA_PS (0x00000000800) -#define BLE_LL_S_NCA_AS (0x00000001000) -#define BLE_LL_S_SA_AS (0x00000002000) -#define BLE_LL_S_CA_AS (0x00000004000) -#define BLE_LL_S_HDCA_AS (0x00000008000) -#define BLE_LL_S_NCA_INIT (0x00000010000) -#define BLE_LL_S_SA_INIT (0x00000020000) -#define BLE_LL_S_NCA_MASTER (0x00000040000) -#define BLE_LL_S_SA_MASTER (0x00000080000) -#define BLE_LL_S_NCA_SLAVE (0x00000100000) -#define BLE_LL_S_SA_SLAVE (0x00000200000) -#define BLE_LL_S_PS_INIT (0x00000400000) -#define BLE_LL_S_AS_INIT (0x00000800000) -#define BLE_LL_S_PS_MASTER (0x00001000000) -#define BLE_LL_S_AS_MASTER (0x00002000000) -#define BLE_LL_S_PS_SLAVE (0x00004000000) -#define BLE_LL_S_AS_SLAVE (0x00008000000) -#define BLE_LL_S_INIT_MASTER (0x00010000000) -#define BLE_LL_S_LDCA (0x00020000000) -#define BLE_LL_S_LDCA_PS (0x00040000000) -#define BLE_LL_S_LDCA_AS (0x00080000000) -#define BLE_LL_S_CA_INIT (0x00100000000) -#define BLE_LL_S_HDCA_INIT (0x00200000000) -#define BLE_LL_S_LDCA_INIT (0x00400000000) -#define BLE_LL_S_CA_MASTER (0x00800000000) -#define BLE_LL_S_HDCA_MASTER (0x01000000000) -#define BLE_LL_S_LDCA_MASTER (0x02000000000) -#define BLE_LL_S_CA_SLAVE (0x04000000000) -#define BLE_LL_S_HDCA_SLAVE (0x08000000000) -#define BLE_LL_S_LDCA_SLAVE (0x10000000000) -#define BLE_LL_S_INIT_SLAVE (0x20000000000) +#if MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) +#define BLE_LL_S_NCA ((uint64_t)1 << 0) +#define BLE_LL_S_SA ((uint64_t)1 << 1) +#else +#define BLE_LL_S_NCA ((uint64_t)0 << 0) +#define BLE_LL_S_SA ((uint64_t)0 << 1) +#endif + +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) +#define BLE_LL_S_CA ((uint64_t)1 << 2) +#define BLE_LL_S_HDCA ((uint64_t)1 << 3) +#else +#define BLE_LL_S_CA ((uint64_t)0 << 2) +#define BLE_LL_S_HDCA ((uint64_t)0 << 3) +#endif + +#if MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) +#define BLE_LL_S_PS ((uint64_t)1 << 4) +#define BLE_LL_S_AS ((uint64_t)1 << 5) +#else +#define BLE_LL_S_PS ((uint64_t)0 << 4) +#define BLE_LL_S_AS ((uint64_t)0 << 5) +#endif + +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) +#define BLE_LL_S_INIT ((uint64_t)1 << 6) +#else +#define BLE_LL_S_INIT ((uint64_t)0 << 6) +#endif + +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) +#define BLE_LL_S_PERIPH ((uint64_t)1 << 7) +#else +#define BLE_LL_S_PERIPH ((uint64_t)0 << 7) +#endif + +#if MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) && MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) +#define BLE_LL_S_NCA_PS ((uint64_t)1 << 8) +#define BLE_LL_S_SA_PS ((uint64_t)1 << 9) +#else +#define BLE_LL_S_NCA_PS ((uint64_t)0 << 8) +#define BLE_LL_S_SA_PS ((uint64_t)0 << 9) +#endif + +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) && MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) +#define BLE_LL_S_CA_PS ((uint64_t)1 << 10) +#define BLE_LL_S_HDCA_PS ((uint64_t)1 << 11) +#else +#define BLE_LL_S_CA_PS ((uint64_t)0 << 10) +#define BLE_LL_S_HDCA_PS ((uint64_t)0 << 11) +#endif + +#if MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) && MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) +#define BLE_LL_S_NCA_AS ((uint64_t)1 << 12) +#define BLE_LL_S_SA_AS ((uint64_t)1 << 13) +#else +#define BLE_LL_S_NCA_AS ((uint64_t)0 << 12) +#define BLE_LL_S_SA_AS ((uint64_t)0 << 13) +#endif + +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) && MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) +#define BLE_LL_S_CA_AS ((uint64_t)1 << 14) +#define BLE_LL_S_HDCA_AS ((uint64_t)1 << 15) +#else +#define BLE_LL_S_CA_AS ((uint64_t)0 << 14) +#define BLE_LL_S_HDCA_AS ((uint64_t)0 << 15) +#endif + +#if MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) && MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) +#define BLE_LL_S_NCA_INIT ((uint64_t)1 << 16) +#define BLE_LL_S_SA_INIT ((uint64_t)1 << 17) +#define BLE_LL_S_NCA_CENTRAL ((uint64_t)1 << 18) +#define BLE_LL_S_SA_CENTRAL ((uint64_t)1 << 19) +#else +#define BLE_LL_S_NCA_INIT ((uint64_t)0 << 16) +#define BLE_LL_S_SA_INIT ((uint64_t)0 << 17) +#define BLE_LL_S_NCA_CENTRAL ((uint64_t)0 << 18) +#define BLE_LL_S_SA_CENTRAL ((uint64_t)0 << 19) +#endif + +#if MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) && MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) +#define BLE_LL_S_NCA_PERIPH ((uint64_t)1 << 20) +#define BLE_LL_S_SA_PERIPH ((uint64_t)1 << 21) +#else +#define BLE_LL_S_NCA_PERIPH ((uint64_t)0 << 20) +#define BLE_LL_S_SA_PERIPH ((uint64_t)0 << 21) +#endif + +#if MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) && MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) +/* We do not support passive scanning while initiating yet */ +#define BLE_LL_S_PS_INIT ((uint64_t)0 << 22) +/* We do not support active scanning while initiating yet */ +#define BLE_LL_S_AS_INIT ((uint64_t)0 << 23) +#define BLE_LL_S_PS_CENTRAL ((uint64_t)1 << 24) +#define BLE_LL_S_AS_CENTRAL ((uint64_t)1 << 25) +#else +#define BLE_LL_S_PS_INIT ((uint64_t)0 << 22) +#define BLE_LL_S_AS_INIT ((uint64_t)0 << 23) +#define BLE_LL_S_PS_CENTRAL ((uint64_t)0 << 24) +#define BLE_LL_S_AS_CENTRAL ((uint64_t)0 << 25) +#endif + +#if MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) && MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) +#define BLE_LL_S_PS_PERIPH ((uint64_t)1 << 26) +#define BLE_LL_S_AS_PERIPH ((uint64_t)1 << 27) +#else +#define BLE_LL_S_PS_PERIPH ((uint64_t)0 << 26) +#define BLE_LL_S_AS_PERIPH ((uint64_t)0 << 27) +#endif + +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) +#define BLE_LL_S_INIT_CENTRAL ((uint64_t)1 << 28) +#else +#define BLE_LL_S_INIT_CENTRAL ((uint64_t)0 << 28) +#endif + +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) +#define BLE_LL_S_LDCA ((uint64_t)1 << 29) +#else +#define BLE_LL_S_LDCA ((uint64_t)0 << 29) +#endif + +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) && MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) +#define BLE_LL_S_LDCA_PS ((uint64_t)1 << 30) +#define BLE_LL_S_LDCA_AS ((uint64_t)1 << 31) +#else +#define BLE_LL_S_LDCA_PS ((uint64_t)0 << 30) +#define BLE_LL_S_LDCA_AS ((uint64_t)0 << 31) +#endif + +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) && MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) +#define BLE_LL_S_CA_INIT ((uint64_t)1 << 32) +#define BLE_LL_S_HDCA_INIT ((uint64_t)1 << 33) +#define BLE_LL_S_LDCA_INIT ((uint64_t)1 << 34) +#define BLE_LL_S_CA_CENTRAL ((uint64_t)1 << 35) +#define BLE_LL_S_HDCA_CENTRAL ((uint64_t)1 << 36) +#define BLE_LL_S_LDCA_CENTRAL ((uint64_t)1 << 37) +#else +#define BLE_LL_S_CA_INIT ((uint64_t)0 << 32) +#define BLE_LL_S_HDCA_INIT ((uint64_t)0 << 33) +#define BLE_LL_S_LDCA_INIT ((uint64_t)0 << 34) +#define BLE_LL_S_CA_CENTRAL ((uint64_t)0 << 35) +#define BLE_LL_S_HDCA_CENTRAL ((uint64_t)0 << 36) +#define BLE_LL_S_LDCA_CENTRAL ((uint64_t)0 << 37) +#endif + +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) +#define BLE_LL_S_CA_PERIPH ((uint64_t)1 << 38) +#define BLE_LL_S_HDCA_PERIPH ((uint64_t)1 << 39) +#define BLE_LL_S_LDCA_PERIPH ((uint64_t)1 << 40) +#else +#define BLE_LL_S_CA_PERIPH ((uint64_t)0 << 38) +#define BLE_LL_S_HDCA_PERIPH ((uint64_t)0 << 39) +#define BLE_LL_S_LDCA_PERIPH ((uint64_t)0 << 40) +#endif + +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) && MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) +#define BLE_LL_S_INIT_PERIPH ((uint64_t)1 << 41) +#else +#define BLE_LL_S_INIT_PERIPH ((uint64_t)0 << 41) +#endif #define BLE_LL_SUPPORTED_STATES \ ( \ @@ -114,7 +269,7 @@ BLE_LL_S_PS | \ BLE_LL_S_AS | \ BLE_LL_S_INIT | \ - BLE_LL_S_SLAVE | \ + BLE_LL_S_PERIPH | \ BLE_LL_S_NCA_PS | \ BLE_LL_S_SA_PS | \ BLE_LL_S_CA_PS | \ @@ -125,30 +280,30 @@ BLE_LL_S_HDCA_AS | \ BLE_LL_S_NCA_INIT | \ BLE_LL_S_SA_INIT | \ - BLE_LL_S_NCA_MASTER | \ - BLE_LL_S_SA_MASTER | \ - BLE_LL_S_NCA_SLAVE | \ - BLE_LL_S_SA_SLAVE | \ + BLE_LL_S_NCA_CENTRAL | \ + BLE_LL_S_SA_CENTRAL | \ + BLE_LL_S_NCA_PERIPH | \ + BLE_LL_S_SA_PERIPH | \ BLE_LL_S_PS_INIT | \ BLE_LL_S_AS_INIT | \ - BLE_LL_S_PS_MASTER | \ - BLE_LL_S_AS_MASTER | \ - BLE_LL_S_PS_SLAVE | \ - BLE_LL_S_AS_SLAVE | \ - BLE_LL_S_INIT_MASTER | \ + BLE_LL_S_PS_CENTRAL | \ + BLE_LL_S_AS_CENTRAL | \ + BLE_LL_S_PS_PERIPH | \ + BLE_LL_S_AS_PERIPH | \ + BLE_LL_S_INIT_CENTRAL | \ BLE_LL_S_LDCA | \ BLE_LL_S_LDCA_PS | \ BLE_LL_S_LDCA_AS | \ BLE_LL_S_CA_INIT | \ BLE_LL_S_HDCA_INIT | \ BLE_LL_S_LDCA_INIT | \ - BLE_LL_S_CA_MASTER | \ - BLE_LL_S_HDCA_MASTER | \ - BLE_LL_S_LDCA_MASTER | \ - BLE_LL_S_CA_SLAVE | \ - BLE_LL_S_HDCA_SLAVE | \ - BLE_LL_S_LDCA_SLAVE | \ - BLE_LL_S_INIT_SLAVE) + BLE_LL_S_CA_CENTRAL | \ + BLE_LL_S_HDCA_CENTRAL | \ + BLE_LL_S_LDCA_CENTRAL | \ + BLE_LL_S_CA_PERIPH | \ + BLE_LL_S_HDCA_PERIPH | \ + BLE_LL_S_LDCA_PERIPH | \ + BLE_LL_S_INIT_PERIPH) /* The global BLE LL data object */ struct ble_ll_obj g_ble_ll_data; @@ -180,6 +335,7 @@ STATS_NAME_START(ble_ll_stats) STATS_NAME(ble_ll_stats, rx_connect_reqs) STATS_NAME(ble_ll_stats, rx_scan_ind) STATS_NAME(ble_ll_stats, rx_aux_connect_rsp) + STATS_NAME(ble_ll_stats, rx_pdu_on_scan_disabled) STATS_NAME(ble_ll_stats, adv_txg) STATS_NAME(ble_ll_stats, adv_late_starts) STATS_NAME(ble_ll_stats, adv_resched_pdu_fail) @@ -223,21 +379,16 @@ STATS_NAME_START(ble_ll_stats) STATS_NAME_END(ble_ll_stats) static void ble_ll_event_rx_pkt(struct ble_npl_event *ev); +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) || MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) static void ble_ll_event_tx_pkt(struct ble_npl_event *ev); static void ble_ll_event_dbuf_overflow(struct ble_npl_event *ev); - -#if MYNEWT - -/* The BLE LL task data structure */ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -#define BLE_LL_STACK_SIZE (120) -#else -#define BLE_LL_STACK_SIZE (90) #endif +#ifdef MYNEWT +/* The BLE LL task data structure */ struct os_task g_ble_ll_task; -OS_TASK_STACK_DEFINE(g_ble_ll_stack, BLE_LL_STACK_SIZE); +OS_TASK_STACK_DEFINE(g_ble_ll_stack, MYNEWT_VAL(BLE_LL_STACK_SIZE)); #endif /* MYNEWT */ @@ -247,25 +398,6 @@ uint8_t g_dev_addr[BLE_DEV_ADDR_LEN]; /** Our random address */ uint8_t g_random_addr[BLE_DEV_ADDR_LEN]; -static const uint16_t g_ble_ll_pdu_header_tx_time[BLE_PHY_NUM_MODE] = -{ - [BLE_PHY_MODE_1M] = - (BLE_LL_PREAMBLE_LEN + BLE_LL_ACC_ADDR_LEN + BLE_LL_CRC_LEN + - BLE_LL_PDU_HDR_LEN) << 3, - [BLE_PHY_MODE_2M] = - (BLE_LL_PREAMBLE_LEN * 2 + BLE_LL_ACC_ADDR_LEN + BLE_LL_CRC_LEN + - BLE_LL_PDU_HDR_LEN) << 2, - /* For Coded PHY we have exact TX times provided by specification: - * - Preamble, Access Address, CI, TERM1 (always coded as S=8) - * - PDU, CRC, TERM2 (coded as S=2 or S=8) - * (Vol 6, Part B, 2.2). - */ - [BLE_PHY_MODE_CODED_125KBPS] = - (80 + 256 + 16 + 24 + 8 * (BLE_LL_PDU_HDR_LEN * 8 + 24 + 3)), - [BLE_PHY_MODE_CODED_500KBPS] = - (80 + 256 + 16 + 24 + 2 * (BLE_LL_PDU_HDR_LEN * 8 + 24 + 3)), -}; - /** * Counts the number of advertising PDU's received, by type. For advertising * PDU's that contain a destination address, we still count these packets even @@ -383,36 +515,6 @@ ble_ll_rxpdu_alloc(uint16_t len) return NULL; } -int -ble_ll_chk_txrx_octets(uint16_t octets) -{ - int rc; - - if ((octets < BLE_LL_CONN_SUPP_BYTES_MIN) || - (octets > BLE_LL_CONN_SUPP_BYTES_MAX)) { - rc = 0; - } else { - rc = 1; - } - - return rc; -} - -int -ble_ll_chk_txrx_time(uint16_t time) -{ - int rc; - - if ((time < BLE_LL_CONN_SUPP_TIME_MIN) || - (time > BLE_LL_CONN_SUPP_TIME_MAX)) { - rc = 0; - } else { - rc = 1; - } - - return rc; -} - /** * Checks to see if the address is a resolvable private address. * @@ -460,8 +562,8 @@ ble_ll_addr_subtype(const uint8_t *addr, uint8_t addr_type) } } -int -ble_ll_is_valid_public_addr(const uint8_t *addr) +static int +ble_ll_is_valid_addr(const uint8_t *addr) { int i; @@ -527,13 +629,13 @@ ble_ll_is_valid_own_addr_type(uint8_t own_addr_type, const uint8_t *random_addr) #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) case BLE_HCI_ADV_OWN_ADDR_PRIV_PUB: #endif - rc = ble_ll_is_valid_public_addr(g_dev_addr); + rc = ble_ll_is_valid_addr(g_dev_addr); break; case BLE_HCI_ADV_OWN_ADDR_RANDOM: #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) case BLE_HCI_ADV_OWN_ADDR_PRIV_RAND: #endif - rc = ble_ll_is_valid_random_addr(random_addr); + rc = ble_ll_is_valid_addr(random_addr); break; default: rc = 0; @@ -576,24 +678,35 @@ ble_ll_set_random_addr(const uint8_t *cmdbuf, uint8_t len, bool hci_adv_ext) * Test specification extends this also to initiating. */ - if (g_ble_ll_conn_create_sm || ble_ll_scan_enabled() || - (!hci_adv_ext && ble_ll_adv_enabled())) { +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + if (g_ble_ll_conn_create_sm.connsm) { return BLE_ERR_CMD_DISALLOWED; } +#endif - if (!ble_ll_is_valid_random_addr(cmd->addr)) { - return BLE_ERR_INV_HCI_CMD_PARMS; +#if MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) + if (ble_ll_scan_enabled()){ + return BLE_ERR_CMD_DISALLOWED; + } +#endif + +#if MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) + if (!hci_adv_ext && ble_ll_adv_enabled()) { + return BLE_ERR_CMD_DISALLOWED; } +#endif memcpy(g_random_addr, cmd->addr, BLE_DEV_ADDR_LEN); #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) +#if MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) /* For instance 0 we need same address if legacy advertising might be * used. If extended advertising is in use than this command doesn't * affect instance 0. */ if (!hci_adv_ext) ble_ll_adv_set_random_addr(cmd->addr, 0); +#endif #endif return BLE_ERR_SUCCESS; @@ -667,26 +780,39 @@ ble_ll_wfr_timer_exp(void *arg) /* If we have started a reception, there is nothing to do here */ if (!rx_start) { switch (lls) { +#if MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) case BLE_LL_STATE_ADV: ble_ll_adv_wfr_timer_exp(); break; +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) case BLE_LL_STATE_CONNECTION: ble_ll_conn_wfr_timer_exp(); break; +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) case BLE_LL_STATE_SCANNING: ble_ll_scan_wfr_timer_exp(); break; - case BLE_LL_STATE_INITIATING: - ble_ll_conn_init_wfr_timer_exp(); +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) + case BLE_LL_STATE_SCAN_AUX: + ble_ll_scan_aux_wfr_timer_exp(); break; +#endif +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) + case BLE_LL_STATE_SYNC: + ble_ll_sync_wfr_timer_exp(); + break; +#endif +#endif #if MYNEWT_VAL(BLE_LL_DTM) case BLE_LL_STATE_DTM: ble_ll_dtm_wfr_timer_exp(); break; #endif -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) - case BLE_LL_STATE_SYNC: - ble_ll_sync_wfr_timer_exp(); +#if MYNEWT_VAL(BLE_LL_EXT) + case BLE_LL_STATE_EXTERNAL: + ble_ll_ext_wfr_timer_exp(); break; #endif default: @@ -703,6 +829,7 @@ ble_ll_wfr_timer_exp(void *arg) * Context: Link layer task * */ +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) || MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) static void ble_ll_tx_pkt_in(void) { @@ -731,7 +858,7 @@ ble_ll_tx_pkt_in(void) /* Do some basic error checking */ pb = handle & 0x3000; - if ((pkthdr->omp_len != length) || (pb > 0x1000) || (length == 0)) { + if ((pkthdr->omp_len != length) || (pb > 0x1000)) { /* This is a bad ACL packet. Count a stat and free it */ STATS_INC(ble_ll_stats, bad_acl_hdr); os_mbuf_free_chain(om); @@ -742,6 +869,7 @@ ble_ll_tx_pkt_in(void) ble_ll_conn_tx_pkt_in(om, handle, length); } } +#endif /** * Count Link Layer statistics for received PDUs @@ -758,7 +886,12 @@ ble_ll_count_rx_stats(struct ble_mbuf_hdr *hdr, uint16_t len, uint8_t pdu_type) bool connection_data; crcok = BLE_MBUF_HDR_CRC_OK(hdr); + +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) connection_data = (BLE_MBUF_HDR_RX_STATE(hdr) == BLE_LL_STATE_CONNECTION); +#else + connection_data = false; +#endif #if MYNEWT_VAL(BLE_LL_DTM) /* Reuse connection stats for DTM */ @@ -825,28 +958,41 @@ ble_ll_rx_pkt_in(void) /* Process the data or advertising pdu */ /* Process the PDU */ switch (BLE_MBUF_HDR_RX_STATE(ble_hdr)) { +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) case BLE_LL_STATE_CONNECTION: ble_ll_conn_rx_data_pdu(m, ble_hdr); /* m is going to be free by function above */ m = NULL; break; +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) case BLE_LL_STATE_ADV: ble_ll_adv_rx_pkt_in(pdu_type, rxbuf, ble_hdr); break; +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) case BLE_LL_STATE_SCANNING: ble_ll_scan_rx_pkt_in(pdu_type, m, ble_hdr); break; - case BLE_LL_STATE_INITIATING: - ble_ll_init_rx_pkt_in(pdu_type, rxbuf, ble_hdr); +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) + case BLE_LL_STATE_SYNC: + ble_ll_sync_rx_pkt_in(m, ble_hdr); break; +#endif +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) + case BLE_LL_STATE_SCAN_AUX: + ble_ll_scan_aux_rx_pkt_in(m, ble_hdr); + break; +#endif +#endif #if MYNEWT_VAL(BLE_LL_DTM) case BLE_LL_STATE_DTM: ble_ll_dtm_rx_pkt_in(m, ble_hdr); break; #endif -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) - case BLE_LL_STATE_SYNC: - ble_ll_sync_rx_pkt_in(m, ble_hdr); +#if MYNEWT_VAL(BLE_LL_EXT) + case BLE_LL_STATE_EXTERNAL: + ble_ll_ext_rx_pkt_in(m, ble_hdr); break; #endif default: @@ -873,9 +1019,10 @@ ble_ll_rx_pdu_in(struct os_mbuf *rxpdu) pkthdr = OS_MBUF_PKTHDR(rxpdu); STAILQ_INSERT_TAIL(&g_ble_ll_data.ll_rx_pkt_q, pkthdr, omp_next); - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &g_ble_ll_data.ll_rx_pkt_ev); + ble_ll_event_add(&g_ble_ll_data.ll_rx_pkt_ev); } +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) || MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) /** * Called to put a packet on the Link Layer transmit packet queue. * @@ -891,7 +1038,7 @@ ble_ll_acl_data_in(struct os_mbuf *txpkt) OS_ENTER_CRITICAL(sr); STAILQ_INSERT_TAIL(&g_ble_ll_data.ll_tx_pkt_q, pkthdr, omp_next); OS_EXIT_CRITICAL(sr); - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &g_ble_ll_data.ll_tx_pkt_ev); + ble_ll_event_add(&g_ble_ll_data.ll_tx_pkt_ev); } /** @@ -904,8 +1051,9 @@ ble_ll_acl_data_in(struct os_mbuf *txpkt) void ble_ll_data_buffer_overflow(void) { - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &g_ble_ll_data.ll_dbuf_overflow_ev); + ble_ll_event_add(&g_ble_ll_data.ll_dbuf_overflow_ev); } +#endif /** * Called when a HW error occurs. @@ -963,26 +1111,39 @@ ble_ll_rx_start(uint8_t *rxbuf, uint8_t chan, struct ble_mbuf_hdr *rxhdr) pdu_type); switch (g_ble_ll_data.ll_state) { +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) case BLE_LL_STATE_CONNECTION: rc = ble_ll_conn_rx_isr_start(rxhdr, ble_phy_access_addr_get()); break; +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) case BLE_LL_STATE_ADV: rc = ble_ll_adv_rx_isr_start(pdu_type); break; - case BLE_LL_STATE_INITIATING: - rc = ble_ll_init_rx_isr_start(pdu_type, rxhdr); - break; +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) case BLE_LL_STATE_SCANNING: rc = ble_ll_scan_rx_isr_start(pdu_type, &rxhdr->rxinfo.flags); break; +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) + case BLE_LL_STATE_SYNC: + rc = ble_ll_sync_rx_isr_start(pdu_type, rxhdr); + break; +#endif +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) + case BLE_LL_STATE_SCAN_AUX: + rc = ble_ll_scan_aux_rx_isr_start(pdu_type, rxhdr); + break; +#endif +#endif #if MYNEWT_VAL(BLE_LL_DTM) case BLE_LL_STATE_DTM: rc = ble_ll_dtm_rx_isr_start(rxhdr, ble_phy_access_addr_get()); break; #endif -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) - case BLE_LL_STATE_SYNC: - rc = ble_ll_sync_rx_isr_start(pdu_type, rxhdr); +#if MYNEWT_VAL(BLE_LL_EXT) + case BLE_LL_STATE_EXTERNAL: + rc = ble_ll_ext_rx_isr_start(pdu_type, rxhdr); break; #endif default: @@ -1028,6 +1189,13 @@ ble_ll_rx_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr) ble_ll_trace_u32x3(BLE_LL_TRACE_ID_RX_END, pdu_type, len, rxhdr->rxinfo.flags); +#if MYNEWT_VAL(BLE_LL_EXT) + if (BLE_MBUF_HDR_RX_STATE(rxhdr) == BLE_LL_STATE_EXTERNAL) { + rc = ble_ll_ext_rx_isr_end(rxbuf, rxhdr); + return rc; + } +#endif + #if MYNEWT_VAL(BLE_LL_DTM) if (BLE_MBUF_HDR_RX_STATE(rxhdr) == BLE_LL_STATE_DTM) { rc = ble_ll_dtm_rx_isr_end(rxbuf, rxhdr); @@ -1035,12 +1203,14 @@ ble_ll_rx_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr) } #endif +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) if (BLE_MBUF_HDR_RX_STATE(rxhdr) == BLE_LL_STATE_CONNECTION) { rc = ble_ll_conn_rx_isr_end(rxbuf, rxhdr); return rc; } +#endif -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) && MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) if (BLE_MBUF_HDR_RX_STATE(rxhdr) == BLE_LL_STATE_SYNC) { rc = ble_ll_sync_rx_isr_end(rxbuf, rxhdr); return rc; @@ -1088,6 +1258,7 @@ ble_ll_rx_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr) /* Hand packet to the appropriate state machine (if crc ok) */ rxpdu = NULL; switch (BLE_MBUF_HDR_RX_STATE(rxhdr)) { +#if MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) case BLE_LL_STATE_ADV: if (!badpkt) { rxpdu = ble_ll_rxpdu_alloc(len + BLE_LL_PDU_HDR_LEN); @@ -1097,6 +1268,8 @@ ble_ll_rx_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr) } rc = ble_ll_adv_rx_isr_end(pdu_type, rxpdu, crcok); break; +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) case BLE_LL_STATE_SCANNING: if (!badpkt) { rxpdu = ble_ll_rxpdu_alloc(len + BLE_LL_PDU_HDR_LEN); @@ -1106,9 +1279,18 @@ ble_ll_rx_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr) } rc = ble_ll_scan_rx_isr_end(rxpdu, crcok); break; - case BLE_LL_STATE_INITIATING: - rc = ble_ll_init_rx_isr_end(rxbuf, crcok, rxhdr); +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) + case BLE_LL_STATE_SCAN_AUX: + if (!badpkt) { + rxpdu = ble_ll_rxpdu_alloc(len + BLE_LL_PDU_HDR_LEN); + if (rxpdu) { + ble_phy_rxpdu_copy(rxbuf, rxpdu); + } + } + rc = ble_ll_scan_aux_rx_isr_end(rxpdu, crcok); break; +#endif +#endif default: rc = -1; STATS_INC(ble_ll_stats, bad_ll_state); @@ -1164,6 +1346,7 @@ ble_ll_event_rx_pkt(struct ble_npl_event *ev) ble_ll_rx_pkt_in(); } +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) || MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) static void ble_ll_event_tx_pkt(struct ble_npl_event *ev) { @@ -1181,6 +1364,7 @@ ble_ll_event_comp_pkts(struct ble_npl_event *ev) { ble_ll_conn_num_comp_pkts_event_send(NULL); } +#endif /** * Link Layer task. @@ -1197,18 +1381,14 @@ ble_ll_task(void *arg) /* Init ble phy */ ble_phy_init(); - /* Set output power to 1mW (0 dBm) */ - ble_phy_txpwr_set(MYNEWT_VAL(BLE_LL_TX_PWR_DBM)); - - /* Register callback for transport */ - ble_hci_trans_cfg_ll(ble_ll_hci_cmd_rx, NULL, ble_ll_hci_acl_rx, NULL); - - /* Tell the host that we are ready to receive packets */ - ble_ll_hci_send_noop(); + /* Set output power to default */ + g_ble_ll_tx_power = ble_ll_tx_power_round(MIN(MYNEWT_VAL(BLE_LL_TX_PWR_DBM), + MYNEWT_VAL(BLE_LL_TX_PWR_MAX_DBM))); + g_ble_ll_tx_power_phy_current = INT8_MAX; while (1) { ev = ble_npl_eventq_get(&g_ble_ll_data.ll_evq, BLE_NPL_TIME_FOREVER); - assert(ev); + BLE_LL_ASSERT(ev); ble_npl_event_run(ev); } } @@ -1226,6 +1406,10 @@ void ble_ll_state_set(uint8_t ll_state) { g_ble_ll_data.ll_state = ll_state; + + if (ll_state == BLE_LL_STATE_STANDBY) { + BLE_LL_DEBUG_GPIO(SCHED_ITEM, 0); + } } /** @@ -1246,16 +1430,29 @@ ble_ll_state_get(void) /** * ble ll event send * - * Send an event to the Link Layer task + * Add an event to the Link Layer task * * @param ev Event to add to the Link Layer event queue. */ void -ble_ll_event_send(struct ble_npl_event *ev) +ble_ll_event_add(struct ble_npl_event *ev) { ble_npl_eventq_put(&g_ble_ll_data.ll_evq, ev); } +/** + * ble ll event remove + * + * Remove an event from the Link Layer task + * + * @param ev Event to remove from the Link Layer event queue. + */ +void +ble_ll_event_remove(struct ble_npl_event *ev) +{ + ble_npl_eventq_remove(&g_ble_ll_data.ll_evq, ev); +} + /** * Returns the features supported by the link layer * @@ -1278,6 +1475,7 @@ ble_ll_read_supp_features(void) return g_ble_ll_data.ll_supp_features; } +#if BLE_LL_HOST_CONTROLLED_FEATURES /** * Sets the features controlled by the host. * @@ -1286,27 +1484,29 @@ ble_ll_read_supp_features(void) int ble_ll_set_host_feat(const uint8_t *cmdbuf, uint8_t len) { - const struct ble_hci_le_set_host_feat_cp *cmd = (const void *) cmdbuf; + const struct ble_hci_le_set_host_feature_cp *cmd = (const void *) cmdbuf; uint64_t mask; if (len != sizeof(*cmd)) { return BLE_ERR_INV_HCI_CMD_PARMS; } +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) || MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) if (!SLIST_EMPTY(&g_ble_ll_conn_active_list)) { return BLE_ERR_CMD_DISALLOWED; } +#endif - if ((cmd->bit_num > 0x3F) || (cmd->val > 1)) { + if ((cmd->bit_num > 0x3F) || (cmd->bit_val > 1)) { return BLE_ERR_INV_HCI_CMD_PARMS; } mask = (uint64_t)1 << (cmd->bit_num); - if (!(mask & BLE_LL_HOST_CONTROLLED_FEATURES)) { + if (!(mask & g_ble_ll_host_controlled_features)) { return BLE_ERR_UNSUPPORTED; } - if (cmd->val == 0) { + if (cmd->bit_val == 0) { g_ble_ll_data.ll_supp_features &= ~(mask); } else { g_ble_ll_data.ll_supp_features |= mask; @@ -1314,6 +1514,8 @@ ble_ll_set_host_feat(const uint8_t *cmdbuf, uint8_t len) return BLE_ERR_SUCCESS; } +#endif + /** * Flush a link layer packet queue. * @@ -1360,7 +1562,7 @@ ble_ll_mbuf_init(struct os_mbuf *m, uint8_t pdulen, uint8_t hdr) /* Set BLE transmit header */ ble_hdr = BLE_MBUF_HDR_PTR(m); - ble_hdr->txinfo.flags = 0; + ble_hdr->txinfo.num_data_pkt = 0; ble_hdr->txinfo.offset = 0; ble_hdr->txinfo.pyld_len = pdulen; ble_hdr->txinfo.hdr_byte = hdr; @@ -1393,6 +1595,7 @@ ble_ll_validate_task(void) int ble_ll_reset(void) { + uint8_t phy_mask; int rc; os_sr_t sr; @@ -1402,22 +1605,39 @@ ble_ll_reset(void) OS_ENTER_CRITICAL(sr); ble_phy_disable(); ble_ll_sched_stop(); +#if MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) ble_ll_scan_reset(); +#endif ble_ll_rfmgmt_reset(); OS_EXIT_CRITICAL(sr); +#if MYNEWT_VAL(BLE_LL_EXT) + ble_ll_ext_reset(); +#endif + +#if MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) /* Stop any advertising */ ble_ll_adv_reset(); +#endif #if MYNEWT_VAL(BLE_LL_DTM) ble_ll_dtm_reset(); #endif /* Stop sync */ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) && MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) ble_ll_sync_reset(); #endif + /* reset power compensation */ + g_ble_ll_tx_power_compensation = 0; + g_ble_ll_rx_power_compensation = 0; + + /* Set output power to default */ + g_ble_ll_tx_power = ble_ll_tx_power_round(MIN(MYNEWT_VAL(BLE_LL_TX_PWR_DBM), + MYNEWT_VAL(BLE_LL_TX_PWR_MAX_DBM))); + g_ble_ll_tx_power_phy_current = INT8_MAX; + /* FLush all packets from Link layer queues */ ble_ll_flush_pkt_queue(&g_ble_ll_data.ll_tx_pkt_q); ble_ll_flush_pkt_queue(&g_ble_ll_data.ll_rx_pkt_q); @@ -1426,11 +1646,27 @@ ble_ll_reset(void) STATS_RESET(ble_ll_stats); /* Reset any preferred PHYs */ - g_ble_ll_data.ll_pref_tx_phys = 0; - g_ble_ll_data.ll_pref_rx_phys = 0; + phy_mask = BLE_PHY_MASK_1M; +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY) + phy_mask |= BLE_PHY_MASK_2M; +#endif +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) + phy_mask |= BLE_PHY_MASK_CODED; +#endif + phy_mask &= MYNEWT_VAL(BLE_LL_CONN_PHY_DEFAULT_PREF_MASK); + BLE_LL_ASSERT(phy_mask); + g_ble_ll_data.ll_pref_tx_phys = phy_mask; + g_ble_ll_data.ll_pref_rx_phys = phy_mask; + + /* Enable all channels in channel map */ + g_ble_ll_data.chan_map_used = BLE_PHY_NUM_DATA_CHANS; + memset(g_ble_ll_data.chan_map, 0xff, BLE_LL_CHAN_MAP_LEN - 1); + g_ble_ll_data.chan_map[4] = 0x1f; +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) /* Reset connection module */ ble_ll_conn_module_reset(); +#endif /* All this does is re-initialize the event masks so call the hci init */ ble_ll_hci_init(); @@ -1452,41 +1688,26 @@ ble_ll_reset(void) ble_ll_resolv_list_reset(); #endif - /* Re-initialize the PHY */ - rc = ble_phy_init(); - - return rc; -} -uint32_t -ble_ll_pdu_tx_time_get(uint16_t payload_len, int phy_mode) -{ - uint32_t usecs; +#if MYNEWT_VAL(BLE_FEM_PA) + ble_fem_pa_init(); +#endif +#if MYNEWT_VAL(BLE_FEM_LNA) + ble_fem_lna_init(); +#endif -#if (BLE_LL_BT5_PHY_SUPPORTED) - if (phy_mode == BLE_PHY_MODE_1M) { - /* 8 usecs per byte */ - usecs = payload_len << 3; - } else if (phy_mode == BLE_PHY_MODE_2M) { - /* 4 usecs per byte */ - usecs = payload_len << 2; - } else if (phy_mode == BLE_PHY_MODE_CODED_125KBPS) { - /* S=8 => 8 * 8 = 64 usecs per byte */ - usecs = payload_len << 6; - } else if (phy_mode == BLE_PHY_MODE_CODED_500KBPS) { - /* S=2 => 2 * 8 = 16 usecs per byte */ - usecs = payload_len << 4; - } else { - BLE_LL_ASSERT(0); - } +#if MYNEWT_VAL(BLE_LL_ISO_BROADCASTER) + ble_ll_iso_big_reset(); +#endif - usecs += g_ble_ll_pdu_header_tx_time[phy_mode]; -#else - usecs = (((payload_len) + BLE_LL_PDU_HDR_LEN + BLE_LL_ACC_ADDR_LEN - + BLE_LL_PREAMBLE_LEN + BLE_LL_CRC_LEN) << 3); +#if MYNEWT_VAL(BLE_LL_ISO) + ble_ll_iso_reset(); #endif - return usecs; + /* Re-initialize the PHY */ + rc = ble_phy_init(); + + return rc; } uint16_t @@ -1497,14 +1718,14 @@ ble_ll_pdu_max_tx_octets_get(uint32_t usecs, int phy_mode) BLE_LL_ASSERT(phy_mode < BLE_PHY_NUM_MODE); - header_tx_time = g_ble_ll_pdu_header_tx_time[phy_mode]; + header_tx_time = ble_ll_pdu_us(0, phy_mode); /* * Current conn max tx time can be too short to even send a packet header * and this can happen if we changed connection form uncoded to coded phy. * However, the lower bound for conn max tx time (all of them) depends on * current phy (uncoded/coded) but it always allows to send at least 27 - * bytes of payload thus we alwyas return at least 27 from here. + * bytes of payload thus we always return at least 27 from here. * * Reference: * Core v5.0, Vol 6, Part B, section 4.5.10 @@ -1534,7 +1755,7 @@ ble_ll_pdu_max_tx_octets_get(uint32_t usecs, int phy_mode) } /* see comment at the beginning */ - return max(27, octets); + return MAX(27, octets); } static inline bool @@ -1543,6 +1764,20 @@ ble_ll_is_addr_empty(const uint8_t *addr) return memcmp(addr, BLE_ADDR_ANY, BLE_DEV_ADDR_LEN) == 0; } +#if MYNEWT_VAL(BLE_LL_HCI_VS_EVENT_ON_ASSERT) +void +ble_ll_assert(const char *file, unsigned line) +{ + ble_ll_hci_ev_send_vs_assert(file, line); + + if (hal_debugger_connected()) { + __BKPT(0); + } + + while (1); +} +#endif + /** * Initialize the Link Layer. Should be called only once * @@ -1553,6 +1788,10 @@ ble_ll_init(void) { int rc; uint64_t features; +#if MYNEWT_VAL(BLE_LL_PUBLIC_DEV_ADDR) + uint64_t pub_dev_addr; + int i; +#endif ble_addr_t addr; struct ble_ll_obj *lldata; @@ -1564,10 +1803,17 @@ ble_ll_init(void) /* Set public device address if not already set */ if (ble_ll_is_addr_empty(g_dev_addr)) { - /* Use sycfg address if configured, otherwise try to read from HW */ - if (!ble_ll_is_addr_empty(MYNEWT_VAL(BLE_PUBLIC_DEV_ADDR))) { - memcpy(g_dev_addr, MYNEWT_VAL(BLE_PUBLIC_DEV_ADDR), BLE_DEV_ADDR_LEN); - } else { +#if MYNEWT_VAL(BLE_LL_PUBLIC_DEV_ADDR) + pub_dev_addr = MYNEWT_VAL(BLE_LL_PUBLIC_DEV_ADDR); + + for (i = 0; i < BLE_DEV_ADDR_LEN; i++) { + g_dev_addr[i] = pub_dev_addr & 0xff; + pub_dev_addr >>= 8; + } +#else + memcpy(g_dev_addr, MYNEWT_VAL(BLE_PUBLIC_DEV_ADDR), BLE_DEV_ADDR_LEN); +#endif + if (ble_ll_is_addr_empty(g_dev_addr)) { rc = ble_hw_get_public_addr(&addr); if (!rc) { memcpy(g_dev_addr, &addr.val[0], BLE_DEV_ADDR_LEN); @@ -1580,9 +1826,16 @@ ble_ll_init(void) /* Get pointer to global data object */ lldata = &g_ble_ll_data; +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) || MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) /* Set acl pkt size and number */ - lldata->ll_num_acl_pkts = MYNEWT_VAL(BLE_ACL_BUF_COUNT); - lldata->ll_acl_pkt_size = MYNEWT_VAL(BLE_ACL_BUF_SIZE); + lldata->ll_num_acl_pkts = MYNEWT_VAL(BLE_TRANSPORT_ACL_FROM_HS_COUNT); + lldata->ll_acl_pkt_size = MYNEWT_VAL(BLE_TRANSPORT_ACL_SIZE); +#endif + +#if MYNEWT_VAL(BLE_LL_ISO) + lldata->ll_num_iso_pkts = MYNEWT_VAL(BLE_TRANSPORT_ISO_FROM_HS_COUNT); + lldata->ll_iso_pkt_size = MYNEWT_VAL(BLE_TRANSPORT_ISO_SIZE); +#endif /* Initialize eventq */ ble_npl_eventq_init(&lldata->ll_evq); @@ -1593,11 +1846,15 @@ ble_ll_init(void) /* Initialize transmit (from host) and receive packet (from phy) event */ ble_npl_event_init(&lldata->ll_rx_pkt_ev, ble_ll_event_rx_pkt, NULL); +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) || MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) ble_npl_event_init(&lldata->ll_tx_pkt_ev, ble_ll_event_tx_pkt, NULL); +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) || MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) /* Initialize data buffer overflow event and completed packets */ ble_npl_event_init(&lldata->ll_dbuf_overflow_ev, ble_ll_event_dbuf_overflow, NULL); ble_npl_event_init(&lldata->ll_comp_pkt_ev, ble_ll_event_comp_pkts, NULL); +#endif /* Initialize the HW error timer */ ble_npl_callout_init(&g_ble_ll_data.ll_hw_err_timer, @@ -1611,14 +1868,20 @@ ble_ll_init(void) /* Init the scheduler */ ble_ll_sched_init(); +#if MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) /* Initialize advertiser */ ble_ll_adv_init(); +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) /* Initialize a scanner */ ble_ll_scan_init(); +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) || MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) /* Initialize the connection module */ ble_ll_conn_module_init(); +#endif /* Set the supported features. NOTE: we always support extended reject. */ features = BLE_LL_FEAT_EXTENDED_REJ; @@ -1629,8 +1892,8 @@ ble_ll_init(void) #if MYNEWT_VAL(BLE_LL_CFG_FEAT_CONN_PARAM_REQ) features |= BLE_LL_FEAT_CONN_PARM_REQ; #endif -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_SLAVE_INIT_FEAT_XCHG) - features |= BLE_LL_FEAT_SLAVE_INIT; +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_PERIPH_INIT_FEAT_XCHG) + features |= BLE_LL_FEAT_PERIPH_INIT; #endif #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) features |= BLE_LL_FEAT_LE_ENCRYPTION; @@ -1664,8 +1927,10 @@ ble_ll_init(void) #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) features |= BLE_LL_FEAT_PERIODIC_ADV; +#if MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) ble_ll_sync_init(); #endif +#endif #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER) features |= BLE_LL_FEAT_SYNC_TRANS_RECV; @@ -1676,11 +1941,25 @@ ble_ll_init(void) features |= BLE_LL_FEAT_SCA_UPDATE; #endif -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ISO) - features |= BLE_LL_FEAT_CIS_MASTER; - features |= BLE_LL_FEAT_CIS_SLAVE; +#if MYNEWT_VAL(BLE_LL_ISO_BROADCASTER) features |= BLE_LL_FEAT_ISO_BROADCASTER; - features |= BLE_LL_FEAT_ISO_HOST_SUPPORT; +#endif + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE) + features |= BLE_LL_FEAT_CONN_SUBRATING; +#endif + +#if MYNEWT_VAL(BLE_LL_CHANNEL_SOUNDING) + features |= BLE_LL_FEAT_CS; + features |= BLE_LL_FEAT_CS_PCT_QUALITY_IND; +#endif + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_ADI_SUPPORT) + features |= BLE_LL_FEAT_PERIODIC_ADV_ADI; +#endif + +#if MYNEWT_VAL(BLE_LL_ADV_CODING_SELECTION) + features |= BLE_LL_FEAT_ADV_CODING_SEL; #endif lldata->ll_supp_features = features; @@ -1700,11 +1979,26 @@ ble_ll_init(void) ble_ll_dtm_init(); #endif -#if MYNEWT +#if MYNEWT_VAL(BLE_LL_HCI_VS) + ble_ll_hci_vs_init(); +#endif + +#if MYNEWT_VAL(BLE_LL_ISO) + ble_ll_iso_init(); +#endif +#if MYNEWT_VAL(BLE_LL_ISO_BROADCASTER) + ble_ll_iso_big_init(); +#endif + +#if MYNEWT_VAL(BLE_LL_EXT) + ble_ll_ext_init(); +#endif + +#ifdef MYNEWT /* Initialize the LL task */ os_task_init(&g_ble_ll_task, "ble_ll", ble_ll_task, NULL, MYNEWT_VAL(BLE_LL_PRIO), OS_WAIT_FOREVER, g_ble_ll_stack, - BLE_LL_STACK_SIZE); + MYNEWT_VAL(BLE_LL_STACK_SIZE)); #else /* @@ -1714,3 +2008,121 @@ ble_ll_init(void) #endif } + +/* Transport APIs for LL side */ + +int +ble_transport_to_ll_cmd_impl(void *buf) +{ + return ble_ll_hci_cmd_rx(buf); +} + +int +ble_transport_to_ll_acl_impl(struct os_mbuf *om) +{ + return ble_ll_hci_acl_rx(om); +} + +int +ble_transport_to_ll_iso_impl(struct os_mbuf *om) +{ + return ble_ll_hci_iso_rx(om); +} + +void +ble_transport_ll_init(void) +{ + /* Tell the host that we are ready to receive packets */ + ble_ll_hci_send_noop(); +} + +int +ble_ll_tx_power_round(int tx_power) +{ +#if MYNEWT_VAL(BLE_FEM_PA) +#if MYNEWT_VAL(BLE_FEM_PA_GAIN_TUNABLE) + tx_power = ble_fem_pa_tx_power_round(tx_power); +#else + tx_power = ble_phy_tx_power_round(tx_power); + tx_power += MYNEWT_VAL(BLE_FEM_PA_GAIN); +#endif +#else + tx_power = ble_phy_tx_power_round(tx_power); +#endif + + return tx_power; +} + +void +ble_ll_tx_power_set(int tx_power) +{ +#if MYNEWT_VAL(BLE_FEM_PA) +#if MYNEWT_VAL(BLE_FEM_PA_GAIN_TUNABLE) + /* TODO should rounding be in assert only? or just skip it and assume + * power is already rounded? + */ + tx_power = ble_fem_pa_tx_power_round(tx_power); + tx_power = ble_fem_pa_tx_power_set(tx_power); +#else + tx_power -= MYNEWT_VAL(BLE_FEM_PA_GAIN); +#endif +#endif + + /* If current TX power configuration matches requested one we don't need + * to update PHY tx power. + */ + if (g_ble_ll_tx_power_phy_current == tx_power) { + return; + } + + g_ble_ll_tx_power_phy_current = tx_power; + ble_phy_tx_power_set(tx_power); +} + +int +ble_ll_is_busy(unsigned int flags) +{ +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) || MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) + struct ble_ll_conn_sm *cur; + int i = 0; +#endif + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) && MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) + if (ble_ll_sync_enabled()) { + return 1; + } +#endif + +#if MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) + if (ble_ll_adv_enabled()) { + return 1; + } +#endif + +#if MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) + if (ble_ll_scan_enabled()) { + return 1; + } +#endif + +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + if (g_ble_ll_conn_create_sm.connsm) { + return 1; + } +#endif + +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) || MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) + if (!(flags & BLE_LL_BUSY_EXCLUDE_CONNECTIONS)) { + STAILQ_FOREACH(cur, &g_ble_ll_conn_free_list, free_stqe) { + i++; + } + + /* check if all connection objects are free */ + if (i < MYNEWT_VAL(BLE_MAX_CONNECTIONS)) { + return 1; + } + } +#endif + + return 0; +} diff --git a/nimble/controller/src/ble_ll_adv.c b/nimble/controller/src/ble_ll_adv.c index 6ab6b24331..e62b2c3a66 100644 --- a/nimble/controller/src/ble_ll_adv.c +++ b/nimble/controller/src/ble_ll_adv.c @@ -16,31 +16,38 @@ * specific language governing permissions and limitations * under the License. */ + +#include #include #include #include #include #include "syscfg/syscfg.h" #include "os/os.h" -#include "os/os_cputime.h" +#include "os/util.h" #include "ble/xcvr.h" #include "nimble/ble.h" #include "nimble/nimble_opt.h" #include "nimble/hci_common.h" -#include "nimble/ble_hci_trans.h" #include "controller/ble_phy.h" #include "controller/ble_hw.h" #include "controller/ble_ll.h" +#include "controller/ble_ll_pdu.h" #include "controller/ble_ll_hci.h" #include "controller/ble_ll_adv.h" #include "controller/ble_ll_sched.h" #include "controller/ble_ll_scan.h" #include "controller/ble_ll_whitelist.h" #include "controller/ble_ll_resolv.h" +#include "controller/ble_ll_tmr.h" #include "controller/ble_ll_trace.h" #include "controller/ble_ll_utils.h" #include "controller/ble_ll_rfmgmt.h" +#include "controller/ble_ll_iso_big.h" #include "ble_ll_conn_priv.h" +#include "ble_ll_priv.h" + +#if MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) /* XXX: TODO * 1) Need to look at advertising and scan request PDUs. Do I allocate these @@ -56,22 +63,27 @@ struct ble_ll_adv_aux { struct ble_ll_sched_item sch; uint32_t start_time; - uint16_t aux_data_offset; + uint16_t data_offset; uint8_t chan; - uint8_t ext_hdr; - uint8_t aux_data_len; + uint8_t ext_hdr_flags; + uint8_t data_len; uint8_t payload_len; + uint8_t auxptr_zero; }; /* Scheduling data for sync PDUs */ struct ble_ll_adv_sync { struct ble_ll_sched_item sch; uint32_t start_time; - uint16_t sync_data_offset; + uint16_t data_offset; uint8_t chan; - uint8_t ext_hdr; - uint8_t sync_data_len; + uint8_t ext_hdr_flags; + uint8_t data_len; uint8_t payload_len; + uint8_t auxptr_zero; +#if MYNEWT_VAL(BLE_LL_ISO_BROADCASTER) + struct ble_ll_iso_big *big; +#endif }; /* @@ -99,13 +111,12 @@ struct ble_ll_adv_sm uint8_t own_addr_type; uint8_t peer_addr_type; uint8_t adv_chan; + uint8_t retry_event; uint8_t adv_pdu_len; int8_t adv_rpa_index; - int8_t adv_txpwr; + int8_t tx_power; uint16_t flags; uint16_t props; - uint16_t adv_itvl_min; - uint16_t adv_itvl_max; uint32_t adv_itvl_usecs; uint32_t adv_event_start_time; uint32_t adv_pdu_start_time; @@ -118,7 +129,9 @@ struct ble_ll_adv_sm struct os_mbuf *new_adv_data; struct os_mbuf *scan_rsp_data; struct os_mbuf *new_scan_rsp_data; +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) uint8_t *conn_comp_ev; +#endif struct ble_npl_event adv_txdone_ev; struct ble_ll_sched_item adv_sch; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CSA2) @@ -142,13 +155,15 @@ struct ble_ll_adv_sm uint8_t events; uint8_t pri_phy; uint8_t sec_phy; +#if MYNEWT_VAL(BLE_VERSION) >= 54 + uint8_t pri_phy_opt; + uint8_t sec_phy_opt; +#endif #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) struct os_mbuf *periodic_adv_data; struct os_mbuf *periodic_new_data; uint32_t periodic_crcinit; /* only 3 bytes are used */ uint32_t periodic_access_addr; - uint16_t periodic_adv_itvl_min; - uint16_t periodic_adv_itvl_max; uint16_t periodic_adv_props; uint16_t periodic_channel_id; uint16_t periodic_event_cntr; @@ -157,18 +172,34 @@ struct ble_ll_adv_sm uint8_t periodic_adv_active : 1; uint8_t periodic_sync_active : 1; uint8_t periodic_sync_index : 1; +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_ADI_SUPPORT) + uint8_t periodic_include_adi : 1; + uint16_t periodic_adv_adi; +#endif uint8_t periodic_num_used_chans; - uint8_t periodic_chanmap[BLE_LL_CONN_CHMAP_LEN]; - uint32_t periodic_adv_itvl_ticks; - uint8_t periodic_adv_itvl_rem_usec; - uint8_t periodic_adv_event_start_time_remainder; - uint32_t periodic_adv_event_start_time; + uint8_t periodic_chanmap[BLE_LL_CHAN_MAP_LEN]; + uint16_t periodic_adv_itvl; + + uint32_t padv_itvl_us; + + uint16_t padv_anchor_offset; + uint32_t padv_anchor; + uint8_t padv_anchor_rem_us; + + uint32_t padv_event_start; + uint8_t padv_event_start_rem_us; + struct ble_ll_adv_sync periodic_sync[2]; struct ble_npl_event adv_periodic_txdone_ev; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER) uint16_t periodic_event_cntr_last_sent; #endif #endif + +#if MYNEWT_VAL(BLE_LL_ISO_BROADCASTER) + struct ble_ll_iso_big *big; +#endif /* BLE_LL_ISO_BROADCASTER */ + #endif }; @@ -186,31 +217,38 @@ struct ble_ll_adv_sm #define BLE_LL_ADV_SM_FLAG_PERIODIC_DATA_INCOMPLETE 0x1000 #define BLE_LL_ADV_SM_FLAG_PERIODIC_SYNC_SENDING 0x2000 #define BLE_LL_ADV_SM_FLAG_PERIODIC_NEW_DATA 0x4000 +#define BLE_LL_ADV_SM_FLAG_CONN_RSP_TXD_ERR 0x8000 #define ADV_DATA_LEN(_advsm) \ - ((_advsm->adv_data) ? OS_MBUF_PKTLEN(advsm->adv_data) : 0) + (((_advsm)->adv_data) ? OS_MBUF_PKTLEN((_advsm)->adv_data) : 0) #define SCAN_RSP_DATA_LEN(_advsm) \ - ((_advsm->scan_rsp_data) ? OS_MBUF_PKTLEN(advsm->scan_rsp_data) : 0) -#define AUX_DATA_LEN(_advsm) \ - (*(_advsm->aux_data) ? OS_MBUF_PKTLEN(*advsm->aux_data) : 0) + (((_advsm)->scan_rsp_data) ? OS_MBUF_PKTLEN((_advsm)->scan_rsp_data) : 0) -#define AUX_CURRENT(_advsm) (&(_advsm->aux[_advsm->aux_index])) -#define AUX_NEXT(_advsm) (&(_advsm->aux[_advsm->aux_index ^ 1])) +#define AUX_CURRENT(_advsm) \ + (&((_advsm)->aux[(_advsm)->aux_index])) +#define AUX_NEXT(_advsm) \ + (&((_advsm)->aux[(_advsm)->aux_index ^ 1])) +#define AUX_DATA_LEN(_advsm) \ + (*((_advsm)->aux_data) ? OS_MBUF_PKTLEN(*(_advsm)->aux_data) : 0) -#define SYNC_CURRENT(_advsm) (&(_advsm->periodic_sync[_advsm->periodic_sync_index])) -#define SYNC_NEXT(_advsm) (&(_advsm->periodic_sync[_advsm->periodic_sync_index ^ 1])) +#define SYNC_CURRENT(_advsm) \ + (&((_advsm)->periodic_sync[(_advsm)->periodic_sync_index])) +#define SYNC_NEXT(_advsm) \ + (&((_advsm)->periodic_sync[(_advsm)->periodic_sync_index ^ 1])) #define SYNC_DATA_LEN(_advsm) \ - (_advsm->periodic_adv_data ? OS_MBUF_PKTLEN(advsm->periodic_adv_data) : 0) + ((_advsm)->periodic_adv_data ? OS_MBUF_PKTLEN((_advsm)->periodic_adv_data) : 0) /* The advertising state machine global object */ struct ble_ll_adv_sm g_ble_ll_adv_sm[BLE_ADV_INSTANCES]; struct ble_ll_adv_sm *g_ble_ll_cur_adv_sm; +static void ble_ll_adv_drop_event(struct ble_ll_adv_sm *advsm, bool preempted); + static struct ble_ll_adv_sm * ble_ll_adv_sm_find_configured(uint8_t instance) { struct ble_ll_adv_sm *advsm; - int i; + unsigned int i; /* in legacy mode we only allow instance 0 */ if (!ble_ll_hci_adv_mode_ext()) { @@ -260,7 +298,7 @@ ble_ll_adv_active_chanset_set_pri(struct ble_ll_adv_sm *advsm) os_sr_t sr; OS_ENTER_CRITICAL(sr); - assert((advsm->flags & BLE_LL_ADV_SM_FLAG_ACTIVE_CHANSET_MASK) == 0); + BLE_LL_ASSERT((advsm->flags & BLE_LL_ADV_SM_FLAG_ACTIVE_CHANSET_MASK) == 0); advsm->flags &= ~BLE_LL_ADV_SM_FLAG_ACTIVE_CHANSET_MASK; advsm->flags |= 0x10; OS_EXIT_CRITICAL(sr); @@ -273,7 +311,7 @@ ble_ll_adv_active_chanset_set_sec(struct ble_ll_adv_sm *advsm) os_sr_t sr; OS_ENTER_CRITICAL(sr); - assert((advsm->flags & BLE_LL_ADV_SM_FLAG_ACTIVE_CHANSET_MASK) == 0); + BLE_LL_ASSERT((advsm->flags & BLE_LL_ADV_SM_FLAG_ACTIVE_CHANSET_MASK) == 0); advsm->flags &= ~BLE_LL_ADV_SM_FLAG_ACTIVE_CHANSET_MASK; advsm->flags |= 0x20; OS_EXIT_CRITICAL(sr); @@ -309,7 +347,9 @@ static void ble_ll_adv_rpa_update(struct ble_ll_adv_sm *advsm) { if (ble_ll_resolv_gen_rpa(advsm->peer_addr, advsm->peer_addr_type, - advsm->adva, 1)) { + advsm->adva, 1) || + (ble_ll_resolv_local_rpa_get(advsm->own_addr_type & 1, + advsm->adva) == 0)) { ble_ll_adv_flags_set(advsm, BLE_LL_ADV_SM_FLAG_TX_ADD); } else { if (advsm->own_addr_type & 1) { @@ -475,7 +515,7 @@ ble_ll_adv_legacy_pdu_make(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte) } /* An invalid advertising data length indicates a memory overwrite */ - assert(adv_data_len <= BLE_ADV_LEGACY_DATA_MAX_LEN); + BLE_LL_ASSERT(adv_data_len <= BLE_ADV_LEGACY_DATA_MAX_LEN); /* Set the PDU length in the state machine (includes header) */ advsm->adv_pdu_len = pdulen + BLE_LL_PDU_HDR_LEN; @@ -539,10 +579,11 @@ ble_ll_adv_pdu_make(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte) uint8_t ext_hdr_len; uint8_t ext_hdr_flags; uint32_t offset; + bool has_adva; advsm = pducb_arg; - assert(ble_ll_adv_active_chanset_is_pri(advsm)); + BLE_LL_ASSERT(ble_ll_adv_active_chanset_is_pri(advsm)); if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) { return ble_ll_adv_legacy_pdu_make(dptr, advsm, hdr_byte); } @@ -550,8 +591,6 @@ ble_ll_adv_pdu_make(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte) /* only ADV_EXT_IND goes on primary advertising channels */ pdu_type = BLE_ADV_PDU_TYPE_ADV_EXT_IND; - *hdr_byte = pdu_type; - adv_mode = 0; if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_CONNECTABLE) { adv_mode |= BLE_LL_EXT_ADV_MODE_CONN; @@ -560,11 +599,19 @@ ble_ll_adv_pdu_make(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte) adv_mode |= BLE_LL_EXT_ADV_MODE_SCAN; } + has_adva = !MYNEWT_VAL(BLE_LL_EXT_ADV_ADVA_IN_AUX) && + !(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_ANON_ADV); + ext_hdr_len = BLE_LL_EXT_ADV_FLAGS_SIZE + BLE_LL_EXT_ADV_DATA_INFO_SIZE + BLE_LL_EXT_ADV_AUX_PTR_SIZE; ext_hdr_flags = (1 << BLE_LL_EXT_ADV_DATA_INFO_BIT) | (1 << BLE_LL_EXT_ADV_AUX_PTR_BIT); + if (has_adva) { + ext_hdr_len += BLE_LL_EXT_ADV_ADVA_SIZE; + ext_hdr_flags |= (1 << BLE_LL_EXT_ADV_ADVA_BIT); + } + /* ext hdr len and adv mode */ dptr[0] = ext_hdr_len | (adv_mode << 6); dptr += 1; @@ -573,6 +620,15 @@ ble_ll_adv_pdu_make(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte) dptr[0] = ext_hdr_flags; dptr += 1; + if (has_adva) { + /* AdvA */ + if (advsm->flags & BLE_LL_ADV_SM_FLAG_TX_ADD) { + pdu_type |= BLE_ADV_PDU_HDR_TXADD_RAND; + } + memcpy(dptr, advsm->adva, BLE_LL_EXT_ADV_ADVA_SIZE); + dptr += BLE_LL_EXT_ADV_ADVA_SIZE; + } + /* ADI */ dptr[0] = advsm->adi & 0x00ff; dptr[1] = advsm->adi >> 8; @@ -580,7 +636,7 @@ ble_ll_adv_pdu_make(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte) /* AuxPtr */ if (AUX_CURRENT(advsm)->sch.enqueued) { - offset = os_cputime_ticks_to_usecs(AUX_CURRENT(advsm)->start_time - advsm->adv_pdu_start_time); + offset = ble_ll_tmr_t2u(AUX_CURRENT(advsm)->start_time - advsm->adv_pdu_start_time); } else { offset = 0; } @@ -588,89 +644,84 @@ ble_ll_adv_pdu_make(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte) ble_ll_adv_put_aux_ptr(AUX_CURRENT(advsm)->chan, advsm->sec_phy, offset, dptr); + *hdr_byte = pdu_type; + return BLE_LL_EXT_ADV_HDR_LEN + ext_hdr_len; } #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) static void ble_ll_adv_put_syncinfo(struct ble_ll_adv_sm *advsm, - struct ble_ll_conn_sm *connsm, uint8_t *conn_event_cnt, + struct ble_ll_conn_sm *connsm, uint8_t *conn_event_cntr, uint8_t *dptr) { + uint32_t offset_us; + uint32_t offset; + uint32_t anchor_ticks; + uint8_t anchor_rem_us; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER) - uint8_t anchor_usecs; - uint16_t conn_cnt; + uint16_t anchor_event_cntr; #endif - unsigned int event_cnt_off = 0; - uint32_t offset = 0; - uint32_t anchor; - uint8_t units; + uint32_t event_start; + uint8_t event_start_us; + uint32_t event_cntr_offset = 0; if (connsm) { #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER) - anchor = connsm->anchor_point; - anchor_usecs = connsm->anchor_point_usecs; - conn_cnt = connsm->event_cntr; - - /* get anchor for conn event that is before periodic_adv_event_start_time */ - while (CPUTIME_GT(anchor, advsm->periodic_adv_event_start_time)) { - ble_ll_conn_get_anchor(connsm, --conn_cnt, &anchor, &anchor_usecs); - } - - offset = os_cputime_ticks_to_usecs(advsm->periodic_adv_event_start_time - anchor); - offset -= anchor_usecs; - offset += advsm->periodic_adv_event_start_time_remainder; + ble_ll_conn_anchor_get(connsm, &anchor_event_cntr, + &anchor_ticks, &anchor_rem_us); /* connEventCount */ - put_le16(conn_event_cnt, conn_cnt); + put_le16(conn_event_cntr, anchor_event_cntr); +#else + BLE_LL_ASSERT(0); #endif } else { - anchor = advsm->periodic_adv_event_start_time; + anchor_ticks = AUX_CURRENT(advsm)->start_time; + anchor_rem_us = 0; + } - /* Get periodic event that is past AUX start time (so that we always - * provide valid offset if it is not too far in future). This can - * happen if advertising event is interleaved with periodic advertising - * event (when chaining). - */ - while (CPUTIME_GT(AUX_CURRENT(advsm)->start_time, anchor)) { - anchor += advsm->periodic_adv_itvl_ticks; - event_cnt_off++; - } + event_start = advsm->padv_event_start; + event_start_us = advsm->padv_event_start_rem_us; - offset = os_cputime_ticks_to_usecs(anchor - AUX_CURRENT(advsm)->start_time); - offset += advsm->periodic_adv_event_start_time_remainder; - offset += advsm->periodic_adv_itvl_rem_usec; + /* Find padv event that is past anchor item */ + while (LL_TMR_LEQ(event_start, anchor_ticks)) { + ble_ll_tmr_add(&event_start, &event_start_us, advsm->padv_itvl_us); + event_cntr_offset++; } + offset_us = ble_ll_tmr_t2u(event_start - anchor_ticks); + offset_us += event_start_us; + offset_us -= anchor_rem_us; + /* Sync Packet Offset (13 bits), Offset Units (1 bit), Offset Adjust (1 bit), * RFU (1 bit) */ - if (offset > 245700) { - units = 0x20; - offset = offset / 300; - + if (offset_us > 245700) { + offset = offset_us / 300; if (offset >= 0x2000) { if (connsm) { offset -= 0x2000; - units |= 0x40; + /* Offset Units = 1, Offset Adjust = 1 */ + offset |= 0x6000; } else { - /* not able to represent time in offset */ offset = 0; - units = 0x00; - event_cnt_off = 0; + event_cntr_offset = 0; } + } else { + /* Offset Units = 1, Offset Adjust = 0 */ + offset |= 0x2000; } } else { - units = 0x00; - offset = offset / 30; + offset = offset_us / 30; + /* Offset Units = 0, Offset Adjust = 0 */ } - dptr[0] = (offset & 0x000000ff); - dptr[1] = ((offset >> 8) & 0x0000001f) | units; + put_le16(&dptr[0], offset); /* Interval (2 bytes) */ - put_le16(&dptr[2], advsm->periodic_adv_itvl_max); + put_le16(&dptr[2], advsm->periodic_adv_itvl); /* Channels Mask (37 bits) */ dptr[4] = advsm->periodic_chanmap[0]; @@ -691,7 +742,7 @@ ble_ll_adv_put_syncinfo(struct ble_ll_adv_sm *advsm, dptr[15] = (uint8_t)(advsm->periodic_crcinit >> 16); /* Event Counter (2 bytes) */ - put_le16(&dptr[16], advsm->periodic_event_cntr + event_cnt_off); + put_le16(&dptr[16], advsm->periodic_event_cntr + event_cntr_offset); } #endif @@ -711,8 +762,8 @@ ble_ll_adv_aux_pdu_make(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte) advsm = pducb_arg; aux = AUX_CURRENT(advsm); - assert(!(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY)); - assert(ble_ll_adv_active_chanset_is_sec(advsm)); + BLE_LL_ASSERT(!(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY)); + BLE_LL_ASSERT(ble_ll_adv_active_chanset_is_sec(advsm)); /* It's the same for AUX_ADV_IND and AUX_CHAIN_IND */ pdu_type = BLE_ADV_PDU_TYPE_AUX_ADV_IND; @@ -723,17 +774,17 @@ ble_ll_adv_aux_pdu_make(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte) adv_mode |= BLE_LL_EXT_ADV_MODE_CONN; } - ext_hdr_len = aux->payload_len - BLE_LL_EXT_ADV_HDR_LEN - aux->aux_data_len; + ext_hdr_len = aux->payload_len - BLE_LL_EXT_ADV_HDR_LEN - aux->data_len; dptr[0] = (adv_mode << 6) | ext_hdr_len; dptr += 1; /* only put flags if needed */ - if (aux->ext_hdr) { - dptr[0] = aux->ext_hdr; + if (aux->ext_hdr_flags) { + dptr[0] = aux->ext_hdr_flags; dptr += 1; } - if (aux->ext_hdr & (1 << BLE_LL_EXT_ADV_ADVA_BIT)) { + if (aux->ext_hdr_flags & (1 << BLE_LL_EXT_ADV_ADVA_BIT)) { /* Set TxAdd to random if needed. */ if (advsm->flags & BLE_LL_ADV_SM_FLAG_TX_ADD) { @@ -744,7 +795,7 @@ ble_ll_adv_aux_pdu_make(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte) dptr += BLE_LL_EXT_ADV_ADVA_SIZE; } - if (aux->ext_hdr & (1 << BLE_LL_EXT_ADV_TARGETA_BIT)) { + if (aux->ext_hdr_flags & (1 << BLE_LL_EXT_ADV_TARGETA_BIT)) { memcpy(dptr, advsm->initiator_addr, BLE_LL_EXT_ADV_TARGETA_SIZE); dptr += BLE_LL_EXT_ADV_TARGETA_SIZE; @@ -754,13 +805,13 @@ ble_ll_adv_aux_pdu_make(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte) } } - if (aux->ext_hdr & (1 << BLE_LL_EXT_ADV_DATA_INFO_BIT)) { + if (aux->ext_hdr_flags & (1 << BLE_LL_EXT_ADV_DATA_INFO_BIT)) { dptr[0] = advsm->adi & 0x00ff; dptr[1] = advsm->adi >> 8; dptr += BLE_LL_EXT_ADV_DATA_INFO_SIZE; } - if (aux->ext_hdr & (1 << BLE_LL_EXT_ADV_AUX_PTR_BIT)) { + if (aux->ext_hdr_flags & (1 << BLE_LL_EXT_ADV_AUX_PTR_BIT)) { if (!AUX_NEXT(advsm)->sch.enqueued) { /* * Trim data here in case we do not have next aux scheduled. This @@ -769,12 +820,14 @@ ble_ll_adv_aux_pdu_make(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte) */ offset = 0; } else if (advsm->rx_ble_hdr) { - offset = os_cputime_ticks_to_usecs(AUX_NEXT(advsm)->start_time - advsm->rx_ble_hdr->beg_cputime); - offset -= (advsm->rx_ble_hdr->rem_usecs + ble_ll_pdu_tx_time_get(12, advsm->sec_phy) + BLE_LL_IFS); + offset = ble_ll_tmr_t2u(AUX_NEXT(advsm)->start_time - advsm->rx_ble_hdr->beg_cputime); + offset -= (advsm->rx_ble_hdr->rem_usecs + ble_ll_pdu_us(12, advsm->sec_phy) + BLE_LL_IFS); } else { - offset = os_cputime_ticks_to_usecs(AUX_NEXT(advsm)->start_time - aux->start_time); + offset = ble_ll_tmr_t2u(AUX_NEXT(advsm)->start_time - aux->start_time); } + aux->auxptr_zero = offset == 0; + ble_ll_adv_put_aux_ptr(AUX_NEXT(advsm)->chan, advsm->sec_phy, offset, dptr); @@ -782,20 +835,20 @@ ble_ll_adv_aux_pdu_make(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte) } #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) - if (aux->ext_hdr & (1 << BLE_LL_EXT_ADV_SYNC_INFO_BIT)) { + if (aux->ext_hdr_flags & (1 << BLE_LL_EXT_ADV_SYNC_INFO_BIT)) { ble_ll_adv_put_syncinfo(advsm, NULL, NULL, dptr); dptr += BLE_LL_EXT_ADV_SYNC_INFO_SIZE; } #endif - if (aux->ext_hdr & (1 << BLE_LL_EXT_ADV_TX_POWER_BIT)) { - dptr[0] = advsm->adv_txpwr + ble_ll_get_tx_pwr_compensation(); + if (aux->ext_hdr_flags & (1 << BLE_LL_EXT_ADV_TX_POWER_BIT)) { + dptr[0] = advsm->tx_power + g_ble_ll_tx_power_compensation; dptr += BLE_LL_EXT_ADV_TX_POWER_SIZE; } - if (aux->aux_data_len) { - os_mbuf_copydata(*advsm->aux_data, aux->aux_data_offset, - aux->aux_data_len, dptr); + if (aux->data_len) { + os_mbuf_copydata(*advsm->aux_data, aux->data_offset, + aux->data_len, dptr); } *hdr_byte = pdu_type; @@ -814,10 +867,10 @@ ble_ll_adv_aux_scannable_pdu_make(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_b advsm = pducb_arg; - assert(!(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY)); - assert(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_SCANNABLE); - assert(advsm->aux_first_pdu); - assert(ble_ll_adv_active_chanset_is_sec(advsm)); + BLE_LL_ASSERT(!(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY)); + BLE_LL_ASSERT(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_SCANNABLE); + BLE_LL_ASSERT(advsm->aux_first_pdu); + BLE_LL_ASSERT(ble_ll_adv_active_chanset_is_sec(advsm)); pdu_type = BLE_ADV_PDU_TYPE_AUX_ADV_IND; @@ -866,7 +919,7 @@ ble_ll_adv_aux_scannable_pdu_make(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_b if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_INC_TX_PWR) { *ext_hdr_len += BLE_LL_EXT_ADV_TX_POWER_SIZE; *ext_hdr |= (1 << BLE_LL_EXT_ADV_TX_POWER_BIT); - dptr[0] = advsm->adv_txpwr + ble_ll_get_tx_pwr_compensation(); + dptr[0] = advsm->tx_power + g_ble_ll_tx_power_compensation; dptr += BLE_LL_EXT_ADV_TX_POWER_SIZE; } @@ -892,7 +945,7 @@ ble_ll_adv_scan_rsp_legacy_pdu_make(uint8_t *dptr, void *pducb_arg, /* Make sure that the length is valid */ scan_rsp_len = SCAN_RSP_DATA_LEN(advsm); - assert(scan_rsp_len <= BLE_SCAN_RSP_LEGACY_DATA_MAX_LEN); + BLE_LL_ASSERT(scan_rsp_len <= BLE_SCAN_RSP_LEGACY_DATA_MAX_LEN); /* Set BLE transmit header */ pdulen = BLE_DEV_ADDR_LEN + scan_rsp_len; @@ -952,6 +1005,7 @@ struct aux_conn_rsp_data { * * @param advsm */ +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) static uint8_t ble_ll_adv_aux_conn_rsp_pdu_make(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte) @@ -1000,6 +1054,7 @@ ble_ll_adv_aux_conn_rsp_pdu_make(uint8_t *dptr, void *pducb_arg, return pdulen; } #endif +#endif /** * Called to indicate the advertising event is over. @@ -1014,9 +1069,6 @@ ble_ll_adv_tx_done(void *arg) { struct ble_ll_adv_sm *advsm; - /* reset power to max after advertising */ - ble_phy_txpwr_set(MYNEWT_VAL(BLE_LL_TX_PWR_DBM)); - advsm = (struct ble_ll_adv_sm *)arg; ble_ll_trace_u32x2(BLE_LL_TRACE_ID_ADV_TXDONE, advsm->adv_instance, @@ -1024,14 +1076,14 @@ ble_ll_adv_tx_done(void *arg) #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) if (ble_ll_adv_active_chanset_is_pri(advsm)) { - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &advsm->adv_txdone_ev); + ble_ll_event_add(&advsm->adv_txdone_ev); } else if (ble_ll_adv_active_chanset_is_sec(advsm)) { - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &advsm->adv_sec_txdone_ev); + ble_ll_event_add(&advsm->adv_sec_txdone_ev); } else { - assert(0); + BLE_LL_ASSERT(0); } #else - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &advsm->adv_txdone_ev); + ble_ll_event_add(&advsm->adv_txdone_ev); #endif ble_ll_state_set(BLE_LL_STATE_STANDBY); @@ -1042,19 +1094,10 @@ ble_ll_adv_tx_done(void *arg) g_ble_ll_cur_adv_sm = NULL; } -/* - * Called when an advertising event has been removed from the scheduler - * without being run. - */ void -ble_ll_adv_event_rmvd_from_sched(struct ble_ll_adv_sm *advsm) +ble_ll_adv_preempted(struct ble_ll_adv_sm *advsm) { - /* - * Need to set advertising channel to final chan so new event gets - * scheduled. - */ - advsm->adv_chan = ble_ll_adv_final_chan(advsm); - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &advsm->adv_txdone_ev); + ble_ll_adv_drop_event(advsm, 1); } #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) @@ -1065,7 +1108,7 @@ ble_ll_adv_event_rmvd_from_sched(struct ble_ll_adv_sm *advsm) void ble_ll_adv_periodic_rmvd_from_sched(struct ble_ll_adv_sm *advsm) { - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &advsm->adv_periodic_txdone_ev); + ble_ll_event_add(&advsm->adv_periodic_txdone_ev); } #endif @@ -1086,6 +1129,9 @@ ble_ll_adv_tx_start_cb(struct ble_ll_sched_item *sch) uint8_t end_trans; uint32_t txstart; struct ble_ll_adv_sm *advsm; +#if MYNEWT_VAL(BLE_LL_PHY) && MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) + uint8_t phy_mode; +#endif /* Get the state machine for the event */ advsm = (struct ble_ll_adv_sm *)sch->cb_arg; @@ -1100,26 +1146,31 @@ ble_ll_adv_tx_start_cb(struct ble_ll_sched_item *sch) goto adv_tx_done; } - /* Set the power */ - ble_phy_txpwr_set(advsm->adv_txpwr); - /* Set channel */ rc = ble_phy_setchan(advsm->adv_chan, BLE_ACCESS_ADDR_ADV, BLE_LL_CRCINIT_ADV); - assert(rc == 0); + BLE_LL_ASSERT(rc == 0); -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) +#if MYNEWT_VAL(BLE_LL_PHY) /* Set phy mode */ #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) +#if MYNEWT_VAL(BLE_VERSION) >= 54 + phy_mode = ble_ll_phy_to_phy_mode(advsm->pri_phy, advsm->pri_phy_opt); +#else + phy_mode = ble_ll_phy_to_phy_mode(advsm->pri_phy, BLE_HCI_LE_PHY_CODED_ANY); +#endif if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) { ble_phy_mode_set(BLE_PHY_MODE_1M, BLE_PHY_MODE_1M); } else { - ble_phy_mode_set(advsm->pri_phy, advsm->pri_phy); + ble_phy_mode_set(phy_mode, phy_mode); } #else ble_phy_mode_set(BLE_PHY_MODE_1M, BLE_PHY_MODE_1M); #endif #endif + /* Set the power */ + ble_ll_tx_power_set(advsm->tx_power); + /* Set transmit start time. */ txstart = sch->start_time + g_ble_ll_sched_offset_ticks; rc = ble_phy_tx_set_start_time(txstart, sch->remainder); @@ -1196,7 +1247,7 @@ ble_ll_adv_set_sched(struct ble_ll_adv_sm *advsm) /* Set end time to maximum time this schedule item may take */ #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) { - max_usecs = ble_ll_pdu_tx_time_get(advsm->adv_pdu_len, BLE_PHY_MODE_1M); + max_usecs = ble_ll_pdu_us(advsm->adv_pdu_len, BLE_PHY_MODE_1M); if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_DIRECTED) { max_usecs += BLE_LL_SCHED_DIRECT_ADV_MAX_USECS; @@ -1208,10 +1259,10 @@ ble_ll_adv_set_sched(struct ble_ll_adv_sm *advsm) * In ADV_EXT_IND we always set only ADI and AUX so the payload length * is always 7 bytes. */ - max_usecs = ble_ll_pdu_tx_time_get(7, advsm->pri_phy); + max_usecs = ble_ll_pdu_us(7, advsm->pri_phy); } #else - max_usecs = ble_ll_pdu_tx_time_get(advsm->adv_pdu_len, BLE_PHY_MODE_1M); + max_usecs = ble_ll_pdu_us(advsm->adv_pdu_len, BLE_PHY_MODE_1M); if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_DIRECTED) { max_usecs += BLE_LL_SCHED_DIRECT_ADV_MAX_USECS; @@ -1222,8 +1273,7 @@ ble_ll_adv_set_sched(struct ble_ll_adv_sm *advsm) sch->start_time = advsm->adv_pdu_start_time - g_ble_ll_sched_offset_ticks; sch->remainder = 0; - sch->end_time = advsm->adv_pdu_start_time + - ble_ll_usecs_to_ticks_round_up(max_usecs); + sch->end_time = advsm->adv_pdu_start_time + ble_ll_tmr_u2t_up(max_usecs); } #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) @@ -1236,6 +1286,9 @@ ble_ll_adv_secondary_tx_start_cb(struct ble_ll_sched_item *sch) struct ble_ll_adv_sm *advsm; ble_phy_tx_pducb_t pducb; struct ble_ll_adv_aux *aux; +#if MYNEWT_VAL(BLE_LL_PHY) + uint8_t phy_mode; +#endif /* Get the state machine for the event */ advsm = (struct ble_ll_adv_sm *)sch->cb_arg; @@ -1245,20 +1298,25 @@ ble_ll_adv_secondary_tx_start_cb(struct ble_ll_sched_item *sch) ble_ll_adv_active_chanset_set_sec(advsm); - /* Set the power */ - ble_phy_txpwr_set(advsm->adv_txpwr); - /* Set channel */ aux = AUX_CURRENT(advsm); rc = ble_phy_setchan(aux->chan, BLE_ACCESS_ADDR_ADV, BLE_LL_CRCINIT_ADV); - assert(rc == 0); + BLE_LL_ASSERT(rc == 0); -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) +#if MYNEWT_VAL(BLE_LL_PHY) +#if MYNEWT_VAL(BLE_VERSION) >= 54 + phy_mode = ble_ll_phy_to_phy_mode(advsm->sec_phy, advsm->sec_phy_opt); +#else + phy_mode = ble_ll_phy_to_phy_mode(advsm->sec_phy, BLE_HCI_LE_PHY_CODED_ANY); +#endif /* Set phy mode */ - ble_phy_mode_set(advsm->sec_phy, advsm->sec_phy); + ble_phy_mode_set(phy_mode, phy_mode); #endif + /* Set the power */ + ble_ll_tx_power_set(advsm->tx_power); + /* Set transmit start time. */ txstart = sch->start_time + g_ble_ll_sched_offset_ticks; rc = ble_phy_tx_set_start_time(txstart, sch->remainder); @@ -1350,117 +1408,180 @@ ble_ll_adv_aux_scannable_pdu_payload_len(struct ble_ll_adv_sm *advsm) return len; } -static void -ble_ll_adv_aux_calculate(struct ble_ll_adv_sm *advsm, - struct ble_ll_adv_aux *aux, uint16_t aux_data_offset) +static uint16_t +ble_ll_adv_aux_calculate_payload(struct ble_ll_adv_sm *advsm, uint16_t props, + struct os_mbuf *data, uint32_t data_offset, + uint8_t *data_len_o, uint8_t *ext_hdr_flags_o) { - uint16_t rem_aux_data_len; - uint8_t hdr_len; + uint16_t rem_data_len; + uint8_t data_len; + uint8_t ext_hdr_flags; + uint8_t ext_hdr_len; bool chainable; + bool first_pdu; - assert(!aux->sch.enqueued); - assert((AUX_DATA_LEN(advsm) > aux_data_offset) || - (AUX_DATA_LEN(advsm) == 0 && aux_data_offset == 0)); - - aux->aux_data_offset = aux_data_offset; - aux->aux_data_len = 0; - aux->payload_len = 0; - aux->ext_hdr = 0; + /* Note: advsm shall only be used to check if periodic advertising is + * enabled, other parameters in advsm may have different values than + * those we want to check (e.g. when reconfiguring instance). + */ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CSA2) - aux->chan = ble_ll_utils_calc_dci_csa2(advsm->event_cntr++, - advsm->channel_id, - g_ble_ll_conn_params.num_used_chans, - g_ble_ll_conn_params.master_chan_map); -#else - aux->chan = ble_ll_utils_remapped_channel(ble_ll_rand() % BLE_PHY_NUM_DATA_CHANS, - g_ble_ll_conn_params.master_chan_map); -#endif + rem_data_len = (data ? OS_MBUF_PKTLEN(data) : 0) - data_offset; + BLE_LL_ASSERT((int16_t)rem_data_len >= 0); - rem_aux_data_len = AUX_DATA_LEN(advsm) - aux_data_offset; - chainable = !(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_CONNECTABLE); + first_pdu = (data_offset == 0); + chainable = !(props & BLE_HCI_LE_SET_EXT_ADV_PROP_CONNECTABLE); - hdr_len = BLE_LL_EXT_ADV_HDR_LEN; + ext_hdr_flags = 0; + ext_hdr_len = BLE_LL_EXT_ADV_HDR_LEN; - if (!(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_SCANNABLE)) { - /* ADI */ - aux->ext_hdr |= (1 << BLE_LL_EXT_ADV_DATA_INFO_BIT); - hdr_len += BLE_LL_EXT_ADV_DATA_INFO_SIZE; + /* ADI for anything but scannable */ + if (!(props & BLE_HCI_LE_SET_EXT_ADV_PROP_SCANNABLE)) { + ext_hdr_flags |= (1 << BLE_LL_EXT_ADV_DATA_INFO_BIT); + ext_hdr_len += BLE_LL_EXT_ADV_DATA_INFO_SIZE; } - /* AdvA for 1st PDU in chain (i.e. AUX_ADV_IND or AUX_SCAN_RSP) */ - if (aux_data_offset == 0 && - !(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_ANON_ADV)) { - aux->ext_hdr |= (1 << BLE_LL_EXT_ADV_ADVA_BIT); - hdr_len += BLE_LL_EXT_ADV_ADVA_SIZE; + /* AdvA if: + * - 1st PDU + * - not anonymous + * - scannable/connectable or ADVA_IN_AUX selected + */ + if (first_pdu && + !(props & BLE_HCI_LE_SET_EXT_ADV_PROP_ANON_ADV) && + ((props & (BLE_HCI_LE_SET_EXT_ADV_PROP_CONNECTABLE | + BLE_HCI_LE_SET_EXT_ADV_PROP_SCANNABLE)) || + MYNEWT_VAL(BLE_LL_EXT_ADV_ADVA_IN_AUX))) { + ext_hdr_flags |= (1 << BLE_LL_EXT_ADV_ADVA_BIT); + ext_hdr_len += BLE_LL_EXT_ADV_ADVA_SIZE; } - /* Note: this function does not calculate AUX_ADV_IND when advertising is - * scannable. Instead it is calculated in ble_ll_adv_aux_schedule_first(). - * - * However this function calculates length of AUX_SCAN_RSP and according - * to BT 5.0 Vol 6 Part B, 2.3.2.3, TargetA shall not be include there. - * - * This is why TargetA is added to all directed advertising here unless it - * is scannable one. + /* TargetA in 1st PDU, if directed * - * Note. TargetA shall not be also in AUX_CHAIN_IND + * Note that for scannable this calculates AUX_SCAN_RSP which shall not + * include TargetA (see: Core 5.3, Vol 6, Part B, 2.3.2.3). For scannable + * TargetA is included in AUX_ADV_IND which is in that case calculated in + * ble_ll_adv_aux_schedule_first(). */ - if (aux_data_offset == 0 && - (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_DIRECTED) && - !(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_SCANNABLE)) { - aux->ext_hdr |= (1 << BLE_LL_EXT_ADV_TARGETA_BIT); - hdr_len += BLE_LL_EXT_ADV_TARGETA_SIZE; + if (first_pdu && + (props & BLE_HCI_LE_SET_EXT_ADV_PROP_DIRECTED) && + !(props & BLE_HCI_LE_SET_EXT_ADV_PROP_SCANNABLE)) { + ext_hdr_flags |= (1 << BLE_LL_EXT_ADV_TARGETA_BIT); + ext_hdr_len += BLE_LL_EXT_ADV_TARGETA_SIZE; } - /* TxPower if configured. - * Note: TxPower should not be be present in AUX_CHAIN_IND - */ - if (aux_data_offset == 0 && - (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_INC_TX_PWR)) { - aux->ext_hdr |= (1 << BLE_LL_EXT_ADV_TX_POWER_BIT); - hdr_len += BLE_LL_EXT_ADV_TX_POWER_SIZE; + /* TxPower in 1st PDU, if configured */ + if (first_pdu && + (props & BLE_HCI_LE_SET_EXT_ADV_PROP_INC_TX_PWR)) { + ext_hdr_flags |= (1 << BLE_LL_EXT_ADV_TX_POWER_BIT); + ext_hdr_len += BLE_LL_EXT_ADV_TX_POWER_SIZE; } #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) - /* SyncInfo for 1st PDU in chain (i.e. AUX_ADV_IND only) if periodic - * advertising is enabled - */ - if (aux_data_offset == 0 && advsm->periodic_adv_active) { - aux->ext_hdr |= (1 << BLE_LL_EXT_ADV_SYNC_INFO_BIT); - hdr_len += BLE_LL_EXT_ADV_SYNC_INFO_SIZE; + /* SyncInfo in 1st PDU, if periodic advertising is enabled */ + if (first_pdu && advsm->periodic_adv_active) { + ext_hdr_flags |= (1 << BLE_LL_EXT_ADV_SYNC_INFO_BIT); + ext_hdr_len += BLE_LL_EXT_ADV_SYNC_INFO_SIZE; } #endif - /* if we have any fields in ext header we need to add flags, note that Aux - * PTR is handled later and it will account for flags if needed + /* Flags, if any field is present in header + * + * Note that this does not account for AuxPtr which is added later if + * remaining data does not fit in single PDU. */ - if (aux->ext_hdr) { - hdr_len += BLE_LL_EXT_ADV_FLAGS_SIZE; + if (ext_hdr_flags) { + ext_hdr_len += BLE_LL_EXT_ADV_FLAGS_SIZE; } - /* AdvData always */ - aux->aux_data_len = min(BLE_LL_MAX_PAYLOAD_LEN - hdr_len, rem_aux_data_len); + /* AdvData */ + data_len = MIN(BLE_LL_MAX_PAYLOAD_LEN - ext_hdr_len, rem_data_len); /* AuxPtr if there are more AdvData remaining that we can fit here */ - if (chainable && (rem_aux_data_len > aux->aux_data_len)) { - /* adjust for flags that needs to be added if AuxPtr is only field - * in Extended Header - */ - if (!aux->ext_hdr) { - hdr_len += BLE_LL_EXT_ADV_FLAGS_SIZE; - aux->aux_data_len -= BLE_LL_EXT_ADV_FLAGS_SIZE; - } + if (chainable && (rem_data_len > data_len)) { + /* Add flags if not already added */ + if (!ext_hdr_flags) { + ext_hdr_len += BLE_LL_EXT_ADV_FLAGS_SIZE; + data_len -= BLE_LL_EXT_ADV_FLAGS_SIZE; + } - aux->ext_hdr |= (1 << BLE_LL_EXT_ADV_AUX_PTR_BIT); - hdr_len += BLE_LL_EXT_ADV_AUX_PTR_SIZE; - aux->aux_data_len -= BLE_LL_EXT_ADV_AUX_PTR_SIZE; + ext_hdr_flags |= (1 << BLE_LL_EXT_ADV_AUX_PTR_BIT); + ext_hdr_len += BLE_LL_EXT_ADV_AUX_PTR_SIZE; - /* PDU payload should be full if chained */ - assert(hdr_len + aux->aux_data_len == BLE_LL_MAX_PAYLOAD_LEN); + data_len -= BLE_LL_EXT_ADV_AUX_PTR_SIZE; + + /* PDU payload should be full if adding AuxPtr */ + BLE_LL_ASSERT(ext_hdr_len + data_len == BLE_LL_MAX_PAYLOAD_LEN); } - aux->payload_len = hdr_len + aux->aux_data_len; + *data_len_o = data_len; + *ext_hdr_flags_o = ext_hdr_flags; + + return ext_hdr_len + data_len; +} + +static void +ble_ll_adv_aux_calculate(struct ble_ll_adv_sm *advsm, + struct ble_ll_adv_aux *aux, uint16_t data_offset) +{ + BLE_LL_ASSERT(!aux->sch.enqueued); + BLE_LL_ASSERT((AUX_DATA_LEN(advsm) > data_offset) || + (AUX_DATA_LEN(advsm) == 0 && data_offset == 0)); + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CSA2) + aux->chan = ble_ll_utils_dci_csa2(advsm->event_cntr++, + advsm->channel_id, + g_ble_ll_data.chan_map_used, + g_ble_ll_data.chan_map); +#else + aux->chan = ble_ll_utils_remapped_channel(ble_ll_rand() % BLE_PHY_NUM_DATA_CHANS, + g_ble_ll_data.chan_map); +#endif + + aux->data_offset = data_offset; + aux->payload_len = ble_ll_adv_aux_calculate_payload(advsm, advsm->props, + *advsm->aux_data, + data_offset, + &aux->data_len, + &aux->ext_hdr_flags); +} + +static bool +ble_ll_adv_aux_check_data_itvl(struct ble_ll_adv_sm *advsm, uint16_t props, + uint8_t pri_phy, uint8_t sec_phy, + struct os_mbuf *data, uint32_t interval_us) +{ + uint32_t max_usecs; + uint16_t data_offset; + uint16_t pdu_len; + uint8_t data_len; + uint8_t ext_hdr_flags; + + /* FIXME: + * We should include PDUs on primary channel when calculating advertising + * event duration, but the actual time varies a bit in our case due to + * scheduling. For now let's assume we always schedule all PDUs 300us apart + * and we use shortest possible payload (ADI+AuxPtr, no AdvA). + * + * Note that calculations below do not take channel map and max skip into + * account, but we do not support max skip anyway for now. + */ + + max_usecs = 3 * (ble_ll_pdu_us(7, pri_phy) + 300) + + BLE_LL_MAFS + MYNEWT_VAL(BLE_LL_SCHED_AUX_MAFS_DELAY); + + data_offset = 0; + + do { + pdu_len = ble_ll_adv_aux_calculate_payload(advsm, props, data, data_offset, + &data_len, &ext_hdr_flags); + + max_usecs += ble_ll_pdu_us(pdu_len, sec_phy); + max_usecs += BLE_LL_MAFS + MYNEWT_VAL(BLE_LL_SCHED_AUX_CHAIN_MAFS_DELAY); + + data_offset += data_len; + + } while (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_AUX_PTR_BIT)); + + return max_usecs < interval_us; } static void @@ -1478,16 +1599,16 @@ ble_ll_adv_aux_schedule_next(struct ble_ll_adv_sm *advsm) struct ble_ll_adv_aux *aux; struct ble_ll_adv_aux *aux_next; struct ble_ll_sched_item *sch; - uint16_t rem_aux_data_len; - uint16_t next_aux_data_offset; + uint16_t rem_data_len; + uint16_t next_data_offset; uint32_t max_usecs; - assert(advsm->aux_active); + BLE_LL_ASSERT(advsm->aux_active); aux = AUX_CURRENT(advsm); aux_next = AUX_NEXT(advsm); - assert(!aux_next->sch.enqueued); + BLE_LL_ASSERT(!aux_next->sch.enqueued); /* * Do not schedule next aux if current aux is no longer scheduled since we @@ -1501,36 +1622,36 @@ ble_ll_adv_aux_schedule_next(struct ble_ll_adv_sm *advsm) * Do not schedule next aux if current aux does not have AuxPtr in extended * header as this means we do not need subsequent ADV_CHAIN_IND to be sent. */ - if (!(aux->ext_hdr & (1 << BLE_LL_EXT_ADV_AUX_PTR_BIT))) { + if (!(aux->ext_hdr_flags & (1 << BLE_LL_EXT_ADV_AUX_PTR_BIT))) { return; } - next_aux_data_offset = aux->aux_data_offset + aux->aux_data_len; + next_data_offset = aux->data_offset + aux->data_len; - assert(AUX_DATA_LEN(advsm) >= next_aux_data_offset); + BLE_LL_ASSERT(AUX_DATA_LEN(advsm) >= next_data_offset); - rem_aux_data_len = AUX_DATA_LEN(advsm) - next_aux_data_offset; - assert(rem_aux_data_len > 0); + rem_data_len = AUX_DATA_LEN(advsm) - next_data_offset; + BLE_LL_ASSERT(rem_data_len > 0); - ble_ll_adv_aux_calculate(advsm, aux_next, next_aux_data_offset); - max_usecs = ble_ll_pdu_tx_time_get(aux_next->payload_len, advsm->sec_phy); + ble_ll_adv_aux_calculate(advsm, aux_next, next_data_offset); + max_usecs = ble_ll_pdu_us(aux_next->payload_len, advsm->sec_phy); aux_next->start_time = aux->sch.end_time + - ble_ll_usecs_to_ticks_round_up(BLE_LL_MAFS + MYNEWT_VAL(BLE_LL_SCHED_AUX_CHAIN_MAFS_DELAY)); + ble_ll_tmr_u2t_up(BLE_LL_MAFS + + MYNEWT_VAL(BLE_LL_SCHED_AUX_CHAIN_MAFS_DELAY)); sch = &aux_next->sch; sch->start_time = aux_next->start_time - g_ble_ll_sched_offset_ticks; sch->remainder = 0; - sch->end_time = aux_next->start_time + - ble_ll_usecs_to_ticks_round_up(max_usecs); + sch->end_time = aux_next->start_time + ble_ll_tmr_u2t_up(max_usecs); ble_ll_sched_adv_new(&aux_next->sch, ble_ll_adv_aux_scheduled, aux_next); - /* - * In case duration is set for advertising set we need to check if newly - * scheduled aux will fit inside duration. If not, remove it from scheduler - * so advertising will stop after current aux. + /* Remove aux if previous one was already sent with zero offset or new one + * is scheduled past advertising duration (if set). */ - if (advsm->duration && (aux_next->sch.end_time > advsm->adv_end_time)) { + if (aux->auxptr_zero || + (advsm->duration && LL_TMR_GT(aux_next->sch.end_time, + advsm->adv_end_time))) { ble_ll_sched_rmv_elem(&aux_next->sch); } } @@ -1542,9 +1663,9 @@ ble_ll_adv_aux_schedule_first(struct ble_ll_adv_sm *advsm) struct ble_ll_sched_item *sch; uint32_t max_usecs; - assert(!advsm->aux_active); - assert(!advsm->aux[0].sch.enqueued); - assert(!advsm->aux[1].sch.enqueued); + BLE_LL_ASSERT(!advsm->aux_active); + BLE_LL_ASSERT(!advsm->aux[0].sch.enqueued); + BLE_LL_ASSERT(!advsm->aux[1].sch.enqueued); advsm->aux_active = 1; advsm->aux_index = 0; @@ -1553,17 +1674,18 @@ ble_ll_adv_aux_schedule_first(struct ble_ll_adv_sm *advsm) advsm->aux_dropped = 0; aux = AUX_CURRENT(advsm); + aux->auxptr_zero = 0; ble_ll_adv_aux_calculate(advsm, aux, 0); /* Set end time to maximum time this schedule item may take */ if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_CONNECTABLE) { - max_usecs = ble_ll_pdu_tx_time_get(aux->payload_len, advsm->sec_phy) + + max_usecs = ble_ll_pdu_us(aux->payload_len, advsm->sec_phy) + BLE_LL_IFS + /* AUX_CONN_REQ */ - ble_ll_pdu_tx_time_get(34 + 14, advsm->sec_phy) + + ble_ll_pdu_us(34 + 14, advsm->sec_phy) + BLE_LL_IFS + /* AUX_CONN_RSP */ - ble_ll_pdu_tx_time_get(14, advsm->sec_phy); + ble_ll_pdu_us(14, advsm->sec_phy); } else if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_SCANNABLE) { /* For scannable advertising we need to calculate how much time we * need for AUX_ADV_IND along with AUX_SCAN_REQ, AUX_SCAN_RSP and @@ -1575,22 +1697,22 @@ ble_ll_adv_aux_schedule_first(struct ble_ll_adv_sm *advsm) * 2. length of AUX_ADV_IND is calculated by special function: * ble_ll_adv_aux_scannable_pdu_payload_len() */ - max_usecs = ble_ll_pdu_tx_time_get(ble_ll_adv_aux_scannable_pdu_payload_len(advsm), + max_usecs = ble_ll_pdu_us(ble_ll_adv_aux_scannable_pdu_payload_len(advsm), advsm->sec_phy) + BLE_LL_IFS + /* AUX_SCAN_REQ */ - ble_ll_pdu_tx_time_get(12, advsm->sec_phy) + + ble_ll_pdu_us(12, advsm->sec_phy) + BLE_LL_IFS + /* AUX_SCAN_RSP */ - ble_ll_pdu_tx_time_get(aux->payload_len, advsm->sec_phy); + ble_ll_pdu_us(aux->payload_len, advsm->sec_phy); } else { - max_usecs = ble_ll_pdu_tx_time_get(aux->payload_len, advsm->sec_phy); + max_usecs = ble_ll_pdu_us(aux->payload_len, advsm->sec_phy); } sch = &aux->sch; sch->start_time = aux->start_time - g_ble_ll_sched_offset_ticks; sch->remainder = 0; - sch->end_time = aux->start_time + ble_ll_usecs_to_ticks_round_up(max_usecs); + sch->end_time = aux->start_time + ble_ll_tmr_u2t_up(max_usecs); ble_ll_sched_adv_new(sch, ble_ll_adv_aux_scheduled, aux); } @@ -1603,40 +1725,31 @@ ble_ll_adv_aux_set_start_time(struct ble_ll_adv_sm *advsm) uint32_t adv_event_dur; uint8_t chans; - assert(!advsm->aux_active); - assert(!advsm->aux[0].sch.enqueued); - assert(!advsm->aux[1].sch.enqueued); + BLE_LL_ASSERT(!advsm->aux_active); + BLE_LL_ASSERT(!advsm->aux[0].sch.enqueued); + BLE_LL_ASSERT(!advsm->aux[1].sch.enqueued); assert(advsm->adv_chanmask > 0 && advsm->adv_chanmask <= BLE_HCI_ADV_CHANMASK_DEF); chans = bits[advsm->adv_chanmask]; - /* - * We want to schedule auxiliary packet as soon as possible after the end - * of advertising event, but no sooner than T_MAFS. The interval between - * advertising packets is 250 usecs (8.19 ticks) on LE Coded and a bit less - * on 1M, but it can vary a bit due to scheduling which we can't really - * control. Since we round ticks up for both interval and T_MAFS, we still - * have some margin here. The worst thing that can happen is that we skip - * last advertising packet which is not a bit problem so leave it as-is, no - * need to make code more complicated. - */ - - /* - * XXX: this could be improved if phy has TX-TX transition with controlled - * or predefined interval, but since it makes advertising code even - * more complicated let's skip it for now... - */ - adv_pdu_dur = (int32_t)(sched->end_time - sched->start_time) - g_ble_ll_sched_offset_ticks; - /* 9 is 8.19 ticks rounded up - see comment above */ - adv_event_dur = (adv_pdu_dur * chans) + (9 * (chans - 1)); + /* The interval between advertising PDUs may vary due to scheduling, but in + * general we reserve 3 ticks for end-to-schedule time and add scheduler + * offset. That should be more that enough to make sure there's at least + * T_mafs delay between last advertising PDU and auxiliary PDU. + * + * TODO we can make this much more efficient with TX-TX transition + */ + adv_event_dur = (adv_pdu_dur * chans) + + ((3 + g_ble_ll_sched_offset_ticks) * (chans - 1)); advsm->aux[0].start_time = advsm->adv_event_start_time + adv_event_dur + - ble_ll_usecs_to_ticks_round_up(BLE_LL_MAFS + MYNEWT_VAL(BLE_LL_SCHED_AUX_MAFS_DELAY)); + ble_ll_tmr_u2t_up(BLE_LL_MAFS + + MYNEWT_VAL(BLE_LL_SCHED_AUX_MAFS_DELAY)); } static void @@ -1660,7 +1773,7 @@ ble_ll_adv_aux_schedule(struct ble_ll_adv_sm *advsm) * not start extended advertising event which we cannot finish in time. */ if (advsm->duration && - (AUX_CURRENT(advsm)->sch.end_time > advsm->adv_end_time)) { + LL_TMR_GT(AUX_CURRENT(advsm)->sch.end_time, advsm->adv_end_time)) { ble_ll_adv_sm_stop_timeout(advsm); } } @@ -1683,24 +1796,21 @@ ble_ll_adv_halt(void) ble_ll_trace_u32(BLE_LL_TRACE_ID_ADV_HALT, advsm->adv_instance); - ble_phy_txpwr_set(MYNEWT_VAL(BLE_LL_TX_PWR_DBM)); - #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) if (advsm->flags & BLE_LL_ADV_SM_FLAG_PERIODIC_SYNC_SENDING) { ble_ll_adv_flags_clear(advsm, BLE_LL_ADV_SM_FLAG_PERIODIC_SYNC_SENDING); - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, - &advsm->adv_periodic_txdone_ev); + ble_ll_event_add(&advsm->adv_periodic_txdone_ev); ble_ll_state_set(BLE_LL_STATE_STANDBY); g_ble_ll_cur_adv_sm = NULL; return; } #endif - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &advsm->adv_txdone_ev); + ble_ll_event_add(&advsm->adv_txdone_ev); #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) if (!(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY)) { - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &advsm->adv_sec_txdone_ev); + ble_ll_event_add(&advsm->adv_sec_txdone_ev); } #endif @@ -1730,6 +1840,7 @@ ble_ll_adv_set_adv_params(const uint8_t *cmdbuf, uint8_t len) uint8_t adv_filter_policy; uint16_t adv_itvl_min; uint16_t adv_itvl_max; + uint32_t adv_itvl_usecs; uint16_t props; if (len != sizeof(*cmd)) { @@ -1752,6 +1863,7 @@ ble_ll_adv_set_adv_params(const uint8_t *cmdbuf, uint8_t len) adv_filter_policy = cmd->filter_policy; switch (cmd->type) { +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) case BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_HD: adv_filter_policy = BLE_HCI_ADV_FILT_NONE; memcpy(advsm->peer_addr, cmd->peer_addr, BLE_DEV_ADDR_LEN); @@ -1771,6 +1883,7 @@ ble_ll_adv_set_adv_params(const uint8_t *cmdbuf, uint8_t len) case BLE_HCI_ADV_TYPE_ADV_IND: props = BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY_IND; break; +#endif case BLE_HCI_ADV_TYPE_ADV_NONCONN_IND: props = BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY_NONCONN; break; @@ -1799,7 +1912,7 @@ ble_ll_adv_set_adv_params(const uint8_t *cmdbuf, uint8_t len) return BLE_ERR_INV_HCI_CMD_PARMS; } - advsm->adv_txpwr = MYNEWT_VAL(BLE_LL_TX_PWR_DBM); + advsm->tx_power = ble_ll_tx_power_round(g_ble_ll_tx_power - g_ble_ll_tx_power_compensation); #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) if (cmd->own_addr_type > BLE_HCI_ADV_OWN_ADDR_RANDOM) { @@ -1823,23 +1936,30 @@ ble_ll_adv_set_adv_params(const uint8_t *cmdbuf, uint8_t len) return BLE_ERR_INV_HCI_CMD_PARMS; } + /* Determine the advertising interval we will use */ + if (props & BLE_HCI_LE_SET_EXT_ADV_PROP_HD_DIRECTED) { + /* Set it to max. allowed for high duty cycle advertising */ + adv_itvl_usecs = BLE_LL_ADV_PDU_ITVL_HD_MS_MAX; + } else { + adv_itvl_usecs = adv_itvl_max * BLE_LL_ADV_ITVL; + } + /* Fill out rest of advertising state machine */ advsm->own_addr_type = cmd->own_addr_type; advsm->peer_addr_type = cmd->peer_addr_type; advsm->adv_filter_policy = adv_filter_policy; advsm->adv_chanmask = cmd->chan_map; - advsm->adv_itvl_min = adv_itvl_min; - advsm->adv_itvl_max = adv_itvl_max; + advsm->adv_itvl_usecs = adv_itvl_usecs; advsm->props = props; return 0; } #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -static void -ble_ll_adv_update_did(struct ble_ll_adv_sm *advsm) +static uint16_t +ble_ll_adv_update_did(uint16_t old_adi) { - uint16_t old_adi = advsm->adi; + uint16_t new_adi; /* * The Advertising DID for a given advertising set shall be initialized @@ -1850,8 +1970,10 @@ ble_ll_adv_update_did(struct ble_ll_adv_sm *advsm) * the previously used value. */ do { - advsm->adi = (advsm->adi & 0xf000) | (ble_ll_rand() & 0x0fff); - } while (old_adi == advsm->adi); + new_adi = (old_adi & 0xf000) | (ble_ll_rand() & 0x0fff); + } while (old_adi == new_adi); + + return new_adi; } #endif @@ -1885,7 +2007,7 @@ ble_ll_adv_update_adv_scan_rsp_data(struct ble_ll_adv_sm *advsm) #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) /* DID shall be updated when host provides new advertising data */ - ble_ll_adv_update_did(advsm); + advsm->adi = ble_ll_adv_update_did(advsm->adi); #endif } @@ -1932,16 +2054,18 @@ ble_ll_adv_sm_stop(struct ble_ll_adv_sm *advsm) #endif OS_EXIT_CRITICAL(sr); - ble_npl_eventq_remove(&g_ble_ll_data.ll_evq, &advsm->adv_txdone_ev); + ble_ll_event_remove(&advsm->adv_txdone_ev); #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - ble_npl_eventq_remove(&g_ble_ll_data.ll_evq, &advsm->adv_sec_txdone_ev); + ble_ll_event_remove(&advsm->adv_sec_txdone_ev); #endif +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) /* If there is an event buf we need to free it */ if (advsm->conn_comp_ev) { - ble_hci_trans_buf_free(advsm->conn_comp_ev); + ble_transport_free(advsm->conn_comp_ev); advsm->conn_comp_ev = NULL; } +#endif ble_ll_adv_active_chanset_clear(advsm); @@ -1964,6 +2088,7 @@ ble_ll_adv_sm_stop_timeout(struct ble_ll_adv_sm *advsm) } #endif +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) /* * For high duty directed advertising we need to send connection * complete event with proper status @@ -1973,6 +2098,7 @@ ble_ll_adv_sm_stop_timeout(struct ble_ll_adv_sm *advsm) advsm->conn_comp_ev, advsm); advsm->conn_comp_ev = NULL; } +#endif /* Disable advertising */ ble_ll_adv_sm_stop(advsm); @@ -1994,11 +2120,13 @@ ble_ll_adv_sm_stop_limit_reached(struct ble_ll_adv_sm *advsm) * be used if HD directed advertising was terminated before timeout due to * events count limit. For now just use same code as with duration timeout. */ +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_HD_DIRECTED) { ble_ll_conn_comp_event_send(NULL, BLE_ERR_DIR_ADV_TMO, advsm->conn_comp_ev, advsm); advsm->conn_comp_ev = NULL; } +#endif /* Disable advertising */ ble_ll_adv_sm_stop(advsm); @@ -2018,14 +2146,14 @@ ble_ll_adv_scheduled(struct ble_ll_adv_sm *advsm, uint32_t sch_start, void *arg) */ if (advsm->duration) { advsm->adv_end_time = advsm->adv_event_start_time + - os_cputime_usecs_to_ticks(advsm->duration * 10000); + ble_ll_tmr_u2t(advsm->duration * 10000); } #else /* Set the time at which we must end directed, high-duty cycle advertising. */ if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_HD_DIRECTED) { advsm->adv_end_time = advsm->adv_event_start_time + - os_cputime_usecs_to_ticks(BLE_LL_ADV_STATE_HD_MAX * 1000); + ble_ll_tmr_u2t(BLE_LL_ADV_STATE_HD_MAX * 1000); } #endif } @@ -2039,13 +2167,16 @@ ble_ll_adv_sync_pdu_make(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte) uint8_t adv_mode; uint8_t pdu_type; uint8_t ext_hdr_len; +#if MYNEWT_VAL(BLE_LL_ISO_BROADCASTER) + uint8_t biginfo_len; +#endif uint32_t offset; advsm = pducb_arg; sync = SYNC_CURRENT(advsm); - assert(!ble_ll_adv_active_chanset_is_sec(advsm)); - assert(advsm->flags & BLE_LL_ADV_SM_FLAG_PERIODIC_SYNC_SENDING); + BLE_LL_ASSERT(!ble_ll_adv_active_chanset_is_sec(advsm)); + BLE_LL_ASSERT(advsm->flags & BLE_LL_ADV_SM_FLAG_PERIODIC_SYNC_SENDING); /* It's the same for AUX_SYNC_IND and AUX_CHAIN_IND */ pdu_type = BLE_ADV_PDU_TYPE_AUX_SYNC_IND; @@ -2053,17 +2184,30 @@ ble_ll_adv_sync_pdu_make(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte) /* non-connectable and non-scannable */ adv_mode = 0; - ext_hdr_len = sync->payload_len - BLE_LL_EXT_ADV_HDR_LEN - sync->sync_data_len; + ext_hdr_len = sync->payload_len - BLE_LL_EXT_ADV_HDR_LEN - sync->data_len; dptr[0] = (adv_mode << 6) | ext_hdr_len; dptr += 1; /* only put flags if needed */ - if (sync->ext_hdr) { - dptr[0] = sync->ext_hdr; +#if MYNEWT_VAL(BLE_LL_ISO_BROADCASTER) + if (sync->ext_hdr_flags || sync->big) { + dptr[0] = sync->ext_hdr_flags; dptr += 1; } +#else + if (sync->ext_hdr_flags) { + dptr[0] = sync->ext_hdr_flags; + dptr += 1; + } +#endif +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_ADI_SUPPORT) + if (sync->ext_hdr_flags & (1 << BLE_LL_EXT_ADV_DATA_INFO_BIT)) { + put_le16(dptr, advsm->periodic_adv_adi); + dptr += BLE_LL_EXT_ADV_DATA_INFO_SIZE; + } +#endif - if (sync->ext_hdr & (1 << BLE_LL_EXT_ADV_AUX_PTR_BIT)) { + if (sync->ext_hdr_flags & (1 << BLE_LL_EXT_ADV_AUX_PTR_BIT)) { if (!SYNC_NEXT(advsm)->sch.enqueued) { /* * Trim data here in case we do not have next sync scheduled. This @@ -2072,23 +2216,37 @@ ble_ll_adv_sync_pdu_make(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte) */ offset = 0; } else { - offset = os_cputime_ticks_to_usecs(SYNC_NEXT(advsm)->start_time - sync->start_time); + offset = ble_ll_tmr_t2u(SYNC_NEXT(advsm)->start_time - + sync->start_time); } + sync->auxptr_zero = offset == 0; + ble_ll_adv_put_aux_ptr(SYNC_NEXT(advsm)->chan, advsm->sec_phy, offset, dptr); dptr += BLE_LL_EXT_ADV_AUX_PTR_SIZE; } - if (sync->ext_hdr & (1 << BLE_LL_EXT_ADV_TX_POWER_BIT)) { - dptr[0] = advsm->adv_txpwr + ble_ll_get_tx_pwr_compensation(); + if (sync->ext_hdr_flags & (1 << BLE_LL_EXT_ADV_TX_POWER_BIT)) { + dptr[0] = advsm->tx_power + g_ble_ll_tx_power_compensation; dptr += BLE_LL_EXT_ADV_TX_POWER_SIZE; } - if (sync->sync_data_len) { - os_mbuf_copydata(advsm->periodic_adv_data, sync->sync_data_offset, - sync->sync_data_len, dptr); +#if MYNEWT_VAL(BLE_LL_ISO_BROADCASTER) + if (advsm->big) { + biginfo_len = ble_ll_iso_big_biginfo_copy(advsm->big, dptr, + sync->sch.start_time + + g_ble_ll_sched_offset_ticks, + sync->sch.remainder); + + dptr += biginfo_len; + } +#endif + + if (sync->data_len) { + os_mbuf_copydata(advsm->periodic_adv_data, sync->data_offset, + sync->data_len, dptr); } *hdr_byte = pdu_type; @@ -2100,16 +2258,13 @@ ble_ll_adv_sync_pdu_make(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte) static void ble_ll_adv_sync_tx_done(struct ble_ll_adv_sm *advsm) { - /* reset power to max after advertising */ - ble_phy_txpwr_set(MYNEWT_VAL(BLE_LL_TX_PWR_DBM)); - /* for sync we trace a no pri nor sec set */ ble_ll_trace_u32x2(BLE_LL_TRACE_ID_ADV_TXDONE, advsm->adv_instance, 0); - assert(advsm->flags & BLE_LL_ADV_SM_FLAG_PERIODIC_SYNC_SENDING); - assert(!ble_ll_adv_active_chanset_is_sec(advsm)); + BLE_LL_ASSERT(advsm->flags & BLE_LL_ADV_SM_FLAG_PERIODIC_SYNC_SENDING); + BLE_LL_ASSERT(!ble_ll_adv_active_chanset_is_sec(advsm)); - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &advsm->adv_periodic_txdone_ev); + ble_ll_event_add(&advsm->adv_periodic_txdone_ev); ble_ll_state_set(BLE_LL_STATE_STANDBY); ble_ll_adv_flags_clear(advsm, BLE_LL_ADV_SM_FLAG_PERIODIC_SYNC_SENDING); @@ -2156,21 +2311,21 @@ ble_ll_adv_sync_tx_start_cb(struct ble_ll_sched_item *sch) ble_ll_adv_active_chanset_clear(advsm); ble_ll_adv_flags_set(advsm, BLE_LL_ADV_SM_FLAG_PERIODIC_SYNC_SENDING); - /* Set the power */ - ble_phy_txpwr_set(advsm->adv_txpwr); - /* Set channel */ sync = SYNC_CURRENT(advsm); rc = ble_phy_setchan(sync->chan, advsm->periodic_access_addr, advsm->periodic_crcinit); - assert(rc == 0); + BLE_LL_ASSERT(rc == 0); -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) +#if MYNEWT_VAL(BLE_LL_PHY) /* Set phy mode */ ble_phy_mode_set(advsm->sec_phy, advsm->sec_phy); #endif + /* Set the power */ + ble_ll_tx_power_set(advsm->tx_power); + /* Set transmit start time. */ txstart = sch->start_time + g_ble_ll_sched_offset_ticks; rc = ble_phy_tx_set_start_time(txstart, sch->remainder); @@ -2212,34 +2367,40 @@ ble_ll_adv_sync_tx_start_cb(struct ble_ll_sched_item *sch) static void ble_ll_adv_sync_calculate(struct ble_ll_adv_sm *advsm, - struct ble_ll_adv_sync *sync, - uint16_t sync_data_offset, + struct ble_ll_adv_sync *sync, uint16_t data_offset, uint8_t chan) { - uint16_t rem_sync_data_len; - uint8_t hdr_len; + uint16_t rem_data_len; + uint8_t ext_hdr_len; - assert(!sync->sch.enqueued); - assert((SYNC_DATA_LEN(advsm) > sync_data_offset) || - (SYNC_DATA_LEN(advsm) == 0 && sync_data_offset == 0)); + BLE_LL_ASSERT(!sync->sch.enqueued); + BLE_LL_ASSERT((SYNC_DATA_LEN(advsm) > data_offset) || + (SYNC_DATA_LEN(advsm) == 0 && data_offset == 0)); - sync->sync_data_offset = sync_data_offset; - sync->sync_data_len = 0; + sync->data_offset = data_offset; + sync->data_len = 0; sync->payload_len = 0; - sync->ext_hdr = 0; + sync->ext_hdr_flags = 0; sync->chan = chan; - rem_sync_data_len = SYNC_DATA_LEN(advsm) - sync_data_offset; + rem_data_len = SYNC_DATA_LEN(advsm) - data_offset; + + ext_hdr_len = BLE_LL_EXT_ADV_HDR_LEN; - hdr_len = BLE_LL_EXT_ADV_HDR_LEN; +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_ADI_SUPPORT) + if (advsm->periodic_include_adi) { + sync->ext_hdr_flags |= (1 << BLE_LL_EXT_ADV_DATA_INFO_BIT); + ext_hdr_len += BLE_LL_EXT_ADV_DATA_INFO_SIZE; + } +#endif /* TxPower if configured * Note: TxPower shall not be present in chain PDU for SYNC */ - if (sync_data_offset == 0 && + if (data_offset == 0 && (advsm->periodic_adv_props & BLE_HCI_LE_SET_PERIODIC_ADV_PROP_INC_TX_PWR)) { - sync->ext_hdr |= (1 << BLE_LL_EXT_ADV_TX_POWER_BIT); - hdr_len += BLE_LL_EXT_ADV_TX_POWER_SIZE; + sync->ext_hdr_flags |= (1 << BLE_LL_EXT_ADV_TX_POWER_BIT); + ext_hdr_len += BLE_LL_EXT_ADV_TX_POWER_SIZE; } /* if we have any fields in ext header we need to add flags, note that Aux @@ -2249,32 +2410,48 @@ ble_ll_adv_sync_calculate(struct ble_ll_adv_sm *advsm, * how Aux calculate works and this also make it easier to add more fields * into flags if needed in future */ - if (sync->ext_hdr) { - hdr_len += BLE_LL_EXT_ADV_FLAGS_SIZE; +#if MYNEWT_VAL(BLE_LL_ISO_BROADCASTER) + sync->big = advsm->big; + /* If BIG is present flags will always be also present even if none is set + * to indicate ACAD is present. + */ + if (sync->ext_hdr_flags || sync->big) { + ext_hdr_len += BLE_LL_EXT_ADV_FLAGS_SIZE; + } +#else + if (sync->ext_hdr_flags) { + ext_hdr_len += BLE_LL_EXT_ADV_FLAGS_SIZE; + } +#endif + +#if MYNEWT_VAL(BLE_LL_ISO_BROADCASTER) + if (advsm->big) { + ext_hdr_len += ble_ll_iso_big_biginfo_len(advsm->big); } +#endif /* AdvData always */ - sync->sync_data_len = min(BLE_LL_MAX_PAYLOAD_LEN - hdr_len, rem_sync_data_len); + sync->data_len = MIN(BLE_LL_MAX_PAYLOAD_LEN - ext_hdr_len, rem_data_len); /* AuxPtr if there are more AdvData remaining that we can fit here */ - if ((rem_sync_data_len > sync->sync_data_len)) { - /* adjust for flags that needs to be added if AuxPtr is only field - * in Extended Header - */ - if (!sync->ext_hdr) { - hdr_len += BLE_LL_EXT_ADV_FLAGS_SIZE; - sync->sync_data_len -= BLE_LL_EXT_ADV_FLAGS_SIZE; - } + if ((rem_data_len > sync->data_len)) { + /* adjust for flags that needs to be added if AuxPtr is only field + * in Extended Header + */ + if (!sync->ext_hdr_flags) { + ext_hdr_len += BLE_LL_EXT_ADV_FLAGS_SIZE; + sync->data_len -= BLE_LL_EXT_ADV_FLAGS_SIZE; + } - sync->ext_hdr |= (1 << BLE_LL_EXT_ADV_AUX_PTR_BIT); - hdr_len += BLE_LL_EXT_ADV_AUX_PTR_SIZE; - sync->sync_data_len -= BLE_LL_EXT_ADV_AUX_PTR_SIZE; + sync->ext_hdr_flags |= (1 << BLE_LL_EXT_ADV_AUX_PTR_BIT); + ext_hdr_len += BLE_LL_EXT_ADV_AUX_PTR_SIZE; + sync->data_len -= BLE_LL_EXT_ADV_AUX_PTR_SIZE; - /* PDU payload should be full if chained */ - assert(hdr_len + sync->sync_data_len == BLE_LL_MAX_PAYLOAD_LEN); + /* PDU payload should be full if chained */ + BLE_LL_ASSERT(ext_hdr_len + sync->data_len == BLE_LL_MAX_PAYLOAD_LEN); } - sync->payload_len = hdr_len + sync->sync_data_len; + sync->payload_len = ext_hdr_len + sync->data_len; } static void @@ -2283,19 +2460,19 @@ ble_ll_adv_periodic_schedule_first(struct ble_ll_adv_sm *advsm, { struct ble_ll_adv_sync *sync; struct ble_ll_sched_item *sch; - uint32_t sch_start; uint32_t max_usecs; uint8_t chan; int rc; - assert(!advsm->periodic_sync_active); - assert(!advsm->periodic_sync[0].sch.enqueued); - assert(!advsm->periodic_sync[1].sch.enqueued); + BLE_LL_ASSERT(!advsm->periodic_sync_active); + BLE_LL_ASSERT(!advsm->periodic_sync[0].sch.enqueued); + BLE_LL_ASSERT(!advsm->periodic_sync[1].sch.enqueued); advsm->periodic_sync_active = 1; advsm->periodic_sync_index = 0; sync = SYNC_CURRENT(advsm); + sync->auxptr_zero = 0; /* For first SYNC packet in chain we use separate CSA#2 state to maintain * freq hopping as advertised in SyncInfo @@ -2303,44 +2480,51 @@ ble_ll_adv_periodic_schedule_first(struct ble_ll_adv_sm *advsm, * Preincrement event counter as we later send this in PDU so make sure * same values are used */ - chan = ble_ll_utils_calc_dci_csa2(++advsm->periodic_event_cntr, - advsm->periodic_channel_id, - advsm->periodic_num_used_chans, - advsm->periodic_chanmap); + chan = ble_ll_utils_dci_csa2(advsm->periodic_event_cntr, + advsm->periodic_channel_id, + advsm->periodic_num_used_chans, + advsm->periodic_chanmap); ble_ll_adv_sync_calculate(advsm, sync, 0, chan); /* sync is always non-connectable and non-scannable*/ - max_usecs = ble_ll_pdu_tx_time_get(sync->payload_len, advsm->sec_phy); + max_usecs = ble_ll_pdu_us(sync->payload_len, advsm->sec_phy); sch = &sync->sch; - advsm->periodic_adv_event_start_time_remainder += advsm->periodic_adv_itvl_rem_usec; - if (advsm->periodic_adv_event_start_time_remainder >= 31) { - advsm->periodic_adv_event_start_time++; - advsm->periodic_adv_event_start_time_remainder -= 31; + advsm->padv_event_start = advsm->padv_anchor; + advsm->padv_event_start_rem_us = advsm->padv_anchor_rem_us; + ble_ll_tmr_add(&advsm->padv_event_start, &advsm->padv_event_start_rem_us, + advsm->padv_itvl_us * advsm->padv_anchor_offset); + + if (advsm->padv_anchor_offset == UINT16_MAX) { + advsm->padv_anchor_offset = 0; + advsm->padv_anchor = advsm->padv_event_start; + advsm->padv_anchor_rem_us = advsm->padv_event_start_rem_us; } - sch->start_time = advsm->periodic_adv_event_start_time; - sch->remainder = advsm->periodic_adv_event_start_time_remainder; - sch->end_time = sch->start_time + ble_ll_usecs_to_ticks_round_up(max_usecs); - sch->start_time -= g_ble_ll_sched_offset_ticks; + sch->start_time = advsm->padv_event_start - g_ble_ll_sched_offset_ticks; + sch->remainder = advsm->padv_event_start_rem_us; + sch->end_time = advsm->padv_event_start + ble_ll_tmr_u2t_up(max_usecs); - rc = ble_ll_sched_periodic_adv(sch, &sch_start, first_pdu); + rc = ble_ll_sched_periodic_adv(sch, first_pdu); if (rc) { STATS_INC(ble_ll_stats, periodic_adv_drop_event); - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, - &advsm->adv_periodic_txdone_ev); + ble_ll_event_add(&advsm->adv_periodic_txdone_ev); return; } - sync->start_time = sch_start + g_ble_ll_sched_offset_ticks; + sync->start_time = sch->start_time + g_ble_ll_sched_offset_ticks; assert(first_pdu || - (sync->start_time == advsm->periodic_adv_event_start_time)); + (sync->start_time == advsm->padv_event_start)); - /* The event start time is when we start transmission of the SYNC PDU */ - advsm->periodic_adv_event_start_time = sync->start_time; + if (first_pdu) { + /* Need to update anchor on 1st PDU since it's start time can be changed + * while scheduling */ + advsm->padv_anchor = sync->start_time; + advsm->padv_event_start = sync->start_time; + } } static void @@ -2358,17 +2542,17 @@ ble_ll_adv_periodic_schedule_next(struct ble_ll_adv_sm *advsm) struct ble_ll_adv_sync *sync; struct ble_ll_adv_sync *sync_next; struct ble_ll_sched_item *sch; - uint16_t rem_sync_data_len; - uint16_t next_sync_data_offset; + uint16_t rem_data_len; + uint16_t next_data_offset; uint32_t max_usecs; uint8_t chan; - assert(advsm->periodic_sync_active); + BLE_LL_ASSERT(advsm->periodic_sync_active); sync = SYNC_CURRENT(advsm); sync_next = SYNC_NEXT(advsm); - assert(!sync_next->sch.enqueued); + BLE_LL_ASSERT(!sync_next->sch.enqueued); /* * Do not schedule next sync if current sync is no longer scheduled since we @@ -2382,48 +2566,49 @@ ble_ll_adv_periodic_schedule_next(struct ble_ll_adv_sm *advsm) * Do not schedule next sync if current sync does not have AuxPtr in extended * header as this means we do not need subsequent ADV_CHAIN_IND to be sent. */ - if (!(sync->ext_hdr & (1 << BLE_LL_EXT_ADV_AUX_PTR_BIT))) { + if (!(sync->ext_hdr_flags & (1 << BLE_LL_EXT_ADV_AUX_PTR_BIT))) { return; } - next_sync_data_offset = sync->sync_data_offset + sync->sync_data_len; + next_data_offset = sync->data_offset + sync->data_len; - assert(SYNC_DATA_LEN(advsm) >= next_sync_data_offset); + BLE_LL_ASSERT(SYNC_DATA_LEN(advsm) >= next_data_offset); - rem_sync_data_len = SYNC_DATA_LEN(advsm) - next_sync_data_offset; - assert(rem_sync_data_len > 0); + rem_data_len = SYNC_DATA_LEN(advsm) - next_data_offset; + BLE_LL_ASSERT(rem_data_len > 0); /* we use separate counter for chaining */ - chan = ble_ll_utils_calc_dci_csa2(advsm->periodic_chain_event_cntr++, - advsm->periodic_channel_id, - advsm->periodic_num_used_chans, - advsm->periodic_chanmap); + chan = ble_ll_utils_dci_csa2(advsm->periodic_chain_event_cntr++, + advsm->periodic_channel_id, + advsm->periodic_num_used_chans, + advsm->periodic_chanmap); - ble_ll_adv_sync_calculate(advsm, sync_next, next_sync_data_offset, chan); - max_usecs = ble_ll_pdu_tx_time_get(sync_next->payload_len, advsm->sec_phy); + ble_ll_adv_sync_calculate(advsm, sync_next, next_data_offset, chan); + max_usecs = ble_ll_pdu_us(sync_next->payload_len, advsm->sec_phy); sync_next->start_time = sync->sch.end_time + - ble_ll_usecs_to_ticks_round_up(BLE_LL_MAFS + MYNEWT_VAL(BLE_LL_SCHED_AUX_CHAIN_MAFS_DELAY)); + ble_ll_tmr_u2t_up(BLE_LL_MAFS + + MYNEWT_VAL(BLE_LL_SCHED_AUX_CHAIN_MAFS_DELAY)); sch = &sync_next->sch; sch->start_time = sync_next->start_time - g_ble_ll_sched_offset_ticks; /* adjust for previous packets remainder */ sch->remainder = sync->sch.remainder; - sch->end_time = sync_next->start_time + - ble_ll_usecs_to_ticks_round_up(max_usecs); + sch->end_time = sync_next->start_time + ble_ll_tmr_u2t_up(max_usecs); /* here we can use ble_ll_sched_adv_new as we don't care about timing */ ble_ll_sched_adv_new(&sync_next->sch, ble_ll_adv_sync_next_scheduled, sync_next); - /* if we are pass advertising interval, drop chain */ - if (sch->end_time > advsm->periodic_adv_event_start_time + - advsm->periodic_adv_itvl_ticks) { + /* Remove aux if previous one was already sent with zero offset or new one + * is scheduled past advertising interval. + */ + if (sync->auxptr_zero || + (LL_TMR_GT(sch->end_time, advsm->padv_event_start + + ble_ll_tmr_u2t(advsm->padv_itvl_us)))) { STATS_INC(ble_ll_stats, periodic_chain_drop_event); ble_ll_sched_rmv_elem(&sync->sch); - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, - &advsm->adv_periodic_txdone_ev); } } @@ -2445,7 +2630,9 @@ ble_ll_adv_sync_schedule(struct ble_ll_adv_sm *advsm, bool first_pdu) static void ble_ll_adv_reschedule_periodic_event(struct ble_ll_adv_sm *advsm) { - advsm->periodic_adv_event_start_time += advsm->periodic_adv_itvl_ticks; + advsm->periodic_event_cntr++; + advsm->padv_anchor_offset++; + ble_ll_adv_sync_schedule(advsm, false); } @@ -2464,6 +2651,9 @@ ble_ll_adv_update_periodic_data(struct ble_ll_adv_sm *advsm) os_mbuf_free_chain(advsm->periodic_adv_data); advsm->periodic_adv_data = advsm->periodic_new_data; advsm->periodic_new_data = NULL; +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_ADI_SUPPORT) + advsm->periodic_adv_adi = ble_ll_adv_update_did(advsm->periodic_adv_adi); +#endif } ble_ll_adv_flags_clear(advsm, BLE_LL_ADV_SM_FLAG_PERIODIC_NEW_DATA); @@ -2482,9 +2672,9 @@ ble_ll_adv_periodic_done(struct ble_ll_adv_sm *advsm) struct ble_ll_adv_sync *sync; struct ble_ll_adv_sync *sync_next; - assert(advsm->periodic_adv_enabled); - assert(advsm->periodic_adv_active); - assert(advsm->periodic_sync_active); + BLE_LL_ASSERT(advsm->periodic_adv_enabled); + BLE_LL_ASSERT(advsm->periodic_adv_active); + BLE_LL_ASSERT(advsm->periodic_sync_active); ble_ll_rfmgmt_release(); @@ -2493,7 +2683,7 @@ ble_ll_adv_periodic_done(struct ble_ll_adv_sm *advsm) /* Remove anything else scheduled for periodic */ ble_ll_sched_rmv_elem(&sync->sch); - ble_npl_eventq_remove(&g_ble_ll_data.ll_evq, &advsm->adv_periodic_txdone_ev); + ble_ll_event_remove(&advsm->adv_periodic_txdone_ev); /* If we have next SYNC scheduled, try to schedule another one */ if (sync_next->sch.enqueued) { @@ -2519,9 +2709,6 @@ ble_ll_adv_periodic_event_done(struct ble_npl_event *ev) static void ble_ll_adv_sm_start_periodic(struct ble_ll_adv_sm *advsm) { - uint32_t usecs; - uint32_t ticks; - /* * The Advertising DID is not required to change when a SyncInfo field is * added to or removed from an advertising set. However, if it does not @@ -2531,38 +2718,32 @@ ble_ll_adv_sm_start_periodic(struct ble_ll_adv_sm *advsm) * advertisers should update the Advertising DID when a periodic advertising * train is enabled. */ - ble_ll_adv_update_did(advsm); + advsm->adi = ble_ll_adv_update_did(advsm->adi); + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_ADI_SUPPORT) + /* + * Since periodic advertising can be started without data we initialize DID here + * instead of after setting periodic advertising data. + */ + advsm->periodic_adv_adi = ble_ll_adv_update_did(advsm->periodic_adv_adi); +#endif advsm->periodic_adv_active = 1; /* keep channel map since we cannot change it later on */ - memcpy(advsm->periodic_chanmap, g_ble_ll_conn_params.master_chan_map, - BLE_LL_CONN_CHMAP_LEN); - advsm->periodic_num_used_chans = g_ble_ll_conn_params.num_used_chans; + memcpy(advsm->periodic_chanmap, g_ble_ll_data.chan_map, BLE_LL_CHAN_MAP_LEN); + advsm->periodic_num_used_chans = g_ble_ll_data.chan_map_used; advsm->periodic_event_cntr = 0; /* for chaining we start with random counter as we share access addr */ advsm->periodic_chain_event_cntr = ble_ll_rand(); - advsm->periodic_access_addr = ble_ll_utils_calc_access_addr(); + advsm->periodic_access_addr = ble_ll_utils_calc_aa(); advsm->periodic_channel_id = ((advsm->periodic_access_addr & 0xffff0000) >> 16) ^ (advsm->periodic_access_addr & 0x0000ffff); advsm->periodic_crcinit = ble_ll_rand() & 0xffffff; - usecs = (uint32_t)advsm->periodic_adv_itvl_max * BLE_LL_ADV_PERIODIC_ITVL; - ticks = os_cputime_usecs_to_ticks(usecs); - - advsm->periodic_adv_itvl_rem_usec = (usecs - os_cputime_ticks_to_usecs(ticks)); - if (advsm->periodic_adv_itvl_rem_usec == 31) { - advsm->periodic_adv_itvl_rem_usec = 0; - ticks++; - } - advsm->periodic_adv_itvl_ticks = ticks; - - /* There is no point in starting periodic advertising until next advertising - * event since SyncInfo is needed for synchronization - */ - advsm->periodic_adv_event_start_time_remainder = 0; - advsm->periodic_adv_event_start_time = advsm->adv_pdu_start_time + - os_cputime_usecs_to_ticks(advsm->adv_itvl_usecs + 5000); + advsm->padv_anchor_offset = 1; + advsm->padv_anchor = ble_ll_tmr_get(); + advsm->padv_anchor_rem_us = 0; ble_ll_adv_sync_schedule(advsm, true); } @@ -2588,7 +2769,7 @@ ble_ll_adv_sm_stop_periodic(struct ble_ll_adv_sm *advsm) * advertisers should update the Advertising DID when a periodic advertising * train is disabled. */ - ble_ll_adv_update_did(advsm); + advsm->adi = ble_ll_adv_update_did(advsm->adi); /* Remove any scheduled advertising items */ advsm->periodic_adv_active = 0; @@ -2609,8 +2790,7 @@ ble_ll_adv_sm_stop_periodic(struct ble_ll_adv_sm *advsm) ble_ll_adv_flags_clear(advsm, BLE_LL_ADV_SM_FLAG_PERIODIC_SYNC_SENDING); - ble_npl_eventq_remove(&g_ble_ll_data.ll_evq, - &advsm->adv_periodic_txdone_ev); + ble_ll_event_remove(&advsm->adv_periodic_txdone_ev); ble_ll_adv_update_periodic_data(advsm); } @@ -2632,7 +2812,6 @@ ble_ll_adv_sm_start(struct ble_ll_adv_sm *advsm) { uint8_t adv_chan; uint8_t *addr; - uint8_t *evbuf; uint32_t start_delay_us; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CSA2) uint32_t access_addr; @@ -2660,16 +2839,17 @@ ble_ll_adv_sm_start(struct ble_ll_adv_sm *advsm) * Get an event with which to send the connection complete event if * this is connectable */ +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_CONNECTABLE) { /* We expect this to be NULL but if not we wont allocate one... */ if (advsm->conn_comp_ev == NULL) { - evbuf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); - if (!evbuf) { + advsm->conn_comp_ev = ble_transport_alloc_evt(0); + if (!advsm->conn_comp_ev) { return BLE_ERR_MEM_CAPACITY; } - advsm->conn_comp_ev = evbuf; } } +#endif /* Set advertising address */ if ((advsm->own_addr_type & 1) == 0) { @@ -2703,20 +2883,11 @@ ble_ll_adv_sm_start(struct ble_ll_adv_sm *advsm) #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CSA2) advsm->event_cntr = 0; - access_addr = ble_ll_utils_calc_access_addr(); + access_addr = ble_ll_utils_calc_aa(); advsm->channel_id = ((access_addr & 0xffff0000) >> 16) ^ (access_addr & 0x0000ffff); #endif - /* Determine the advertising interval we will use */ - if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_HD_DIRECTED) { - /* Set it to max. allowed for high duty cycle advertising */ - advsm->adv_itvl_usecs = BLE_LL_ADV_PDU_ITVL_HD_MS_MAX; - } else { - advsm->adv_itvl_usecs = (uint32_t)advsm->adv_itvl_max; - advsm->adv_itvl_usecs *= BLE_LL_ADV_ITVL; - } - /* Set first advertising channel */ adv_chan = ble_ll_adv_first_chan(advsm); advsm->adv_chan = adv_chan; @@ -2735,8 +2906,8 @@ ble_ll_adv_sm_start(struct ble_ll_adv_sm *advsm) earliest_start_time = ble_ll_rfmgmt_enable_now(); start_delay_us = ble_ll_rand() % (BLE_LL_ADV_DELAY_MS_MAX * 1000); - advsm->adv_pdu_start_time = os_cputime_get32() + - os_cputime_usecs_to_ticks(start_delay_us); + advsm->adv_pdu_start_time = ble_ll_tmr_get() + + ble_ll_tmr_u2t(start_delay_us); ble_ll_adv_set_sched(advsm); @@ -2778,7 +2949,7 @@ ble_ll_adv_read_txpwr(uint8_t *rspbuf, uint8_t *rsplen) { struct ble_hci_le_rd_adv_chan_txpwr_rp *rsp = (void *) rspbuf; - rsp->power_level = MYNEWT_VAL(BLE_LL_TX_PWR_DBM); + rsp->power_level = g_ble_ll_tx_power; *rsplen = sizeof(*rsp); return BLE_ERR_SUCCESS; @@ -2878,7 +3049,7 @@ ble_ll_adv_update_data_mbuf(struct os_mbuf **omp, bool new_data, uint16_t maxlen } } - assert(om); + BLE_LL_ASSERT(om); if (OS_MBUF_PKTLEN(om) + datalen > maxlen) { os_mbuf_free_chain(om); @@ -2987,6 +3158,19 @@ ble_ll_adv_set_scan_rsp_data(const uint8_t *data, uint8_t datalen, if (!advsm->new_scan_rsp_data) { return BLE_ERR_MEM_CAPACITY; } + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) + if (!(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) && + !ble_ll_adv_aux_check_data_itvl(advsm, advsm->props, advsm->pri_phy, + advsm->sec_phy, + advsm->new_scan_rsp_data, + advsm->adv_itvl_usecs)) { + os_mbuf_free_chain(advsm->new_scan_rsp_data); + advsm->new_scan_rsp_data = NULL; + return BLE_ERR_PACKET_TOO_LONG; + } +#endif + ble_ll_adv_flags_set(advsm, BLE_LL_ADV_SM_FLAG_NEW_SCAN_RSP_DATA); } else { ble_ll_adv_update_data_mbuf(&advsm->scan_rsp_data, new_data, @@ -2996,8 +3180,18 @@ ble_ll_adv_set_scan_rsp_data(const uint8_t *data, uint8_t datalen, } #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) + if (!(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) && + !ble_ll_adv_aux_check_data_itvl(advsm, advsm->props, advsm->pri_phy, + advsm->sec_phy, + advsm->scan_rsp_data, + advsm->adv_itvl_usecs)) { + os_mbuf_free_chain(advsm->scan_rsp_data); + advsm->scan_rsp_data = NULL; + return BLE_ERR_PACKET_TOO_LONG; + } + /* DID shall be updated when host provides new scan response data */ - ble_ll_adv_update_did(advsm); + advsm->adi = ble_ll_adv_update_did(advsm->adi); #endif } @@ -3072,7 +3266,7 @@ ble_ll_adv_set_adv_data(const uint8_t *data, uint8_t datalen, uint8_t instance, } /* update DID only */ - ble_ll_adv_update_did(advsm); + advsm->adi = ble_ll_adv_update_did(advsm->adi); return BLE_ERR_SUCCESS; case BLE_HCI_LE_SET_DATA_OPER_LAST: ble_ll_adv_flags_clear(advsm, BLE_LL_ADV_SM_FLAG_ADV_DATA_INCOMPLETE); @@ -3129,6 +3323,18 @@ ble_ll_adv_set_adv_data(const uint8_t *data, uint8_t datalen, uint8_t instance, if (!advsm->new_adv_data) { return BLE_ERR_MEM_CAPACITY; } + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) + if (!(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) && + !ble_ll_adv_aux_check_data_itvl(advsm, advsm->props, advsm->pri_phy, + advsm->sec_phy, advsm->new_adv_data, + advsm->adv_itvl_usecs)) { + os_mbuf_free_chain(advsm->new_adv_data); + advsm->new_adv_data = NULL; + return BLE_ERR_PACKET_TOO_LONG; + } +#endif + ble_ll_adv_flags_set(advsm, BLE_LL_ADV_SM_FLAG_NEW_ADV_DATA); } else { ble_ll_adv_update_data_mbuf(&advsm->adv_data, new_data, @@ -3138,8 +3344,17 @@ ble_ll_adv_set_adv_data(const uint8_t *data, uint8_t datalen, uint8_t instance, } #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) + if (!(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) && + !ble_ll_adv_aux_check_data_itvl(advsm, advsm->props, advsm->pri_phy, + advsm->sec_phy, advsm->adv_data, + advsm->adv_itvl_usecs)) { + os_mbuf_free_chain(advsm->adv_data); + advsm->adv_data = NULL; + return BLE_ERR_PACKET_TOO_LONG; + } + /* DID shall be updated when host provides new advertising data */ - ble_ll_adv_update_did(advsm); + advsm->adi = ble_ll_adv_update_did(advsm->adi); #endif } @@ -3195,7 +3410,7 @@ static struct ble_ll_adv_sm * ble_ll_adv_sm_get(uint8_t instance) { struct ble_ll_adv_sm *advsm; - int i; + unsigned int i; advsm = ble_ll_adv_sm_find_configured(instance); if (advsm) { @@ -3226,6 +3441,7 @@ ble_ll_adv_ext_set_param(const uint8_t *cmdbuf, uint8_t len, struct ble_ll_adv_sm *advsm; uint32_t adv_itvl_min; uint32_t adv_itvl_max; + uint32_t adv_itvl_usecs; uint16_t props; int rc; @@ -3266,16 +3482,40 @@ ble_ll_adv_ext_set_param(const uint8_t *cmdbuf, uint8_t len, } #endif - adv_itvl_min = cmd->pri_itvl_min[2] << 16 | cmd->pri_itvl_min[1] << 8 | - cmd->pri_itvl_min[0]; - adv_itvl_max = cmd->pri_itvl_max[2] << 16 | cmd->pri_itvl_max[1] << 8 | - cmd->pri_itvl_max[0]; + adv_itvl_min = get_le24(cmd->pri_itvl_min); + adv_itvl_max = get_le24(cmd->pri_itvl_max); if (props & ~BLE_HCI_LE_SET_EXT_ADV_PROP_MASK) { rc = BLE_ERR_INV_HCI_CMD_PARMS; goto done; } + /* Anonymous advertising only makes sense for non-connectable, non-scannable + * and non-legacy. This is not explicitly stated anywhere in HCI/LL part of + * the spec, but Vol 3, Part C, 9.1.1.2 (GAP) states: + * "A device in the Broadcast mode may send non-connectable and non- + * scannable undirected or non-connectable and non-scannable directed + * advertising events anonymously by excluding the Broadcaster's address." + * And Vol 4, Part E, 7.8.53 (HCI) states: + * "If the Advertising_Event_Properties parameter does not describe an + * event type supported by the Controller, contains an invalid bit + * combination, or specifies a type that does not support advertising + * data when the advertising set already contains some, the Controller + * shall return the error code Invalid HCI Command Parameters (0x12)." + * + * So let's just assume anonymous on connectable/scannable/legacy is an + * invalid bit combination. + */ + if (props & BLE_HCI_LE_SET_EXT_ADV_PROP_ANON_ADV) { + if (props & (BLE_HCI_LE_SET_EXT_ADV_PROP_CONNECTABLE | + BLE_HCI_LE_SET_EXT_ADV_PROP_SCANNABLE | + BLE_HCI_LE_SET_EXT_ADV_PROP_HD_DIRECTED | + BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY)) { + rc = BLE_ERR_INV_HCI_CMD_PARMS; + goto done; + } + } + if (props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) { if (ADV_DATA_LEN(advsm) > BLE_ADV_LEGACY_DATA_MAX_LEN || SCAN_RSP_DATA_LEN(advsm) > BLE_SCAN_RSP_LEGACY_DATA_MAX_LEN) { @@ -3285,9 +3525,11 @@ ble_ll_adv_ext_set_param(const uint8_t *cmdbuf, uint8_t len, /* if legacy bit is set possible values are limited */ switch (props) { +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) case BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY_IND: case BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY_LD_DIR: case BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY_HD_DIR: +#endif case BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY_SCAN: case BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY_NONCONN: break; @@ -3296,6 +3538,12 @@ ble_ll_adv_ext_set_param(const uint8_t *cmdbuf, uint8_t len, goto done; } } else { +#if !MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) + if (props & BLE_HCI_LE_SET_EXT_ADV_PROP_CONNECTABLE) { + rc = BLE_ERR_INV_HCI_CMD_PARMS; + goto done; + } +#endif /* HD directed advertising allowed only on legacy PDUs */ if (props & BLE_HCI_LE_SET_EXT_ADV_PROP_HD_DIRECTED) { rc = BLE_ERR_INV_HCI_CMD_PARMS; @@ -3399,13 +3647,29 @@ ble_ll_adv_ext_set_param(const uint8_t *cmdbuf, uint8_t len, goto done; } + /* Determine the advertising interval we will use */ + if (props & BLE_HCI_LE_SET_EXT_ADV_PROP_HD_DIRECTED) { + /* Set it to max. allowed for high duty cycle advertising */ + adv_itvl_usecs = BLE_LL_ADV_PDU_ITVL_HD_MS_MAX; + } else { + adv_itvl_usecs = adv_itvl_max * BLE_LL_ADV_ITVL; + } + + if (!ble_ll_adv_aux_check_data_itvl(advsm, props, cmd->pri_phy, cmd->sec_phy, + advsm->adv_data, adv_itvl_usecs) || + !ble_ll_adv_aux_check_data_itvl(advsm, props, cmd->pri_phy, cmd->sec_phy, + advsm->scan_rsp_data, adv_itvl_usecs)) { + return BLE_ERR_PACKET_TOO_LONG; + } + rc = BLE_ERR_SUCCESS; if (cmd->tx_power == 127) { /* no preference */ - advsm->adv_txpwr = MYNEWT_VAL(BLE_LL_TX_PWR_DBM); + advsm->tx_power = ble_ll_tx_power_round(g_ble_ll_tx_power - g_ble_ll_tx_power_compensation); } else { - advsm->adv_txpwr = ble_phy_txpower_round(cmd->tx_power); + advsm->tx_power = ble_ll_tx_power_round(MIN(cmd->tx_power, MYNEWT_VAL(BLE_LL_TX_PWR_MAX_DBM)) - + g_ble_ll_tx_power_compensation); } /* we can always store as those are validated and used only when needed */ @@ -3414,12 +3678,14 @@ ble_ll_adv_ext_set_param(const uint8_t *cmdbuf, uint8_t len, advsm->own_addr_type = cmd->own_addr_type; advsm->adv_filter_policy = cmd->filter_policy; advsm->adv_chanmask = cmd->pri_chan_map; - advsm->adv_itvl_min = adv_itvl_min; - advsm->adv_itvl_max = adv_itvl_max; + advsm->adv_itvl_usecs = adv_itvl_usecs; advsm->pri_phy = cmd->pri_phy; advsm->sec_phy = cmd->sec_phy; /* Update SID only */ advsm->adi = (advsm->adi & 0x0fff) | ((cmd->sid << 12)); +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_ADI_SUPPORT) + advsm->periodic_adv_adi = (advsm->periodic_adv_adi & 0x0fff) | ((cmd->sid << 12)); +#endif advsm->props = props; @@ -3442,12 +3708,65 @@ ble_ll_adv_ext_set_param(const uint8_t *cmdbuf, uint8_t len, done: /* Update TX power */ - rsp->tx_power = rc ? 0 : advsm->adv_txpwr; + rsp->tx_power = rc ? 0 : (advsm->tx_power + g_ble_ll_tx_power_compensation); *rsplen = sizeof(*rsp); return rc; } +#if MYNEWT_VAL(BLE_VERSION) >= 54 +static inline uint8_t +ble_ll_adv_convert_phy_opt(uint8_t cmd_phy_opt) +{ + switch (cmd_phy_opt) { + case BLE_HCI_ADVERTISING_PHY_OPT_NO_PREF: + return BLE_HCI_LE_PHY_CODED_ANY; + case BLE_HCI_ADVERTISING_PHY_OPT_S2_PREF: + case BLE_HCI_ADVERTISING_PHY_OPT_S2_REQ: + return BLE_HCI_LE_PHY_CODED_S2_PREF; + case BLE_HCI_ADVERTISING_PHY_OPT_S8_PREF: + case BLE_HCI_ADVERTISING_PHY_OPT_S8_REQ: + return BLE_HCI_LE_PHY_CODED_S8_PREF; + default: + BLE_LL_ASSERT(0); + } +} + +int +ble_ll_adv_ext_set_param_v2(const uint8_t *cmdbuf, uint8_t len, + uint8_t *rspbuf, uint8_t *rsplen) +{ + const struct ble_hci_le_set_ext_adv_params_v2_cp *cmd = (const void *) cmdbuf; + struct ble_ll_adv_sm *advsm; + int rc; + + if (len != sizeof(*cmd)) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + if ((cmd->pri_phy_opt > BLE_HCI_ADVERTISING_PHY_OPT_S8_REQ) || + (cmd->sec_phy_opt > BLE_HCI_ADVERTISING_PHY_OPT_S8_REQ)) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + rc = ble_ll_adv_ext_set_param(cmdbuf, len - 2, rspbuf, rsplen); + if (rc != 0) { + return rc; + } + + advsm = ble_ll_adv_sm_get(cmd->params_v1.adv_handle); + + if (advsm->pri_phy == BLE_HCI_LE_PHY_CODED) { + advsm->pri_phy_opt = ble_ll_adv_convert_phy_opt(cmd->pri_phy_opt); + } + if (advsm->sec_phy == BLE_HCI_LE_PHY_CODED) { + advsm->sec_phy_opt = ble_ll_adv_convert_phy_opt(cmd->sec_phy_opt); + } + + return rc; +} +#endif + int ble_ll_adv_ext_set_adv_data(const uint8_t *cmdbuf, uint8_t cmdlen) { @@ -3703,7 +4022,7 @@ ble_ll_adv_sync_get_pdu_len(uint16_t data_len, uint16_t *data_offset, } /* AdvData always */ - data_len = min(BLE_LL_MAX_PAYLOAD_LEN - hdr_len, rem_data_len); + data_len = MIN(BLE_LL_MAX_PAYLOAD_LEN - hdr_len, rem_data_len); /* AuxPtr if there are more AdvData remaining that we can fit here */ if (rem_data_len > data_len) { @@ -3739,9 +4058,8 @@ ble_ll_adv_periodic_check_data_itvl(uint16_t payload_len, uint16_t props, while (offset < payload_len) { pdu_len = ble_ll_adv_sync_get_pdu_len(payload_len, &offset, props); - max_usecs += ble_ll_pdu_tx_time_get(pdu_len, phy); - max_usecs += ble_ll_usecs_to_ticks_round_up(BLE_LL_MAFS + - MYNEWT_VAL(BLE_LL_SCHED_AUX_CHAIN_MAFS_DELAY)); + max_usecs += ble_ll_pdu_us(pdu_len, phy); + max_usecs += BLE_LL_MAFS + MYNEWT_VAL(BLE_LL_SCHED_AUX_CHAIN_MAFS_DELAY); } itvl_usecs = (uint32_t)itvl * BLE_LL_ADV_PERIODIC_ITVL; @@ -3812,8 +4130,8 @@ ble_ll_adv_periodic_set_param(const uint8_t *cmdbuf, uint8_t len) return BLE_ERR_PACKET_TOO_LONG; } - advsm->periodic_adv_itvl_min = adv_itvl_min; - advsm->periodic_adv_itvl_max = adv_itvl_max; + advsm->periodic_adv_itvl = adv_itvl_max; + advsm->padv_itvl_us = adv_itvl_max * BLE_LL_ADV_PERIODIC_ITVL; advsm->periodic_adv_props = props; ble_ll_adv_flags_set(advsm, BLE_LL_ADV_SM_FLAG_PERIODIC_CONFIGURED); @@ -3850,6 +4168,10 @@ ble_ll_adv_periodic_set_data(const uint8_t *cmdbuf, uint8_t len) switch (cmd->operation) { case BLE_HCI_LE_SET_DATA_OPER_LAST: case BLE_HCI_LE_SET_DATA_OPER_INT: + if (advsm->periodic_adv_enabled) { + return BLE_ERR_CMD_DISALLOWED; + } + if (!(advsm->flags & BLE_LL_ADV_SM_FLAG_PERIODIC_DATA_INCOMPLETE)) { return BLE_ERR_INV_HCI_CMD_PARMS; } @@ -3857,10 +4179,6 @@ ble_ll_adv_periodic_set_data(const uint8_t *cmdbuf, uint8_t len) if (!advsm->periodic_adv_data || !cmd->adv_data_len) { return BLE_ERR_INV_HCI_CMD_PARMS; } - - if (advsm->periodic_adv_enabled) { - return BLE_ERR_CMD_DISALLOWED; - } break; case BLE_HCI_LE_SET_DATA_OPER_FIRST: if (advsm->periodic_adv_enabled) { @@ -3875,6 +4193,23 @@ ble_ll_adv_periodic_set_data(const uint8_t *cmdbuf, uint8_t len) case BLE_HCI_LE_SET_DATA_OPER_COMPLETE: new_data = true; break; +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_ADI_SUPPORT) + case BLE_HCI_LE_SET_DATA_OPER_UNCHANGED: + if (!advsm->periodic_adv_enabled) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + if (advsm->periodic_adv_data->om_len == 0) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + if (cmd->adv_data_len != 0) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + advsm->periodic_adv_adi = ble_ll_adv_update_did(advsm->periodic_adv_adi); + return BLE_ERR_SUCCESS; +#endif default: return BLE_ERR_INV_HCI_CMD_PARMS; } @@ -3893,7 +4228,7 @@ ble_ll_adv_periodic_set_data(const uint8_t *cmdbuf, uint8_t len) */ if (!ble_ll_adv_periodic_check_data_itvl(payload_total_len, advsm->periodic_adv_props, - advsm->periodic_adv_itvl_max, + advsm->periodic_adv_itvl, advsm->sec_phy)) { return BLE_ERR_PACKET_TOO_LONG; } @@ -3951,23 +4286,54 @@ ble_ll_adv_periodic_enable(const uint8_t *cmdbuf, uint8_t len) return BLE_ERR_UNK_ADV_INDENT; } - if (cmd->enable) { +#if !MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_ADI_SUPPORT) + if (cmd->enable & 0x02) { + return BLE_ERR_UNSUPPORTED; + } +#endif + +#if MYNEWT_VAL(BLE_VERSION) >= 53 + if (cmd->enable & 0xfc) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } +#else + if (cmd->enable & 0xfe) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } +#endif + + if (cmd->enable & 0x1) { + if (advsm->props & (BLE_HCI_LE_SET_EXT_ADV_PROP_ANON_ADV | + BLE_HCI_LE_SET_EXT_ADV_PROP_SCANNABLE | + BLE_HCI_LE_SET_EXT_ADV_PROP_CONNECTABLE | + BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY)) { + return BLE_ERR_CMD_DISALLOWED; + } + if (advsm->flags & BLE_LL_ADV_SM_FLAG_PERIODIC_DATA_INCOMPLETE) { return BLE_ERR_CMD_DISALLOWED; } + if (!(advsm->flags & BLE_LL_ADV_SM_FLAG_PERIODIC_CONFIGURED)) { + return BLE_ERR_CMD_DISALLOWED; + } + /* If Enable is set to 0x01 and the length of the periodic advertising * data is greater than the maximum that the Controller can transmit - * within the chosen periodicadvertising interval, the Controller shall + * within the chosen periodic advertising interval, the Controller shall * return the error code Packet Too Long (0x45). */ if (!ble_ll_adv_periodic_check_data_itvl(SYNC_DATA_LEN(advsm), advsm->periodic_adv_props, - advsm->periodic_adv_itvl_max, + advsm->periodic_adv_itvl, advsm->sec_phy)) { return BLE_ERR_PACKET_TOO_LONG; } +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_ADI_SUPPORT) + advsm->periodic_include_adi = !!(cmd->enable & 0x2); +#endif + /* If the advertising set is not currently enabled (see the * LE_Set_Extended_Advertising_Enable command), the periodic advertising * is not started until the advertising set is enabled. @@ -4067,7 +4433,7 @@ ble_ll_adv_periodic_set_info_transfer(const uint8_t *cmdbuf, uint8_t len, goto done; } - connsm = ble_ll_conn_find_active_conn(handle); + connsm = ble_ll_conn_find_by_handle(handle); if (!connsm) { rc = BLE_ERR_UNK_CONN_ID; goto done; @@ -4078,7 +4444,7 @@ ble_ll_adv_periodic_set_info_transfer(const uint8_t *cmdbuf, uint8_t len, * * Allow initiate LL procedure only if remote supports it. */ - if (!(connsm->remote_features[2] & (BLE_LL_FEAT_SYNC_TRANS_RECV >> (8 * 3)))) { + if (!ble_ll_conn_rem_feature_check(connsm, BLE_LL_FEAT_SYNC_TRANS_RECV)) { rc = BLE_ERR_UNSUPP_REM_FEATURE; goto done; } @@ -4093,35 +4459,6 @@ ble_ll_adv_periodic_set_info_transfer(const uint8_t *cmdbuf, uint8_t len, #endif #endif -/** - * Says whether the specified address is already connected or not. - * @param [in] addr The peer address. - * @param [in] addr_type Public address (0) or random address (1). - * @return Return 1 if already connected, 0 otherwise. - */ -static int -ble_ll_adv_already_connected(const uint8_t* addr, uint8_t addr_type) -{ - struct ble_ll_conn_sm *connsm; - - /* extracted from ble_ll_conn_slave_start function */ - SLIST_FOREACH(connsm, &g_ble_ll_conn_active_list, act_sle) { - if (!memcmp(&connsm->peer_addr, addr, BLE_DEV_ADDR_LEN)) { - if (addr_type == BLE_ADDR_RANDOM) { - if (connsm->peer_addr_type & 1) { - return 1; - } - } else { - if ((connsm->peer_addr_type & 1) == 0) { - return 1; - } - } - } - } - - return 0; -} - /** * Called when the LL receives a scan request or connection request * @@ -4146,9 +4483,11 @@ ble_ll_adv_rx_req(uint8_t pdu_type, struct os_mbuf *rxpdu) uint8_t *peer; struct ble_mbuf_hdr *ble_hdr; struct ble_ll_adv_sm *advsm; +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) struct aux_conn_rsp_data rsp_data; #endif +#endif #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) struct ble_ll_resolv_entry *rl; #endif @@ -4255,8 +4594,9 @@ ble_ll_adv_rx_req(uint8_t pdu_type, struct os_mbuf *rxpdu) STATS_INC(ble_ll_stats, scan_rsp_txg); } } else if (pdu_type == BLE_ADV_PDU_TYPE_AUX_CONNECT_REQ) { +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) /* See if the device is already connected */ - if (ble_ll_adv_already_connected(peer, peer_addr_type)) { + if (ble_ll_conn_find_by_peer_addr(peer, peer_addr_type)) { return -1; } @@ -4287,6 +4627,7 @@ ble_ll_adv_rx_req(uint8_t pdu_type, struct os_mbuf *rxpdu) ble_ll_adv_flags_set(advsm, BLE_LL_ADV_SM_FLAG_CONN_RSP_TXD); STATS_INC(ble_ll_stats, aux_conn_rsp_tx); } +#endif #endif } @@ -4303,6 +4644,7 @@ ble_ll_adv_rx_req(uint8_t pdu_type, struct os_mbuf *rxpdu) * * @return 0: no connection started. 1: connection started */ +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) static int ble_ll_adv_conn_req_rxd(uint8_t *rxbuf, struct ble_mbuf_hdr *hdr, struct ble_ll_adv_sm *advsm) @@ -4380,19 +4722,26 @@ ble_ll_adv_conn_req_rxd(uint8_t *rxbuf, struct ble_mbuf_hdr *hdr, } #endif - /* Try to start slave connection. If successful, stop advertising */ - valid = ble_ll_conn_slave_start(rxbuf, addr_type, hdr, - !(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY)); + /* Try to start peripheral connection. If successful, stop advertising */ + valid = ble_ll_conn_periph_start(rxbuf, addr_type, hdr, + !(advsm->props & + BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY)); if (valid) { /* stop advertising only if not transmitting connection response */ if (!(advsm->flags & BLE_LL_ADV_SM_FLAG_CONN_RSP_TXD)) { ble_ll_adv_sm_stop(advsm); } + } else if (advsm->flags & BLE_LL_ADV_SM_FLAG_CONN_RSP_TXD) { +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) + ble_ll_adv_flags_set(advsm, BLE_LL_ADV_SM_FLAG_CONN_RSP_TXD_ERR); + valid = 1; +#endif } } return valid; } +#endif /** * Called on phy rx pdu end when in advertising state. @@ -4433,7 +4782,7 @@ ble_ll_adv_rx_isr_end(uint8_t pdu_type, struct os_mbuf *rxpdu, int crcok) if (ble_ll_adv_active_chanset_is_sec(g_ble_ll_cur_adv_sm)) { rxhdr->rxinfo.flags |= BLE_MBUF_HDR_F_EXT_ADV_SEC; } else { - assert(ble_ll_adv_active_chanset_is_pri(g_ble_ll_cur_adv_sm)); + BLE_LL_ASSERT(ble_ll_adv_active_chanset_is_pri(g_ble_ll_cur_adv_sm)); } #endif if (crcok) { @@ -4483,7 +4832,7 @@ ble_ll_adv_rx_pkt_in(uint8_t ptype, uint8_t *rxbuf, struct ble_mbuf_hdr *hdr) #endif /* - * It is possible that advertising was stopped and a packet plcaed on the + * It is possible that advertising was stopped and a packet placed on the * LL receive packet queue. In this case, just ignore the received packet * as the advertising state machine is no longer "valid" */ @@ -4501,9 +4850,11 @@ ble_ll_adv_rx_pkt_in(uint8_t ptype, uint8_t *rxbuf, struct ble_mbuf_hdr *hdr) adv_event_over = 1; if (BLE_MBUF_HDR_CRC_OK(hdr)) { if (ptype == BLE_ADV_PDU_TYPE_CONNECT_IND) { +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) if (ble_ll_adv_conn_req_rxd(rxbuf, hdr, advsm)) { adv_event_over = 0; } +#endif } else { if ((ptype == BLE_ADV_PDU_TYPE_SCAN_REQ) && (hdr->rxinfo.flags & BLE_MBUF_HDR_F_SCAN_RSP_TXD)) { @@ -4568,8 +4919,10 @@ ble_ll_adv_rx_isr_start(uint8_t pdu_type) } static void -ble_ll_adv_drop_event(struct ble_ll_adv_sm *advsm) +ble_ll_adv_drop_event(struct ble_ll_adv_sm *advsm, bool preempted) { + os_sr_t sr; + STATS_INC(ble_ll_stats, adv_drop_event); ble_ll_sched_rmv_elem(&advsm->adv_sch); @@ -4577,41 +4930,47 @@ ble_ll_adv_drop_event(struct ble_ll_adv_sm *advsm) ble_ll_sched_rmv_elem(&advsm->aux[0].sch); ble_ll_sched_rmv_elem(&advsm->aux[1].sch); - ble_npl_eventq_remove(&g_ble_ll_data.ll_evq, &advsm->adv_sec_txdone_ev); + ble_ll_event_remove(&advsm->adv_sec_txdone_ev); advsm->aux_active = 0; #endif + if (preempted) { + OS_ENTER_CRITICAL(sr); + advsm->retry_event = !(advsm->flags & BLE_LL_ADV_SM_FLAG_ACTIVE_CHANSET_MASK); + OS_EXIT_CRITICAL(sr); + } + advsm->adv_chan = ble_ll_adv_final_chan(advsm); - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &advsm->adv_txdone_ev); + ble_ll_event_add(&advsm->adv_txdone_ev); } static void ble_ll_adv_reschedule_event(struct ble_ll_adv_sm *advsm) { - int rc; - uint32_t start_time; + struct ble_ll_sched_item *sch; uint32_t max_delay_ticks; + int rc; - assert(advsm->adv_enabled); + BLE_LL_ASSERT(advsm->adv_enabled); + + sch = &advsm->adv_sch; - if (!advsm->adv_sch.enqueued) { + if (!sch->enqueued) { if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_HD_DIRECTED) { max_delay_ticks = 0; } else { - max_delay_ticks = - os_cputime_usecs_to_ticks(BLE_LL_ADV_DELAY_MS_MAX * 1000); + max_delay_ticks = ble_ll_tmr_u2t(BLE_LL_ADV_DELAY_MS_MAX * 1000); } - rc = ble_ll_sched_adv_reschedule(&advsm->adv_sch, &start_time, - max_delay_ticks); + rc = ble_ll_sched_adv_reschedule(sch, max_delay_ticks); if (rc) { - ble_ll_adv_drop_event(advsm); + ble_ll_adv_drop_event(advsm, 0); return; } - start_time += g_ble_ll_sched_offset_ticks; - advsm->adv_event_start_time = start_time; - advsm->adv_pdu_start_time = start_time; + advsm->adv_event_start_time = sch->start_time + + g_ble_ll_sched_offset_ticks; + advsm->adv_pdu_start_time = advsm->adv_event_start_time; } #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) @@ -4642,7 +5001,7 @@ ble_ll_adv_done(struct ble_ll_adv_sm *advsm) uint32_t tick_itvl; uint32_t start_time; - assert(advsm->adv_enabled); + BLE_LL_ASSERT(advsm->adv_enabled); ble_ll_rfmgmt_release(); @@ -4661,7 +5020,7 @@ ble_ll_adv_done(struct ble_ll_adv_sm *advsm) /* Remove the element from the schedule if it is still there. */ ble_ll_sched_rmv_elem(&advsm->adv_sch); - ble_npl_eventq_remove(&g_ble_ll_data.ll_evq, &advsm->adv_txdone_ev); + ble_ll_event_remove(&advsm->adv_txdone_ev); /* * Check if we have ended our advertising event. If our last advertising @@ -4671,25 +5030,35 @@ ble_ll_adv_done(struct ble_ll_adv_sm *advsm) final_adv_chan = ble_ll_adv_final_chan(advsm); if (advsm->adv_chan == final_adv_chan) { -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - if (advsm->events_max) { - advsm->events++; - } -#endif - ble_ll_scan_chk_resume(); /* This event is over. Set adv channel to first one */ advsm->adv_chan = ble_ll_adv_first_chan(advsm); - /* - * Calculate start time of next advertising event. NOTE: we do not - * add the random advDelay as the scheduling code will do that. - */ itvl = advsm->adv_itvl_usecs; - tick_itvl = os_cputime_usecs_to_ticks(itvl); - advsm->adv_event_start_time += tick_itvl; - advsm->adv_pdu_start_time = advsm->adv_event_start_time; + tick_itvl = ble_ll_tmr_u2t(itvl); + + /* do not calculate new event time if current event should be retried; + * this happens if event was preempted, so we just try to schedule one + * more time with the same start time + */ + + if (!advsm->retry_event) { +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) + if (advsm->events_max) { + advsm->events++; + } +#endif + + /* + * Calculate start time of next advertising event. NOTE: we do not + * add the random advDelay as the scheduling code will do that. + */ + advsm->adv_event_start_time += tick_itvl; + advsm->adv_pdu_start_time = advsm->adv_event_start_time; + } else { + advsm->retry_event = 0; + } /* * The scheduled time better be in the future! If it is not, we will @@ -4697,7 +5066,7 @@ ble_ll_adv_done(struct ble_ll_adv_sm *advsm) */ start_time = advsm->adv_pdu_start_time - g_ble_ll_sched_offset_ticks; - delta_t = (int32_t)(start_time - os_cputime_get32()); + delta_t = (int32_t)(start_time - ble_ll_tmr_get()); if (delta_t < 0) { /* * NOTE: we just the same interval that we calculated earlier. @@ -4722,19 +5091,20 @@ ble_ll_adv_done(struct ble_ll_adv_sm *advsm) ++advsm->adv_chan; } - /* - * We will transmit right away. Set next pdu start time to now - * plus a xcvr start delay just so we dont count late adv starts + /* We want to send next PDU right away so start time is set to "now" + * plus scheduling offset. Add an extra tick since LL timer may tick + * when we calculate other things in the meantime. */ - advsm->adv_pdu_start_time = os_cputime_get32() + - g_ble_ll_sched_offset_ticks; + advsm->adv_pdu_start_time = ble_ll_tmr_get() + + g_ble_ll_sched_offset_ticks + 1; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) /* If we're past aux (unlikely, but can happen), just drop an event */ if (!(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY) && advsm->aux_active && - advsm->adv_pdu_start_time > AUX_CURRENT(advsm)->start_time) { - ble_ll_adv_drop_event(advsm); + LL_TMR_GT(advsm->adv_pdu_start_time, + AUX_CURRENT(advsm)->start_time)) { + ble_ll_adv_drop_event(advsm, 0); return; } #endif @@ -4745,7 +5115,7 @@ ble_ll_adv_done(struct ble_ll_adv_sm *advsm) /* check if advertising timed out */ #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) if (advsm->duration && - advsm->adv_pdu_start_time >= advsm->adv_end_time) { + LL_TMR_GEQ(advsm->adv_pdu_start_time, advsm->adv_end_time)) { /* Legacy PDUs need to be stop here. * For ext adv it will be stopped when AUX is done (unless it was * dropped so check if AUX is active here as well). @@ -4759,7 +5129,7 @@ ble_ll_adv_done(struct ble_ll_adv_sm *advsm) } #else if ((advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_HD_DIRECTED) && - (advsm->adv_pdu_start_time >= advsm->adv_end_time)) { + LL_TMR_GEQ(advsm->adv_pdu_start_time, advsm->adv_end_time)) { ble_ll_adv_sm_stop_timeout(advsm); return; } @@ -4800,7 +5170,7 @@ ble_ll_adv_done(struct ble_ll_adv_sm *advsm) rc = ble_ll_sched_adv_resched_pdu(&advsm->adv_sch); if (rc) { STATS_INC(ble_ll_stats, adv_resched_pdu_fail); - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &advsm->adv_txdone_ev); + ble_ll_event_add(&advsm->adv_txdone_ev); } } @@ -4824,8 +5194,8 @@ ble_ll_adv_sec_done(struct ble_ll_adv_sm *advsm) struct ble_ll_adv_aux *aux; struct ble_ll_adv_aux *aux_next; - assert(advsm->adv_enabled); - assert(advsm->aux_active); + BLE_LL_ASSERT(advsm->adv_enabled); + BLE_LL_ASSERT(advsm->aux_active); aux = AUX_CURRENT(advsm); aux_next = AUX_NEXT(advsm); @@ -4834,7 +5204,7 @@ ble_ll_adv_sec_done(struct ble_ll_adv_sm *advsm) ble_ll_rfmgmt_release(); if (advsm->aux_dropped) { - ble_ll_adv_drop_event(advsm); + ble_ll_adv_drop_event(advsm, 0); return; } @@ -4844,12 +5214,17 @@ ble_ll_adv_sec_done(struct ble_ll_adv_sm *advsm) /* Remove anything else scheduled for secondary channel */ ble_ll_sched_rmv_elem(&aux->sch); - ble_npl_eventq_remove(&g_ble_ll_data.ll_evq, &advsm->adv_sec_txdone_ev); + ble_ll_event_remove(&advsm->adv_sec_txdone_ev); /* Stop advertising due to transmitting connection response */ if (advsm->flags & BLE_LL_ADV_SM_FLAG_CONN_RSP_TXD) { - ble_ll_adv_sm_stop(advsm); - return; + if (!(advsm->flags & BLE_LL_ADV_SM_FLAG_CONN_RSP_TXD_ERR)) { + ble_ll_adv_sm_stop(advsm); + return; + } else { + ble_ll_adv_flags_clear(advsm, BLE_LL_ADV_SM_FLAG_CONN_RSP_TXD | + BLE_LL_ADV_SM_FLAG_CONN_RSP_TXD_ERR); + } } /* If we have next AUX scheduled, try to schedule another one */ @@ -4863,7 +5238,8 @@ ble_ll_adv_sec_done(struct ble_ll_adv_sm *advsm) ble_ll_scan_chk_resume(); /* Check if advertising timed out */ - if (advsm->duration && (advsm->adv_pdu_start_time >= advsm->adv_end_time)) { + if (advsm->duration && + LL_TMR_GEQ(advsm->adv_pdu_start_time, advsm->adv_end_time)) { ble_ll_adv_sm_stop_timeout(advsm); return; } @@ -4890,12 +5266,12 @@ ble_ll_adv_make_done(struct ble_ll_adv_sm *advsm, struct ble_mbuf_hdr *hdr) { #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) if (BLE_MBUF_HDR_EXT_ADV_SEC(hdr)) { - assert(!(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY)); - assert(ble_ll_adv_active_chanset_is_sec(advsm)); + BLE_LL_ASSERT(!(advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY)); + BLE_LL_ASSERT(ble_ll_adv_active_chanset_is_sec(advsm)); ble_ll_adv_active_chanset_clear(advsm); ble_ll_adv_sec_done(advsm); } else { - assert(ble_ll_adv_active_chanset_is_pri(advsm)); + BLE_LL_ASSERT(ble_ll_adv_active_chanset_is_pri(advsm)); ble_ll_adv_active_chanset_clear(advsm); ble_ll_adv_done(advsm); } @@ -4937,11 +5313,11 @@ ble_ll_adv_can_chg_whitelist(void) * * @return uint8_t* Pointer to event buffer */ +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) void ble_ll_adv_send_conn_comp_ev(struct ble_ll_conn_sm *connsm, struct ble_mbuf_hdr *rxhdr) { - uint8_t *evbuf; struct ble_ll_adv_sm *advsm; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) @@ -4950,12 +5326,11 @@ ble_ll_adv_send_conn_comp_ev(struct ble_ll_conn_sm *connsm, advsm = &g_ble_ll_adv_sm[0]; #endif - evbuf = advsm->conn_comp_ev; - assert(evbuf != NULL); + BLE_LL_ASSERT(advsm->conn_comp_ev != NULL); + ble_ll_conn_comp_event_send(connsm, BLE_ERR_SUCCESS, advsm->conn_comp_ev, + advsm); advsm->conn_comp_ev = NULL; - ble_ll_conn_comp_event_send(connsm, BLE_ERR_SUCCESS, evbuf, advsm); - #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CSA2) ble_ll_hci_ev_le_csa(connsm); #endif @@ -4967,6 +5342,7 @@ ble_ll_adv_send_conn_comp_ev(struct ble_ll_conn_sm *connsm, } #endif } +#endif /** * Returns the local resolvable private address currently being using by @@ -5073,8 +5449,6 @@ ble_ll_adv_sm_init(struct ble_ll_adv_sm *advsm) { memset(advsm, 0, sizeof(struct ble_ll_adv_sm)); - advsm->adv_itvl_min = BLE_HCI_ADV_ITVL_DEF; - advsm->adv_itvl_max = BLE_HCI_ADV_ITVL_DEF; advsm->adv_chanmask = BLE_HCI_ADV_CHANMASK_DEF; /* Initialize advertising tx done event */ @@ -5114,6 +5488,72 @@ ble_ll_adv_sm_init(struct ble_ll_adv_sm *advsm) advsm->props |= BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY; } +#if MYNEWT_VAL(BLE_LL_ISO_BROADCASTER) +struct ble_ll_adv_sm * +ble_ll_adv_sync_get(uint8_t handle) +{ + struct ble_ll_adv_sm *advsm; + + advsm = ble_ll_adv_sm_find_configured(handle); + if (!advsm) { + return NULL; + } + + if (!(advsm->flags & BLE_LL_ADV_SM_FLAG_PERIODIC_CONFIGURED)) { + return NULL; + } + + return advsm; +} + +int +ble_ll_adv_padv_event_start_get(struct ble_ll_adv_sm *advsm, + uint32_t *event_start, + uint8_t *event_start_rem_us) +{ + if (!advsm || !advsm->periodic_adv_active) { + return -EINVAL; + } + + *event_start = advsm->padv_event_start; + if (event_start_rem_us) { + *event_start_rem_us = advsm->padv_event_start_rem_us; + } + + return 0; +} + +int +ble_ll_adv_sync_big_add(struct ble_ll_adv_sm *advsm, + struct ble_ll_iso_big *big) +{ + if (!(advsm->flags & BLE_LL_ADV_SM_FLAG_PERIODIC_CONFIGURED)) { + return -EINVAL; + } + + if (advsm->big && (advsm->big != big)) { + return -EBUSY; + } + + advsm->big = big; + + return 0; +} + +int +ble_ll_adv_sync_big_remove(struct ble_ll_adv_sm *advsm, + struct ble_ll_iso_big *big) +{ + if (advsm->big != big) { + return -EINVAL; + } + + advsm->big = NULL; + + return 0; +} +#endif /* BLE_LL_ISO_BROADCASTER */ + /** * Initialize the advertising functionality of a BLE device. This should * be called once on initialization @@ -5128,3 +5568,5 @@ ble_ll_adv_init(void) ble_ll_adv_sm_init(&g_ble_ll_adv_sm[i]); } } + +#endif diff --git a/nimble/controller/src/ble_ll_conn.c b/nimble/controller/src/ble_ll_conn.c index af610b50ba..a702f35323 100644 --- a/nimble/controller/src/ble_ll_conn.c +++ b/nimble/controller/src/ble_ll_conn.c @@ -21,15 +21,15 @@ #include #include #include +#include #include "syscfg/syscfg.h" #include "os/os.h" -#include "os/os_cputime.h" #include "nimble/ble.h" -#include "nimble/nimble_opt.h" #include "nimble/hci_common.h" -#include "nimble/ble_hci_trans.h" -#include "ble/xcvr.h" +#include "nimble/transport.h" #include "controller/ble_ll.h" +#include "controller/ble_ll_pdu.h" +#include "controller/ble_ll_conn.h" #include "controller/ble_ll_hci.h" #include "controller/ble_ll_scan.h" #include "controller/ble_ll_whitelist.h" @@ -39,15 +39,24 @@ #include "controller/ble_ll_adv.h" #include "controller/ble_ll_trace.h" #include "controller/ble_ll_rfmgmt.h" +#include "controller/ble_ll_tmr.h" #include "controller/ble_phy.h" -#include "controller/ble_hw.h" #include "controller/ble_ll_utils.h" #include "ble_ll_conn_priv.h" +#include "ble_ll_ctrl_priv.h" +#include "ble_ll_priv.h" +#if MYNEWT_PKG_apache_mynewt_nimble__nimble_transport_common_hci_ipc +#include +#endif #if (BLETEST_THROUGHPUT_TEST == 1) extern void bletest_completed_pkt(uint16_t handle); #endif +#if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) +struct ble_ll_conn_sm *g_ble_ll_conn_css_ref; +#endif + /* XXX TODO * 1) I think if we are initiating and we already have a connection with * a device that we will still try and connect to it. Fix this. @@ -64,8 +73,8 @@ extern void bletest_completed_pkt(uint16_t handle); * 2) Make sure we check incoming data packets for size and all that. You * know, supported octets and all that. For both rx and tx. * - * 3) Make sure we are setting the schedule end time properly for both slave - * and master. We should just set this to the end of the connection event. + * 3) Make sure we are setting the schedule end time properly for both peripheral + * and central. We should just set this to the end of the connection event. * We might want to guarantee a IFS time as well since the next event needs * to be scheduled prior to the start of the event to account for the time it * takes to get a frame ready (which is pretty much the IFS time). @@ -85,15 +94,15 @@ extern void bletest_completed_pkt(uint16_t handle); * * 8) Right now I use a fixed definition for required slots. CHange this. * - * 10) See what connection state machine elements are purely master and - * purely slave. We can make a union of them. + * 10) See what connection state machine elements are purely central and + * purely peripheral. We can make a union of them. * * 11) Not sure I am dealing with the connection terminate timeout perfectly. * I may extend a connection event too long although if it is always in terms * of connection events I am probably fine. Checking at end that the next * connection event will occur past terminate timeould would be fine. * - * 12) When a slave receives a data packet in a connection it has to send a + * 12) When a peripheral receives a data packet in a connection it has to send a * response. Well, it should. If this packet will overrun the next scheduled * event, what should we do? Transmit anyway? Not transmit? For now, we just * transmit. @@ -119,6 +128,11 @@ extern void bletest_completed_pkt(uint16_t handle); * 1) The current connection event has not ended but a schedule item starts */ +/* Global LL connection parameters */ +struct ble_ll_conn_global_params g_ble_ll_conn_params; + +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + /* This is a dummy structure we use for the empty PDU */ struct ble_ll_empty_pdu { @@ -132,19 +146,19 @@ struct ble_ll_empty_pdu #error "Maximum # of connections is 254" #endif +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) /* Global connection complete event. Used when initiating */ uint8_t *g_ble_ll_conn_comp_ev; - -/* Global LL connection parameters */ -struct ble_ll_conn_global_params g_ble_ll_conn_params; +#endif #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER) /* Global default sync transfer params */ struct ble_ll_conn_sync_transfer_params g_ble_ll_conn_sync_transfer_params; #endif -/* Pointer to connection state machine we are trying to create */ -struct ble_ll_conn_sm *g_ble_ll_conn_create_sm; +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) +struct ble_ll_conn_create_sm g_ble_ll_conn_create_sm; +#endif /* Pointer to current connection */ struct ble_ll_conn_sm *g_ble_ll_conn_cur_sm; @@ -158,6 +172,11 @@ struct ble_ll_conn_active_list g_ble_ll_conn_active_list; /* List of free connections */ struct ble_ll_conn_free_list g_ble_ll_conn_free_list; +#if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) +static uint16_t g_ble_ll_conn_css_next_slot = BLE_LL_CONN_CSS_NO_SLOT; +struct ble_ll_conn_css_list g_ble_ll_conn_css_list; +#endif + STATS_SECT_START(ble_ll_conn_stats) STATS_SECT_ENTRY(cant_set_sched) STATS_SECT_ENTRY(conn_ev_late) @@ -167,8 +186,8 @@ STATS_SECT_START(ble_ll_conn_stats) STATS_SECT_ENTRY(no_free_conn_sm) STATS_SECT_ENTRY(rx_data_pdu_no_conn) STATS_SECT_ENTRY(rx_data_pdu_bad_aa) - STATS_SECT_ENTRY(slave_rxd_bad_conn_req_params) - STATS_SECT_ENTRY(slave_ce_failures) + STATS_SECT_ENTRY(periph_rxd_bad_conn_req_params) + STATS_SECT_ENTRY(periph_ce_failures) STATS_SECT_ENTRY(data_pdu_rx_dup) STATS_SECT_ENTRY(data_pdu_txg) STATS_SECT_ENTRY(data_pdu_txf) @@ -200,8 +219,8 @@ STATS_NAME_START(ble_ll_conn_stats) STATS_NAME(ble_ll_conn_stats, no_free_conn_sm) STATS_NAME(ble_ll_conn_stats, rx_data_pdu_no_conn) STATS_NAME(ble_ll_conn_stats, rx_data_pdu_bad_aa) - STATS_NAME(ble_ll_conn_stats, slave_rxd_bad_conn_req_params) - STATS_NAME(ble_ll_conn_stats, slave_ce_failures) + STATS_NAME(ble_ll_conn_stats, periph_rxd_bad_conn_req_params) + STATS_NAME(ble_ll_conn_stats, periph_ce_failures) STATS_NAME(ble_ll_conn_stats, data_pdu_rx_dup) STATS_NAME(ble_ll_conn_stats, data_pdu_txg) STATS_NAME(ble_ll_conn_stats, data_pdu_txf) @@ -298,7 +317,7 @@ ble_ll_conn_cth_flow_error_fn(struct ble_npl_event *ev) struct ble_hci_ev_command_complete *hci_ev_cp; uint16_t opcode; - hci_ev = (void *)ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); + hci_ev = ble_transport_alloc_evt(0); if (!hci_ev) { /* Not much we can do anyway... */ return; @@ -365,7 +384,7 @@ ble_ll_conn_cth_flow_process_cmd(const uint8_t *cmdbuf) cp = (const void *)cmd->data; if (cmd->length != sizeof(cp->handles) + cp->handles * sizeof(cp->h[0])) { - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &g_ble_ll_conn_cth_flow_error_ev); + ble_ll_event_add(&g_ble_ll_conn_cth_flow_error_ev); return; } @@ -377,7 +396,7 @@ ble_ll_conn_cth_flow_process_cmd(const uint8_t *cmdbuf) * case we can simply ignore command for that connection since credits * are returned by LL already. */ - connsm = ble_ll_conn_find_active_conn(cp->h[i].handle); + connsm = ble_ll_conn_find_by_handle(cp->h[i].handle); if (connsm) { ble_ll_conn_cth_flow_free_credit(connsm, cp->h[i].count); } @@ -385,61 +404,199 @@ ble_ll_conn_cth_flow_process_cmd(const uint8_t *cmdbuf) } #endif -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) -/** - * Checks to see if we should start a PHY update procedure - * - * If current phy is not one of the preferred we need to start control - * procedure. - * - * XXX: we could also decide to change the PHY if RSSI is really good - * and we are currently at 1Mbps or lower data rate and we could use - * a higher data rate. - * - * @param connsm - * @return 0: success; -1: no phy update procedure started - */ +#if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) +static void +ble_ll_conn_css_update_list(struct ble_ll_conn_sm *connsm) +{ + struct ble_ll_conn_sm *e; + struct ble_ll_conn_sm *e_last; + struct ble_ll_conn_sm *e_insert_after = NULL; + bool found_to_insert = false; + + if (SLIST_FIRST(&g_ble_ll_conn_css_list) == connsm) { + SLIST_REMOVE_HEAD(&g_ble_ll_conn_css_list, css_sle); + } else { + e_last = NULL; + SLIST_FOREACH(e, &g_ble_ll_conn_css_list, css_sle) { + if (e == connsm) { + SLIST_NEXT(e_last, css_sle) = SLIST_NEXT(e, css_sle); + break; + } + e_last = e; + } + } + + if (SLIST_EMPTY(&g_ble_ll_conn_css_list)) { + SLIST_INSERT_HEAD(&g_ble_ll_conn_css_list, connsm, css_sle); + return; + } + + e_last = NULL; + SLIST_FOREACH(e, &g_ble_ll_conn_css_list, css_sle) { + if (e->css_slot_idx > connsm->css_slot_idx) { + found_to_insert = true; + e_insert_after = e_last; + break; + } + + e_last = e; + } + + if (found_to_insert) { + if (e_insert_after) { + SLIST_INSERT_AFTER(e_last, connsm, css_sle); + } else { + SLIST_INSERT_HEAD(&g_ble_ll_conn_css_list, connsm, css_sle); + } + } else { + SLIST_INSERT_AFTER(e_last, connsm, css_sle); + } +} + +void +ble_ll_conn_css_set_next_slot(uint16_t slot_idx) +{ + g_ble_ll_conn_css_next_slot = slot_idx; +} + +uint16_t +ble_ll_conn_css_get_next_slot(void) +{ + struct ble_ll_conn_sm *connsm; + uint16_t slot_idx = 0; + + if (g_ble_ll_conn_css_next_slot != BLE_LL_CONN_CSS_NO_SLOT) { + return g_ble_ll_conn_css_next_slot; + } + + /* CSS connections are sorted in active conn list so just need to find 1st + * free value. + */ + SLIST_FOREACH(connsm, &g_ble_ll_conn_css_list, css_sle) { + if ((connsm->css_slot_idx != slot_idx) && + (connsm->css_slot_idx_pending != slot_idx)) { + break; + } + slot_idx++; + } + + if (slot_idx >= ble_ll_sched_css_get_period_slots()) { + slot_idx = BLE_LL_CONN_CSS_NO_SLOT; + } + + return slot_idx; +} + +int +ble_ll_conn_css_is_slot_busy(uint16_t slot_idx) +{ + struct ble_ll_conn_sm *connsm; + + if (g_ble_ll_conn_css_next_slot == slot_idx) { + return 1; + } + + SLIST_FOREACH(connsm, &g_ble_ll_conn_css_list, css_sle) { + if ((connsm->css_slot_idx == slot_idx) || + (connsm->css_slot_idx_pending == slot_idx)) { + return 1; + } + } + + return 0; +} + int -ble_ll_conn_chk_phy_upd_start(struct ble_ll_conn_sm *csm) +ble_ll_conn_css_move(struct ble_ll_conn_sm *connsm, uint16_t slot_idx) { + int16_t slot_diff; + uint32_t offset; int rc; - /* If no host preferences or */ - if (((csm->phy_data.host_pref_tx_phys_mask == 0) && - (csm->phy_data.host_pref_rx_phys_mask == 0)) || - ((csm->phy_data.host_pref_tx_phys_mask & CONN_CUR_TX_PHY_MASK(csm)) && - (csm->phy_data.host_pref_rx_phys_mask & CONN_CUR_RX_PHY_MASK(csm)))) { - rc = -1; - } else { - csm->phy_data.req_pref_tx_phys_mask = csm->phy_data.host_pref_tx_phys_mask; - csm->phy_data.req_pref_rx_phys_mask = csm->phy_data.host_pref_rx_phys_mask; - ble_ll_ctrl_proc_start(csm, BLE_LL_CTRL_PROC_PHY_UPDATE); - rc = 0; + /* Assume connsm and slot_idx are valid */ + BLE_LL_ASSERT(connsm->conn_state != BLE_LL_CONN_STATE_IDLE); + BLE_LL_ASSERT(connsm->conn_role == BLE_LL_CONN_ROLE_CENTRAL); + BLE_LL_ASSERT((slot_idx < ble_ll_sched_css_get_period_slots()) || + (slot_idx != BLE_LL_CONN_CSS_NO_SLOT)); + + slot_diff = slot_idx - connsm->css_slot_idx; + if (slot_diff < 0) { + slot_diff += ble_ll_sched_css_get_period_slots(); + } + + offset = slot_diff * ble_ll_sched_css_get_slot_us() / BLE_LL_CONN_ITVL_USECS; + + if (offset >= 0xffff) { + return -1; + } + + rc = ble_ll_conn_move_anchor(connsm, offset); + if (!rc) { + connsm->css_slot_idx_pending = slot_idx; } return rc; } #endif -static void -ble_ll_conn_calc_itvl_ticks(struct ble_ll_conn_sm *connsm) +struct ble_ll_conn_sm * +ble_ll_conn_find_by_peer_addr(const uint8_t *addr, uint8_t addr_type) { - uint32_t ticks; - uint32_t usecs; + struct ble_ll_conn_sm *connsm; - /* - * Precalculate the number of ticks and remaining microseconds for - * the connection interval - */ - usecs = connsm->conn_itvl * BLE_LL_CONN_ITVL_USECS; - ticks = os_cputime_usecs_to_ticks(usecs); - connsm->conn_itvl_usecs = (uint8_t)(usecs - - os_cputime_ticks_to_usecs(ticks)); - if (connsm->conn_itvl_usecs == 31) { - connsm->conn_itvl_usecs = 0; - ++ticks; - } - connsm->conn_itvl_ticks = ticks; + SLIST_FOREACH(connsm, &g_ble_ll_conn_active_list, act_sle) { + if (!memcmp(&connsm->peer_addr, addr, BLE_DEV_ADDR_LEN) && + !((connsm->peer_addr_type ^ addr_type) & 1)) { + return connsm; + } + } + + return NULL; +} + +#if MYNEWT_VAL(BLE_LL_PHY) +static inline int +ble_ll_conn_phy_should_update(uint8_t pref_mask, uint8_t curr_mask) +{ +#if MYNEWT_VAL(BLE_LL_CONN_PHY_PREFER_2M) + /* Should change to 2M if preferred, but not active */ + if ((pref_mask & BLE_PHY_MASK_2M) && (curr_mask != BLE_PHY_MASK_2M)) { + return 1; + } +#endif + + /* Should change to active phy is not preferred */ + if ((curr_mask & pref_mask) == 0) { + return 1; + } + + return 0; +} + +int +ble_ll_conn_phy_update_if_needed(struct ble_ll_conn_sm *connsm) +{ + if (!ble_ll_conn_phy_should_update(connsm->phy_data.pref_mask_tx, + CONN_CUR_TX_PHY_MASK(connsm)) && + !ble_ll_conn_phy_should_update(connsm->phy_data.pref_mask_rx, + CONN_CUR_RX_PHY_MASK(connsm))) { + return -1; + } + + connsm->phy_data.pref_mask_tx_req = connsm->phy_data.pref_mask_tx; + connsm->phy_data.pref_mask_rx_req = connsm->phy_data.pref_mask_rx; + + ble_ll_ctrl_proc_start(connsm, BLE_LL_CTRL_PROC_PHY_UPDATE); + + return 0; +} +#endif + +void +ble_ll_conn_itvl_to_ticks(uint32_t itvl, uint32_t *itvl_ticks, + uint8_t *itvl_usecs) +{ + *itvl_ticks = ble_ll_tmr_u2t_r(itvl * BLE_LL_CONN_ITVL_USECS, itvl_usecs); } /** @@ -448,6 +605,7 @@ ble_ll_conn_calc_itvl_ticks(struct ble_ll_conn_sm *connsm) * * @return uint8_t* */ +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) static uint8_t * ble_ll_init_get_conn_comp_ev(void) { @@ -459,6 +617,7 @@ ble_ll_init_get_conn_comp_ev(void) return evbuf; } +#endif #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) /** @@ -492,7 +651,7 @@ ble_ll_conn_is_lru(struct ble_ll_conn_sm *s1, struct ble_ll_conn_sm *s2) int rc; /* Set time that we last serviced the schedule */ - if (CPUTIME_LT(s1->last_scheduled, s2->last_scheduled)) { + if (LL_TMR_LT(s1->last_scheduled, s2->last_scheduled)) { rc = 1; } else { rc = 0; @@ -515,7 +674,7 @@ ble_ll_conn_get_ce_end_time(void) if (g_ble_ll_conn_cur_sm) { ce_end_time = g_ble_ll_conn_cur_sm->ce_end_time; } else { - ce_end_time = os_cputime_get32(); + ce_end_time = ble_ll_tmr_get(); } return ce_end_time; } @@ -555,7 +714,7 @@ ble_ll_conn_current_sm_over(struct ble_ll_conn_sm *connsm) * need to post to the LL the connection event end event */ if (connsm) { - ble_ll_event_send(&connsm->conn_ev_end); + ble_ll_event_add(&connsm->conn_ev_end); } } @@ -567,7 +726,7 @@ ble_ll_conn_current_sm_over(struct ble_ll_conn_sm *connsm) * @return struct ble_ll_conn_sm* */ struct ble_ll_conn_sm * -ble_ll_conn_find_active_conn(uint16_t handle) +ble_ll_conn_find_by_handle(uint16_t handle) { struct ble_ll_conn_sm *connsm; @@ -617,14 +776,14 @@ ble_ll_conn_calc_dci_csa1(struct ble_ll_conn_sm *conn) /* Is this a valid channel? */ bitpos = 1 << (curchan & 0x07); - if (conn->chanmap[curchan >> 3] & bitpos) { + if (conn->chan_map[curchan >> 3] & bitpos) { return curchan; } /* Calculate remap index */ - remap_index = curchan % conn->num_used_chans; + remap_index = curchan % conn->chan_map_used; - return ble_ll_utils_remapped_channel(remap_index, conn->chanmap); + return ble_ll_utils_chan_map_remap(conn->chan_map, remap_index); } /** @@ -642,9 +801,9 @@ ble_ll_conn_calc_dci(struct ble_ll_conn_sm *conn, uint16_t latency) uint8_t index; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CSA2) - if (CONN_F_CSA2_SUPP(conn)) { - return ble_ll_utils_calc_dci_csa2(conn->event_cntr, conn->channel_id, - conn->num_used_chans, conn->chanmap); + if (conn->flags.csa2) { + return ble_ll_utils_dci_csa2(conn->event_cntr, conn->channel_id, + conn->chan_map_used, conn->chan_map); } #endif @@ -674,66 +833,8 @@ ble_ll_conn_wfr_timer_exp(void) STATS_INC(ble_ll_conn_stats, wfr_expirations); } -void -ble_ll_conn_reset_pending_aux_conn_rsp(void) -{ -#if !MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - return; -#endif - struct ble_ll_conn_sm *connsm; - - connsm = g_ble_ll_conn_create_sm; - if (!connsm) { - return; - } - - if (CONN_F_AUX_CONN_REQ(connsm)) { - STATS_INC(ble_ll_stats, aux_conn_rsp_err); - CONN_F_CONN_REQ_TXD(connsm) = 0; - CONN_F_AUX_CONN_REQ(connsm) = 0; - ble_ll_sched_rmv_elem(&connsm->conn_sch); - return; - } - - return; -} - -bool -ble_ll_conn_init_pending_aux_conn_rsp(void) -{ -#if !MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - return false; -#endif - struct ble_ll_conn_sm *connsm; - - connsm = g_ble_ll_conn_create_sm; - if (!connsm) { - return false; - } - - return CONN_F_AUX_CONN_REQ(connsm); -} - -void -ble_ll_conn_init_wfr_timer_exp(void) -{ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - struct ble_ll_conn_sm *connsm; - - connsm = g_ble_ll_conn_create_sm; - if (!connsm) { - return; - } - - ble_ll_conn_reset_pending_aux_conn_rsp(); - connsm->inita_identity_used = 0; - - ble_ll_scan_interrupted(connsm->scansm); - -#endif -} /** - * Callback for slave when it transmits a data pdu and the connection event + * Callback for peripheral when it transmits a data pdu and the connection event * ends after the transmission. * * Context: Interrupt @@ -757,22 +858,24 @@ ble_ll_conn_start_rx_encrypt(void *arg) struct ble_ll_conn_sm *connsm; connsm = (struct ble_ll_conn_sm *)arg; - CONN_F_ENCRYPTED(connsm) = 1; - ble_phy_encrypt_enable(connsm->enc_data.rx_pkt_cntr, - connsm->enc_data.iv, - connsm->enc_data.enc_block.cipher_text, - !CONN_IS_MASTER(connsm)); + connsm->flags.encrypted = 1; + ble_phy_encrypt_enable(connsm->enc_data.enc_block.cipher_text); + ble_phy_encrypt_iv_set(connsm->enc_data.iv); + ble_phy_encrypt_counter_set(connsm->enc_data.rx_pkt_cntr, + !CONN_IS_CENTRAL(connsm)); } +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) static void ble_ll_conn_start_rx_unencrypt(void *arg) { struct ble_ll_conn_sm *connsm; connsm = (struct ble_ll_conn_sm *)arg; - CONN_F_ENCRYPTED(connsm) = 0; + connsm->flags.encrypted = 0; ble_phy_encrypt_disable(); } +#endif static void ble_ll_conn_txend_encrypt(void *arg) @@ -780,19 +883,21 @@ ble_ll_conn_txend_encrypt(void *arg) struct ble_ll_conn_sm *connsm; connsm = (struct ble_ll_conn_sm *)arg; - CONN_F_ENCRYPTED(connsm) = 1; + connsm->flags.encrypted = 1; ble_ll_conn_current_sm_over(connsm); } +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) static void ble_ll_conn_rxend_unencrypt(void *arg) { struct ble_ll_conn_sm *connsm; connsm = (struct ble_ll_conn_sm *)arg; - CONN_F_ENCRYPTED(connsm) = 0; + connsm->flags.encrypted = 0; ble_ll_conn_current_sm_over(connsm); } +#endif static void ble_ll_conn_continue_rx_encrypt(void *arg) @@ -800,8 +905,8 @@ ble_ll_conn_continue_rx_encrypt(void *arg) struct ble_ll_conn_sm *connsm; connsm = (struct ble_ll_conn_sm *)arg; - ble_phy_encrypt_set_pkt_cntr(connsm->enc_data.rx_pkt_cntr, - !CONN_IS_MASTER(connsm)); + ble_phy_encrypt_counter_set(connsm->enc_data.rx_pkt_cntr, + !CONN_IS_CENTRAL(connsm)); } #endif @@ -824,27 +929,30 @@ ble_ll_conn_continue_rx_encrypt(void *arg) static uint32_t ble_ll_conn_get_next_sched_time(struct ble_ll_conn_sm *connsm) { -#if MYNEWT_VAL(BLE_LL_STRICT_CONN_SCHEDULING) - uint32_t ce_end; - ce_end = connsm->ce_end_time; -#else uint32_t ce_end; uint32_t next_sched_time; + uint8_t rem_us; /* Calculate time at which next connection event will start */ /* NOTE: We dont care if this time is tick short. */ ce_end = connsm->anchor_point + connsm->conn_itvl_ticks - g_ble_ll_sched_offset_ticks; - if ((connsm->anchor_point_usecs + connsm->conn_itvl_usecs) >= 31) { - ++ce_end; + rem_us = connsm->anchor_point_usecs; + ble_ll_tmr_add_u(&ce_end, &rem_us, connsm->conn_itvl_usecs); + + ce_end -= ble_ll_tmr_u2t_up(MYNEWT_VAL(BLE_LL_CONN_EVENT_END_MARGIN)); + + if (connsm->max_ce_len_ticks) { + if (LL_TMR_LT(connsm->anchor_point + connsm->max_ce_len_ticks, ce_end)) { + ce_end = connsm->anchor_point + connsm->max_ce_len_ticks; + } } if (ble_ll_sched_next_time(&next_sched_time)) { - if (CPUTIME_LT(next_sched_time, ce_end)) { + if (LL_TMR_LT(next_sched_time, ce_end)) { ce_end = next_sched_time; } } -#endif return ce_end; } @@ -861,16 +969,26 @@ ble_ll_conn_chk_csm_flags(struct ble_ll_conn_sm *connsm) uint8_t update_status; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - if (connsm->csmflags.cfbit.send_ltk_req) { + if (connsm->flags.encrypt_ltk_req) { /* * Send Long term key request event to host. If masked, we need to - * send a REJECT_IND. + * send a REJECT_IND or TERMINATE_IND. */ if (ble_ll_hci_ev_ltk_req(connsm)) { - ble_ll_ctrl_reject_ind_send(connsm, BLE_LL_CTRL_ENC_REQ, - BLE_ERR_PINKEY_MISSING); + /* Core 6.1 | Vol 6, Part B | 5.1.3.1 + * If this procedure is being performed after a Pause Encryption procedure, and the + * Peripheral's Host does not provide a Long Term Key, the Peripheral shall perform the + * ACL Termination procedure with the error code PIN or Key Missing (0x06). + */ + if (connsm->flags.encrypt_paused) { + connsm->disconnect_reason = BLE_ERR_PINKEY_MISSING; + ble_ll_ctrl_terminate_start(connsm); + } else { + ble_ll_ctrl_reject_ind_send(connsm, BLE_LL_CTRL_ENC_REQ, + BLE_ERR_PINKEY_MISSING); + } } - connsm->csmflags.cfbit.send_ltk_req = 0; + connsm->flags.encrypt_ltk_req = 0; } #endif @@ -880,7 +998,7 @@ ble_ll_conn_chk_csm_flags(struct ble_ll_conn_sm *connsm) * has passed the instant. * 2) We successfully sent the reject reason. */ - if (connsm->csmflags.cfbit.host_expects_upd_event) { + if (connsm->flags.conn_update_host_w4event) { update_status = BLE_ERR_SUCCESS; if (IS_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_CONN_UPDATE)) { ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_CONN_UPDATE); @@ -891,18 +1009,30 @@ ble_ll_conn_chk_csm_flags(struct ble_ll_conn_sm *connsm) } } ble_ll_hci_ev_conn_update(connsm, update_status); - connsm->csmflags.cfbit.host_expects_upd_event = 0; + connsm->flags.conn_update_host_w4event = 0; } /* Check if we need to send PHY update complete event */ -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) - if (CONN_F_PHY_UPDATE_EVENT(connsm)) { +#if MYNEWT_VAL(BLE_LL_PHY) + if (connsm->flags.phy_update_host_w4event) { if (!ble_ll_hci_ev_phy_update(connsm, BLE_ERR_SUCCESS)) { /* Sent event. Clear flag */ - CONN_F_PHY_UPDATE_EVENT(connsm) = 0; + connsm->flags.phy_update_host_w4event = 0; } } #endif + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE) +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + if (connsm->flags.subrate_ind_txd) { + ble_ll_conn_subrate_set(connsm, &connsm->subrate_trans); + connsm->subrate_trans.subrate_factor = 0; + ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_SUBRATE_UPDATE); + connsm->flags.subrate_ind_txd = 0; + connsm->flags.subrate_host_req = 0; + } +#endif /* BLE_LL_CTRL_SUBRATE_IND */ +#endif /* BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE */ } /** @@ -917,35 +1047,41 @@ ble_ll_conn_chk_csm_flags(struct ble_ll_conn_sm *connsm) static uint16_t ble_ll_conn_adjust_pyld_len(struct ble_ll_conn_sm *connsm, uint16_t pyld_len) { - uint16_t phy_max_tx_octets; + uint16_t max_pyld_len; uint16_t ret; -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) +#if MYNEWT_VAL(BLE_LL_PHY) uint8_t phy_mode; if (connsm->phy_tx_transition) { phy_mode = ble_ll_phy_to_phy_mode(connsm->phy_tx_transition, - connsm->phy_data.phy_options); + connsm->phy_data.pref_opts); } else { phy_mode = connsm->phy_data.tx_phy_mode; } - phy_max_tx_octets = ble_ll_pdu_max_tx_octets_get(connsm->eff_max_tx_time, - phy_mode); + max_pyld_len = ble_ll_pdu_max_tx_octets_get(connsm->eff_max_tx_time, + phy_mode); #else - phy_max_tx_octets = ble_ll_pdu_max_tx_octets_get(connsm->eff_max_tx_time, - BLE_PHY_MODE_1M); + max_pyld_len = ble_ll_pdu_max_tx_octets_get(connsm->eff_max_tx_time, + BLE_PHY_MODE_1M); #endif ret = pyld_len; +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) + if (connsm->flags.encrypted) { + max_pyld_len -= BLE_LL_DATA_MIC_LEN; + } +#endif + if (ret > connsm->eff_max_tx_octets) { ret = connsm->eff_max_tx_octets; } - if (ret > phy_max_tx_octets) { - ret = phy_max_tx_octets; + if (ret > max_pyld_len) { + ret = max_pyld_len; } return ret; @@ -983,11 +1119,11 @@ ble_ll_conn_tx_pdu(struct ble_ll_conn_sm *connsm) md = 0; hdr_byte = BLE_LL_LLID_DATA_FRAG; - if (connsm->csmflags.cfbit.terminate_ind_rxd) { + if (connsm->flags.terminate_ind_rxd) { /* We just received terminate indication. * Just send empty packet as an ACK */ - CONN_F_EMPTY_PDU_TXD(connsm) = 1; + connsm->flags.empty_pdu_txd = 1; goto conn_tx_pdu; } @@ -996,8 +1132,8 @@ ble_ll_conn_tx_pdu(struct ble_ll_conn_sm *connsm) * the transmit queue. */ pkthdr = STAILQ_FIRST(&connsm->conn_txq); - if (!connsm->cur_tx_pdu && !CONN_F_EMPTY_PDU_TXD(connsm) && !pkthdr) { - CONN_F_EMPTY_PDU_TXD(connsm) = 1; + if (!connsm->cur_tx_pdu && !connsm->flags.empty_pdu_txd && !pkthdr) { + connsm->flags.empty_pdu_txd = 1; goto conn_tx_pdu; } @@ -1006,7 +1142,7 @@ ble_ll_conn_tx_pdu(struct ble_ll_conn_sm *connsm) * the connection transmit queue */ cur_offset = 0; - if (!connsm->cur_tx_pdu && !CONN_F_EMPTY_PDU_TXD(connsm)) { + if (!connsm->cur_tx_pdu && !connsm->flags.empty_pdu_txd) { /* Convert packet header to mbuf */ m = OS_MBUF_PKTHDR_TO_MBUF(pkthdr); nextpkthdr = STAILQ_NEXT(pkthdr, omp_next); @@ -1020,22 +1156,22 @@ ble_ll_conn_tx_pdu(struct ble_ll_conn_sm *connsm) * LL_ENC_RSP is sent. */ if (((connsm->enc_data.enc_state > CONN_ENC_S_ENCRYPTED) && - CONN_IS_MASTER(connsm)) || + CONN_IS_CENTRAL(connsm)) || ((connsm->enc_data.enc_state > CONN_ENC_S_ENC_RSP_TO_BE_SENT) && - CONN_IS_SLAVE(connsm))) { + CONN_IS_PERIPHERAL(connsm))) { if (!ble_ll_ctrl_enc_allowed_pdu_tx(pkthdr)) { - CONN_F_EMPTY_PDU_TXD(connsm) = 1; + connsm->flags.empty_pdu_txd = 1; goto conn_tx_pdu; } /* * We will allow a next packet if it itself is allowed or we are - * a slave and we are sending the START_ENC_RSP. The master has - * to wait to receive the START_ENC_RSP from the slave before + * a peripheral and we are sending the START_ENC_RSP. The central has + * to wait to receive the START_ENC_RSP from the peripheral before * packets can be let go. */ if (nextpkthdr && !ble_ll_ctrl_enc_allowed_pdu_tx(nextpkthdr) - && ((connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) || + && (CONN_IS_CENTRAL(connsm) || !ble_ll_ctrl_is_start_enc_rsp(m))) { nextpkthdr = NULL; } @@ -1058,6 +1194,7 @@ ble_ll_conn_tx_pdu(struct ble_ll_conn_sm *connsm) pktlen = pkthdr->omp_len; if (llid == BLE_LL_LLID_CTRL) { cur_txlen = pktlen; + ble_ll_ctrl_tx_start(connsm, m); } else { cur_txlen = ble_ll_conn_adjust_pyld_len(connsm, pktlen); } @@ -1082,7 +1219,7 @@ ble_ll_conn_tx_pdu(struct ble_ll_conn_sm *connsm) /* We will allow a next packet if it itself is allowed */ pkthdr = OS_MBUF_PKTHDR(connsm->cur_tx_pdu); if (nextpkthdr && !ble_ll_ctrl_enc_allowed_pdu_tx(nextpkthdr) - && ((connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) || + && (CONN_IS_CENTRAL(connsm) || !ble_ll_ctrl_is_start_enc_rsp(connsm->cur_tx_pdu))) { nextpkthdr = NULL; } @@ -1121,7 +1258,7 @@ ble_ll_conn_tx_pdu(struct ble_ll_conn_sm *connsm) * -> wait IFS, send the next frame. * -> wait IFS, receive a maximum size frame. * - * For slave: + * For peripheral: * -> wait IFS, send current frame. * -> wait IFS, receive maximum size frame. * -> wait IFS, send next frame. @@ -1141,29 +1278,31 @@ ble_ll_conn_tx_pdu(struct ble_ll_conn_sm *connsm) * now. This is not the most accurate especially if we have * received a frame and we are replying to it. */ -#if BLE_LL_BT5_PHY_SUPPORTED +#if MYNEWT_VAL(BLE_LL_PHY) tx_phy_mode = connsm->phy_data.tx_phy_mode; #else tx_phy_mode = BLE_PHY_MODE_1M; #endif - ticks = (BLE_LL_IFS * 3) + connsm->eff_max_rx_time + - ble_ll_pdu_tx_time_get(next_txlen, tx_phy_mode) + - ble_ll_pdu_tx_time_get(cur_txlen, tx_phy_mode); + ticks = (BLE_LL_IFS * 3) + connsm->ota_max_rx_time + + ble_ll_pdu_us(next_txlen, tx_phy_mode) + + ble_ll_pdu_us(cur_txlen, tx_phy_mode); - if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { - ticks += (BLE_LL_IFS + connsm->eff_max_rx_time); +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + if (connsm->conn_role == BLE_LL_CONN_ROLE_CENTRAL) { + ticks += (BLE_LL_IFS + connsm->ota_max_rx_time); } +#endif - ticks = os_cputime_usecs_to_ticks(ticks); - if (CPUTIME_LT(os_cputime_get32() + ticks, next_event_time)) { + ticks = ble_ll_tmr_u2t(ticks); + if (LL_TMR_LT(ble_ll_tmr_get() + ticks, next_event_time)) { md = 1; } } /* If we send an empty PDU we need to initialize the header */ conn_tx_pdu: - if (CONN_F_EMPTY_PDU_TXD(connsm)) { + if (connsm->flags.empty_pdu_txd) { /* * This looks strange, but we dont use the data pointer in the mbuf * when we have an empty pdu. @@ -1172,7 +1311,7 @@ ble_ll_conn_tx_pdu(struct ble_ll_conn_sm *connsm) m->om_data = (uint8_t *)&empty_pdu; m->om_data += BLE_MBUF_MEMBLOCK_OVERHEAD; ble_hdr = &empty_pdu.ble_hdr; - ble_hdr->txinfo.flags = 0; + ble_hdr->txinfo.num_data_pkt = 0; ble_hdr->txinfo.offset = 0; ble_hdr->txinfo.pyld_len = 0; } @@ -1196,23 +1335,24 @@ ble_ll_conn_tx_pdu(struct ble_ll_conn_sm *connsm) ble_hdr->txinfo.hdr_byte = hdr_byte; /* - * If we are a slave, check to see if this transmission will end the + * If we are a peripheral, check to see if this transmission will end the * connection event. We will end the connection event if we have * received a valid frame with the more data bit set to 0 and we dont * have more data. * - * XXX: for a slave, we dont check to see if we can: - * -> wait IFS, rx frame from master (either big or small). + * XXX: for a peripheral, we dont check to see if we can: + * -> wait IFS, rx frame from central (either big or small). * -> wait IFS, send empty pdu or next pdu. * * We could do this. Now, we just keep going and hope that we dont * overrun next scheduled item. */ - if ((connsm->csmflags.cfbit.terminate_ind_rxd) || - ((connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) && (md == 0) && + if ((connsm->flags.terminate_ind_rxd) || + (CONN_IS_PERIPHERAL(connsm) && (md == 0) && (connsm->cons_rxd_bad_crc == 0) && ((connsm->last_rxd_hdr_byte & BLE_LL_DATA_HDR_MD_MASK) == 0) && - !ble_ll_ctrl_is_terminate_ind(hdr_byte, m->om_data[0]))) { + ((connsm->flags.empty_pdu_txd) || + !ble_ll_ctrl_is_terminate_ind(hdr_byte, m->om_data[0])))) { /* We will end the connection event */ end_transition = BLE_PHY_TRANSITION_NONE; txend_func = ble_ll_conn_wait_txend; @@ -1234,21 +1374,24 @@ ble_ll_conn_tx_pdu(struct ble_ll_conn_sm *connsm) if (is_ctrl && (opcode == BLE_LL_CTRL_START_ENC_RSP)) { /* - * Both master and slave send the START_ENC_RSP encrypted and receive + * Both central and peripheral send the START_ENC_RSP encrypted and receive * encrypted */ - CONN_F_ENCRYPTED(connsm) = 1; + connsm->flags.encrypted = 1; connsm->enc_data.tx_encrypted = 1; - ble_phy_encrypt_enable(connsm->enc_data.tx_pkt_cntr, - connsm->enc_data.iv, - connsm->enc_data.enc_block.cipher_text, - CONN_IS_MASTER(connsm)); + ble_phy_encrypt_enable(connsm->enc_data.enc_block.cipher_text); + ble_phy_encrypt_iv_set(connsm->enc_data.iv); + ble_phy_encrypt_counter_set(connsm->enc_data.tx_pkt_cntr, + CONN_IS_CENTRAL(connsm)); + if (txend_func == NULL) { + txend_func = ble_ll_conn_continue_rx_encrypt; + } } else if (is_ctrl && (opcode == BLE_LL_CTRL_START_ENC_REQ)) { /* - * Only the slave sends this and it gets sent unencrypted but + * Only the peripheral sends this and it gets sent unencrypted but * we receive encrypted */ - CONN_F_ENCRYPTED(connsm) = 0; + connsm->flags.encrypted = 0; connsm->enc_data.enc_state = CONN_ENC_S_START_ENC_RSP_WAIT; connsm->enc_data.tx_encrypted = 0; ble_phy_encrypt_disable(); @@ -1259,33 +1402,43 @@ ble_ll_conn_tx_pdu(struct ble_ll_conn_sm *connsm) } } else if (is_ctrl && (opcode == BLE_LL_CTRL_PAUSE_ENC_RSP)) { /* - * The slave sends the PAUSE_ENC_RSP encrypted. The master sends + * The peripheral sends the PAUSE_ENC_RSP encrypted. The central sends * it unencrypted (note that link was already set unencrypted). */ - if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) { - CONN_F_ENCRYPTED(connsm) = 1; + switch (connsm->conn_role) { +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + case BLE_LL_CONN_ROLE_CENTRAL: + connsm->flags.encrypted = 0; + connsm->enc_data.enc_state = CONN_ENC_S_PAUSED; + connsm->enc_data.tx_encrypted = 0; + ble_phy_encrypt_disable(); + break; +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) + case BLE_LL_CONN_ROLE_PERIPHERAL: + connsm->flags.encrypted = 1; connsm->enc_data.tx_encrypted = 1; - ble_phy_encrypt_enable(connsm->enc_data.tx_pkt_cntr, - connsm->enc_data.iv, - connsm->enc_data.enc_block.cipher_text, - CONN_IS_MASTER(connsm)); + ble_phy_encrypt_enable(connsm->enc_data.enc_block.cipher_text); + ble_phy_encrypt_iv_set(connsm->enc_data.iv); + ble_phy_encrypt_counter_set(connsm->enc_data.tx_pkt_cntr, + CONN_IS_CENTRAL(connsm)); if (txend_func == NULL) { txend_func = ble_ll_conn_start_rx_unencrypt; } else { txend_func = ble_ll_conn_rxend_unencrypt; } - } else { - CONN_F_ENCRYPTED(connsm) = 0; - connsm->enc_data.enc_state = CONN_ENC_S_PAUSED; - connsm->enc_data.tx_encrypted = 0; - ble_phy_encrypt_disable(); + break; +#endif + default: + BLE_LL_ASSERT(0); + break; } } else { /* If encrypted set packet counter */ - if (CONN_F_ENCRYPTED(connsm)) { + if (connsm->flags.encrypted) { connsm->enc_data.tx_encrypted = 1; - ble_phy_encrypt_set_pkt_cntr(connsm->enc_data.tx_pkt_cntr, - CONN_IS_MASTER(connsm)); + ble_phy_encrypt_counter_set(connsm->enc_data.tx_pkt_cntr, + CONN_IS_CENTRAL(connsm)); if (txend_func == NULL) { txend_func = ble_ll_conn_continue_rx_encrypt; } @@ -1303,18 +1456,24 @@ ble_ll_conn_tx_pdu(struct ble_ll_conn_sm *connsm) ble_hdr->txinfo.offset); /* Set last transmitted MD bit */ - CONN_F_LAST_TXD_MD(connsm) = md; + connsm->flags.last_txd_md = md; /* Increment packets transmitted */ - if (CONN_F_EMPTY_PDU_TXD(connsm)) { - if (connsm->csmflags.cfbit.terminate_ind_rxd) { - connsm->csmflags.cfbit.terminate_ind_rxd_acked = 1; + if (connsm->flags.empty_pdu_txd) { + if (connsm->flags.terminate_ind_rxd) { + connsm->flags.terminate_ind_rxd_acked = 1; } STATS_INC(ble_ll_conn_stats, tx_empty_pdus); } else if ((hdr_byte & BLE_LL_DATA_HDR_LLID_MASK) == BLE_LL_LLID_CTRL) { +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE) + connsm->has_nonempty_pdu = 1; +#endif STATS_INC(ble_ll_conn_stats, tx_ctrl_pdus); STATS_INCN(ble_ll_conn_stats, tx_ctrl_bytes, cur_txlen); } else { +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE) + connsm->has_nonempty_pdu = 1; +#endif STATS_INC(ble_ll_conn_stats, tx_l2cap_pdus); STATS_INCN(ble_ll_conn_stats, tx_l2cap_bytes, cur_txlen); } @@ -1334,8 +1493,10 @@ ble_ll_conn_tx_pdu(struct ble_ll_conn_sm *connsm) static int ble_ll_conn_event_start_cb(struct ble_ll_sched_item *sch) { - int rc; + int rc = 0; +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) uint32_t usecs; +#endif uint32_t start; struct ble_ll_conn_sm *connsm; @@ -1345,12 +1506,12 @@ ble_ll_conn_event_start_cb(struct ble_ll_sched_item *sch) connsm = (struct ble_ll_conn_sm *)sch->cb_arg; g_ble_ll_conn_cur_sm = connsm; BLE_LL_ASSERT(connsm); + + /* In rare cases 1st connection event is fired before LL finished processing + * new connection. In such case just skip this connection event and LL will + * reschedule to next connection event. + */ if (connsm->conn_state == BLE_LL_CONN_STATE_IDLE) { - /* That should not happen. If it does it means connection - * is already closed - */ - STATS_INC(ble_ll_conn_stats, sched_start_in_idle); - BLE_LL_ASSERT(0); ble_ll_conn_current_sm_over(connsm); return BLE_LL_SCHED_STATE_DONE; } @@ -1372,21 +1533,25 @@ ble_ll_conn_event_start_cb(struct ble_ll_sched_item *sch) ble_phy_resolv_list_disable(); #endif -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) +#if MYNEWT_VAL(BLE_LL_PHY) ble_phy_mode_set(connsm->phy_data.tx_phy_mode, connsm->phy_data.rx_phy_mode); #endif - if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { + /* Set the power */ + ble_ll_tx_power_set(g_ble_ll_tx_power); + + switch (connsm->conn_role) { +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + case BLE_LL_CONN_ROLE_CENTRAL: /* Set start time of transmission */ start = sch->start_time + g_ble_ll_sched_offset_ticks; rc = ble_phy_tx_set_start_time(start, sch->remainder); if (!rc) { #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - if (CONN_F_ENCRYPTED(connsm)) { - ble_phy_encrypt_enable(connsm->enc_data.tx_pkt_cntr, - connsm->enc_data.iv, - connsm->enc_data.enc_block.cipher_text, - 1); + if (connsm->flags.encrypted) { + ble_phy_encrypt_enable(connsm->enc_data.enc_block.cipher_text); + ble_phy_encrypt_iv_set(connsm->enc_data.iv); + ble_phy_encrypt_counter_set(connsm->enc_data.tx_pkt_cntr, 1); } else { ble_phy_encrypt_disable(); } @@ -1402,35 +1567,37 @@ ble_ll_conn_event_start_cb(struct ble_ll_sched_item *sch) STATS_INC(ble_ll_conn_stats, conn_ev_late); rc = BLE_LL_SCHED_STATE_DONE; } - } else { + break; +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) + case BLE_LL_CONN_ROLE_PERIPHERAL: #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - if (CONN_F_ENCRYPTED(connsm)) { - ble_phy_encrypt_enable(connsm->enc_data.rx_pkt_cntr, - connsm->enc_data.iv, - connsm->enc_data.enc_block.cipher_text, - 1); + if (connsm->flags.encrypted) { + ble_phy_encrypt_enable(connsm->enc_data.enc_block.cipher_text); + ble_phy_encrypt_iv_set(connsm->enc_data.iv); + ble_phy_encrypt_counter_set(connsm->enc_data.rx_pkt_cntr, 1); } else { ble_phy_encrypt_disable(); } #endif - /* XXX: what is this really for the slave? */ + /* XXX: what is this really for the peripheral? */ start = sch->start_time + g_ble_ll_sched_offset_ticks; rc = ble_phy_rx_set_start_time(start, sch->remainder); if (rc) { /* End the connection event as we have no more buffers */ - STATS_INC(ble_ll_conn_stats, slave_ce_failures); + STATS_INC(ble_ll_conn_stats, periph_ce_failures); rc = BLE_LL_SCHED_STATE_DONE; } else { /* - * Set flag that tells slave to set last anchor point if a packet + * Set flag that tells peripheral to set last anchor point if a packet * has been received. */ - connsm->csmflags.cfbit.slave_set_last_anchor = 1; + connsm->flags.periph_set_last_anchor = 1; /* * Set the wait for response time. The anchor point is when we - * expect the master to start transmitting. Worst-case, we expect + * expect the central to start transmitting. Worst-case, we expect * to hear a reply within the anchor point plus: * -> current tx window size * -> current window widening amount (includes +/- 16 usec jitter) @@ -1452,31 +1619,33 @@ ble_ll_conn_event_start_cb(struct ble_ll_sched_item *sch) * 2) The address rx time and jitter is accounted for in the * phy function */ - usecs = connsm->slave_cur_tx_win_usecs + 61 + - (2 * connsm->slave_cur_window_widening); + usecs = connsm->periph_cur_tx_win_usecs + 61 + + (2 * connsm->periph_cur_window_widening); ble_phy_wfr_enable(BLE_PHY_WFR_ENABLE_RX, 0, usecs); /* Set next wakeup time to connection event end time */ rc = BLE_LL_SCHED_STATE_RUNNING; } + break; +#endif + default: + BLE_LL_ASSERT(0); + break; } if (rc == BLE_LL_SCHED_STATE_DONE) { - ble_ll_event_send(&connsm->conn_ev_end); - ble_phy_disable(); - ble_ll_state_set(BLE_LL_STATE_STANDBY); - g_ble_ll_conn_cur_sm = NULL; + ble_ll_conn_current_sm_over(connsm); } /* Set time that we last serviced the schedule */ - connsm->last_scheduled = os_cputime_get32(); + connsm->last_scheduled = ble_ll_tmr_get(); return rc; } /** * Called to determine if the device is allowed to send the next pdu in the - * connection event. This will always return 'true' if we are a slave. If we - * are a master, we must be able to send the next fragment and get a minimum - * sized response from the slave. + * connection event. This will always return 'true' if we are a peripheral. If we + * are a central, we must be able to send the next fragment and get a minimum + * sized response from the peripheral. * * Context: Interrupt context (rx end isr). * @@ -1489,6 +1658,7 @@ static int ble_ll_conn_can_send_next_pdu(struct ble_ll_conn_sm *connsm, uint32_t begtime, uint32_t add_usecs) { +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) int rc; uint16_t rem_bytes; uint32_t ticks; @@ -1500,14 +1670,14 @@ ble_ll_conn_can_send_next_pdu(struct ble_ll_conn_sm *connsm, uint32_t begtime, uint32_t allowed_usecs; int tx_phy_mode; -#if BLE_LL_BT5_PHY_SUPPORTED +#if MYNEWT_VAL(BLE_LL_PHY) tx_phy_mode = connsm->phy_data.tx_phy_mode; #else tx_phy_mode = BLE_PHY_MODE_1M; #endif rc = 1; - if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { + if (connsm->conn_role == BLE_LL_CONN_ROLE_CENTRAL) { /* Get next scheduled item time */ next_sched_time = ble_ll_conn_get_next_sched_time(connsm); @@ -1529,21 +1699,24 @@ ble_ll_conn_can_send_next_pdu(struct ble_ll_conn_sm *connsm, uint32_t begtime, if (rem_bytes > connsm->eff_max_tx_octets) { rem_bytes = connsm->eff_max_tx_octets; } - usecs = ble_ll_pdu_tx_time_get(rem_bytes, tx_phy_mode); + usecs = ble_ll_pdu_us(rem_bytes, tx_phy_mode); } else { /* We will send empty pdu (just a LL header) */ - usecs = ble_ll_pdu_tx_time_get(0, tx_phy_mode); + usecs = ble_ll_pdu_us(0, tx_phy_mode); } - usecs += (BLE_LL_IFS * 2) + connsm->eff_max_rx_time; + usecs += (BLE_LL_IFS * 2) + connsm->ota_max_rx_time; ticks = (uint32_t)(next_sched_time - begtime); - allowed_usecs = os_cputime_ticks_to_usecs(ticks); + allowed_usecs = ble_ll_tmr_t2u(ticks); if ((usecs + add_usecs) >= allowed_usecs) { rc = 0; } } return rc; +#else + return 1; +#endif } #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_PING) @@ -1584,12 +1757,13 @@ ble_ll_conn_auth_pyld_timer_start(struct ble_ll_conn_sm *connsm) } #endif +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) static void -ble_ll_conn_master_common_init(struct ble_ll_conn_sm *connsm) +ble_ll_conn_central_common_init(struct ble_ll_conn_sm *connsm) { - /* Set master role */ - connsm->conn_role = BLE_LL_CONN_ROLE_MASTER; + /* Set central role */ + connsm->conn_role = BLE_LL_CONN_ROLE_CENTRAL; /* Set default ce parameters */ @@ -1599,18 +1773,25 @@ ble_ll_conn_master_common_init(struct ble_ll_conn_sm *connsm) */ connsm->tx_win_size = BLE_LL_CONN_TX_WIN_MIN + 1; connsm->tx_win_off = 0; - connsm->master_sca = BLE_LL_SCA_ENUM; + connsm->central_sca = BLE_LL_SCA_ENUM; /* Hop increment is a random value between 5 and 16. */ connsm->hop_inc = (ble_ll_rand() % 12) + 5; /* Set channel map to map requested by host */ - connsm->num_used_chans = g_ble_ll_conn_params.num_used_chans; - memcpy(connsm->chanmap, g_ble_ll_conn_params.master_chan_map, - BLE_LL_CONN_CHMAP_LEN); + connsm->chan_map_used = g_ble_ll_data.chan_map_used; + memcpy(connsm->chan_map, g_ble_ll_data.chan_map, BLE_LL_CHAN_MAP_LEN); + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE) + connsm->acc_subrate_min = g_ble_ll_conn_params.acc_subrate_min; + connsm->acc_subrate_max = g_ble_ll_conn_params.acc_subrate_max; + connsm->acc_max_latency = g_ble_ll_conn_params.acc_max_latency; + connsm->acc_cont_num = g_ble_ll_conn_params.acc_cont_num; + connsm->acc_supervision_tmo = g_ble_ll_conn_params.acc_supervision_tmo; +#endif /* Calculate random access address and crc initialization value */ - connsm->access_addr = ble_ll_utils_calc_access_addr(); + connsm->access_addr = ble_ll_utils_calc_aa(); connsm->crcinit = ble_ll_rand() & 0xffffff; /* Set initial schedule callback */ @@ -1618,7 +1799,7 @@ ble_ll_conn_master_common_init(struct ble_ll_conn_sm *connsm) } /** * Called when a create connection command has been received. This initializes - * a connection state machine in the master role. + * a connection state machine in the central role. * * NOTE: Must be called before the state machine is started * @@ -1626,58 +1807,82 @@ ble_ll_conn_master_common_init(struct ble_ll_conn_sm *connsm) * @param hcc */ void -ble_ll_conn_master_init(struct ble_ll_conn_sm *connsm, - struct hci_create_conn *hcc) +ble_ll_conn_central_init(struct ble_ll_conn_sm *connsm, + struct ble_ll_conn_create_scan *cc_scan, + struct ble_ll_conn_create_params *cc_params) +{ + + ble_ll_conn_central_common_init(connsm); + + connsm->own_addr_type = cc_scan->own_addr_type; + memcpy(&connsm->peer_addr, &cc_scan->peer_addr, BLE_DEV_ADDR_LEN); + connsm->peer_addr_type = cc_scan->peer_addr_type; + + connsm->conn_itvl = cc_params->conn_itvl; + connsm->conn_itvl_ticks = cc_params->conn_itvl_ticks; + connsm->conn_itvl_usecs = cc_params->conn_itvl_usecs; + connsm->periph_latency = cc_params->conn_latency; + connsm->supervision_tmo = cc_params->supervision_timeout; + connsm->max_ce_len_ticks = ble_ll_tmr_u2t_up(cc_params->max_ce_len * BLE_LL_CONN_CE_USECS); +} +#endif + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_DATA_LEN_EXT) +int +ble_ll_conn_set_data_len(struct ble_ll_conn_sm *connsm, + uint16_t tx_octets, uint16_t tx_time, + uint16_t rx_octets, uint16_t rx_time) { + int init_dle = 0; - ble_ll_conn_master_common_init(connsm); + /* Note: octets/time shall be checked by caller! */ - /* Set slave latency and supervision timeout */ - connsm->slave_latency = hcc->conn_latency; - connsm->supervision_tmo = hcc->supervision_timeout; +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) + /* Keep original values requested by host since we may want to recalculate + * after PHY changes between coded and uncoded. + */ + connsm->host_req_max_tx_time = tx_time; + connsm->host_req_max_rx_time = rx_time; - /* Set own address type and peer address if needed */ - connsm->own_addr_type = hcc->own_addr_type; - if (hcc->filter_policy == 0) { - memcpy(&connsm->peer_addr, &hcc->peer_addr, BLE_DEV_ADDR_LEN); - connsm->peer_addr_type = hcc->peer_addr_type; + /* If peer does not support coded, we cannot use value larger than 2120us */ + if (!ble_ll_conn_rem_feature_check(connsm, BLE_LL_FEAT_LE_CODED_PHY)) { + tx_time = MIN(tx_time, BLE_LL_CONN_SUPP_TIME_MAX_UNCODED); + rx_time = MIN(rx_time, BLE_LL_CONN_SUPP_TIME_MAX_UNCODED); } +#else + tx_time = MIN(tx_time, BLE_LL_CONN_SUPP_TIME_MAX_UNCODED); + rx_time = MIN(rx_time, BLE_LL_CONN_SUPP_TIME_MAX_UNCODED); +#endif - /* XXX: for now, just make connection interval equal to max */ - connsm->conn_itvl = hcc->conn_itvl_max; + if (connsm->max_tx_time != tx_time) { + connsm->max_tx_time = tx_time; + init_dle = 1; + } - /* Check the min/max CE lengths are less than connection interval */ - if (hcc->min_ce_len > (connsm->conn_itvl * 2)) { - connsm->min_ce_len = connsm->conn_itvl * 2; - } else { - connsm->min_ce_len = hcc->min_ce_len; + if (connsm->max_tx_octets != tx_octets) { + connsm->max_tx_octets = tx_octets; + init_dle = 1; } - if (hcc->max_ce_len > (connsm->conn_itvl * 2)) { - connsm->max_ce_len = connsm->conn_itvl * 2; - } else { - connsm->max_ce_len = hcc->max_ce_len; + if (rx_time && (connsm->max_rx_time != rx_time)) { + connsm->max_rx_time = rx_time; + init_dle = 1; } -} -static void -ble_ll_update_max_tx_octets_phy_mode(struct ble_ll_conn_sm *connsm) -{ - uint32_t usecs; + if (rx_octets && (connsm->max_rx_octets != rx_octets)) { + connsm->max_rx_octets = rx_octets; + init_dle = 1; + } - usecs = connsm->eff_max_tx_time; + if (init_dle) { + ble_ll_ctrl_initiate_dle(connsm, false); + } - connsm->max_tx_octets_phy_mode[BLE_PHY_MODE_1M] = - ble_ll_pdu_max_tx_octets_get(usecs, BLE_PHY_MODE_1M); - connsm->max_tx_octets_phy_mode[BLE_PHY_MODE_2M] = - ble_ll_pdu_max_tx_octets_get(usecs, BLE_PHY_MODE_2M); - connsm->max_tx_octets_phy_mode[BLE_PHY_MODE_CODED_125KBPS] = - ble_ll_pdu_max_tx_octets_get(usecs, BLE_PHY_MODE_CODED_125KBPS); - connsm->max_tx_octets_phy_mode[BLE_PHY_MODE_CODED_500KBPS] = - ble_ll_pdu_max_tx_octets_get(usecs, BLE_PHY_MODE_CODED_500KBPS); + return 0; } +#endif -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) +#if MYNEWT_VAL(BLE_LL_PHY) static void ble_ll_conn_set_phy(struct ble_ll_conn_sm *connsm, int tx_phy, int rx_phy) @@ -1713,7 +1918,7 @@ ble_ll_conn_init_phy(struct ble_ll_conn_sm *connsm, int phy) connsm->rem_max_tx_time = BLE_LL_CONN_SUPP_TIME_MIN_CODED; connsm->rem_max_rx_time = BLE_LL_CONN_SUPP_TIME_MIN_CODED; /* Assume peer does support coded */ - connsm->remote_features[0] |= (BLE_LL_FEAT_LE_CODED_PHY >> 8); + ble_ll_conn_rem_feature_add(connsm, BLE_LL_FEAT_LE_CODED_PHY); } else { connsm->max_tx_time = conngp->conn_init_max_tx_time_uncoded; connsm->max_rx_time = BLE_LL_CONN_SUPP_TIME_MAX_UNCODED; @@ -1726,74 +1931,37 @@ ble_ll_conn_init_phy(struct ble_ll_conn_sm *connsm, int phy) connsm->rem_max_rx_octets = BLE_LL_CONN_SUPP_BYTES_MIN; connsm->eff_max_tx_octets = BLE_LL_CONN_SUPP_BYTES_MIN; connsm->eff_max_rx_octets = BLE_LL_CONN_SUPP_BYTES_MIN; - - ble_ll_update_max_tx_octets_phy_mode(connsm); } #endif #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - -void -ble_ll_conn_ext_master_init(struct ble_ll_conn_sm *connsm, - struct hci_ext_create_conn *hcc) +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) +static void +ble_ll_conn_create_set_params(struct ble_ll_conn_sm *connsm, uint8_t phy) { + struct ble_ll_conn_create_params *cc_params; - ble_ll_conn_master_common_init(connsm); + cc_params = &g_ble_ll_conn_create_sm.params[phy - 1]; - /* Set own address type and peer address if needed */ - connsm->own_addr_type = hcc->own_addr_type; - if (hcc->filter_policy == 0) { - memcpy(&connsm->peer_addr, &hcc->peer_addr, BLE_DEV_ADDR_LEN); - connsm->peer_addr_type = hcc->peer_addr_type; - } + connsm->periph_latency = cc_params->conn_latency; + connsm->supervision_tmo = cc_params->supervision_timeout; - connsm->initial_params = *hcc; + connsm->conn_itvl = cc_params->conn_itvl; + connsm->conn_itvl_ticks = cc_params->conn_itvl_ticks; + connsm->conn_itvl_usecs = cc_params->conn_itvl_usecs; } +#endif +#endif -void -ble_ll_conn_ext_set_params(struct ble_ll_conn_sm *connsm, - struct hci_ext_conn_params *hcc_params, int phy) +static void +ble_ll_conn_set_csa(struct ble_ll_conn_sm *connsm, bool chsel) { - /* Set slave latency and supervision timeout */ - connsm->slave_latency = hcc_params->conn_latency; - connsm->supervision_tmo = hcc_params->supervision_timeout; - - /* XXX: for now, just make connection interval equal to max */ - connsm->conn_itvl = hcc_params->conn_itvl_max; - - - /* Check the min/max CE lengths are less than connection interval */ - if (hcc_params->min_ce_len > (connsm->conn_itvl * 2)) { - connsm->min_ce_len = connsm->conn_itvl * 2; - } else { - connsm->min_ce_len = hcc_params->min_ce_len; - } - - if (hcc_params->max_ce_len > (connsm->conn_itvl * 2)) { - connsm->max_ce_len = connsm->conn_itvl * 2; - } else { - connsm->max_ce_len = hcc_params->max_ce_len; - } - - ble_ll_conn_calc_itvl_ticks(connsm); - -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) - ble_ll_conn_init_phy(connsm, phy); -#endif -} - - -#endif - -static void -ble_ll_conn_set_csa(struct ble_ll_conn_sm *connsm, bool chsel) -{ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CSA2) - if (chsel) { - CONN_F_CSA2_SUPP(connsm) = 1; - connsm->channel_id = ((connsm->access_addr & 0xffff0000) >> 16) ^ - (connsm->access_addr & 0x0000ffff); +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CSA2) + if (chsel) { + connsm->flags.csa2 = 1; + connsm->channel_id = ((connsm->access_addr & 0xffff0000) >> 16) ^ + (connsm->access_addr & 0x0000ffff); /* calculate the next data channel */ connsm->data_chan_index = ble_ll_conn_calc_dci(connsm, 0); @@ -1810,7 +1978,7 @@ ble_ll_conn_set_csa(struct ble_ll_conn_sm *connsm, bool chsel) /** * Create a new connection state machine. This is done once per * connection when the HCI command "create connection" is issued to the - * controller or when a slave receives a connect request. + * controller or when a peripheral receives a connect request. * * Context: Link Layer task * @@ -1822,7 +1990,7 @@ ble_ll_conn_sm_new(struct ble_ll_conn_sm *connsm) struct ble_ll_conn_global_params *conn_params; /* Reset following elements */ - connsm->csmflags.conn_flags = 0; + memset(&connsm->flags, 0, sizeof(connsm->flags)); connsm->event_cntr = 0; connsm->conn_state = BLE_LL_CONN_STATE_IDLE; connsm->disconnect_reason = 0; @@ -1834,9 +2002,16 @@ ble_ll_conn_sm_new(struct ble_ll_conn_sm *connsm) connsm->sub_vers_nr = 0; connsm->reject_reason = BLE_ERR_SUCCESS; connsm->conn_rssi = BLE_LL_CONN_UNKNOWN_RSSI; - connsm->rpa_index = -1; connsm->inita_identity_used = 0; +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE) + connsm->subrate_base_event = 0; + connsm->subrate_factor = 1; + connsm->cont_num = 0; + connsm->cont_num_left = 0; + connsm->has_nonempty_pdu = 0; +#endif + #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER) connsm->sync_transfer_sync_timeout = g_ble_ll_conn_sync_transfer_params.sync_timeout_us; connsm->sync_transfer_mode = g_ble_ll_conn_sync_transfer_params.mode; @@ -1844,16 +2019,16 @@ ble_ll_conn_sm_new(struct ble_ll_conn_sm *connsm) #endif /* XXX: TODO set these based on PHY that started connection */ -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) +#if MYNEWT_VAL(BLE_LL_PHY) connsm->phy_data.cur_tx_phy = BLE_PHY_1M; connsm->phy_data.cur_rx_phy = BLE_PHY_1M; connsm->phy_data.tx_phy_mode = BLE_PHY_MODE_1M; connsm->phy_data.rx_phy_mode = BLE_PHY_MODE_1M; - connsm->phy_data.req_pref_tx_phys_mask = 0; - connsm->phy_data.req_pref_rx_phys_mask = 0; - connsm->phy_data.host_pref_tx_phys_mask = g_ble_ll_data.ll_pref_tx_phys; - connsm->phy_data.host_pref_rx_phys_mask = g_ble_ll_data.ll_pref_rx_phys; - connsm->phy_data.phy_options = 0; + connsm->phy_data.pref_mask_tx_req = 0; + connsm->phy_data.pref_mask_rx_req = 0; + connsm->phy_data.pref_mask_tx = g_ble_ll_data.ll_pref_tx_phys; + connsm->phy_data.pref_mask_rx = g_ble_ll_data.ll_pref_rx_phys; + connsm->phy_data.pref_opts = 0; connsm->phy_tx_transition = 0; #endif @@ -1873,6 +2048,8 @@ ble_ll_conn_sm_new(struct ble_ll_conn_sm *connsm) /* Initialize transmit queue and ack/flow control elements */ STAILQ_INIT(&connsm->conn_txq); + connsm->conn_txq_num_data_pkt = 0; + connsm->conn_txq_num_zero_pkt = 0; connsm->cur_tx_pdu = NULL; connsm->tx_seqnum = 0; connsm->next_exp_seqnum = 0; @@ -1890,16 +2067,16 @@ ble_ll_conn_sm_new(struct ble_ll_conn_sm *connsm) connsm->rem_max_rx_time = BLE_LL_CONN_SUPP_TIME_MIN; connsm->eff_max_tx_time = BLE_LL_CONN_SUPP_TIME_MIN; connsm->eff_max_rx_time = BLE_LL_CONN_SUPP_TIME_MIN; + connsm->ota_max_rx_time = BLE_LL_CONN_SUPP_TIME_MIN; connsm->rem_max_tx_octets = BLE_LL_CONN_SUPP_BYTES_MIN; connsm->rem_max_rx_octets = BLE_LL_CONN_SUPP_BYTES_MIN; connsm->eff_max_tx_octets = BLE_LL_CONN_SUPP_BYTES_MIN; connsm->eff_max_rx_octets = BLE_LL_CONN_SUPP_BYTES_MIN; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) connsm->host_req_max_tx_time = 0; + connsm->host_req_max_rx_time = 0; #endif - ble_ll_update_max_tx_octets_phy_mode(connsm); - /* Reset encryption data */ #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) memset(&connsm->enc_data, 0, sizeof(struct ble_ll_conn_enc_data)); @@ -1908,63 +2085,83 @@ ble_ll_conn_sm_new(struct ble_ll_conn_sm *connsm) #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_PING) connsm->auth_pyld_tmo = BLE_LL_CONN_DEF_AUTH_PYLD_TMO; - CONN_F_LE_PING_SUPP(connsm) = 1; - ble_npl_callout_init(&connsm->auth_pyld_timer, - &g_ble_ll_data.ll_evq, - ble_ll_conn_auth_pyld_timer_cb, - connsm); + connsm->flags.le_ping_supp = 1; #endif - ble_ll_conn_calc_itvl_ticks(connsm); - /* Add to list of active connections */ SLIST_INSERT_HEAD(&g_ble_ll_conn_active_list, connsm, act_sle); + +#if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) + if (ble_ll_sched_css_is_enabled() && + (connsm->conn_role == BLE_LL_CONN_ROLE_CENTRAL)) { + ble_ll_conn_css_update_list(connsm); + } +#endif } void ble_ll_conn_update_eff_data_len(struct ble_ll_conn_sm *connsm) { + int ota_max_rx_time_calc = 0; int send_event; uint16_t eff_time; uint16_t eff_bytes; + uint16_t ota_time; + uint8_t phy_mode; /* Assume no event sent */ send_event = 0; /* See if effective times have changed */ - eff_time = min(connsm->rem_max_tx_time, connsm->max_rx_time); + eff_time = MIN(connsm->rem_max_tx_time, connsm->max_rx_time); #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) if (connsm->phy_data.cur_rx_phy == BLE_PHY_CODED) { - eff_time = max(eff_time, BLE_LL_CONN_SUPP_TIME_MIN_CODED); + eff_time = MAX(eff_time, BLE_LL_CONN_SUPP_TIME_MIN_CODED); } #endif if (eff_time != connsm->eff_max_rx_time) { connsm->eff_max_rx_time = eff_time; + ota_max_rx_time_calc = 1; send_event = 1; } - eff_time = min(connsm->rem_max_rx_time, connsm->max_tx_time); + eff_time = MIN(connsm->rem_max_rx_time, connsm->max_tx_time); #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) if (connsm->phy_data.cur_tx_phy == BLE_PHY_CODED) { - eff_time = max(eff_time, BLE_LL_CONN_SUPP_TIME_MIN_CODED); + eff_time = MAX(eff_time, BLE_LL_CONN_SUPP_TIME_MIN_CODED); } #endif if (eff_time != connsm->eff_max_tx_time) { connsm->eff_max_tx_time = eff_time; send_event = 1; - - ble_ll_update_max_tx_octets_phy_mode(connsm); } - eff_bytes = min(connsm->rem_max_tx_octets, connsm->max_rx_octets); + eff_bytes = MIN(connsm->rem_max_tx_octets, connsm->max_rx_octets); if (eff_bytes != connsm->eff_max_rx_octets) { connsm->eff_max_rx_octets = eff_bytes; + ota_max_rx_time_calc = 1; send_event = 1; } - eff_bytes = min(connsm->rem_max_rx_octets, connsm->max_tx_octets); + eff_bytes = MIN(connsm->rem_max_rx_octets, connsm->max_tx_octets); if (eff_bytes != connsm->eff_max_tx_octets) { connsm->eff_max_tx_octets = eff_bytes; send_event = 1; } + /* If effective rx octets and/or time value changes, we need to calculate + * actual OTA max rx time, i.e. lesser of effective max rx time and rx time + * of PDU containing max rx octets of payload. This is then used to calculate + * connection events timings. + */ + if (ota_max_rx_time_calc) { +#if MYNEWT_VAL(BLE_LL_PHY) + phy_mode = ble_ll_phy_to_phy_mode(connsm->phy_data.cur_rx_phy, + BLE_HCI_LE_PHY_CODED_S8_PREF); +#else + phy_mode = BLE_PHY_MODE_1M; +#endif + ota_time = ble_ll_pdu_us(connsm->eff_max_rx_octets, phy_mode); + connsm->ota_max_rx_time = MIN(ota_time, connsm->eff_max_rx_time); + } + if (send_event) { ble_ll_hci_ev_datalen_chg(connsm); } @@ -2010,6 +2207,21 @@ ble_ll_conn_end(struct ble_ll_conn_sm *connsm, uint8_t ble_err) /* Remove from the active connection list */ SLIST_REMOVE(&g_ble_ll_conn_active_list, connsm, ble_ll_conn_sm, act_sle); +#if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) + if (ble_ll_sched_css_is_enabled() && + (connsm->conn_role == BLE_LL_CONN_ROLE_CENTRAL)) { + /* If current connection was reference for CSS, we need to find another + * one. It does not matter which one we'll pick. + */ + OS_ENTER_CRITICAL(sr); + SLIST_REMOVE(&g_ble_ll_conn_css_list, connsm, ble_ll_conn_sm, css_sle); + if (connsm == g_ble_ll_conn_css_ref) { + g_ble_ll_conn_css_ref = SLIST_FIRST(&g_ble_ll_conn_css_list); + } + OS_EXIT_CRITICAL(sr); + } +#endif + #if MYNEWT_VAL(BLE_LL_CFG_FEAT_CTRL_TO_HOST_FLOW_CONTROL) ble_ll_conn_cth_flow_free_credit(connsm, connsm->cth_flow_pending); #endif @@ -2034,17 +2246,7 @@ ble_ll_conn_end(struct ble_ll_conn_sm *connsm, uint8_t ble_err) } /* Make sure events off queue */ - ble_npl_eventq_remove(&g_ble_ll_data.ll_evq, &connsm->conn_ev_end); - -#if MYNEWT_VAL(BLE_LL_STRICT_CONN_SCHEDULING) - /* Remove from occupied periods */ - OS_ENTER_CRITICAL(sr); - BLE_LL_ASSERT(g_ble_ll_sched_data.sch_num_occ_periods > 0); - BLE_LL_ASSERT(g_ble_ll_sched_data.sch_occ_period_mask & connsm->period_occ_mask); - --g_ble_ll_sched_data.sch_num_occ_periods; - g_ble_ll_sched_data.sch_occ_period_mask &= ~connsm->period_occ_mask; - OS_EXIT_CRITICAL(sr); -#endif + ble_ll_event_remove(&connsm->conn_ev_end); /* Connection state machine is now idle */ connsm->conn_state = BLE_LL_CONN_STATE_IDLE; @@ -2053,19 +2255,19 @@ ble_ll_conn_end(struct ble_ll_conn_sm *connsm, uint8_t ble_err) * If we have features and there's pending HCI command, send an event before * disconnection event so it does make sense to host. */ - if (connsm->csmflags.cfbit.pending_hci_rd_features && - connsm->csmflags.cfbit.rxd_features) { + if (connsm->flags.features_host_req && + connsm->flags.features_rxd) { ble_ll_hci_ev_rd_rem_used_feat(connsm, BLE_ERR_SUCCESS); - connsm->csmflags.cfbit.pending_hci_rd_features = 0; + connsm->flags.features_host_req = 0; } /* * If there is still pending read features request HCI command, send an * event to complete it. */ - if (connsm->csmflags.cfbit.pending_hci_rd_features) { + if (connsm->flags.features_host_req) { ble_ll_hci_ev_rd_rem_used_feat(connsm, ble_err); - connsm->csmflags.cfbit.pending_hci_rd_features = 0; + connsm->flags.features_host_req = 0; } /* @@ -2077,7 +2279,7 @@ ble_ll_conn_end(struct ble_ll_conn_sm *connsm, uint8_t ble_err) * received and we should not send an event. */ if (ble_err && (ble_err != BLE_ERR_UNK_CONN_ID || - connsm->csmflags.cfbit.terminate_ind_rxd)) { + connsm->flags.terminate_ind_rxd)) { ble_ll_disconn_comp_event_send(connsm, ble_err); } @@ -2089,32 +2291,53 @@ ble_ll_conn_end(struct ble_ll_conn_sm *connsm, uint8_t ble_err) connsm->event_cntr, (uint32_t)ble_err); } -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER) void -ble_ll_conn_get_anchor(struct ble_ll_conn_sm *connsm, uint16_t conn_event, +ble_ll_conn_anchor_get(struct ble_ll_conn_sm *connsm, uint16_t *event_cntr, uint32_t *anchor, uint8_t *anchor_usecs) { - uint32_t ticks; + *event_cntr = connsm->event_cntr; + *anchor = connsm->anchor_point; + *anchor_usecs = connsm->anchor_point_usecs; +} + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER) +void +ble_ll_conn_anchor_event_cntr_get(struct ble_ll_conn_sm *connsm, + uint16_t event_cntr, uint32_t *anchor, + uint8_t *anchor_usecs) +{ uint32_t itvl; itvl = (connsm->conn_itvl * BLE_LL_CONN_ITVL_USECS); - if ((int16_t)(conn_event - connsm->event_cntr) < 0) { - itvl *= connsm->event_cntr - conn_event; - ticks = os_cputime_usecs_to_ticks(itvl); - *anchor = connsm->anchor_point - ticks; + *anchor = connsm->anchor_point; + *anchor_usecs = connsm->anchor_point_usecs; + + if ((int16_t)(event_cntr - connsm->event_cntr) < 0) { + itvl *= connsm->event_cntr - event_cntr; + ble_ll_tmr_sub(anchor, anchor_usecs, itvl); } else { - itvl *= conn_event - connsm->event_cntr; - ticks = os_cputime_usecs_to_ticks(itvl); - *anchor = connsm->anchor_point + ticks; + itvl *= event_cntr - connsm->event_cntr; + ble_ll_tmr_add(anchor, anchor_usecs, itvl); } +} +#endif - *anchor_usecs = connsm->anchor_point_usecs; - *anchor_usecs += (itvl - os_cputime_ticks_to_usecs(ticks)); - if (*anchor_usecs >= 31) { - (*anchor)++; - *anchor_usecs -= 31; +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) +int +ble_ll_conn_move_anchor(struct ble_ll_conn_sm *connsm, uint16_t offset) +{ + BLE_LL_ASSERT(connsm->conn_role == BLE_LL_CONN_ROLE_CENTRAL); + + if (IS_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_CONN_PARAM_REQ) || + IS_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_CONN_UPDATE)) { + return -1; } + + connsm->conn_update_anchor_offset_req = offset; + ble_ll_ctrl_proc_start(connsm, BLE_LL_CTRL_PROC_CONN_UPDATE); + + return 0; } #endif @@ -2130,30 +2353,77 @@ ble_ll_conn_get_anchor(struct ble_ll_conn_sm *connsm, uint16_t conn_event, static int ble_ll_conn_next_event(struct ble_ll_conn_sm *connsm) { - uint16_t latency; - uint32_t itvl; + uint32_t conn_itvl_us; + uint32_t ce_duration; +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) uint32_t cur_ww; uint32_t max_ww; +#endif struct ble_ll_conn_upd_req *upd; - uint32_t ticks; + uint8_t skip_anchor_calc = 0; uint32_t usecs; + uint8_t use_periph_latency; + uint16_t base_event_cntr; + uint16_t next_event_cntr; + uint8_t next_is_subrated; + uint16_t subrate_factor; + uint16_t event_cntr_diff; +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE) + struct ble_ll_conn_subrate_params *cstp; + uint16_t trans_next_event_cntr; + uint16_t subrate_conn_upd_event_cntr; +#endif +#if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) + uint8_t anchor_calc_for_css = 0; +#endif /* XXX: deal with connection request procedure here as well */ ble_ll_conn_chk_csm_flags(connsm); /* If unable to start terminate procedure, start it now */ - if (connsm->disconnect_reason && !CONN_F_TERMINATE_STARTED(connsm)) { + if (connsm->disconnect_reason && !connsm->flags.terminate_started) { ble_ll_ctrl_terminate_start(connsm); } - if (CONN_F_TERMINATE_STARTED(connsm) && (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE)) { + if (connsm->flags.terminate_started && CONN_IS_PERIPHERAL(connsm)) { /* Some of the devices waits whole connection interval to ACK our * TERMINATE_IND sent as a Slave. Since we are here it means we are still waiting for ACK. * Make sure we catch it in next connection event. */ - connsm->slave_latency = 0; + connsm->periph_latency = 0; } + next_is_subrated = 1; +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE) + base_event_cntr = connsm->subrate_base_event; + subrate_factor = connsm->subrate_factor; + + /* We need to restore remaining continuation events counter if a non-empty + * PDU was txd/rxd in this connection event. Also we need to set counter to + * 0 in case there was no valid PDU at subrated event, since we should not + * use continuation events in such case (i.e. ignore any valid PDUs prior + * to subrated event). + * + * Note that has_nonempty_pdu flag is also cleared here since LL may move to + * next connection event due to scheduling conflict and there will be no + * start callback for new event. + */ + if (connsm->has_nonempty_pdu) { + connsm->cont_num_left = connsm->cont_num; + connsm->has_nonempty_pdu = 0; + } else if (connsm->event_cntr == connsm->subrate_base_event) { + connsm->cont_num_left = 0; + } + + if (connsm->cont_num_left > 0) { + connsm->cont_num_left--; + next_is_subrated = 0; + } +#else + base_event_cntr = connsm->event_cntr; + subrate_factor = 1; +#endif + /* * XXX: TODO Probably want to add checks to see if we need to start * a control procedure here as an instant may have prevented us from @@ -2161,39 +2431,117 @@ ble_ll_conn_next_event(struct ble_ll_conn_sm *connsm) */ /* - * XXX TODO: I think this is technically incorrect. We can allow slave + * XXX TODO: I think this is technically incorrect. We can allow peripheral * latency if we are doing one of these updates as long as we - * know that the master has received the ACK to the PDU that set + * know that the central has received the ACK to the PDU that set * the instant */ /* Set event counter to the next connection event that we will tx/rx in */ - itvl = connsm->conn_itvl * BLE_LL_CONN_ITVL_USECS; - latency = 1; - if (connsm->csmflags.cfbit.allow_slave_latency && - !connsm->csmflags.cfbit.conn_update_sched && - !CONN_F_PHY_UPDATE_SCHED(connsm) && - !connsm->csmflags.cfbit.chanmap_update_scheduled) { - if (connsm->csmflags.cfbit.pkt_rxd) { - latency += connsm->slave_latency; - itvl = itvl * latency; + + use_periph_latency = next_is_subrated && + connsm->flags.periph_use_latency && + !connsm->flags.conn_update_sched && + !connsm->flags.phy_update_sched && + !connsm->flags.chanmap_update_sched && + connsm->flags.pkt_rxd; + + if (next_is_subrated) { + next_event_cntr = base_event_cntr + subrate_factor; + if (use_periph_latency) { + next_event_cntr += subrate_factor * connsm->periph_latency; } - } - connsm->event_cntr += latency; - /* Set next connection event start time */ - /* We can use pre-calculated values for one interval if latency is 1. */ - if (latency == 1) { - connsm->anchor_point += connsm->conn_itvl_ticks; - connsm->anchor_point_usecs += connsm->conn_itvl_usecs; +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE) + /* If we are in subrate transition mode, we should also listen on + * subrated connection events based on new parameters. + */ + if (connsm->flags.subrate_trans) { + BLE_LL_ASSERT(CONN_IS_CENTRAL(connsm)); + + cstp = &connsm->subrate_trans; + trans_next_event_cntr = cstp->subrate_base_event; + while (INT16_LTE(trans_next_event_cntr, connsm->event_cntr)) { + trans_next_event_cntr += cstp->subrate_factor; + } + cstp->subrate_base_event = trans_next_event_cntr; + + if (INT16_LT(trans_next_event_cntr, next_event_cntr)) { + next_event_cntr = trans_next_event_cntr; + next_is_subrated = 0; + } + } +#endif } else { - uint32_t ticks; - ticks = os_cputime_usecs_to_ticks(itvl); - connsm->anchor_point += ticks; - connsm->anchor_point_usecs += (itvl - os_cputime_ticks_to_usecs(ticks)); + next_event_cntr = connsm->event_cntr + 1; } - if (connsm->anchor_point_usecs >= 31) { - ++connsm->anchor_point; - connsm->anchor_point_usecs -= 31; + + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE) + /* If connection update is scheduled, peripheral shall listen at instant + * and one connection event before instant regardless of subrating. + */ + if (CONN_IS_PERIPHERAL(connsm) && + connsm->flags.conn_update_sched && + (connsm->subrate_factor > 1)) { + subrate_conn_upd_event_cntr = connsm->conn_update_req.instant - 1; + if (connsm->event_cntr == subrate_conn_upd_event_cntr) { + subrate_conn_upd_event_cntr++; + } + + if (INT16_GT(next_event_cntr, subrate_conn_upd_event_cntr)) { + next_event_cntr = subrate_conn_upd_event_cntr; + next_is_subrated = 0; + } + } + + /* Set next connection event as a subrate base event if that connection + * event is a subrated event, this simplifies calculations later. + * Note that according to spec base event should only be changed on + * wrap-around, but since we only use this value internally we can use any + * valid value. + */ + if (next_is_subrated || + (connsm->subrate_base_event + + connsm->subrate_factor == next_event_cntr)) { + connsm->subrate_base_event = next_event_cntr; + } +#endif + + event_cntr_diff = next_event_cntr - connsm->event_cntr; + BLE_LL_ASSERT(event_cntr_diff > 0); + + connsm->event_cntr = next_event_cntr; + +#if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) + if (ble_ll_sched_css_is_enabled() && + connsm->conn_role == BLE_LL_CONN_ROLE_CENTRAL) { + connsm->css_period_idx += event_cntr_diff; + + /* If this is non-reference connection, we calculate anchor point from + * reference connection instead of using connection interval. This is + * to make sure connections do not drift over time. + */ + if (g_ble_ll_conn_css_ref != connsm) { + anchor_calc_for_css = 1; + skip_anchor_calc = 1; + } + } +#endif + + if (!skip_anchor_calc) { + /* Calculate next anchor point for connection. + * We can use pre-calculated values for one interval if latency is 1. + */ + if (event_cntr_diff == 1) { + connsm->anchor_point += connsm->conn_itvl_ticks; + ble_ll_tmr_add_u(&connsm->anchor_point, &connsm->anchor_point_usecs, + connsm->conn_itvl_usecs); + } else { + conn_itvl_us = connsm->conn_itvl * BLE_LL_CONN_ITVL_USECS; + + ble_ll_tmr_add(&connsm->anchor_point, &connsm->anchor_point_usecs, + conn_itvl_us * event_cntr_diff); + } } /* @@ -2202,45 +2550,86 @@ ble_ll_conn_next_event(struct ble_ll_conn_sm *connsm) * connection by the the transmit window offset. We also copy in the * update parameters as they now should take effect. */ - if (connsm->csmflags.cfbit.conn_update_sched && + if (connsm->flags.conn_update_sched && (connsm->event_cntr == connsm->conn_update_req.instant)) { - /* Set flag so we send connection update event */ + /* Set flag to send event to host if request was issued by host or + * any of parameters changed (i.e. skip on anchor moves) + */ upd = &connsm->conn_update_req; - if ((connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) || - ((connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) && - IS_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_CONN_PARAM_REQ)) || - (connsm->conn_itvl != upd->interval) || - (connsm->slave_latency != upd->latency) || + if (connsm->flags.conn_update_host_initd || + (connsm->conn_itvl != upd->interval) || + (connsm->periph_latency != upd->latency) || (connsm->supervision_tmo != upd->timeout)) { - connsm->csmflags.cfbit.host_expects_upd_event = 1; + connsm->flags.conn_update_host_w4event = 1; + connsm->flags.conn_update_host_initd = 0; + } + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE) + if (connsm->conn_itvl != upd->interval) { + connsm->subrate_base_event = connsm->event_cntr; + connsm->subrate_factor = 1; + connsm->cont_num = 0; } +#endif + +#if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) + if (ble_ll_sched_css_is_enabled() && + connsm->conn_role == BLE_LL_CONN_ROLE_CENTRAL) { + BLE_LL_ASSERT(connsm->css_slot_idx_pending != + BLE_LL_CONN_CSS_NO_SLOT); + + /* If we are moving to an earlier slot, we are effectively skipping + * one period. + */ + if (connsm->css_slot_idx_pending < connsm->css_slot_idx) { + connsm->css_period_idx++; + } + + connsm->css_slot_idx = connsm->css_slot_idx_pending; + connsm->css_slot_idx_pending = BLE_LL_CONN_CSS_NO_SLOT; + + ble_ll_conn_css_update_list(connsm); + + if (anchor_calc_for_css) { + ble_ll_sched_css_set_conn_anchor(connsm); + anchor_calc_for_css = 0; + } + +#if MYNEWT_VAL(BLE_LL_HCI_VS_CONN_STRICT_SCHED) + ble_ll_hci_ev_send_vs_css_slot_changed(connsm->conn_handle, + connsm->css_slot_idx); +#endif + } +#endif connsm->supervision_tmo = upd->timeout; - connsm->slave_latency = upd->latency; + connsm->periph_latency = upd->latency; connsm->tx_win_size = upd->winsize; - connsm->slave_cur_tx_win_usecs = + connsm->periph_cur_tx_win_usecs = connsm->tx_win_size * BLE_LL_CONN_TX_WIN_USECS; connsm->tx_win_off = upd->winoffset; connsm->conn_itvl = upd->interval; - ble_ll_conn_calc_itvl_ticks(connsm); + + ble_ll_conn_itvl_to_ticks(connsm->conn_itvl, &connsm->conn_itvl_ticks, + &connsm->conn_itvl_usecs); + + if (connsm->conn_param_req.handle != 0) { + connsm->max_ce_len_ticks = ble_ll_tmr_u2t_up(connsm->conn_param_req.max_ce_len * BLE_LL_CONN_CE_USECS); + connsm->conn_param_req.handle = 0; + } + if (upd->winoffset != 0) { usecs = upd->winoffset * BLE_LL_CONN_ITVL_USECS; - ticks = os_cputime_usecs_to_ticks(usecs); - connsm->anchor_point += ticks; - usecs = usecs - os_cputime_ticks_to_usecs(ticks); - connsm->anchor_point_usecs += usecs; - if (connsm->anchor_point_usecs >= 31) { - ++connsm->anchor_point; - connsm->anchor_point_usecs -= 31; - } + ble_ll_tmr_add(&connsm->anchor_point, &connsm->anchor_point_usecs, + usecs); } /* Reset the starting point of the connection supervision timeout */ connsm->last_rxd_pdu_cputime = connsm->anchor_point; /* Reset update scheduled flag */ - connsm->csmflags.cfbit.conn_update_sched = 0; + connsm->flags.conn_update_sched = 0; } /* @@ -2252,18 +2641,18 @@ ble_ll_conn_next_event(struct ble_ll_conn_sm *connsm) * new channel map once the event counter equals or has passed channel * map update instant. */ - if (connsm->csmflags.cfbit.chanmap_update_scheduled && + if (connsm->flags.chanmap_update_sched && ((int16_t)(connsm->chanmap_instant - connsm->event_cntr) <= 0)) { /* XXX: there is a chance that the control packet is still on - * the queue of the master. This means that we never successfully + * the queue of the central. This means that we never successfully * transmitted update request. Would end up killing connection - on slave side. Could ignore it or see if still enqueued. */ - connsm->num_used_chans = - ble_ll_utils_calc_num_used_chans(connsm->req_chanmap); - memcpy(connsm->chanmap, connsm->req_chanmap, BLE_LL_CONN_CHMAP_LEN); + on peripheral side. Could ignore it or see if still enqueued. */ + connsm->chan_map_used = + ble_ll_utils_chan_map_used_get(connsm->req_chanmap); + memcpy(connsm->chan_map, connsm->req_chanmap, BLE_LL_CHAN_MAP_LEN); - connsm->csmflags.cfbit.chanmap_update_scheduled = 0; + connsm->flags.chanmap_update_sched = 0; ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_CHAN_MAP_UPD); @@ -2271,8 +2660,14 @@ ble_ll_conn_next_event(struct ble_ll_conn_sm *connsm) check to make sure we dont have to restart! */ } -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) - if (CONN_F_PHY_UPDATE_SCHED(connsm) && +#if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) + if (anchor_calc_for_css) { + ble_ll_sched_css_set_conn_anchor(connsm); + } +#endif + +#if MYNEWT_VAL(BLE_LL_PHY) + if (connsm->flags.phy_update_sched && (connsm->event_cntr == connsm->phy_instant)) { /* Set cur phy to new phy */ @@ -2280,19 +2675,19 @@ ble_ll_conn_next_event(struct ble_ll_conn_sm *connsm) connsm->phy_data.cur_tx_phy = connsm->phy_data.new_tx_phy; connsm->phy_data.tx_phy_mode = ble_ll_phy_to_phy_mode(connsm->phy_data.cur_tx_phy, - connsm->phy_data.phy_options); + connsm->phy_data.pref_opts); } if (connsm->phy_data.new_rx_phy) { connsm->phy_data.cur_rx_phy = connsm->phy_data.new_rx_phy; connsm->phy_data.rx_phy_mode = ble_ll_phy_to_phy_mode(connsm->phy_data.cur_rx_phy, - connsm->phy_data.phy_options); + connsm->phy_data.pref_opts); } /* Clear flags and set flag to send event at next instant */ - CONN_F_PHY_UPDATE_SCHED(connsm) = 0; - CONN_F_PHY_UPDATE_EVENT(connsm) = 1; + connsm->flags.phy_update_sched = 0; + connsm->flags.phy_update_host_w4event = 1; ble_ll_ctrl_phy_update_proc_complete(connsm); @@ -2308,53 +2703,67 @@ ble_ll_conn_next_event(struct ble_ll_conn_sm *connsm) */ if (((connsm->phy_data.cur_tx_phy == BLE_PHY_CODED) || (connsm->phy_data.cur_rx_phy == BLE_PHY_CODED)) && - !(connsm->remote_features[0] & (BLE_LL_FEAT_LE_CODED_PHY >> 8))) { - connsm->remote_features[0] |= (BLE_LL_FEAT_LE_CODED_PHY >> 8); + !ble_ll_conn_rem_feature_check(connsm, BLE_LL_FEAT_LE_CODED_PHY)) { + ble_ll_conn_rem_feature_add(connsm, BLE_LL_FEAT_LE_CODED_PHY); connsm->max_rx_time = BLE_LL_CONN_SUPP_TIME_MAX_CODED; - ble_ll_ctrl_initiate_dle(connsm); + ble_ll_ctrl_initiate_dle(connsm, false); } #endif } #endif /* Calculate data channel index of next connection event */ - connsm->data_chan_index = ble_ll_conn_calc_dci(connsm, latency); + connsm->data_chan_index = ble_ll_conn_calc_dci(connsm, event_cntr_diff); /* * If we are trying to terminate connection, check if next wake time is * passed the termination timeout. If so, no need to continue with * connection as we will time out anyway. */ - if (CONN_F_TERMINATE_STARTED(connsm)) { + if (connsm->flags.terminate_started) { if ((int32_t)(connsm->terminate_timeout - connsm->anchor_point) <= 0) { return -1; } } /* - * Calculate ce end time. For a slave, we need to add window widening and - * the transmit window if we still have one. + * Calculate ce end time. For a peripheral, we need to add window widening + * and the transmit window if we still have one. + */ +#if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) + /* If css is enabled, use slot duration instead of conn_init_slots for + * reservation. */ -#if MYNEWT_VAL(BLE_LL_STRICT_CONN_SCHEDULING) - itvl = g_ble_ll_sched_data.sch_ticks_per_period; + if (ble_ll_sched_css_is_enabled() && + connsm->conn_role == BLE_LL_CONN_ROLE_CENTRAL) { + ce_duration = ble_ll_tmr_u2t(ble_ll_sched_css_get_slot_us()); + } else { + ce_duration = ble_ll_tmr_u2t(MYNEWT_VAL(BLE_LL_CONN_INIT_SLOTS) * + BLE_LL_SCHED_USECS_PER_SLOT); + } #else - itvl = MYNEWT_VAL(BLE_LL_CONN_INIT_SLOTS) * BLE_LL_SCHED_32KHZ_TICKS_PER_SLOT; + ce_duration = ble_ll_tmr_u2t(MYNEWT_VAL(BLE_LL_CONN_INIT_SLOTS) * + BLE_LL_SCHED_USECS_PER_SLOT); #endif - if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) { + +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) + if (connsm->conn_role == BLE_LL_CONN_ROLE_PERIPHERAL) { cur_ww = ble_ll_utils_calc_window_widening(connsm->anchor_point, connsm->last_anchor_point, - connsm->master_sca); + connsm->central_sca); max_ww = (connsm->conn_itvl * (BLE_LL_CONN_ITVL_USECS/2)) - BLE_LL_IFS; if (cur_ww >= max_ww) { return -1; } cur_ww += BLE_LL_JITTER_USECS; - connsm->slave_cur_window_widening = cur_ww; - itvl += os_cputime_usecs_to_ticks(cur_ww + connsm->slave_cur_tx_win_usecs); + connsm->periph_cur_window_widening = cur_ww; + ce_duration += ble_ll_tmr_u2t(cur_ww + + connsm->periph_cur_tx_win_usecs); } - itvl -= g_ble_ll_sched_offset_ticks; - connsm->ce_end_time = connsm->anchor_point + itvl; +#endif + ce_duration -= g_ble_ll_sched_offset_ticks; + connsm->ce_end_time = connsm->anchor_point + ce_duration; return 0; } @@ -2378,9 +2787,12 @@ static int ble_ll_conn_created(struct ble_ll_conn_sm *connsm, struct ble_mbuf_hdr *rxhdr) { int rc; +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) uint8_t *evbuf; - uint32_t endtime; +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) uint32_t usecs; +#endif /* XXX: TODO this assumes we received in 1M phy */ @@ -2388,10 +2800,10 @@ ble_ll_conn_created(struct ble_ll_conn_sm *connsm, struct ble_mbuf_hdr *rxhdr) connsm->conn_state = BLE_LL_CONN_STATE_CREATED; /* Clear packet received flag */ - connsm->csmflags.cfbit.pkt_rxd = 0; + connsm->flags.pkt_rxd = 0; /* Consider time created the last scheduled time */ - connsm->last_scheduled = os_cputime_get32(); + connsm->last_scheduled = ble_ll_tmr_get(); /* * Set the last rxd pdu time since this is where we want to start the @@ -2400,12 +2812,13 @@ ble_ll_conn_created(struct ble_ll_conn_sm *connsm, struct ble_mbuf_hdr *rxhdr) connsm->last_rxd_pdu_cputime = connsm->last_scheduled; /* - * Set first connection event time. If slave the endtime is the receive end + * Set first connection event time. If peripheral the endtime is the receive end * time of the connect request. The actual connection starts 1.25 msecs plus * the transmit window offset from the end of the connection request. */ rc = 1; - if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) { +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) + if (connsm->conn_role == BLE_LL_CONN_ROLE_PERIPHERAL) { /* * With a 32.768 kHz crystal we dont care about the remaining usecs * when setting last anchor point. The only thing last anchor is used @@ -2416,7 +2829,7 @@ ble_ll_conn_created(struct ble_ll_conn_sm *connsm, struct ble_mbuf_hdr *rxhdr) usecs = rxhdr->rem_usecs + 1250 + (connsm->tx_win_off * BLE_LL_CONN_TX_WIN_USECS) + - ble_ll_pdu_tx_time_get(BLE_CONNECT_REQ_LEN, + ble_ll_pdu_us(BLE_CONNECT_REQ_LEN, rxhdr->rxinfo.phy_mode); if (rxhdr->rxinfo.channel < BLE_PHY_NUM_DATA_CHANS) { @@ -2435,30 +2848,20 @@ ble_ll_conn_created(struct ble_ll_conn_sm *connsm, struct ble_mbuf_hdr *rxhdr) } /* Anchor point is cputime. */ - endtime = os_cputime_usecs_to_ticks(usecs); - connsm->anchor_point = rxhdr->beg_cputime + endtime; - connsm->anchor_point_usecs = usecs - os_cputime_ticks_to_usecs(endtime); - if (connsm->anchor_point_usecs == 31) { - ++connsm->anchor_point; - connsm->anchor_point_usecs = 0; - } + connsm->anchor_point = rxhdr->beg_cputime; + connsm->anchor_point_usecs = 0; + ble_ll_tmr_add(&connsm->anchor_point, &connsm->anchor_point_usecs, + usecs); - connsm->slave_cur_tx_win_usecs = + connsm->periph_cur_tx_win_usecs = connsm->tx_win_size * BLE_LL_CONN_TX_WIN_USECS; -#if MYNEWT_VAL(BLE_LL_STRICT_CONN_SCHEDULING) - connsm->ce_end_time = connsm->anchor_point + - g_ble_ll_sched_data.sch_ticks_per_period + - os_cputime_usecs_to_ticks(connsm->slave_cur_tx_win_usecs) + 1; - -#else connsm->ce_end_time = connsm->anchor_point + - (MYNEWT_VAL(BLE_LL_CONN_INIT_SLOTS) * BLE_LL_SCHED_32KHZ_TICKS_PER_SLOT) - + os_cputime_usecs_to_ticks(connsm->slave_cur_tx_win_usecs) + 1; -#endif - connsm->slave_cur_window_widening = BLE_LL_JITTER_USECS; + ble_ll_tmr_u2t(MYNEWT_VAL(BLE_LL_CONN_INIT_SLOTS) * + BLE_LL_SCHED_USECS_PER_SLOT + + connsm->periph_cur_tx_win_usecs) + 1; /* Start the scheduler for the first connection event */ - while (ble_ll_sched_slave_new(connsm)) { + while (ble_ll_sched_conn_periph_new(connsm)) { if (ble_ll_conn_next_event(connsm)) { STATS_INC(ble_ll_conn_stats, cant_set_sched); rc = 0; @@ -2466,10 +2869,11 @@ ble_ll_conn_created(struct ble_ll_conn_sm *connsm, struct ble_mbuf_hdr *rxhdr) } } } +#endif /* Send connection complete event to inform host of connection */ if (rc) { -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) +#if MYNEWT_VAL(BLE_LL_PHY) && MYNEWT_VAL(BLE_LL_CONN_PHY_INIT_UPDATE) /* * If we have default phy preferences and they are different than * the current PHY's in use, start update procedure. @@ -2478,13 +2882,20 @@ ble_ll_conn_created(struct ble_ll_conn_sm *connsm, struct ble_mbuf_hdr *rxhdr) * XXX: should we attempt to start this without knowing if * the other side can support it? */ - if (!ble_ll_conn_chk_phy_upd_start(connsm)) { - CONN_F_CTRLR_PHY_UPDATE(connsm) = 1; + if (!ble_ll_conn_phy_update_if_needed(connsm)) { + connsm->flags.phy_update_self_initiated = 1; } #endif - if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) { - ble_ll_adv_send_conn_comp_ev(connsm, rxhdr); - } else { + switch (connsm->conn_role) { +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + case BLE_LL_CONN_ROLE_CENTRAL: +#if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) + if (ble_ll_sched_css_is_enabled()) { + ble_ll_sched_css_update_anchor(connsm); + ble_ll_conn_css_set_next_slot(BLE_LL_CONN_CSS_NO_SLOT); + } +#endif + evbuf = ble_ll_init_get_conn_comp_ev(); ble_ll_conn_comp_event_send(connsm, BLE_ERR_SUCCESS, evbuf, NULL); #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CSA2) @@ -2494,12 +2905,22 @@ ble_ll_conn_created(struct ble_ll_conn_sm *connsm, struct ble_mbuf_hdr *rxhdr) /* * Initiate features exchange * - * XXX we do this only as a master as it was observed that sending - * LL_SLAVE_FEATURE_REQ after connection breaks some recent iPhone - * models; for slave just assume master will initiate features xchg + * XXX we do this only as a central as it was observed that sending + * LL_PERIPH_FEATURE_REQ after connection breaks some recent iPhone + * models; for peripheral just assume central will initiate features xchg * if it has some additional features to use. */ ble_ll_ctrl_proc_start(connsm, BLE_LL_CTRL_PROC_FEATURE_XCHG); + break; +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) + case BLE_LL_CONN_ROLE_PERIPHERAL: + ble_ll_adv_send_conn_comp_ev(connsm, rxhdr); + break; +#endif + default: + BLE_LL_ASSERT(0); + break; } } @@ -2526,20 +2947,6 @@ ble_ll_conn_event_end(struct ble_npl_event *ev) /* Better be a connection state machine! */ connsm = (struct ble_ll_conn_sm *)ble_npl_event_get_arg(ev); BLE_LL_ASSERT(connsm); - if (connsm->conn_state == BLE_LL_CONN_STATE_IDLE) { - /* That should not happen. If it does it means connection - * is already closed. - * Make sure LL state machine is in idle - */ - STATS_INC(ble_ll_conn_stats, sched_end_in_idle); - BLE_LL_ASSERT(0); - - /* Just in case */ - ble_ll_state_set(BLE_LL_STATE_STANDBY); - - ble_ll_scan_chk_resume(); - return; - } /* Log event end */ ble_ll_trace_u32x2(BLE_LL_TRACE_ID_CONN_EV_END, connsm->conn_handle, @@ -2548,10 +2955,10 @@ ble_ll_conn_event_end(struct ble_npl_event *ev) ble_ll_scan_chk_resume(); /* If we have transmitted the terminate IND successfully, we are done */ - if ((connsm->csmflags.cfbit.terminate_ind_txd) || - (connsm->csmflags.cfbit.terminate_ind_rxd && - connsm->csmflags.cfbit.terminate_ind_rxd_acked)) { - if (connsm->csmflags.cfbit.terminate_ind_txd) { + if ((connsm->flags.terminate_ind_txd) || + (connsm->flags.terminate_ind_rxd && + connsm->flags.terminate_ind_rxd_acked)) { + if (connsm->flags.terminate_ind_txd) { ble_err = BLE_ERR_CONN_TERM_LOCAL; } else { /* Make sure the disconnect reason is valid! */ @@ -2565,14 +2972,14 @@ ble_ll_conn_event_end(struct ble_npl_event *ev) } /* Remove any connection end events that might be enqueued */ - ble_npl_eventq_remove(&g_ble_ll_data.ll_evq, &connsm->conn_ev_end); + ble_ll_event_remove(&connsm->conn_ev_end); /* * If we have received a packet, we can set the current transmit window * usecs to 0 since we dont need to listen in the transmit window. */ - if (connsm->csmflags.cfbit.pkt_rxd) { - connsm->slave_cur_tx_win_usecs = 0; + if (connsm->flags.pkt_rxd) { + connsm->periph_cur_tx_win_usecs = 0; } #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_PING) @@ -2598,7 +3005,7 @@ ble_ll_conn_event_end(struct ble_npl_event *ev) /* Reset "per connection event" variables */ connsm->cons_rxd_bad_crc = 0; - connsm->csmflags.cfbit.pkt_rxd = 0; + connsm->flags.pkt_rxd = 0; /* See if we need to start any control procedures */ ble_ll_ctrl_chk_proc_start(connsm); @@ -2639,7 +3046,7 @@ ble_ll_conn_event_end(struct ble_npl_event *ev) ble_err = BLE_ERR_CONN_SPVN_TMO; } /* XXX: Convert to ticks to usecs calculation instead??? */ - tmo = os_cputime_usecs_to_ticks(tmo); + tmo = ble_ll_tmr_u2t(tmo); if ((int32_t)(connsm->anchor_point - connsm->last_rxd_pdu_cputime) >= tmo) { ble_ll_conn_end(connsm, ble_err); return; @@ -2649,10 +3056,10 @@ ble_ll_conn_event_end(struct ble_npl_event *ev) ble_ll_conn_num_comp_pkts_event_send(connsm); /* If we have features and there's pending HCI command, send an event */ - if (connsm->csmflags.cfbit.pending_hci_rd_features && - connsm->csmflags.cfbit.rxd_features) { + if (connsm->flags.features_host_req && + connsm->flags.features_rxd) { ble_ll_hci_ev_rd_rem_used_feat(connsm, BLE_ERR_SUCCESS); - connsm->csmflags.cfbit.pending_hci_rd_features = 0; + connsm->flags.features_host_req = 0; } } @@ -2668,18 +3075,15 @@ ble_ll_conn_event_end(struct ble_npl_event *ev) * @param txoffset The tx window offset for this connection */ -static void -ble_ll_conn_connect_ind_prepare(struct ble_ll_conn_sm *connsm, +void +ble_ll_conn_prepare_connect_ind(struct ble_ll_conn_sm *connsm, struct ble_ll_scan_pdu_data *pdu_data, - uint8_t adva_type, uint8_t *adva, - uint8_t inita_type, uint8_t *inita, - int rpa_index, uint8_t channel) + struct ble_ll_scan_addr_data *addrd, + uint8_t channel) { uint8_t hdr; uint8_t *addr; - #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - int is_rpa; struct ble_ll_resolv_entry *rl; #endif @@ -2692,19 +3096,45 @@ ble_ll_conn_connect_ind_prepare(struct ble_ll_conn_sm *connsm, } #endif - if (adva_type) { + if (addrd->adva_type) { /* Set random address */ hdr |= BLE_ADV_PDU_HDR_RXADD_MASK; } - if (inita) { - memcpy(pdu_data->inita, inita, BLE_DEV_ADDR_LEN); - if (inita_type) { + if (addrd->targeta) { +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + if (addrd->targeta_resolved) { + if (connsm->own_addr_type > BLE_OWN_ADDR_RANDOM) { + /* If TargetA was resolved we should reply with a different RPA + * in InitA (see Core 5.3, Vol 6, Part B, 6.4). + */ + BLE_LL_ASSERT(addrd->rpa_index >= 0); + rl = &g_ble_ll_resolv_list[addrd->rpa_index]; + hdr |= BLE_ADV_PDU_HDR_TXADD_RAND; + ble_ll_resolv_get_priv_addr(rl, 1, pdu_data->inita); + } else { + /* Host does not want us to use RPA so use identity */ + if ((connsm->own_addr_type & 1) == 0) { + memcpy(pdu_data->inita, g_dev_addr, BLE_DEV_ADDR_LEN); + } else { + hdr |= BLE_ADV_PDU_HDR_TXADD_RAND; + memcpy(pdu_data->inita, g_random_addr, BLE_DEV_ADDR_LEN); + } + } + } else { + memcpy(pdu_data->inita, addrd->targeta, BLE_DEV_ADDR_LEN); + if (addrd->targeta_type) { + hdr |= BLE_ADV_PDU_HDR_TXADD_RAND; + } + } +#else + memcpy(pdu_data->inita, addrd->targeta, BLE_DEV_ADDR_LEN); + if (addrd->targeta_type) { hdr |= BLE_ADV_PDU_HDR_TXADD_RAND; } +#endif } else { /* Get pointer to our device address */ - connsm = g_ble_ll_conn_create_sm; if ((connsm->own_addr_type & 1) == 0) { addr = g_dev_addr; } else { @@ -2715,28 +3145,19 @@ ble_ll_conn_connect_ind_prepare(struct ble_ll_conn_sm *connsm, /* XXX: do this ahead of time? Calculate the local rpa I mean */ #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) if (connsm->own_addr_type > BLE_HCI_ADV_OWN_ADDR_RANDOM) { - rl = NULL; - is_rpa = ble_ll_is_rpa(adva, adva_type); - if (is_rpa) { - if (rpa_index >= 0) { - rl = &g_ble_ll_resolv_list[rpa_index]; - } - } else { - /* we look for RL entry to generate local RPA regardless if - * resolving is enabled or not (as this is is for local RPA - * not peer RPA) + if (addrd->rpa_index >= 0) { + /* We are using RPA and advertiser was on our resolving list, so + * we'll use RPA to reply (see Core 5.3, Vol 6, Part B, 6.4). */ - rl = ble_ll_resolv_list_find(adva, adva_type); - } - - /* - * If peer in on resolving list, we use RPA generated with Local IRK - * from resolving list entry. In other case, we need to use our identity - * address (see Core 5.0, Vol 6, Part B, section 6.4). - */ - if (rl && rl->rl_has_local) { + rl = &g_ble_ll_resolv_list[addrd->rpa_index]; + if (rl->rl_has_local) { + hdr |= BLE_ADV_PDU_HDR_TXADD_RAND; + ble_ll_resolv_get_priv_addr(rl, 1, pdu_data->inita); + addr = NULL; + } + } else if (ble_ll_resolv_local_rpa_get(connsm->own_addr_type & 1, + pdu_data->inita) == 0) { hdr |= BLE_ADV_PDU_HDR_TXADD_RAND; - ble_ll_resolv_get_priv_addr(rl, 1, pdu_data->inita); addr = NULL; } } @@ -2749,115 +3170,13 @@ ble_ll_conn_connect_ind_prepare(struct ble_ll_conn_sm *connsm, } } - memcpy(pdu_data->adva, adva, BLE_DEV_ADDR_LEN); + memcpy(pdu_data->adva, addrd->adva, BLE_DEV_ADDR_LEN); pdu_data->hdr_byte = hdr; } -/* Returns true if the address matches the connection peer address having in - * mind privacy mode - */ -static int -ble_ll_conn_is_peer_adv(uint8_t addr_type, uint8_t *adva, int index) -{ - int rc; - uint8_t *peer_addr = NULL; - struct ble_ll_conn_sm *connsm; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - struct ble_ll_resolv_entry *rl; -#endif - - /* XXX: Deal with different types of random addresses here! */ - connsm = g_ble_ll_conn_create_sm; - if (!connsm) { - return 0; - } - - switch (connsm->peer_addr_type) { - /* Fall-through intentional */ - case BLE_HCI_CONN_PEER_ADDR_PUBLIC: - case BLE_HCI_CONN_PEER_ADDR_RANDOM: -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - if (ble_ll_addr_is_id(adva, addr_type)) { - /* Peer uses its identity address. Let's verify privacy mode. - * - * Note: Core Spec 5.0 Vol 6, Part B - * If the Host has added the peer device to the resolving list - * with an all-zero peer IRK, the Controller shall only accept - * the peer's identity address. - */ - if (ble_ll_resolv_enabled()) { - rl = ble_ll_resolv_list_find(adva, addr_type); - if (rl && (rl->rl_priv_mode == BLE_HCI_PRIVACY_NETWORK) && - rl->rl_has_peer) { - return 0; - } - } - } - - /* Check if peer uses RPA. If so and it match, use it as controller - * supports privacy mode - */ - if ((index >= 0) && - (g_ble_ll_resolv_list[index].rl_addr_type == connsm->peer_addr_type)) { - peer_addr = g_ble_ll_resolv_list[index].rl_identity_addr; - } -#endif - /* - * If we are here it means we don't know the device, lets - * check if type is what we are looking for and later - * if address matches - */ - if ((connsm->peer_addr_type == addr_type) && !peer_addr) { - peer_addr = adva; - } - - break; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - case BLE_HCI_CONN_PEER_ADDR_PUBLIC_IDENT: - if ((index < 0) || - (g_ble_ll_resolv_list[index].rl_addr_type != 0)) { - return 0; - } - peer_addr = g_ble_ll_resolv_list[index].rl_identity_addr; - break; - case BLE_HCI_CONN_PEER_ADDR_RANDOM_IDENT: - if ((index < 0) || - (g_ble_ll_resolv_list[index].rl_addr_type != 1)) { - return 0; - } - peer_addr = g_ble_ll_resolv_list[index].rl_identity_addr; - break; -#endif - default: - peer_addr = NULL; - break; - } - - rc = 0; - if (peer_addr) { - if (!memcmp(peer_addr, connsm->peer_addr, BLE_DEV_ADDR_LEN)) { - rc = 1; - } - } - - return rc; -} - -static void -ble_ll_conn_connect_ind_txend_to_standby(void *arg) -{ - ble_ll_state_set(BLE_LL_STATE_STANDBY); -} - -static void -ble_ll_conn_connect_ind_txend_to_init(void *arg) -{ - ble_ll_state_set(BLE_LL_STATE_INITIATING); -} - -static uint8_t -ble_ll_conn_connect_ind_tx_pducb(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte) +uint8_t +ble_ll_conn_tx_connect_ind_pducb(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte) { struct ble_ll_conn_sm *connsm; struct ble_ll_scan_pdu_data *pdu_data; @@ -2881,40 +3200,16 @@ ble_ll_conn_connect_ind_tx_pducb(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_by dptr[7] = connsm->tx_win_size; put_le16(dptr + 8, connsm->tx_win_off); put_le16(dptr + 10, connsm->conn_itvl); - put_le16(dptr + 12, connsm->slave_latency); + put_le16(dptr + 12, connsm->periph_latency); put_le16(dptr + 14, connsm->supervision_tmo); - memcpy(dptr + 16, &connsm->chanmap, BLE_LL_CONN_CHMAP_LEN); - dptr[21] = connsm->hop_inc | (connsm->master_sca << 5); + memcpy(dptr + 16, &connsm->chan_map, BLE_LL_CHAN_MAP_LEN); + dptr[21] = connsm->hop_inc | (connsm->central_sca << 5); *hdr_byte = pdu_data->hdr_byte; return 34; } -/** - * Send a connection requestion to an advertiser - * - * Context: Interrupt - * - * @param addr_type Address type of advertiser - * @param adva Address of advertiser - */ -int -ble_ll_conn_connect_ind_send(struct ble_ll_conn_sm *connsm, uint8_t end_trans) -{ - int rc; - - if (end_trans == BLE_PHY_TRANSITION_NONE) { - ble_phy_set_txend_cb(ble_ll_conn_connect_ind_txend_to_standby, NULL); - } else { - ble_phy_set_txend_cb(ble_ll_conn_connect_ind_txend_to_init, NULL); - } - - rc = ble_phy_tx(ble_ll_conn_connect_ind_tx_pducb, connsm, end_trans); - - return rc; -} - /** * Called when a schedule item overlaps the currently running connection * event. This generally should not happen, but if it does we stop the @@ -2926,589 +3221,170 @@ ble_ll_conn_connect_ind_send(struct ble_ll_conn_sm *connsm, uint8_t end_trans) void ble_ll_conn_event_halt(void) { - ble_ll_state_set(BLE_LL_STATE_STANDBY); - if (g_ble_ll_conn_cur_sm) { - g_ble_ll_conn_cur_sm->csmflags.cfbit.pkt_rxd = 0; - ble_ll_event_send(&g_ble_ll_conn_cur_sm->conn_ev_end); - g_ble_ll_conn_cur_sm = NULL; - } -} - -/** - * Process a received PDU while in the initiating state. - * - * Context: Link Layer task. - * - * @param pdu_type - * @param rxbuf - * @param ble_hdr - */ -void -ble_ll_init_rx_pkt_in(uint8_t pdu_type, uint8_t *rxbuf, - struct ble_mbuf_hdr *ble_hdr) -{ - uint8_t addr_type; - uint8_t *addr; - uint8_t *adv_addr; - uint8_t *inita; - uint8_t inita_type; - struct ble_ll_conn_sm *connsm; - int ext_adv_mode = -1; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - struct ble_ll_aux_data *aux_data = NULL; - - if (ble_hdr->rxinfo.user_data) { - /* aux_data just a local helper, no need to ref - * as ble_hdr->rxinfo.user_data is unref in the end of this function - */ - aux_data = ble_hdr->rxinfo.user_data; - } -#endif - - /* Get the connection state machine we are trying to create */ - connsm = g_ble_ll_conn_create_sm; - if (!connsm) { -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - if (aux_data) { - ble_ll_scan_aux_data_unref(ble_hdr->rxinfo.user_data); - ble_hdr->rxinfo.user_data = NULL; - } -#endif - return; - } - - if (!BLE_MBUF_HDR_CRC_OK(ble_hdr)) { - goto scan_continue; - } - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - if (BLE_MBUF_HDR_AUX_INVALID(ble_hdr)) { - goto scan_continue; - } - - if (pdu_type == BLE_ADV_PDU_TYPE_ADV_EXT_IND) { - if (BLE_MBUF_HDR_WAIT_AUX(ble_hdr)) { - /* Just continue scanning. We are waiting for AUX */ - if (!ble_ll_sched_aux_scan(ble_hdr, connsm->scansm, aux_data)) { - /* ref for aux ptr in the scheduler */ - ble_ll_scan_aux_data_unref(ble_hdr->rxinfo.user_data); - ble_hdr->rxinfo.user_data = NULL; - ble_ll_scan_chk_resume(); - return; - } - goto scan_continue; - } - } - - if (CONN_F_AUX_CONN_REQ(connsm)) { - if (pdu_type != BLE_ADV_PDU_TYPE_AUX_CONNECT_RSP) { - /* Wait for connection response, in this point of time aux is NULL */ - BLE_LL_ASSERT(ble_hdr->rxinfo.user_data == NULL); - return; - } - } -#endif - - /* If we have sent a connect request, we need to enter CONNECTION state */ - if (connsm && CONN_F_CONN_REQ_TXD(connsm)) { - /* Set address of advertiser to which we are connecting. */ - - if (ble_ll_scan_adv_decode_addr(pdu_type, rxbuf, ble_hdr, - &adv_addr, &addr_type, - &inita, &inita_type, &ext_adv_mode)) { - /* Something got wrong, keep trying to connect */ - goto scan_continue; - } - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - /* - * Did we resolve this address? If so, set correct peer address - * and peer address type. - */ - if (connsm->rpa_index >= 0) { - addr_type = g_ble_ll_resolv_list[connsm->rpa_index].rl_addr_type + 2; - addr = g_ble_ll_resolv_list[connsm->rpa_index].rl_identity_addr; - } else { - addr = adv_addr; - } -#else - addr = adv_addr; -#endif - - if (connsm->rpa_index >= 0) { - connsm->peer_addr_type = addr_type; - memcpy(connsm->peer_addr, addr, BLE_DEV_ADDR_LEN); - - ble_ll_scan_set_peer_rpa(adv_addr); - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - /* Update resolving list with current peer RPA */ - ble_ll_resolv_set_peer_rpa(connsm->rpa_index, rxbuf + BLE_LL_PDU_HDR_LEN); - if (ble_ll_is_rpa(inita, inita_type)) { - ble_ll_resolv_set_local_rpa(connsm->rpa_index, inita); - } - -#endif - } else if (ble_ll_scan_whitelist_enabled()) { - /* if WL is used we need to store peer addr also if it was not - * resolved - */ - connsm->peer_addr_type = addr_type; - memcpy(connsm->peer_addr, addr, BLE_DEV_ADDR_LEN); - } - - /* Connection has been created. Stop scanning */ - g_ble_ll_conn_create_sm = NULL; - ble_ll_scan_sm_stop(0); - - /* For AUX Connect CSA2 is mandatory. Otherwise we need to check bit - * mask - */ - if (ble_hdr->rxinfo.channel < BLE_PHY_NUM_DATA_CHANS) { - ble_ll_conn_set_csa(connsm, 1); - } else { - ble_ll_conn_set_csa(connsm, rxbuf[0] & BLE_ADV_PDU_HDR_CHSEL_MASK); - } - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) - /* Lets take last used phy */ - ble_ll_conn_init_phy(connsm, ble_hdr->rxinfo.phy); -#endif - if (aux_data) { - ble_ll_scan_aux_data_unref(ble_hdr->rxinfo.user_data); - ble_hdr->rxinfo.user_data = NULL; - } -#endif - ble_ll_conn_created(connsm, NULL); - return; - } - -scan_continue: -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - /* Drop last reference and keep continue to connect */ - if (aux_data) { - ble_ll_scan_aux_data_unref(ble_hdr->rxinfo.user_data); - ble_hdr->rxinfo.user_data = NULL; - } -#endif - ble_ll_scan_chk_resume(); -} - -/** - * Called when a receive PDU has started and we are in the initiating state. - * - * Context: Interrupt - * - * @param pdu_type - * @param ble_hdr - * - * @return int - * 0: we will not attempt to reply to this frame - * 1: we may send a response to this frame. - */ -int -ble_ll_init_rx_isr_start(uint8_t pdu_type, struct ble_mbuf_hdr *ble_hdr) -{ - struct ble_ll_conn_sm *connsm; - - connsm = g_ble_ll_conn_create_sm; - if (!connsm) { - return 0; - } - - if ((pdu_type == BLE_ADV_PDU_TYPE_ADV_IND) || - (pdu_type == BLE_ADV_PDU_TYPE_ADV_DIRECT_IND || - pdu_type == BLE_ADV_PDU_TYPE_AUX_CONNECT_RSP)) { - return 1; - } - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - if (pdu_type == BLE_ADV_PDU_TYPE_ADV_EXT_IND && - connsm->scansm->ext_scanning) { - if (connsm->scansm->cur_aux_data) { - STATS_INC(ble_ll_stats, aux_received); - } - - ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_EXT_ADV; - return 1; - } -#endif - - return 0; -} - -/** - * Called when a receive PDU has ended and we are in the initiating state. - * - * Context: Interrupt - * - * @param rxpdu - * @param crcok - * @param ble_hdr - * - * @return int - * < 0: Disable the phy after reception. - * == 0: Success. Do not disable the PHY. - * > 0: Do not disable PHY as that has already been done. - */ -int -ble_ll_init_rx_isr_end(uint8_t *rxbuf, uint8_t crcok, - struct ble_mbuf_hdr *ble_hdr) -{ - int rc; - int resolved; - int chk_wl; - int index; - uint8_t pdu_type; - uint8_t adv_addr_type; - uint8_t peer_addr_type; - uint8_t *adv_addr = NULL; - uint8_t *peer; - uint8_t *init_addr = NULL; - uint8_t init_addr_type; - uint8_t pyld_len; - uint8_t inita_is_rpa; - uint8_t conn_req_end_trans; - struct os_mbuf *rxpdu; - struct ble_ll_conn_sm *connsm; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - struct ble_ll_resolv_entry *rl; -#endif -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - struct ble_ll_scan_sm *scansm; - uint8_t phy; -#endif - int ext_adv_mode = -1; - - /* Get connection state machine to use if connection to be established */ - connsm = g_ble_ll_conn_create_sm; - /* This could happen if connection init was cancelled while isr end was - * already pending - */ - if (!connsm) { - ble_ll_state_set(BLE_LL_STATE_STANDBY); - return -1; - } - - rc = -1; - pdu_type = rxbuf[0] & BLE_ADV_PDU_HDR_TYPE_MASK; - pyld_len = rxbuf[1]; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - scansm = connsm->scansm; - if (scansm->cur_aux_data) { - ble_hdr->rxinfo.user_data = scansm->cur_aux_data; - scansm->cur_aux_data = NULL; - } -#endif - - if (!crcok) { -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - /* Invalid packet - make sure we do not wait for AUX_CONNECT_RSP */ - ble_ll_conn_reset_pending_aux_conn_rsp(); -#endif - - /* Ignore this packet */ - goto init_rx_isr_exit; - } - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - /* If we sent AUX_CONNECT_REQ, we only expect AUX_CONNECT_RSP here */ - if (CONN_F_AUX_CONN_REQ(connsm)) { - if (pdu_type != BLE_ADV_PDU_TYPE_AUX_CONNECT_RSP) { - STATS_INC(ble_ll_stats, aux_conn_rsp_err); - CONN_F_CONN_REQ_TXD(connsm) = 0; - CONN_F_AUX_CONN_REQ(connsm) = 0; - ble_ll_sched_rmv_elem(&connsm->conn_sch); - } - goto init_rx_isr_exit; + ble_ll_state_set(BLE_LL_STATE_STANDBY); + if (g_ble_ll_conn_cur_sm) { + g_ble_ll_conn_cur_sm->flags.pkt_rxd = 0; + ble_ll_event_add(&g_ble_ll_conn_cur_sm->conn_ev_end); + g_ble_ll_conn_cur_sm = NULL; } -#endif +} - inita_is_rpa = 0; +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) +int +ble_ll_conn_send_connect_req(struct os_mbuf *rxpdu, + struct ble_ll_scan_addr_data *addrd, + uint8_t ext) +{ + struct ble_ll_conn_sm *connsm; + struct ble_mbuf_hdr *rxhdr; + uint8_t phy; + uint8_t phy_mode; + uint32_t sch_next; + uint32_t conn_req_us; + uint32_t conn_req_end; + int rc; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - if (pdu_type == BLE_ADV_PDU_TYPE_ADV_EXT_IND) { - if (!scansm->ext_scanning) { - goto init_rx_isr_exit; - } + connsm = g_ble_ll_conn_create_sm.connsm; + rxhdr = BLE_MBUF_HDR_PTR(rxpdu); - rc = ble_ll_scan_update_aux_data(ble_hdr, rxbuf, NULL); - if (rc < 0) { - /* No memory or broken packet */ - ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_AUX_INVALID; - goto init_rx_isr_exit; - } - } +#if MYNEWT_VAL(BLE_LL_PHY) + phy = rxhdr->rxinfo.phy; + phy_mode = rxhdr->rxinfo.phy_mode; +#else + phy = BLE_PHY_1M; + phy_mode = BLE_PHY_MODE_1M; #endif - /* Lets get addresses from advertising report*/ - if (ble_ll_scan_adv_decode_addr(pdu_type, rxbuf, ble_hdr, - &adv_addr, &adv_addr_type, - &init_addr, &init_addr_type, - &ext_adv_mode)) { #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_AUX_INVALID; -#endif - goto init_rx_isr_exit; + if (ext) { + ble_ll_conn_create_set_params(connsm, phy); } +#else + (void)phy; +#endif - switch (pdu_type) { - case BLE_ADV_PDU_TYPE_ADV_IND: - break; - + rc = ble_ll_sched_next_time(&sch_next); + if (rc) { + conn_req_us = rxhdr->rem_usecs + ble_ll_pdu_us(34, phy_mode); #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - case BLE_ADV_PDU_TYPE_ADV_EXT_IND: - rc = -1; - - /* If this is not connectable adv mode, lets skip it */ - if (!(ext_adv_mode & BLE_LL_EXT_ADV_MODE_CONN)) { - goto init_rx_isr_exit; - } - - if (!adv_addr) { - ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_AUX_PTR_WAIT; - goto init_rx_isr_exit; - } - - if (!init_addr) { - break; + if (ext) { + conn_req_us += BLE_LL_IFS + ble_ll_pdu_us(14, phy_mode); } - /* if there is direct address lets fall down and check it.*/ - // no break #endif - case BLE_ADV_PDU_TYPE_ADV_DIRECT_IND: - inita_is_rpa = (uint8_t)ble_ll_is_rpa(init_addr, init_addr_type); - if (!inita_is_rpa) { + conn_req_end = rxhdr->beg_cputime + ble_ll_tmr_u2t_up(conn_req_us); - /* Resolving will be done later. Check if identity InitA matches */ - if (!ble_ll_is_our_devaddr(init_addr, init_addr_type)) { - goto init_rx_isr_exit; - } - } -#if !MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - else { - /* If privacy is off - reject RPA InitA*/ - goto init_rx_isr_exit; + if (LL_TMR_LEQ(sch_next, conn_req_end)) { + return -1; } -#endif - - break; - default: - goto init_rx_isr_exit; } - /* Should we send a connect request? */ - index = -1; - peer = adv_addr; - peer_addr_type = adv_addr_type; - - resolved = 0; - chk_wl = ble_ll_scan_whitelist_enabled(); + if (ble_ll_sched_conn_central_new(connsm, rxhdr, 0)) { + return -1; + } -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - if (ble_ll_is_rpa(adv_addr, adv_addr_type) && ble_ll_resolv_enabled()) { - index = ble_hw_resolv_list_match(); - if (index >= 0) { - rl = &g_ble_ll_resolv_list[index]; - - ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_RESOLVED; - connsm->rpa_index = index; - peer = rl->rl_identity_addr; - peer_addr_type = rl->rl_addr_type; - resolved = 1; - - /* Assure privacy */ - if ((rl->rl_priv_mode == BLE_HCI_PRIVACY_NETWORK) && init_addr && - !inita_is_rpa && rl->rl_has_local) { - goto init_rx_isr_exit; - } + ble_ll_conn_prepare_connect_ind(connsm, ble_ll_scan_get_pdu_data(), addrd, + rxhdr->rxinfo.channel); - /* - * If the InitA is a RPA, we must see if it resolves based on the - * identity address of the resolved ADVA. - */ - if (init_addr && inita_is_rpa) { - if (!ble_ll_resolv_rpa(init_addr, - g_ble_ll_resolv_list[index].rl_local_irk)) { - goto init_rx_isr_exit; - } + ble_phy_set_txend_cb(NULL, NULL); + rc = ble_phy_tx(ble_ll_conn_tx_connect_ind_pducb, connsm, + ext ? BLE_PHY_TRANSITION_TX_RX : BLE_PHY_TRANSITION_NONE); + if (rc) { + ble_ll_conn_send_connect_req_cancel(); + return -1; + } - /* Core Specification Vol 6, Part B, Section 6.4: - * "The Link Layer should not set the InitA field to the same - * value as the TargetA field in the received advertising PDU." - * - * We update the received PDU directly here, so ble_ll_init_rx_pkt_in - * can process it as is. - */ - memcpy(init_addr, rl->rl_local_rpa, BLE_DEV_ADDR_LEN); - } +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) && MYNEWT_VAL(BLE_LL_PHY) + if (ext) { + ble_ll_conn_init_phy(connsm, phy); + } +#endif - } else { - if (chk_wl) { - goto init_rx_isr_exit; - } + return 0; +} - /* Could not resolved InitA */ - if (init_addr && inita_is_rpa) { - goto init_rx_isr_exit; - } - } - } else if (init_addr) { +void +ble_ll_conn_send_connect_req_cancel(void) +{ + struct ble_ll_conn_sm *connsm; - /* If resolving is off and InitA is RPA we reject advertising */ - if (inita_is_rpa && !ble_ll_resolv_enabled()) { - goto init_rx_isr_exit; - } + connsm = g_ble_ll_conn_create_sm.connsm; - /* Let's see if we have IRK with that peer.*/ - rl = ble_ll_resolv_list_find(adv_addr, adv_addr_type); + ble_ll_sched_rmv_elem(&connsm->conn_sch); +} - /* Lets make sure privacy mode is correct together with InitA in case it - * is identity address - */ - if (rl && !inita_is_rpa && - (rl->rl_priv_mode == BLE_HCI_PRIVACY_NETWORK) && - rl->rl_has_local) { - goto init_rx_isr_exit; - } +static void +ble_ll_conn_central_start(uint8_t phy, uint8_t csa, + struct ble_ll_scan_addr_data *addrd, uint8_t *targeta) +{ + struct ble_ll_conn_sm *connsm; - /* - * If the InitA is a RPA, we must see if it resolves based on the - * identity address of the resolved ADVA. - */ - if (inita_is_rpa) { - if (!rl || !ble_ll_resolv_rpa(init_addr, rl->rl_local_irk)) { - goto init_rx_isr_exit; - } + connsm = g_ble_ll_conn_create_sm.connsm; + g_ble_ll_conn_create_sm.connsm = NULL; - /* Core Specification Vol 6, Part B, Section 6.4: - * "The Link Layer should not set the InitA field to the same - * value as the TargetA field in the received advertising PDU." - * - * We update the received PDU directly here, so ble_ll_init_rx_pkt_in - * can process it as is. - */ - memcpy(init_addr, rl->rl_local_rpa, BLE_DEV_ADDR_LEN); - } - } else if (!ble_ll_is_rpa(adv_addr, adv_addr_type)) { - /* undirected with ID address, assure privacy if on RL */ - rl = ble_ll_resolv_list_find(adv_addr, adv_addr_type); - if (rl && (rl->rl_priv_mode == BLE_HCI_PRIVACY_NETWORK) && - rl->rl_has_peer) { - goto init_rx_isr_exit; - } - } -#endif + connsm->peer_addr_type = addrd->adv_addr_type; + memcpy(connsm->peer_addr, addrd->adv_addr, 6); - /* Check filter policy */ - if (chk_wl) { - if (!ble_ll_whitelist_match(peer, peer_addr_type, resolved)) { - goto init_rx_isr_exit; - } +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + if (addrd->adva_resolved) { + BLE_LL_ASSERT(addrd->rpa_index >= 0); + connsm->peer_addr_resolved = 1; + ble_ll_resolv_set_peer_rpa(addrd->rpa_index, addrd->adva); + ble_ll_scan_set_peer_rpa(addrd->adva); } else { - /* Must match the connection address */ - if (!ble_ll_conn_is_peer_adv(adv_addr_type, adv_addr, index)) { - goto init_rx_isr_exit; - } - } - ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_DEVMATCH; - - /* For CONNECT_IND we don't go into RX state */ - conn_req_end_trans = BLE_PHY_TRANSITION_NONE; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - /* Check if we should send AUX_CONNECT_REQ and wait for AUX_CONNECT_RSP */ - if (ble_hdr->rxinfo.channel < BLE_PHY_NUM_DATA_CHANS) { - conn_req_end_trans = BLE_PHY_TRANSITION_TX_RX; + connsm->peer_addr_resolved = 0; } - if (connsm->scansm->ext_scanning) { - phy = ble_hdr->rxinfo.phy; - - /* Update connection state machine with appropriate parameters for - * certain PHY - */ - ble_ll_conn_ext_set_params(connsm, - &connsm->initial_params.params[phy - 1], - phy); - + if (addrd->targeta_resolved) { + BLE_LL_ASSERT(addrd->rpa_index >= 0); + BLE_LL_ASSERT(targeta); } #endif - /* Schedule new connection */ - if (ble_ll_sched_master_new(connsm, ble_hdr, pyld_len)) { - STATS_INC(ble_ll_conn_stats, cant_set_sched); - goto init_rx_isr_exit; - } - - /* Prepare data for connect request */ - ble_ll_conn_connect_ind_prepare(connsm, - ble_ll_scan_get_pdu_data(), - adv_addr_type, adv_addr, - init_addr_type, init_addr, - index, ble_hdr->rxinfo.channel); + ble_ll_conn_set_csa(connsm, csa); +#if MYNEWT_VAL(BLE_LL_PHY) + ble_ll_conn_init_phy(connsm, phy); +#endif + ble_ll_conn_created(connsm, NULL); +} - /* Setup to transmit the connect request */ - rc = ble_ll_conn_connect_ind_send(connsm, conn_req_end_trans); - if (rc) { - ble_ll_sched_rmv_elem(&connsm->conn_sch); - goto init_rx_isr_exit; - } +void +ble_ll_conn_created_on_legacy(struct os_mbuf *rxpdu, + struct ble_ll_scan_addr_data *addrd, + uint8_t *targeta) +{ + uint8_t *rxbuf; + uint8_t csa; - if (init_addr && !inita_is_rpa) { - connsm->inita_identity_used = 1; - } + rxbuf = rxpdu->om_data; + csa = rxbuf[0] & BLE_ADV_PDU_HDR_CHSEL_MASK; - CONN_F_CONN_REQ_TXD(connsm) = 1; + ble_ll_conn_central_start(BLE_PHY_1M, csa, addrd, targeta); +} +#endif #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - if (ble_hdr->rxinfo.channel < BLE_PHY_NUM_DATA_CHANS) { - /* Lets wait for AUX_CONNECT_RSP */ - CONN_F_AUX_CONN_REQ(connsm) = 1; - /* Keep aux data until we get scan response */ - scansm->cur_aux_data = ble_hdr->rxinfo.user_data; - ble_hdr->rxinfo.user_data = NULL; - STATS_INC(ble_ll_stats, aux_conn_req_tx); - } +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) +void +ble_ll_conn_created_on_aux(struct os_mbuf *rxpdu, + struct ble_ll_scan_addr_data *addrd, + uint8_t *targeta) +{ +#if MYNEWT_VAL(BLE_LL_PHY) + struct ble_mbuf_hdr *rxhdr; #endif + uint8_t phy; - STATS_INC(ble_ll_conn_stats, conn_req_txd); - -init_rx_isr_exit: - - /* - * We have to restart receive if we cant hand up pdu. We return 0 so that - * the phy does not get disabled. - */ - rxpdu = ble_ll_rxpdu_alloc(pyld_len + BLE_LL_PDU_HDR_LEN); - if (rxpdu == NULL) { - /* - * XXX: possible allocate the PDU when we start initiating? - * I cannot say I like this solution, but if we cannot allocate a PDU - * to hand up to the LL, we need to remove the connection we just - * scheduled since the connection state machine will not get processed - * by link layer properly. For now, just remove it from the scheduler - */ - if (CONN_F_CONN_REQ_TXD(connsm) == 1) { - CONN_F_CONN_REQ_TXD(connsm) = 0; - CONN_F_AUX_CONN_REQ(connsm) = 0; - ble_ll_sched_rmv_elem(&connsm->conn_sch); - } - ble_phy_restart_rx(); - rc = 0; - } else { - ble_phy_rxpdu_copy(rxbuf, rxpdu); - ble_ll_rx_pdu_in(rxpdu); - } - - if (rc) { - ble_ll_state_set(BLE_LL_STATE_STANDBY); - } +#if MYNEWT_VAL(BLE_LL_PHY) + rxhdr = BLE_MBUF_HDR_PTR(rxpdu); + phy = rxhdr->rxinfo.phy; +#else + phy = BLE_PHY_1M; +#endif - return rc; + ble_ll_conn_central_start(phy, 1, addrd, targeta); } +#endif +#endif /* BLE_LL_CFG_FEAT_LL_EXT_ADV */ /** * Function called when a timeout has occurred for a connection. There are @@ -3568,7 +3444,7 @@ ble_ll_conn_rx_isr_start(struct ble_mbuf_hdr *rxhdr, uint32_t aa) if (aa != connsm->access_addr) { STATS_INC(ble_ll_conn_stats, rx_data_pdu_bad_aa); ble_ll_state_set(BLE_LL_STATE_STANDBY); - ble_ll_event_send(&connsm->conn_ev_end); + ble_ll_event_add(&connsm->conn_ev_end); g_ble_ll_conn_cur_sm = NULL; return -1; } @@ -3577,14 +3453,14 @@ ble_ll_conn_rx_isr_start(struct ble_mbuf_hdr *rxhdr, uint32_t aa) rxhdr->rxinfo.handle = connsm->conn_handle; /* Set flag denoting we have received a packet in connection event */ - connsm->csmflags.cfbit.pkt_rxd = 1; + connsm->flags.pkt_rxd = 1; /* Connection is established */ connsm->conn_state = BLE_LL_CONN_STATE_ESTABLISHED; /* Set anchor point (and last) if 1st rxd frame in connection event */ - if (connsm->csmflags.cfbit.slave_set_last_anchor) { - connsm->csmflags.cfbit.slave_set_last_anchor = 0; + if (connsm->flags.periph_set_last_anchor) { + connsm->flags.periph_set_last_anchor = 0; connsm->last_anchor_point = rxhdr->beg_cputime; connsm->anchor_point = connsm->last_anchor_point; connsm->anchor_point_usecs = rxhdr->rem_usecs; @@ -3618,7 +3494,7 @@ ble_ll_conn_rx_data_pdu(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *hdr) /* XXX: there is a chance that the connection was thrown away and re-used before processing packets here. Fix this. */ /* We better have a connection state machine */ - connsm = ble_ll_conn_find_active_conn(hdr->rxinfo.handle); + connsm = ble_ll_conn_find_by_handle(hdr->rxinfo.handle); if (!connsm) { STATS_INC(ble_ll_conn_stats, no_conn_sm); goto conn_rx_data_pdu_end; @@ -3632,6 +3508,21 @@ ble_ll_conn_rx_data_pdu(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *hdr) hdr_byte = rxbuf[0]; acl_len = rxbuf[1]; llid = hdr_byte & BLE_LL_DATA_HDR_LLID_MASK; + rxd_sn = hdr_byte & BLE_LL_DATA_HDR_SN_MASK; + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) + if (BLE_MBUF_HDR_MIC_FAILURE(hdr)) { + /* MIC failure is expected on retransmissions since packet counter does + * not match, so we simply ignore retransmitted PDU with MIC failure as + * they do not have proper decrypted contents. + */ + if (rxd_sn != connsm->last_rxd_sn) { + STATS_INC(ble_ll_conn_stats, mic_failures); + ble_ll_conn_timeout(connsm, BLE_ERR_CONN_TERM_MIC); + } + goto conn_rx_data_pdu_end; + } +#endif /* * Check that the LLID and payload length are reasonable. @@ -3649,10 +3540,10 @@ ble_ll_conn_rx_data_pdu(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *hdr) * Reference: Core 5.0, Vol 6, Part B, 5.1.3.1 */ if ((connsm->enc_data.enc_state > CONN_ENC_S_PAUSE_ENC_RSP_WAIT && - CONN_IS_MASTER(connsm)) || + CONN_IS_CENTRAL(connsm)) || (connsm->enc_data.enc_state >= CONN_ENC_S_ENC_RSP_TO_BE_SENT && - CONN_IS_SLAVE(connsm))) { - if (!ble_ll_ctrl_enc_allowed_pdu_rx(rxpdu)) { + CONN_IS_PERIPHERAL(connsm))) { + if (!ble_ll_ctrl_enc_allowed_pdu_rx(connsm, rxpdu)) { ble_ll_conn_timeout(connsm, BLE_ERR_CONN_TERM_MIC); goto conn_rx_data_pdu_end; } @@ -3666,29 +3557,30 @@ ble_ll_conn_rx_data_pdu(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *hdr) * connection */ if ((connsm->enc_data.enc_state == CONN_ENC_S_ENCRYPTED) && - CONN_F_LE_PING_SUPP(connsm) && (acl_len != 0)) { + connsm->flags.le_ping_supp && (acl_len != 0)) { ble_ll_conn_auth_pyld_timer_start(connsm); } #endif /* Update RSSI */ - connsm->conn_rssi = hdr->rxinfo.rssi; + connsm->conn_rssi = hdr->rxinfo.rssi - ble_ll_rx_gain(); /* - * If we are a slave, we can only start to use slave latency - * once we have received a NESN of 1 from the master + * If we are a peripheral, we can only start to use peripheral latency + * once we have received a NESN of 1 from the central */ - if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) { +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) + if (connsm->conn_role == BLE_LL_CONN_ROLE_PERIPHERAL) { if (hdr_byte & BLE_LL_DATA_HDR_NESN_MASK) { - connsm->csmflags.cfbit.allow_slave_latency = 1; + connsm->flags.periph_use_latency = 1; } } +#endif /* * Discard the received PDU if the sequence number is the same * as the last received sequence number */ - rxd_sn = hdr_byte & BLE_LL_DATA_HDR_SN_MASK; if (rxd_sn == connsm->last_rxd_sn) { STATS_INC(ble_ll_conn_stats, data_pdu_rx_dup); goto conn_rx_data_pdu_end; @@ -3702,16 +3594,8 @@ ble_ll_conn_rx_data_pdu(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *hdr) goto conn_rx_data_pdu_end; } -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - /* - * XXX: should we check to see if we are in a state where we - * might expect to get an encrypted PDU? - */ - if (BLE_MBUF_HDR_MIC_FAILURE(hdr)) { - STATS_INC(ble_ll_conn_stats, mic_failures); - ble_ll_conn_timeout(connsm, BLE_ERR_CONN_TERM_MIC); - goto conn_rx_data_pdu_end; - } +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE) + connsm->has_nonempty_pdu = 1; #endif if (llid == BLE_LL_LLID_CTRL) { @@ -3733,7 +3617,7 @@ ble_ll_conn_rx_data_pdu(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *hdr) acl_hdr = (llid << 12) | connsm->conn_handle; put_le16(rxbuf, acl_hdr); put_le16(rxbuf + 2, acl_len); - ble_hci_trans_ll_acl_tx(rxpdu); + ble_transport_to_hs_acl(rxpdu); } /* NOTE: we dont free the mbuf since we handed it off! */ @@ -3741,6 +3625,12 @@ ble_ll_conn_rx_data_pdu(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *hdr) /* Free buffer */ conn_rx_data_pdu_end: +#if MYNEWT_PKG_apache_mynewt_nimble__nimble_transport_common_hci_ipc + if (hdr->rxinfo.flags & BLE_MBUF_HDR_F_CONN_CREDIT_INT) { + hci_ipc_put(HCI_IPC_TYPE_ACL); + } +#endif + #if MYNEWT_VAL(BLE_LL_CFG_FEAT_CTRL_TO_HOST_FLOW_CONTROL) /* Need to give credit back if we allocated one for this PDU */ if (hdr->rxinfo.flags & BLE_MBUF_HDR_F_CONN_CREDIT) { @@ -3773,7 +3663,7 @@ ble_ll_conn_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr) uint8_t hdr_nesn; uint8_t conn_sn; uint8_t conn_nesn; - uint8_t reply; + uint8_t reply = 0; uint16_t rem_bytes; uint8_t opcode = 0; uint8_t rx_pyld_len; @@ -3801,6 +3691,19 @@ ble_ll_conn_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr) alloc_rxpdu = false; } +#if MYNEWT_PKG_apache_mynewt_nimble__nimble_transport_common_hci_ipc + /* If IPC transport is used, make sure there is buffer available on app side + * for this PDU. We'll just nak in LL if there are no free buffers. + */ + if (alloc_rxpdu && BLE_LL_LLID_IS_DATA(hdr_byte) && (rx_pyld_len > 0)) { + if (hci_ipc_get(HCI_IPC_TYPE_ACL)) { + rxhdr->rxinfo.flags |= BLE_MBUF_HDR_F_CONN_CREDIT_INT; + } else { + alloc_rxpdu = false; + } + } +#endif + #if MYNEWT_VAL(BLE_LL_CFG_FEAT_CTRL_TO_HOST_FLOW_CONTROL) /* * If flow control is enabled, we need to have credit available for each @@ -3813,6 +3716,10 @@ ble_ll_conn_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr) if (ble_ll_conn_cth_flow_alloc_credit(connsm)) { rxhdr->rxinfo.flags |= BLE_MBUF_HDR_F_CONN_CREDIT; } else { +#if MYNEWT_PKG_apache_mynewt_nimble__nimble_transport_common_hci_ipc + /* Need to return app buffer to pool since we won't use it */ + hci_ipc_put(HCI_IPC_TYPE_ACL); +#endif alloc_rxpdu = false; } } @@ -3844,52 +3751,36 @@ ble_ll_conn_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr) * to the 'additional usecs' field to save some calculations. */ begtime = rxhdr->beg_cputime; -#if BLE_LL_BT5_PHY_SUPPORTED +#if MYNEWT_VAL(BLE_LL_PHY) rx_phy_mode = connsm->phy_data.rx_phy_mode; #else rx_phy_mode = BLE_PHY_MODE_1M; #endif add_usecs = rxhdr->rem_usecs + - ble_ll_pdu_tx_time_get(rx_pyld_len, rx_phy_mode); + ble_ll_pdu_us(rx_pyld_len, rx_phy_mode); /* * Check the packet CRC. A connection event can continue even if the * received PDU does not pass the CRC check. If we receive two consecutive - * CRC errors we end the conection event. + * CRC errors we end the connection event. */ if (!BLE_MBUF_HDR_CRC_OK(rxhdr)) { /* - * Increment # of consecutively received CRC errors. If more than - * one we will end the connection event. + * Increment # of consecutively received CRC errors. + * + * If more than one, we will end the connection event and no reply is needed. + * If less or equal to one, we always reply: + * - peripheral always replies + * - central replies to allow peripheral retransmit the packet */ ++connsm->cons_rxd_bad_crc; - if (connsm->cons_rxd_bad_crc >= 2) { - reply = 0; - } else { - if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { - reply = CONN_F_LAST_TXD_MD(connsm); - } else { - /* A slave always responds with a packet */ - reply = 1; - } - } + reply = connsm->cons_rxd_bad_crc < 2; } else { /* Reset consecutively received bad crcs (since this one was good!) */ connsm->cons_rxd_bad_crc = 0; /* Set last valid received pdu time (resets supervision timer) */ - connsm->last_rxd_pdu_cputime = begtime + - os_cputime_usecs_to_ticks(add_usecs); - - /* - * Check for valid LLID before proceeding. We have seen some weird - * things with the PHY where the CRC is OK but we dont have a valid - * LLID. This should really never happen but if it does we will just - * bail. An error stat will get incremented at the LL. - */ - if ((hdr_byte & BLE_LL_DATA_HDR_LLID_MASK) == 0) { - goto conn_exit; - } + connsm->last_rxd_pdu_cputime = begtime + ble_ll_tmr_u2t(add_usecs); /* Set last received header byte */ connsm->last_rxd_hdr_byte = hdr_byte; @@ -3907,7 +3798,7 @@ ble_ll_conn_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr) if (rxpdu && ((hdr_sn && conn_nesn) || (!hdr_sn && !conn_nesn))) { connsm->next_exp_seqnum ^= 1; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - if (CONN_F_ENCRYPTED(connsm) && !ble_ll_conn_is_empty_pdu(rxbuf)) { + if (connsm->flags.encrypted && !ble_ll_conn_is_empty_pdu(rxbuf)) { ++connsm->enc_data.rx_pkt_cntr; } #endif @@ -3920,7 +3811,7 @@ ble_ll_conn_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr) * Check NESN bit from header. If same as tx seq num, the transmission * is acknowledged. Otherwise we need to resend this PDU. */ - if (CONN_F_EMPTY_PDU_TXD(connsm) || connsm->cur_tx_pdu) { + if (connsm->flags.empty_pdu_txd || connsm->cur_tx_pdu) { hdr_nesn = hdr_byte & BLE_LL_DATA_HDR_NESN_MASK; conn_sn = connsm->tx_seqnum; if ((hdr_nesn && conn_sn) || (!hdr_nesn && !conn_sn)) { @@ -3932,8 +3823,8 @@ ble_ll_conn_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr) STATS_INC(ble_ll_conn_stats, data_pdu_txg); /* If we transmitted the empty pdu, clear flag */ - if (CONN_F_EMPTY_PDU_TXD(connsm)) { - CONN_F_EMPTY_PDU_TXD(connsm) = 0; + if (connsm->flags.empty_pdu_txd) { + connsm->flags.empty_pdu_txd = 0; goto chk_rx_terminate_ind; } @@ -3970,10 +3861,10 @@ ble_ll_conn_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr) #if (BLETEST_THROUGHPUT_TEST == 1) bletest_completed_pkt(connsm->conn_handle); #endif - ++connsm->completed_pkts; + BLE_LL_ASSERT(txhdr->txinfo.num_data_pkt >= 1); + connsm->completed_pkts += txhdr->txinfo.num_data_pkt; if (connsm->completed_pkts > 2) { - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, - &g_ble_ll_data.ll_comp_pkt_ev); + ble_ll_event_add(&g_ble_ll_data.ll_comp_pkt_ev); } } os_mbuf_free_chain(txpdu); @@ -3982,9 +3873,9 @@ ble_ll_conn_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr) rem_bytes = OS_MBUF_PKTLEN(txpdu) - txhdr->txinfo.offset; /* Adjust payload for max TX time and octets */ -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) +#if MYNEWT_VAL(BLE_LL_PHY) if (BLE_LL_LLID_IS_CTRL(hdr_byte) && - (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) && + CONN_IS_PERIPHERAL(connsm) && (opcode == BLE_LL_CTRL_PHY_UPDATE_IND)) { connsm->phy_tx_transition = ble_ll_ctrl_phy_tx_transition_get(rxbuf[3]); @@ -4005,21 +3896,31 @@ ble_ll_conn_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr) if (BLE_LL_LLID_IS_CTRL(hdr_byte) && (opcode == BLE_LL_CTRL_TERMINATE_IND) && (rx_pyld_len == (1 + BLE_LL_CTRL_TERMINATE_IND_LEN))) { - connsm->csmflags.cfbit.terminate_ind_rxd = 1; + connsm->flags.terminate_ind_rxd = 1; connsm->rxd_disconnect_reason = rxbuf[3]; } - if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { - reply = CONN_F_LAST_TXD_MD(connsm) || (hdr_byte & BLE_LL_DATA_HDR_MD_MASK); - } else { - /* A slave always replies */ + switch (connsm->conn_role) { +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + case BLE_LL_CONN_ROLE_CENTRAL: + reply = connsm->flags.last_txd_md || (hdr_byte & BLE_LL_DATA_HDR_MD_MASK); + break; +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) + case BLE_LL_CONN_ROLE_PERIPHERAL: + /* A peripheral always replies */ reply = 1; + break; +#endif + default: + BLE_LL_ASSERT(0); + break; } } /* If reply flag set, send data pdu and continue connection event */ rc = -1; - if (rx_pyld_len && CONN_F_ENCRYPTED(connsm)) { + if (rx_pyld_len && connsm->flags.encrypted) { rx_pyld_len += BLE_LL_DATA_MIC_LEN; } if (reply && ble_ll_conn_can_send_next_pdu(connsm, begtime, add_usecs)) { @@ -4062,17 +3963,46 @@ ble_ll_conn_enqueue_pkt(struct ble_ll_conn_sm *connsm, struct os_mbuf *om, os_sr_t sr; struct os_mbuf_pkthdr *pkthdr; struct ble_mbuf_hdr *ble_hdr; + uint8_t num_pkt; int lifo; + /* We cannot send empty payload with LLID=0b10. Instead, we need to wait for + * non-empty payload and combine it together. Since we don't really recombine + * fragments we just count number of consecutive empty payloads and use 1st + * non-empty as a start packet. Empty payloads can be freed immediately as + * we don't need to enqueue them. + * + * Reference: Core 6.0, Vol 6, Part B, 2.4.1 + */ + if ((length == 0) && + ((hdr_byte == BLE_LL_LLID_DATA_START) || (connsm->conn_txq_num_zero_pkt > 0))) { + connsm->conn_txq_num_zero_pkt++; + os_mbuf_free_chain(om); + return; + } + /* Set mbuf length and packet length if a control PDU */ if (hdr_byte == BLE_LL_LLID_CTRL) { om->om_len = length; OS_MBUF_PKTHDR(om)->omp_len = length; + num_pkt = 0; + } else { + num_pkt = 1; + + /* This is the 1st non-empty data fragment so adjust LLID accordingly. + * num_pkt is updated to make sure we send back proper numbber of + * completed packets back to host. + */ + if (connsm->conn_txq_num_zero_pkt) { + hdr_byte = BLE_LL_LLID_DATA_START; + num_pkt += connsm->conn_txq_num_zero_pkt; + connsm->conn_txq_num_zero_pkt = 0; + } } /* Set BLE transmit header */ ble_hdr = BLE_MBUF_HDR_PTR(om); - ble_hdr->txinfo.flags = 0; + ble_hdr->txinfo.num_data_pkt = num_pkt; ble_hdr->txinfo.offset = 0; ble_hdr->txinfo.hdr_byte = hdr_byte; @@ -4101,9 +4031,11 @@ ble_ll_conn_enqueue_pkt(struct ble_ll_conn_sm *connsm, struct os_mbuf *om, lifo = 1; break; case BLE_LL_CTRL_PAUSE_ENC_RSP: - if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + if (connsm->conn_role == BLE_LL_CONN_ROLE_CENTRAL) { lifo = 1; } +#endif break; case BLE_LL_CTRL_ENC_REQ: case BLE_LL_CTRL_ENC_RSP: @@ -4129,6 +4061,7 @@ ble_ll_conn_enqueue_pkt(struct ble_ll_conn_sm *connsm, struct os_mbuf *om, } else { STAILQ_INSERT_TAIL(&connsm->conn_txq, pkthdr, omp_next); } + connsm->conn_txq_num_data_pkt += num_pkt; OS_EXIT_CRITICAL(sr); } @@ -4153,7 +4086,7 @@ ble_ll_conn_tx_pkt_in(struct os_mbuf *om, uint16_t handle, uint16_t length) /* See if we have an active matching connection handle */ conn_handle = handle & 0x0FFF; - connsm = ble_ll_conn_find_active_conn(conn_handle); + connsm = ble_ll_conn_find_by_handle(conn_handle); if (connsm) { /* Construct LL header in buffer (NOTE: pb already checked) */ pb = handle & 0x3000; @@ -4174,41 +4107,28 @@ ble_ll_conn_tx_pkt_in(struct os_mbuf *om, uint16_t handle, uint16_t length) os_mbuf_free_chain(om); } } +#endif -/** - * Called to set the global channel mask that we use for all connections. - * - * @param num_used_chans - * @param chanmap - */ void -ble_ll_conn_set_global_chanmap(uint8_t num_used_chans, const uint8_t *chanmap) +ble_ll_conn_chan_map_update(void) { +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) struct ble_ll_conn_sm *connsm; - struct ble_ll_conn_global_params *conn_params; - - /* Do nothing if same channel map */ - conn_params = &g_ble_ll_conn_params; - if (!memcmp(conn_params->master_chan_map, chanmap, BLE_LL_CONN_CHMAP_LEN)) { - return; - } - - /* Change channel map and cause channel map update procedure to start */ - conn_params->num_used_chans = num_used_chans; - memcpy(conn_params->master_chan_map, chanmap, BLE_LL_CONN_CHMAP_LEN); /* Perform channel map update */ SLIST_FOREACH(connsm, &g_ble_ll_conn_active_list, act_sle) { - if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { + if (connsm->conn_role == BLE_LL_CONN_ROLE_CENTRAL) { ble_ll_ctrl_proc_start(connsm, BLE_LL_CTRL_PROC_CHAN_MAP_UPD); } } +#endif } +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) /** * Called when a device has received a connect request while advertising and * the connect request has passed the advertising filter policy and is for - * us. This will start a connection in the slave role assuming that we dont + * us. This will start a connection in the peripheral role assuming that we dont * already have a connection with this device and that the connect request * parameters are valid. * @@ -4218,9 +4138,10 @@ ble_ll_conn_set_global_chanmap(uint8_t num_used_chans, const uint8_t *chanmap) * * @return 0: connection not started; 1 connecton started */ +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) int -ble_ll_conn_slave_start(uint8_t *rxbuf, uint8_t pat, struct ble_mbuf_hdr *rxhdr, - bool force_csa2) +ble_ll_conn_periph_start(uint8_t *rxbuf, uint8_t pat, struct ble_mbuf_hdr *rxhdr, + bool force_csa2) { int rc; uint32_t temp; @@ -4263,26 +4184,27 @@ ble_ll_conn_slave_start(uint8_t *rxbuf, uint8_t pat, struct ble_mbuf_hdr *rxhdr, connsm->tx_win_size = dptr[7]; connsm->tx_win_off = get_le16(dptr + 8); connsm->conn_itvl = get_le16(dptr + 10); - connsm->slave_latency = get_le16(dptr + 12); + connsm->periph_latency = get_le16(dptr + 12); connsm->supervision_tmo = get_le16(dptr + 14); - memcpy(&connsm->chanmap, dptr + 16, BLE_LL_CONN_CHMAP_LEN); + memcpy(&connsm->chan_map, dptr + 16, BLE_LL_CHAN_MAP_LEN); connsm->hop_inc = dptr[21] & 0x1F; - connsm->master_sca = dptr[21] >> 5; + connsm->central_sca = dptr[21] >> 5; /* Error check parameters */ if ((connsm->tx_win_off > connsm->conn_itvl) || (connsm->conn_itvl < BLE_HCI_CONN_ITVL_MIN) || (connsm->conn_itvl > BLE_HCI_CONN_ITVL_MAX) || (connsm->tx_win_size < BLE_LL_CONN_TX_WIN_MIN) || - (connsm->slave_latency > BLE_LL_CONN_SLAVE_LATENCY_MAX)) { - goto err_slave_start; + (connsm->periph_latency > BLE_LL_CONN_PERIPH_LATENCY_MAX) || + (connsm->hop_inc < 5) || (connsm->hop_inc > 16)) { + goto err_periph_start; } /* Slave latency cannot cause a supervision timeout */ - temp = (connsm->slave_latency + 1) * (connsm->conn_itvl * 2) * - BLE_LL_CONN_ITVL_USECS; + temp = (connsm->periph_latency + 1) * (connsm->conn_itvl * 2) * + BLE_LL_CONN_ITVL_USECS; if ((connsm->supervision_tmo * 10000) <= temp ) { - goto err_slave_start; + goto err_periph_start; } /* @@ -4294,7 +4216,7 @@ ble_ll_conn_slave_start(uint8_t *rxbuf, uint8_t pat, struct ble_mbuf_hdr *rxhdr, temp = 8; } if (connsm->tx_win_size > temp) { - goto err_slave_start; + goto err_periph_start; } /* Set the address of device that we are connecting with */ @@ -4302,16 +4224,19 @@ ble_ll_conn_slave_start(uint8_t *rxbuf, uint8_t pat, struct ble_mbuf_hdr *rxhdr, connsm->peer_addr_type = pat; /* Calculate number of used channels; make sure it meets min requirement */ - connsm->num_used_chans = ble_ll_utils_calc_num_used_chans(connsm->chanmap); - if (connsm->num_used_chans < 2) { - goto err_slave_start; + connsm->chan_map_used = ble_ll_utils_chan_map_used_get(connsm->chan_map); + if (connsm->chan_map_used < 2) { + goto err_periph_start; } + ble_ll_conn_itvl_to_ticks(connsm->conn_itvl, &connsm->conn_itvl_ticks, + &connsm->conn_itvl_usecs); + /* Start the connection state machine */ - connsm->conn_role = BLE_LL_CONN_ROLE_SLAVE; + connsm->conn_role = BLE_LL_CONN_ROLE_PERIPHERAL; ble_ll_conn_sm_new(connsm); -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) +#if MYNEWT_VAL(BLE_LL_PHY) /* Use the same PHY as we received CONNECT_REQ on */ ble_ll_conn_init_phy(connsm, rxhdr->rxinfo.phy); #endif @@ -4328,18 +4253,165 @@ ble_ll_conn_slave_start(uint8_t *rxbuf, uint8_t pat, struct ble_mbuf_hdr *rxhdr, } return rc; -err_slave_start: +err_periph_start: STAILQ_INSERT_TAIL(&g_ble_ll_conn_free_list, connsm, free_stqe); - STATS_INC(ble_ll_conn_stats, slave_rxd_bad_conn_req_params); + STATS_INC(ble_ll_conn_stats, periph_rxd_bad_conn_req_params); + return 0; +} +#endif + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE) +int +ble_ll_conn_subrate_req_hci(struct ble_ll_conn_sm *connsm, + struct ble_ll_conn_subrate_req_params *srp) +{ + uint32_t t1, t2; + + if ((srp->subrate_min < 0x0001) || (srp->subrate_min > 0x01f4) || + (srp->subrate_max < 0x0001) || (srp->subrate_max > 0x01f4) || + (srp->max_latency > 0x01f3) || (srp->cont_num > 0x01f3) || + (srp->supervision_tmo < 0x000a) || (srp->supervision_tmo > 0x0c80)) { + return -EINVAL; + } + + if (srp->subrate_max * (srp->max_latency + 1) > 500) { + return -EINVAL; + } + + t1 = connsm->conn_itvl * srp->subrate_max * (srp->max_latency + 1) * + BLE_LL_CONN_ITVL_USECS; + t2 = srp->supervision_tmo * BLE_HCI_CONN_SPVN_TMO_UNITS * 1000 / 2; + if (t1 > t2) { + return -EINVAL; + } + + if (srp->subrate_max < srp->subrate_min) { + return -EINVAL; + } + + if (srp->cont_num >= srp->subrate_max) { + return -EINVAL; + } + +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + if ((connsm->conn_role == BLE_LL_CONN_ROLE_CENTRAL) && + !ble_ll_conn_rem_feature_check(connsm, + BLE_LL_FEAT_CONN_SUBRATING_HOST)) { + return -ENOTSUP; + } +#endif + + if (connsm->cur_ctrl_proc == BLE_LL_CTRL_PROC_CONN_PARAM_REQ) { + return -EBUSY; + } + + switch (connsm->conn_role) { +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + case BLE_LL_CONN_ROLE_CENTRAL: + connsm->subrate_trans.subrate_factor = srp->subrate_max; + connsm->subrate_trans.subrate_base_event = connsm->event_cntr; + connsm->subrate_trans.periph_latency = srp->max_latency; + connsm->subrate_trans.cont_num = srp->cont_num; + connsm->subrate_trans.supervision_tmo = srp->supervision_tmo; + connsm->flags.subrate_host_req = 1; + ble_ll_ctrl_proc_start(connsm, BLE_LL_CTRL_PROC_SUBRATE_UPDATE); + break; +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) + case BLE_LL_CONN_ROLE_PERIPHERAL: + connsm->subrate_req = *srp; + connsm->flags.subrate_host_req = 1; + ble_ll_ctrl_proc_start(connsm, BLE_LL_CTRL_PROC_SUBRATE_REQ); + break; +#endif + default: + BLE_LL_ASSERT(0); + } + + + return 0; +} + +int +ble_ll_conn_subrate_req_llcp(struct ble_ll_conn_sm *connsm, + struct ble_ll_conn_subrate_req_params *srp) +{ + BLE_LL_ASSERT(connsm->conn_role == BLE_LL_CONN_ROLE_CENTRAL); + + if ((srp->subrate_min < 0x0001) || (srp->subrate_min > 0x01f4) || + (srp->subrate_max < 0x0001) || (srp->subrate_max > 0x01f4) || + (srp->max_latency > 0x01f3) || (srp->cont_num > 0x01f3) || + (srp->supervision_tmo < 0x000a) || (srp->supervision_tmo > 0x0c80)) { + return -EINVAL; + } + + if (connsm->cur_ctrl_proc == BLE_LL_CTRL_PROC_CONN_PARAM_REQ) { + return -EBUSY; + } + + if ((srp->max_latency > connsm->acc_max_latency) || + (srp->supervision_tmo > connsm->acc_supervision_tmo) || + (srp->subrate_max < connsm->acc_subrate_min) || + (srp->subrate_min > connsm->acc_subrate_max) || + ((connsm->conn_itvl * BLE_LL_CONN_ITVL_USECS * srp->subrate_min * + (srp->max_latency + 1)) * 2 >= srp->supervision_tmo * + BLE_HCI_CONN_SPVN_TMO_UNITS * 1000)) { + return -EINVAL; + } + + connsm->subrate_trans.subrate_factor = MIN(connsm->acc_subrate_max, + srp->subrate_max); + connsm->subrate_trans.subrate_base_event = connsm->event_cntr; + connsm->subrate_trans.periph_latency = MIN(connsm->acc_max_latency, + srp->max_latency); + connsm->subrate_trans.cont_num = MIN(MAX(connsm->acc_cont_num, + srp->cont_num), + connsm->subrate_trans.subrate_factor - 1); + connsm->subrate_trans.supervision_tmo = MIN(connsm->supervision_tmo, + srp->supervision_tmo); + + ble_ll_ctrl_proc_start(connsm, BLE_LL_CTRL_PROC_SUBRATE_UPDATE); + return 0; } +void +ble_ll_conn_subrate_set(struct ble_ll_conn_sm *connsm, + struct ble_ll_conn_subrate_params *sp) +{ + int16_t event_cntr_diff; + int16_t subrate_events_diff; + uint8_t send_ev; + + /* Assume parameters were checked by caller */ + + send_ev = connsm->flags.subrate_host_req || + (connsm->subrate_factor != sp->subrate_factor) || + (connsm->periph_latency != sp->periph_latency) || + (connsm->cont_num != sp->cont_num) || + (connsm->supervision_tmo != sp->supervision_tmo); + + connsm->subrate_factor = sp->subrate_factor; + connsm->subrate_base_event = sp->subrate_base_event; + connsm->periph_latency = sp->periph_latency; + connsm->cont_num = sp->cont_num; + connsm->supervision_tmo = sp->supervision_tmo; + + /* Let's update subrate base event to "latest" one */ + event_cntr_diff = connsm->event_cntr - connsm->subrate_base_event; + subrate_events_diff = event_cntr_diff / connsm->subrate_factor; + connsm->subrate_base_event += connsm->subrate_factor * subrate_events_diff; + + if (send_ev) { + ble_ll_hci_ev_subrate_change(connsm, 0); + } +} +#endif + #define MAX_TIME_UNCODED(_maxbytes) \ - ble_ll_pdu_tx_time_get(_maxbytes + BLE_LL_DATA_MIC_LEN, \ - BLE_PHY_MODE_1M); + ble_ll_pdu_us(_maxbytes + BLE_LL_DATA_MIC_LEN, BLE_PHY_MODE_1M); #define MAX_TIME_CODED(_maxbytes) \ - ble_ll_pdu_tx_time_get(_maxbytes + BLE_LL_DATA_MIC_LEN, \ - BLE_PHY_MODE_CODED_125KBPS); + ble_ll_pdu_us(_maxbytes + BLE_LL_DATA_MIC_LEN, BLE_PHY_MODE_CODED_125KBPS); /** * Called to reset the connection module. When this function is called the @@ -4363,14 +4435,16 @@ ble_ll_conn_module_reset(void) ble_ll_conn_end(connsm, BLE_ERR_SUCCESS); } +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) /* Free the global connection complete event if there is one */ if (g_ble_ll_conn_comp_ev) { - ble_hci_trans_buf_free(g_ble_ll_conn_comp_ev); + ble_transport_free(g_ble_ll_conn_comp_ev); g_ble_ll_conn_comp_ev = NULL; } /* Reset connection we are attempting to create */ - g_ble_ll_conn_create_sm = NULL; + g_ble_ll_conn_create_sm.connsm = NULL; +#endif /* Now go through and end all the connections */ while (1) { @@ -4387,7 +4461,7 @@ ble_ll_conn_module_reset(void) /* Configure the global LL parameters */ conn_params = &g_ble_ll_conn_params; - maxbytes = min(MYNEWT_VAL(BLE_LL_SUPP_MAX_RX_BYTES), max_phy_pyld); + maxbytes = MIN(MYNEWT_VAL(BLE_LL_SUPP_MAX_RX_BYTES), max_phy_pyld); conn_params->supp_max_rx_octets = maxbytes; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) conn_params->supp_max_rx_time = MAX_TIME_CODED(maxbytes); @@ -4395,7 +4469,7 @@ ble_ll_conn_module_reset(void) conn_params->supp_max_rx_time = MAX_TIME_UNCODED(maxbytes); #endif - maxbytes = min(MYNEWT_VAL(BLE_LL_SUPP_MAX_TX_BYTES), max_phy_pyld); + maxbytes = MIN(MYNEWT_VAL(BLE_LL_SUPP_MAX_TX_BYTES), max_phy_pyld); conn_params->supp_max_tx_octets = maxbytes; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) conn_params->supp_max_tx_time = MAX_TIME_CODED(maxbytes); @@ -4403,7 +4477,7 @@ ble_ll_conn_module_reset(void) conn_params->supp_max_tx_time = MAX_TIME_UNCODED(maxbytes); #endif - maxbytes = min(MYNEWT_VAL(BLE_LL_CONN_INIT_MAX_TX_BYTES), max_phy_pyld); + maxbytes = MIN(MYNEWT_VAL(BLE_LL_CONN_INIT_MAX_TX_BYTES), max_phy_pyld); conn_params->conn_init_max_tx_octets = maxbytes; conn_params->conn_init_max_tx_time = MAX_TIME_UNCODED(maxbytes); conn_params->conn_init_max_tx_time_uncoded = MAX_TIME_UNCODED(maxbytes); @@ -4412,10 +4486,13 @@ ble_ll_conn_module_reset(void) conn_params->sugg_tx_octets = BLE_LL_CONN_SUPP_BYTES_MIN; conn_params->sugg_tx_time = BLE_LL_CONN_SUPP_TIME_MIN; - /* Mask in all channels by default */ - conn_params->num_used_chans = BLE_PHY_NUM_DATA_CHANS; - memset(conn_params->master_chan_map, 0xff, BLE_LL_CONN_CHMAP_LEN - 1); - conn_params->master_chan_map[4] = 0x1f; +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE) + conn_params->acc_subrate_min = 0x0001; + conn_params->acc_subrate_max = 0x0001; + conn_params->acc_max_latency = 0x0000; + conn_params->acc_cont_num = 0x0000; + conn_params->acc_supervision_tmo = 0x0c80; +#endif /* Reset statistics */ STATS_RESET(ble_ll_conn_stats); @@ -4432,6 +4509,10 @@ ble_ll_conn_module_reset(void) g_ble_ll_conn_cth_flow.max_buffers = 1; g_ble_ll_conn_cth_flow.num_buffers = 1; #endif + +#if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) + g_ble_ll_conn_css_next_slot = BLE_LL_CONN_CSS_NO_SLOT; +#endif } /* Initialize the connection module */ @@ -4442,10 +4523,14 @@ ble_ll_conn_module_init(void) uint16_t i; struct ble_ll_conn_sm *connsm; - /* Initialize list of active conections */ + /* Initialize list of active connections */ SLIST_INIT(&g_ble_ll_conn_active_list); STAILQ_INIT(&g_ble_ll_conn_free_list); +#if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) + SLIST_INIT(&g_ble_ll_conn_css_list); +#endif + /* * Take all the connections off the free memory pool and add them to * the free connection list, assigning handles in linear order. Note: @@ -4461,6 +4546,9 @@ ble_ll_conn_module_init(void) /* Initialize fixed schedule elements */ connsm->conn_sch.sched_type = BLE_LL_SCHED_TYPE_CONN; connsm->conn_sch.cb_arg = connsm; + + ble_ll_ctrl_init_conn_sm(connsm); + ++connsm; } @@ -4479,3 +4567,4 @@ ble_ll_conn_module_init(void) /* Call reset to finish reset of initialization */ ble_ll_conn_module_reset(); } +#endif diff --git a/nimble/controller/src/ble_ll_conn_hci.c b/nimble/controller/src/ble_ll_conn_hci.c index 9936b9d34e..0a601c4a00 100644 --- a/nimble/controller/src/ble_ll_conn_hci.c +++ b/nimble/controller/src/ble_ll_conn_hci.c @@ -20,12 +20,11 @@ #include #include #include +#include #include "syscfg/syscfg.h" #include "os/os.h" #include "nimble/ble.h" -#include "nimble/nimble_opt.h" #include "nimble/hci_common.h" -#include "nimble/ble_hci_trans.h" #include "controller/ble_ll.h" #include "controller/ble_ll_utils.h" #include "controller/ble_ll_hci.h" @@ -33,8 +32,11 @@ #include "controller/ble_ll_ctrl.h" #include "controller/ble_ll_scan.h" #include "controller/ble_ll_adv.h" +#include "ble_ll_priv.h" #include "ble_ll_conn_priv.h" +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) || MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) + /* * Used to limit the rate at which we send the number of completed packets * event to the host. This is the os time at which we can send an event. @@ -43,19 +45,22 @@ static ble_npl_time_t g_ble_ll_last_num_comp_pkt_evt; extern uint8_t *g_ble_ll_conn_comp_ev; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -static const uint8_t ble_ll_valid_conn_phy_mask = (BLE_HCI_LE_PHY_1M_PREF_MASK +static const uint8_t ble_ll_conn_create_valid_phy_mask = ( + BLE_HCI_LE_PHY_1M_PREF_MASK | #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY) - | BLE_HCI_LE_PHY_2M_PREF_MASK + BLE_HCI_LE_PHY_2M_PREF_MASK | #endif #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) - | BLE_HCI_LE_PHY_CODED_PREF_MASK + BLE_HCI_LE_PHY_CODED_PREF_MASK | #endif - ); -static const uint8_t ble_ll_conn_required_phy_mask = (BLE_HCI_LE_PHY_1M_PREF_MASK + 0); + +static const uint8_t ble_ll_conn_create_required_phy_mask = ( + BLE_HCI_LE_PHY_1M_PREF_MASK | #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) - | BLE_HCI_LE_PHY_CODED_PREF_MASK + BLE_HCI_LE_PHY_CODED_PREF_MASK | #endif - ); + 0); #endif /** @@ -72,7 +77,7 @@ ble_ll_init_alloc_conn_comp_ev(void) rc = 0; evbuf = g_ble_ll_conn_comp_ev; if (evbuf == NULL) { - evbuf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); + evbuf = ble_transport_alloc_evt(0); if (!evbuf) { rc = -1; } else { @@ -136,7 +141,7 @@ ble_ll_conn_comp_event_send(struct ble_ll_conn_sm *connsm, uint8_t status, struct ble_hci_ev_le_subev_enh_conn_complete *enh_ev; struct ble_hci_ev_le_subev_conn_complete *ev; struct ble_hci_ev *hci_ev = (void *) evbuf; - uint8_t *rpa; + uint8_t *rpa = NULL; BLE_LL_ASSERT(evbuf); @@ -156,7 +161,9 @@ ble_ll_conn_comp_event_send(struct ble_ll_conn_sm *connsm, uint8_t status, enh_ev->peer_addr_type = connsm->peer_addr_type; memcpy(enh_ev->peer_addr, connsm->peer_addr, BLE_DEV_ADDR_LEN); - if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { + switch (connsm->conn_role) { +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + case BLE_LL_CONN_ROLE_CENTRAL: if (connsm->inita_identity_used) { /* We used identity address in CONNECT_IND which can be just * fine if @@ -171,35 +178,57 @@ ble_ll_conn_comp_event_send(struct ble_ll_conn_sm *connsm, uint8_t status, } else { rpa = NULL; } - } else { + break; +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) + case BLE_LL_CONN_ROLE_PERIPHERAL: rpa = ble_ll_adv_get_local_rpa(advsm); + break; +#endif + default: + BLE_LL_ASSERT(0); + break; } if (rpa) { memcpy(enh_ev->local_rpa, rpa, BLE_DEV_ADDR_LEN); } - /* We need to adjust peer type if device connected using RPA - * and was resolved since RPA needs to be added to HCI event. - */ - if (connsm->peer_addr_type < BLE_HCI_CONN_PEER_ADDR_PUBLIC_IDENT - && (connsm->rpa_index > -1)) { +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + /* Adjust address type if peer address was resolved */ + if (connsm->peer_addr_resolved) { enh_ev->peer_addr_type += 2; } +#endif if (enh_ev->peer_addr_type > BLE_HCI_CONN_PEER_ADDR_RANDOM) { - if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { + switch (connsm->conn_role) { +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + case BLE_LL_CONN_ROLE_CENTRAL: rpa = ble_ll_scan_get_peer_rpa(); - } else { + break; +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) + case BLE_LL_CONN_ROLE_PERIPHERAL: rpa = ble_ll_adv_get_peer_rpa(advsm); + break; +#endif + default: + BLE_LL_ASSERT(0); + break; } + memcpy(enh_ev->peer_rpa, rpa, BLE_DEV_ADDR_LEN); } enh_ev->conn_itvl = htole16(connsm->conn_itvl); - enh_ev->conn_latency = htole16(connsm->slave_latency); + enh_ev->conn_latency = htole16(connsm->periph_latency); enh_ev->supervision_timeout = htole16(connsm->supervision_tmo); - enh_ev->mca = connsm->master_sca; +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) + if (connsm->conn_role == BLE_LL_CONN_ROLE_PERIPHERAL) { + enh_ev->mca = connsm->central_sca; + } +#endif } ble_ll_hci_event_send(hci_ev); @@ -220,22 +249,22 @@ ble_ll_conn_comp_event_send(struct ble_ll_conn_sm *connsm, uint8_t status, ev->conn_handle = htole16(connsm->conn_handle); ev->role = connsm->conn_role - 1; ev->peer_addr_type = connsm->peer_addr_type; - - if (ev->peer_addr_type > BLE_HCI_CONN_PEER_ADDR_RANDOM) { - ev->peer_addr_type -= 2; - } memcpy(ev->peer_addr, connsm->peer_addr, BLE_DEV_ADDR_LEN); ev->conn_itvl = htole16(connsm->conn_itvl); - ev->conn_latency = htole16(connsm->slave_latency); + ev->conn_latency = htole16(connsm->periph_latency); ev->supervision_timeout = htole16(connsm->supervision_tmo); - ev->mca = connsm->master_sca; +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) + if (connsm->conn_role == BLE_LL_CONN_ROLE_PERIPHERAL) { + ev->mca = connsm->central_sca; + } +#endif } ble_ll_hci_event_send(hci_ev); return; } - ble_hci_trans_buf_free(evbuf); + ble_transport_free(evbuf); } /** @@ -271,7 +300,7 @@ ble_ll_conn_num_comp_pkts_event_send(struct ble_ll_conn_sm *connsm) * entire active list every time. */ if (connsm->completed_pkts) { - hci_ev = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); + hci_ev = ble_transport_alloc_evt(0); if (hci_ev) { hci_ev->opcode = BLE_HCI_EVCODE_NUM_COMP_PKTS; hci_ev->length = sizeof(*ev); @@ -282,6 +311,8 @@ ble_ll_conn_num_comp_pkts_event_send(struct ble_ll_conn_sm *connsm) ev->completed[0].packets = htole16(connsm->completed_pkts); hci_ev->length += sizeof(ev->completed[0]); + BLE_LL_ASSERT(connsm->conn_txq_num_data_pkt >= connsm->completed_pkts); + connsm->conn_txq_num_data_pkt -= connsm->completed_pkts; connsm->completed_pkts = 0; ble_ll_hci_event_send(hci_ev); @@ -302,10 +333,10 @@ ble_ll_conn_num_comp_pkts_event_send(struct ble_ll_conn_sm *connsm) * event and that either has packets enqueued or has completed packets. */ if ((connsm->conn_state != BLE_LL_CONN_STATE_IDLE) && - (connsm->completed_pkts || !STAILQ_EMPTY(&connsm->conn_txq))) { + (connsm->completed_pkts || connsm->conn_txq_num_data_pkt)) { /* If no buffer, get one, If cant get one, leave. */ if (!hci_ev) { - hci_ev = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); + hci_ev = ble_transport_alloc_evt(0); if (!hci_ev) { break; } @@ -323,6 +354,8 @@ ble_ll_conn_num_comp_pkts_event_send(struct ble_ll_conn_sm *connsm) hci_ev->length += sizeof(ev->completed[ev->count]); ev->count++; + BLE_LL_ASSERT(connsm->conn_txq_num_data_pkt >= connsm->completed_pkts); + connsm->conn_txq_num_data_pkt -= connsm->completed_pkts; connsm->completed_pkts = 0; /* Send now if the buffer is full. */ @@ -361,7 +394,7 @@ ble_ll_auth_pyld_tmo_event_send(struct ble_ll_conn_sm *connsm) struct ble_hci_ev *hci_ev; if (ble_ll_hci_is_event_enabled(BLE_HCI_EVCODE_AUTH_PYLD_TMO)) { - hci_ev = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); + hci_ev = ble_transport_alloc_evt(0); if (hci_ev) { hci_ev->opcode = BLE_HCI_EVCODE_AUTH_PYLD_TMO; hci_ev->length = sizeof(*ev); @@ -390,7 +423,7 @@ ble_ll_disconn_comp_event_send(struct ble_ll_conn_sm *connsm, uint8_t reason) struct ble_hci_ev *hci_ev; if (ble_ll_hci_is_event_enabled(BLE_HCI_EVCODE_DISCONN_CMP)) { - hci_ev = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); + hci_ev = ble_transport_alloc_evt(0); if (hci_ev) { hci_ev->opcode = BLE_HCI_EVCODE_DISCONN_CMP; hci_ev->length = sizeof(*ev); @@ -406,18 +439,66 @@ ble_ll_disconn_comp_event_send(struct ble_ll_conn_sm *connsm, uint8_t reason) } } +int +ble_ll_conn_hci_create_check_scan(struct ble_ll_conn_create_scan *p) +{ + if (p->filter_policy > BLE_HCI_INITIATOR_FILT_POLICY_MAX) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + if ((p->filter_policy == 0) && + (p->peer_addr_type > BLE_HCI_CONN_PEER_ADDR_MAX)) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + if (p->own_addr_type > BLE_HCI_ADV_OWN_ADDR_MAX) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) + if (p->init_phy_mask & ~ble_ll_conn_create_valid_phy_mask) { + return BLE_ERR_UNSUPPORTED; + } + + if (!(p->init_phy_mask & ble_ll_conn_create_required_phy_mask)) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } +#endif + + return 0; +} + static int -ble_ll_conn_hci_chk_scan_params(uint16_t itvl, uint16_t window) +ble_ll_conn_hci_create_check_params(struct ble_ll_conn_create_params *cc_params) { - /* Check interval and window */ - if ((itvl < BLE_HCI_SCAN_ITVL_MIN) || - (itvl > BLE_HCI_SCAN_ITVL_MAX) || - (window < BLE_HCI_SCAN_WINDOW_MIN) || - (window > BLE_HCI_SCAN_WINDOW_MAX) || - (itvl < window)) { + int rc; + + rc = ble_ll_conn_hci_chk_conn_params(cc_params->conn_itvl, + cc_params->conn_itvl, + cc_params->conn_latency, + cc_params->supervision_timeout); + if (rc) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + if (cc_params->min_ce_len > cc_params->max_ce_len) { return BLE_ERR_INV_HCI_CMD_PARMS; } + /* Adjust min/max ce length to be less than interval + * Note that interval is in 1.25ms and CE is in 625us + */ + if (cc_params->min_ce_len > cc_params->conn_itvl * 2) { + cc_params->min_ce_len = cc_params->conn_itvl * 2; + } + if (cc_params->max_ce_len > cc_params->conn_itvl * 2) { + cc_params->max_ce_len = cc_params->conn_itvl * 2; + } + + /* Precalculate conn interval */ + ble_ll_conn_itvl_to_ticks(cc_params->conn_itvl, &cc_params->conn_itvl_ticks, + &cc_params->conn_itvl_usecs); + return 0; } @@ -431,11 +512,17 @@ ble_ll_conn_hci_chk_scan_params(uint16_t itvl, uint16_t window) * @return int */ int -ble_ll_conn_create(const uint8_t *cmdbuf, uint8_t len) +ble_ll_conn_hci_create(const uint8_t *cmdbuf, uint8_t len) { const struct ble_hci_le_create_conn_cp *cmd = (const void *) cmdbuf; + struct ble_ll_conn_create_scan cc_scan; + struct ble_ll_conn_create_params cc_params; struct ble_ll_conn_sm *connsm; - struct hci_create_conn hcc = { 0 }; + uint16_t conn_itvl_min; + uint16_t conn_itvl_max; +#if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) + uint16_t css_slot_idx = 0; +#endif int rc; if (len < sizeof(*cmd)) { @@ -443,7 +530,7 @@ ble_ll_conn_create(const uint8_t *cmdbuf, uint8_t len) } /* If we are already creating a connection we should leave */ - if (g_ble_ll_conn_create_sm) { + if (g_ble_ll_conn_create_sm.connsm) { return BLE_ERR_CMD_DISALLOWED; } @@ -452,55 +539,71 @@ ble_ll_conn_create(const uint8_t *cmdbuf, uint8_t len) return BLE_ERR_CMD_DISALLOWED; } - /* Retrieve command data */ - hcc.scan_itvl = le16toh(cmd->scan_itvl); - hcc.scan_window = le16toh(cmd->scan_window); + if (ble_ll_conn_find_by_peer_addr(cmd->peer_addr, cmd->peer_addr_type)) { + return BLE_ERR_ACL_CONN_EXISTS; + } - rc = ble_ll_conn_hci_chk_scan_params(hcc.scan_itvl, hcc.scan_window); - if (rc) { - return BLE_ERR_INV_HCI_CMD_PARMS; +#if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) + if (ble_ll_sched_css_is_enabled()) { + css_slot_idx = ble_ll_conn_css_get_next_slot(); + if (css_slot_idx == BLE_LL_CONN_CSS_NO_SLOT) { + return BLE_ERR_MEM_CAPACITY; + } } +#endif - /* Check filter policy */ - hcc.filter_policy = cmd->filter_policy; - if (hcc.filter_policy > BLE_HCI_INITIATOR_FILT_POLICY_MAX) { - return BLE_ERR_INV_HCI_CMD_PARMS; + cc_scan.own_addr_type = cmd->own_addr_type; + cc_scan.filter_policy = cmd->filter_policy; + if (cc_scan.filter_policy == 0) { + cc_scan.peer_addr_type = cmd->peer_addr_type; + memcpy(&cc_scan.peer_addr, cmd->peer_addr, BLE_DEV_ADDR_LEN); + } else { + cc_scan.peer_addr_type = 0; + memset(&cc_scan.peer_addr, 0, BLE_DEV_ADDR_LEN); } +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) + cc_scan.init_phy_mask = BLE_HCI_LE_PHY_1M_PREF_MASK; +#endif - /* Get peer address type and address only if no whitelist used */ - if (hcc.filter_policy == 0) { - hcc.peer_addr_type = cmd->peer_addr_type; - if (hcc.peer_addr_type > BLE_HCI_CONN_PEER_ADDR_MAX) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } + cc_scan.scan_params[PHY_UNCODED].itvl = le16toh(cmd->scan_itvl); + cc_scan.scan_params[PHY_UNCODED].window = le16toh(cmd->scan_window); - memcpy(&hcc.peer_addr, cmd->peer_addr, BLE_DEV_ADDR_LEN); + rc = ble_ll_conn_hci_create_check_scan(&cc_scan); + if (rc) { + return rc; } - /* Get own address type (used in connection request) */ - hcc.own_addr_type = cmd->own_addr_type; - if (hcc.own_addr_type > BLE_HCI_ADV_OWN_ADDR_MAX) { + conn_itvl_min = le16toh(cmd->min_conn_itvl); + conn_itvl_max = le16toh(cmd->max_conn_itvl); + + /* Check min/max interval here since generic check does not have min/max + * parameters to check. + */ + if (conn_itvl_min > conn_itvl_max) { return BLE_ERR_INV_HCI_CMD_PARMS; } - /* Check connection interval, latency and supervision timeoout */ - hcc.conn_itvl_min = le16toh(cmd->min_conn_itvl); - hcc.conn_itvl_max = le16toh(cmd->max_conn_itvl); - hcc.conn_latency = le16toh(cmd->conn_latency); - hcc.supervision_timeout = le16toh(cmd->tmo); - rc = ble_ll_conn_hci_chk_conn_params(hcc.conn_itvl_min, - hcc.conn_itvl_max, - hcc.conn_latency, - hcc.supervision_timeout); - if (rc) { - return rc; +#if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) + if (ble_ll_sched_css_is_enabled()) { + cc_params.conn_itvl = ble_ll_sched_css_get_conn_interval_us(); + if ((cc_params.conn_itvl < conn_itvl_min) || + (cc_params.conn_itvl > conn_itvl_max)) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + } else { + cc_params.conn_itvl = conn_itvl_max; } +#else + cc_params.conn_itvl = conn_itvl_max; +#endif + cc_params.conn_latency = le16toh(cmd->conn_latency); + cc_params.supervision_timeout = le16toh(cmd->tmo); + cc_params.min_ce_len = le16toh(cmd->min_ce); + cc_params.max_ce_len = le16toh(cmd->max_ce); - /* Min/max connection event lengths */ - hcc.min_ce_len = le16toh(cmd->min_ce); - hcc.max_ce_len = le16toh(cmd->max_ce); - if (hcc.min_ce_len > hcc.max_ce_len) { - return BLE_ERR_INV_HCI_CMD_PARMS; + rc = ble_ll_conn_hci_create_check_params(&cc_params); + if (rc) { + return rc; } /* Make sure we can allocate an event to send the connection complete */ @@ -514,19 +617,25 @@ ble_ll_conn_create(const uint8_t *cmdbuf, uint8_t len) return BLE_ERR_CONN_LIMIT; } - /* Initialize state machine in master role and start state machine */ - ble_ll_conn_master_init(connsm, &hcc); +#if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) + connsm->css_slot_idx = css_slot_idx; + connsm->css_slot_idx_pending = BLE_LL_CONN_CSS_NO_SLOT; +#endif + + /* Initialize state machine in central role and start state machine */ + ble_ll_conn_central_init(connsm, &cc_scan, &cc_params); ble_ll_conn_sm_new(connsm); - /* CSA will be selected when advertising is received */ /* Start scanning */ - rc = ble_ll_scan_initiator_start(&hcc, &connsm->scansm); + rc = ble_ll_scan_initiator_start(connsm, 0, &cc_scan); if (rc) { SLIST_REMOVE(&g_ble_ll_conn_active_list,connsm,ble_ll_conn_sm,act_sle); STAILQ_INSERT_TAIL(&g_ble_ll_conn_free_list, connsm, free_stqe); - } else { - /* Set the connection state machine we are trying to create. */ - g_ble_ll_conn_create_sm = connsm; +#if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) + if (ble_ll_sched_css_is_enabled()) { + SLIST_REMOVE(&g_ble_ll_conn_css_list, connsm, ble_ll_conn_sm, css_sle); + } +#endif } return rc; @@ -534,198 +643,194 @@ ble_ll_conn_create(const uint8_t *cmdbuf, uint8_t len) #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) static void -ble_ll_conn_hcc_params_set_fallback(struct hci_ext_create_conn *hcc, - const struct hci_ext_conn_params *fallback) +ble_ll_conn_hci_ext_create_set_fb_params(uint8_t init_phy_mask, + struct ble_ll_conn_create_params *cc_params_fb) { - BLE_LL_ASSERT(fallback); - - if (!(hcc->init_phy_mask & BLE_PHY_MASK_1M)) { - hcc->params[0] = *fallback; + if ((init_phy_mask & BLE_PHY_MASK_1M) == 0) { + g_ble_ll_conn_create_sm.params[BLE_PHY_IDX_1M] = *cc_params_fb; } #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY) - if (!(hcc->init_phy_mask & BLE_PHY_MASK_2M)) { - hcc->params[1] = *fallback; + if ((init_phy_mask & BLE_PHY_MASK_2M) == 0) { + g_ble_ll_conn_create_sm.params[BLE_PHY_IDX_2M] = *cc_params_fb; } #endif #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) - if (!(hcc->init_phy_mask & BLE_PHY_MASK_CODED)) { - hcc->params[2] = *fallback; + if ((init_phy_mask & BLE_PHY_MASK_CODED) == 0) { + g_ble_ll_conn_create_sm.params[BLE_PHY_IDX_CODED] = *cc_params_fb; } #endif } -int -ble_ll_ext_conn_create(const uint8_t *cmdbuf, uint8_t len) +static int +ble_ll_conn_hci_ext_create_parse_params(const struct conn_params *params, + uint8_t phy, + struct ble_ll_conn_create_scan *cc_scan, + struct ble_ll_conn_create_params *cc_params) { - const struct ble_hci_le_ext_create_conn_cp *cmd = (const void *) cmdbuf; - const struct conn_params *params = cmd->conn_params; - const struct hci_ext_conn_params *fallback_params = NULL; - struct hci_ext_create_conn hcc = { 0 }; - struct ble_ll_conn_sm *connsm; + uint16_t conn_itvl_min; + uint16_t conn_itvl_max; + uint16_t scan_itvl; + uint16_t scan_window; int rc; - /* validate length */ - if (len < sizeof(*cmd)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - len -= sizeof(*cmd); - - /* If we are already creating a connection we should leave */ - if (g_ble_ll_conn_create_sm) { - return BLE_ERR_CMD_DISALLOWED; - } - - /* If already enabled, we return an error */ - if (ble_ll_scan_enabled()) { - return BLE_ERR_CMD_DISALLOWED; - } - - hcc.filter_policy = cmd->filter_policy; - if (hcc.filter_policy > BLE_HCI_INITIATOR_FILT_POLICY_MAX) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } + conn_itvl_min = le16toh(params->conn_min_itvl); + conn_itvl_max = le16toh(params->conn_max_itvl); - hcc.own_addr_type = cmd->own_addr_type; - if (hcc.own_addr_type > BLE_HCI_ADV_OWN_ADDR_MAX) { + /* Check min/max interval here since generic check does not have min/max + * parameters to check. + */ + if (conn_itvl_min > conn_itvl_max) { return BLE_ERR_INV_HCI_CMD_PARMS; } - /* Validate peer address type only if no whitelist used */ - if (hcc.filter_policy == 0) { - hcc.peer_addr_type = cmd->peer_addr_type; - - if (hcc.peer_addr_type > BLE_HCI_CONN_PEER_ADDR_MAX) { +#if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) + if (ble_ll_sched_css_is_enabled()) { + cc_params->conn_itvl = ble_ll_sched_css_get_conn_interval_us(); + if ((cc_params->conn_itvl < conn_itvl_min) || + (cc_params->conn_itvl > conn_itvl_max)) { return BLE_ERR_INV_HCI_CMD_PARMS; } - - memcpy(hcc.peer_addr, cmd->peer_addr, BLE_DEV_ADDR_LEN); + } else { + cc_params->conn_itvl = conn_itvl_max; } +#else + cc_params->conn_itvl = conn_itvl_max; +#endif + cc_params->conn_latency = le16toh(params->conn_latency); + cc_params->supervision_timeout = le16toh(params->supervision_timeout); + cc_params->min_ce_len = le16toh(params->min_ce); + cc_params->max_ce_len = le16toh(params->max_ce); - hcc.init_phy_mask = cmd->init_phy_mask; - if (hcc.init_phy_mask & ~ble_ll_valid_conn_phy_mask) { - return BLE_ERR_INV_HCI_CMD_PARMS; + rc = ble_ll_conn_hci_create_check_params(cc_params); + if (rc) { + return rc; } - if (!(hcc.init_phy_mask & ble_ll_conn_required_phy_mask)) { - /* At least one of those need to be set */ - return BLE_ERR_INV_HCI_CMD_PARMS; - } + if (phy != BLE_PHY_2M) { + scan_itvl = le16toh(params->scan_itvl); + scan_window = le16toh(params->scan_window); - if (hcc.init_phy_mask & BLE_PHY_MASK_1M) { - if (len < sizeof(*params)) { - return BLE_ERR_INV_HCI_CMD_PARMS; + if ((scan_itvl < BLE_HCI_SCAN_ITVL_MIN) || + (scan_itvl > BLE_HCI_SCAN_ITVL_MAX) || + (scan_window < BLE_HCI_SCAN_WINDOW_MIN) || + (scan_window > BLE_HCI_SCAN_WINDOW_MAX) || + (scan_itvl < scan_window)) { + return BLE_ERR_INV_HCI_CMD_PARMS; } - len -= sizeof(*params); - - hcc.params[0].scan_itvl = le16toh(params->scan_itvl); - hcc.params[0].scan_window = le16toh(params->scan_window); - rc = ble_ll_conn_hci_chk_scan_params(hcc.params[0].scan_itvl, - hcc.params[0].scan_window); - if (rc) { - return rc; + if (phy == BLE_PHY_1M) { + cc_scan->scan_params[PHY_UNCODED].itvl = scan_itvl; + cc_scan->scan_params[PHY_UNCODED].window = scan_window; + } else { + cc_scan->scan_params[PHY_CODED].itvl = scan_itvl; + cc_scan->scan_params[PHY_CODED].window = scan_window; } + } - hcc.params[0].conn_itvl_min = le16toh(params->conn_min_itvl); - hcc.params[0].conn_itvl_max = le16toh(params->conn_min_itvl); - hcc.params[0].conn_latency = le16toh(params->conn_latency); - hcc.params[0].supervision_timeout = le16toh(params->supervision_timeout); + return 0; +} - rc = ble_ll_conn_hci_chk_conn_params(hcc.params[0].conn_itvl_min, - hcc.params[0].conn_itvl_max, - hcc.params[0].conn_latency, - hcc.params[0].supervision_timeout); - if (rc) { - return rc; - } +int +ble_ll_conn_hci_ext_create(const uint8_t *cmdbuf, uint8_t len) +{ + static const struct init_phy { + uint8_t idx; + uint8_t mask; + uint8_t phy; + } init_phys[] = { + {BLE_PHY_IDX_1M, BLE_PHY_MASK_1M, BLE_PHY_1M}, +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY) + {BLE_PHY_IDX_2M, BLE_PHY_MASK_2M, BLE_PHY_2M}, +#endif +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) + {BLE_PHY_IDX_CODED, BLE_PHY_MASK_CODED, BLE_PHY_CODED}, +#endif + }; - /* Min/max connection event lengths */ - hcc.params[0].min_ce_len = le16toh(params->min_ce); - hcc.params[0].max_ce_len = le16toh(params->max_ce); - if (hcc.params[0].min_ce_len > hcc.params[0].max_ce_len) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } + const struct ble_hci_le_ext_create_conn_cp *cmd = (const void *)cmdbuf; + const struct conn_params *params = cmd->conn_params; + struct ble_ll_conn_create_scan cc_scan; + struct ble_ll_conn_create_params *cc_params; + struct ble_ll_conn_create_params *cc_params_fb; + struct ble_ll_conn_sm *connsm; + const struct init_phy *init_phy; +#if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) + uint16_t css_slot_idx = 0; +#endif + int rc; - fallback_params = &hcc.params[0]; - params++; + /* validate length */ + if (len < sizeof(*cmd) + + __builtin_popcount(cmd->init_phy_mask) * sizeof(*params)) { + return BLE_ERR_INV_HCI_CMD_PARMS; } -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY) - if (hcc.init_phy_mask & BLE_PHY_MASK_2M) { - if (len < sizeof(*params)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - len -= sizeof(*params); + /* If we are already creating a connection we should leave */ + if (g_ble_ll_conn_create_sm.connsm) { + return BLE_ERR_CMD_DISALLOWED; + } - hcc.params[1].conn_itvl_min = le16toh(params->conn_min_itvl); - hcc.params[1].conn_itvl_max = le16toh(params->conn_min_itvl); - hcc.params[1].conn_latency = le16toh(params->conn_latency); - hcc.params[1].supervision_timeout = le16toh(params->supervision_timeout); + /* If already enabled, we return an error */ + if (ble_ll_scan_enabled()) { + return BLE_ERR_CMD_DISALLOWED; + } - rc = ble_ll_conn_hci_chk_conn_params(hcc.params[1].conn_itvl_min, - hcc.params[1].conn_itvl_max, - hcc.params[1].conn_latency, - hcc.params[1].supervision_timeout); - if (rc) { - return rc; - } + if (ble_ll_conn_find_by_peer_addr(cmd->peer_addr, cmd->peer_addr_type)) { + return BLE_ERR_ACL_CONN_EXISTS; + } - /* Min/max connection event lengths */ - hcc.params[1].min_ce_len = le16toh(params->min_ce); - hcc.params[1].max_ce_len = le16toh(params->max_ce); - if (hcc.params[1].min_ce_len > hcc.params[1].max_ce_len) { - return BLE_ERR_INV_HCI_CMD_PARMS; +#if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) + if (ble_ll_sched_css_is_enabled()) { + css_slot_idx = ble_ll_conn_css_get_next_slot(); + if (css_slot_idx == BLE_LL_CONN_CSS_NO_SLOT) { + return BLE_ERR_MEM_CAPACITY; } - - params++; } #endif -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) - if (hcc.init_phy_mask & BLE_PHY_MASK_CODED) { - if (len < sizeof(*params)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - len -= sizeof(*params); + cc_scan.own_addr_type = cmd->own_addr_type; + cc_scan.filter_policy = cmd->filter_policy; + if (cc_scan.filter_policy == 0) { + cc_scan.peer_addr_type = cmd->peer_addr_type; + memcpy(cc_scan.peer_addr, cmd->peer_addr, BLE_DEV_ADDR_LEN); + } else { + cc_scan.peer_addr_type = 0; + memset(cc_scan.peer_addr, 0, BLE_DEV_ADDR_LEN); + } + cc_scan.init_phy_mask = cmd->init_phy_mask; - hcc.params[2].scan_itvl = le16toh(params->scan_itvl); - hcc.params[2].scan_window = le16toh(params->scan_window); + rc = ble_ll_conn_hci_create_check_scan(&cc_scan); + if (rc) { + return rc; + } - rc = ble_ll_conn_hci_chk_scan_params(hcc.params[2].scan_itvl, - hcc.params[2].scan_window); - if (rc) { - return rc; + cc_params_fb = NULL; + + for (unsigned int i = 0; i < ARRAY_SIZE(init_phys); i++) { + init_phy = &init_phys[i]; + + if ((cc_scan.init_phy_mask & init_phy->mask) == 0) { + continue; } - hcc.params[2].conn_itvl_min = le16toh(params->conn_min_itvl); - hcc.params[2].conn_itvl_max = le16toh(params->conn_min_itvl); - hcc.params[2].conn_latency = le16toh(params->conn_latency); - hcc.params[2].supervision_timeout = le16toh(params->supervision_timeout); + cc_params = &g_ble_ll_conn_create_sm.params[init_phy->idx]; - rc = ble_ll_conn_hci_chk_conn_params(hcc.params[2].conn_itvl_min, - hcc.params[2].conn_itvl_max, - hcc.params[2].conn_latency, - hcc.params[2].supervision_timeout); + rc = ble_ll_conn_hci_ext_create_parse_params(params, init_phy->phy, + &cc_scan, cc_params); if (rc) { return rc; } - /* Min/max connection event lengths */ - hcc.params[2].min_ce_len = le16toh(params->min_ce); - hcc.params[2].max_ce_len = le16toh(params->max_ce); - if (hcc.params[2].min_ce_len > hcc.params[2].max_ce_len) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - if (!fallback_params) { - fallback_params = &hcc.params[2]; + if (!cc_params_fb) { + cc_params_fb = cc_params; } params++; } -#endif + + ble_ll_conn_hci_ext_create_set_fb_params(cc_scan.init_phy_mask, + cc_params_fb); /* Make sure we can allocate an event to send the connection complete */ if (ble_ll_init_alloc_conn_comp_ev()) { @@ -738,22 +843,26 @@ ble_ll_ext_conn_create(const uint8_t *cmdbuf, uint8_t len) return BLE_ERR_CONN_LIMIT; } - ble_ll_conn_hcc_params_set_fallback(&hcc, fallback_params); +#if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) + connsm->css_slot_idx = css_slot_idx; + connsm->css_slot_idx_pending = BLE_LL_CONN_CSS_NO_SLOT; +#endif - /* Initialize state machine in master role and start state machine */ - ble_ll_conn_ext_master_init(connsm, &hcc); + /* Initialize state machine in central role and start state machine */ + ble_ll_conn_central_init(connsm, &cc_scan, + &g_ble_ll_conn_create_sm.params[0]); ble_ll_conn_sm_new(connsm); - /* CSA will be selected when advertising is received */ - /* Start scanning */ - rc = ble_ll_scan_ext_initiator_start(&hcc, &connsm->scansm); + rc = ble_ll_scan_initiator_start(connsm, 1, &cc_scan); if (rc) { SLIST_REMOVE(&g_ble_ll_conn_active_list,connsm,ble_ll_conn_sm,act_sle); STAILQ_INSERT_TAIL(&g_ble_ll_conn_free_list, connsm, free_stqe); - } else { - /* Set the connection state machine we are trying to create. */ - g_ble_ll_conn_create_sm = connsm; +#if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) + if (ble_ll_sched_css_is_enabled()) { + SLIST_REMOVE(&g_ble_ll_conn_css_list, connsm, ble_ll_conn_sm, css_sle); + } +#endif } return rc; @@ -811,13 +920,13 @@ ble_ll_conn_hci_read_rem_features(const uint8_t *cmdbuf, uint8_t len) } /* If no connection handle exit with error */ - connsm = ble_ll_conn_find_active_conn(le16toh(cmd->conn_handle)); + connsm = ble_ll_conn_find_by_handle(le16toh(cmd->conn_handle)); if (!connsm) { return BLE_ERR_UNK_CONN_ID; } /* If already pending exit with error */ - if (connsm->csmflags.cfbit.pending_hci_rd_features) { + if (connsm->flags.features_host_req) { return BLE_ERR_CMD_DISALLOWED; } @@ -825,21 +934,51 @@ ble_ll_conn_hci_read_rem_features(const uint8_t *cmdbuf, uint8_t len) * Start control procedure if we did not receive peer's features and did not * start procedure already. */ - if (!connsm->csmflags.cfbit.rxd_features && - !IS_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_FEATURE_XCHG)) { - if ((connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) && - !(ble_ll_read_supp_features() & BLE_LL_FEAT_SLAVE_INIT)) { + if (!connsm->flags.features_rxd && + !IS_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_FEATURE_XCHG)) { +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) + if ((connsm->conn_role == BLE_LL_CONN_ROLE_PERIPHERAL) && + !(ble_ll_read_supp_features() & BLE_LL_FEAT_PERIPH_INIT)) { return BLE_ERR_CMD_DISALLOWED; } +#endif ble_ll_ctrl_proc_start(connsm, BLE_LL_CTRL_PROC_FEATURE_XCHG); } - connsm->csmflags.cfbit.pending_hci_rd_features = 1; + connsm->flags.features_host_req = 1; return BLE_ERR_SUCCESS; } +static bool +ble_ll_conn_params_in_range(struct ble_ll_conn_sm *connsm, + const struct ble_hci_le_conn_update_cp *cmd) +{ + if (!IN_RANGE(connsm->conn_itvl, le16toh(cmd->conn_itvl_min), + le16toh(cmd->conn_itvl_max))) { + return false; + } + + if (connsm->periph_latency != le16toh(cmd->conn_latency)) { + return false; + } + + if (connsm->supervision_tmo != le16toh(cmd->supervision_timeout)) { + return false; + } + + return true; +} + +static void +ble_ll_conn_hci_update_complete_event(void *user_data) +{ + struct ble_ll_conn_sm *connsm = user_data; + + ble_ll_hci_ev_conn_update(connsm, BLE_ERR_SUCCESS); +} + /** * Called to process a connection update command. * @@ -856,9 +995,10 @@ ble_ll_conn_hci_update(const uint8_t *cmdbuf, uint8_t len) uint16_t handle; struct ble_ll_conn_sm *connsm; struct hci_conn_update *hcu; + uint16_t max_ce_len; /* - * XXX: must deal with slave not supporting this feature and using + * XXX: must deal with peripheral not supporting this feature and using * conn update! Right now, we only check if WE support the connection * parameters request procedure. We dont check if the remote does. * We should also be able to deal with sending the parameter request, @@ -868,11 +1008,41 @@ ble_ll_conn_hci_update(const uint8_t *cmdbuf, uint8_t len) /* If no connection handle exit with error */ handle = le16toh(cmd->conn_handle); - connsm = ble_ll_conn_find_active_conn(handle); + connsm = ble_ll_conn_find_by_handle(handle); if (!connsm) { return BLE_ERR_UNK_CONN_ID; } + /* if current connection parameters fit updated values we don't have to + * trigger LL procedure and just update local values (Min/Max CE Length) + * + * Note that this is also allowed for CSS as nothing changes WRT connections + * scheduling. + */ + if (ble_ll_conn_params_in_range(connsm, cmd)) { + max_ce_len = le16toh(cmd->max_ce_len); + + if (le16toh(cmd->min_ce_len) > max_ce_len) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + connsm->max_ce_len_ticks = ble_ll_tmr_u2t_up(max_ce_len * BLE_LL_CONN_CE_USECS); + + ble_ll_hci_post_cmd_cb_set(ble_ll_conn_hci_update_complete_event, connsm); + + return BLE_ERR_SUCCESS; + } + +#if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) + /* We only allow to change connection parameters if conn_itvl can stay unchanged */ + if (ble_ll_sched_css_is_enabled() && + connsm->conn_role == BLE_LL_CONN_ROLE_CENTRAL && + (connsm->conn_itvl < le16toh(cmd->conn_itvl_min) || + connsm->conn_itvl > le16toh(cmd->conn_itvl_max))) { + return BLE_ERR_CMD_DISALLOWED; + } +#endif + /* Better not have this procedure ongoing! */ if (IS_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_CONN_PARAM_REQ) || IS_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_CONN_UPDATE)) { @@ -881,46 +1051,70 @@ ble_ll_conn_hci_update(const uint8_t *cmdbuf, uint8_t len) /* See if this feature is supported on both sides */ if ((connsm->conn_features & BLE_LL_FEAT_CONN_PARM_REQ) == 0) { - if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) { +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) + if (connsm->conn_role == BLE_LL_CONN_ROLE_PERIPHERAL) { return BLE_ERR_UNSUPP_REM_FEATURE; } +#endif ctrl_proc = BLE_LL_CTRL_PROC_CONN_UPDATE; } else { ctrl_proc = BLE_LL_CTRL_PROC_CONN_PARAM_REQ; } /* - * If we are a slave and the master has initiated the procedure already - * we should deny the slave request for now. If we are a master and the - * slave has initiated the procedure, we need to send a reject to the - * slave. + * If we are a peripheral and the central has initiated the procedure already + * we should deny the peripheral request for now. If we are a central and the + * peripheral has initiated the procedure, we need to send a reject to the + * peripheral. */ - if (connsm->csmflags.cfbit.awaiting_host_reply) { - if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) { - return BLE_ERR_LMP_COLLISION; - } else { - connsm->csmflags.cfbit.awaiting_host_reply = 0; + if (connsm->flags.conn_update_host_w4reply) { + switch (connsm->conn_role) { +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + case BLE_LL_CONN_ROLE_CENTRAL: + connsm->flags.conn_update_host_w4reply = 0; /* XXX: If this fails no reject ind will be sent! */ ble_ll_ctrl_reject_ind_send(connsm, connsm->host_reply_opcode, BLE_ERR_LMP_COLLISION); + break; +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) + case BLE_LL_CONN_ROLE_PERIPHERAL: + return BLE_ERR_LMP_COLLISION; + break; +#endif + default: + BLE_LL_ASSERT(0); + break; } } /* - * If we are a slave and the master has initiated the channel map - * update procedure we should deny the slave request for now. + * If we are a peripheral and the central has initiated the channel map + * update procedure we should deny the peripheral request for now. */ - if (connsm->csmflags.cfbit.chanmap_update_scheduled) { - if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) { +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) + if (connsm->flags.chanmap_update_sched) { + if (connsm->conn_role == BLE_LL_CONN_ROLE_PERIPHERAL) { return BLE_ERR_DIFF_TRANS_COLL; } } +#endif /* Retrieve command data */ hcu = &connsm->conn_param_req; +#if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) + if (ble_ll_sched_css_is_enabled()) { + hcu->conn_itvl_max = connsm->conn_itvl; + hcu->conn_itvl_min = connsm->conn_itvl; + } else { + hcu->conn_itvl_min = le16toh(cmd->conn_itvl_min); + hcu->conn_itvl_max = le16toh(cmd->conn_itvl_max); + } +#else hcu->conn_itvl_min = le16toh(cmd->conn_itvl_min); hcu->conn_itvl_max = le16toh(cmd->conn_itvl_max); +#endif hcu->conn_latency = le16toh(cmd->conn_latency); hcu->supervision_timeout = le16toh(cmd->supervision_timeout); hcu->min_ce_len = le16toh(cmd->min_ce_len); @@ -937,6 +1131,13 @@ ble_ll_conn_hci_update(const uint8_t *cmdbuf, uint8_t len) if (!rc) { hcu->handle = handle; +#if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) + connsm->css_slot_idx_pending = connsm->css_slot_idx; +#endif + + /* Mark procedure as host initiated */ + connsm->flags.conn_update_host_initd = 1; + /* Start the control procedure */ ble_ll_ctrl_proc_start(connsm, ctrl_proc); } @@ -970,7 +1171,7 @@ ble_ll_conn_hci_param_rr(const uint8_t *cmdbuf, uint8_t len, } /* If we dont have a handle we cant do anything */ - connsm = ble_ll_conn_find_active_conn(handle); + connsm = ble_ll_conn_find_by_handle(handle); if (!connsm) { rc = BLE_ERR_UNK_CONN_ID; goto done; @@ -980,7 +1181,7 @@ ble_ll_conn_hci_param_rr(const uint8_t *cmdbuf, uint8_t len, rc = ble_ll_conn_process_conn_params(cmd, connsm); /* The connection should be awaiting a reply. If not, just discard */ - if (connsm->csmflags.cfbit.awaiting_host_reply) { + if (connsm->flags.conn_update_host_w4reply) { /* Get a control packet buffer */ if (rc == BLE_ERR_SUCCESS) { om = os_msys_get_pkthdr(BLE_LL_CTRL_MAX_PDU_LEN, @@ -998,7 +1199,7 @@ ble_ll_conn_hci_param_rr(const uint8_t *cmdbuf, uint8_t len, ble_ll_ctrl_reject_ind_send(connsm, connsm->host_reply_opcode, BLE_ERR_CONN_PARMS); } - connsm->csmflags.cfbit.awaiting_host_reply = 0; + connsm->flags.conn_update_host_w4reply = 0; /* XXX: if we cant get a buffer, what do we do? We need to remember * reason if it was a negative reply. We also would need to have @@ -1036,7 +1237,7 @@ ble_ll_conn_hci_param_nrr(const uint8_t *cmdbuf, uint8_t len, } /* If we dont have a handle we cant do anything */ - connsm = ble_ll_conn_find_active_conn(handle); + connsm = ble_ll_conn_find_by_handle(handle); if (!connsm) { rc = BLE_ERR_UNK_CONN_ID; goto done; @@ -1045,11 +1246,11 @@ ble_ll_conn_hci_param_nrr(const uint8_t *cmdbuf, uint8_t len, rc = BLE_ERR_SUCCESS; /* The connection should be awaiting a reply. If not, just discard */ - if (connsm->csmflags.cfbit.awaiting_host_reply) { + if (connsm->flags.conn_update_host_w4reply) { /* XXX: check return code and deal */ ble_ll_ctrl_reject_ind_send(connsm, connsm->host_reply_opcode, cmd->reason); - connsm->csmflags.cfbit.awaiting_host_reply = 0; + connsm->flags.conn_update_host_w4reply = 0; /* XXX: if we cant get a buffer, what do we do? We need to remember * reason if it was a negative reply. We also would need to have @@ -1068,7 +1269,7 @@ ble_ll_conn_hci_param_nrr(const uint8_t *cmdbuf, uint8_t len, * safe to use g_ble_ll_conn_comp_ev */ static void -ble_ll_conn_hci_cancel_conn_complete_event(void) +ble_ll_conn_hci_cancel_conn_complete_event(void *user_data) { BLE_LL_ASSERT(g_ble_ll_conn_comp_ev); @@ -1086,7 +1287,7 @@ ble_ll_conn_hci_cancel_conn_complete_event(void) * @return int */ int -ble_ll_conn_create_cancel(ble_ll_hci_post_cmd_complete_cb *post_cmd_cb) +ble_ll_conn_create_cancel(void) { int rc; struct ble_ll_conn_sm *connsm; @@ -1099,14 +1300,14 @@ ble_ll_conn_create_cancel(ble_ll_hci_post_cmd_complete_cb *post_cmd_cb) * return disallowed as well */ OS_ENTER_CRITICAL(sr); - connsm = g_ble_ll_conn_create_sm; + connsm = g_ble_ll_conn_create_sm.connsm; if (connsm && (connsm->conn_state == BLE_LL_CONN_STATE_IDLE)) { /* stop scanning and end the connection event */ - g_ble_ll_conn_create_sm = NULL; + g_ble_ll_conn_create_sm.connsm = NULL; ble_ll_scan_sm_stop(1); ble_ll_conn_end(connsm, BLE_ERR_UNK_CONN_ID); - *post_cmd_cb = ble_ll_conn_hci_cancel_conn_complete_event; + ble_ll_hci_post_cmd_cb_set(ble_ll_conn_hci_cancel_conn_complete_event, NULL); rc = BLE_ERR_SUCCESS; } else { @@ -1148,14 +1349,14 @@ ble_ll_conn_hci_disconnect_cmd(const struct ble_hci_lc_disconnect_cp *cmd) case BLE_ERR_UNSUPP_REM_FEATURE: case BLE_ERR_UNIT_KEY_PAIRING: case BLE_ERR_CONN_PARMS: - connsm = ble_ll_conn_find_active_conn(handle); + connsm = ble_ll_conn_find_by_handle(handle); if (connsm) { /* Do not allow command if we are in process of disconnecting */ if (connsm->disconnect_reason) { rc = BLE_ERR_CMD_DISALLOWED; } else { /* This control procedure better not be pending! */ - BLE_LL_ASSERT(CONN_F_TERMINATE_STARTED(connsm) == 0); + BLE_LL_ASSERT(connsm->flags.terminate_started == 0); /* Record the disconnect reason */ connsm->disconnect_reason = cmd->reason; @@ -1197,7 +1398,7 @@ ble_ll_conn_hci_rd_rem_ver_cmd(const uint8_t *cmdbuf, uint8_t len) } /* Check for valid parameters */ - connsm = ble_ll_conn_find_active_conn(le16toh(cmd->conn_handle)); + connsm = ble_ll_conn_find_by_handle(le16toh(cmd->conn_handle)); if (!connsm) { return BLE_ERR_UNK_CONN_ID; } @@ -1214,7 +1415,7 @@ ble_ll_conn_hci_rd_rem_ver_cmd(const uint8_t *cmdbuf, uint8_t len) * NOTE: we cant just send the event here. That would cause the event to * be queued before the command status. */ - if (!connsm->csmflags.cfbit.version_ind_sent) { + if (!connsm->flags.version_ind_txd) { ble_ll_ctrl_proc_start(connsm, BLE_LL_CTRL_PROC_VERSION_XCHG); } else { connsm->pending_ctrl_procs |= (1 << BLE_LL_CTRL_PROC_VERSION_XCHG); @@ -1247,7 +1448,7 @@ ble_ll_conn_hci_rd_rssi(const uint8_t *cmdbuf, uint8_t len, uint8_t *rspbuf, uin rsp->handle = cmd->handle; - connsm = ble_ll_conn_find_active_conn(le16toh(cmd->handle)); + connsm = ble_ll_conn_find_by_handle(le16toh(cmd->handle)); if (!connsm) { rsp->rssi = 127; rc = BLE_ERR_UNK_CONN_ID; @@ -1284,15 +1485,15 @@ ble_ll_conn_hci_rd_chan_map(const uint8_t *cmdbuf, uint8_t len, } handle = le16toh(cmd->conn_handle); - connsm = ble_ll_conn_find_active_conn(handle); + connsm = ble_ll_conn_find_by_handle(handle); if (!connsm) { rc = BLE_ERR_UNK_CONN_ID; memset(rsp->chan_map, 0, sizeof(rsp->chan_map)); } else { - if (connsm->csmflags.cfbit.chanmap_update_scheduled) { - memcpy(rsp->chan_map, connsm->req_chanmap, BLE_LL_CONN_CHMAP_LEN); + if (connsm->flags.chanmap_update_sched) { + memcpy(rsp->chan_map, connsm->req_chanmap, BLE_LL_CHAN_MAP_LEN); } else { - memcpy(rsp->chan_map, connsm->chanmap, BLE_LL_CONN_CHMAP_LEN); + memcpy(rsp->chan_map, connsm->chan_map, BLE_LL_CHAN_MAP_LEN); } rc = BLE_ERR_SUCCESS; } @@ -1302,38 +1503,9 @@ ble_ll_conn_hci_rd_chan_map(const uint8_t *cmdbuf, uint8_t len, *rsplen = sizeof(*rsp); return rc; } +#endif -/** - * Called when the host issues the LE command "set host channel classification" - * - * @param cmdbuf - * - * @return int - */ -int -ble_ll_conn_hci_set_chan_class(const uint8_t *cmdbuf, uint8_t len) -{ - const struct ble_hci_le_set_host_chan_class_cp *cmd = (const void *) cmdbuf; - uint8_t num_used_chans; - - if (len != sizeof(*cmd)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - /* - * The HCI command states that the host is allowed to mask in just one - * channel but the Link Layer needs minimum two channels to operate. So - * I will not allow this command if there are less than 2 channels masked. - */ - num_used_chans = ble_ll_utils_calc_num_used_chans(cmd->chan_map); - if ((num_used_chans < 2) || ((cmd->chan_map[4] & 0xe0) != 0)) { - return BLE_ERR_INV_HCI_CMD_PARMS; - } - - /* Set the host channel mask */ - ble_ll_conn_set_global_chanmap(num_used_chans, cmd->chan_map); - return BLE_ERR_SUCCESS; -} +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) #if MYNEWT_VAL(BLE_LL_CFG_FEAT_DATA_LEN_EXT) int @@ -1344,8 +1516,8 @@ ble_ll_conn_hci_set_data_len(const uint8_t *cmdbuf, uint8_t len, struct ble_hci_le_set_data_len_rp *rsp = (void *) rspbuf; int rc; uint16_t handle; - uint16_t txoctets; - uint16_t txtime; + uint16_t tx_octets; + uint16_t tx_time; struct ble_ll_conn_sm *connsm; if (len != sizeof(*cmd)) { @@ -1354,48 +1526,26 @@ ble_ll_conn_hci_set_data_len(const uint8_t *cmdbuf, uint8_t len, /* Find connection */ handle = le16toh(cmd->conn_handle); - connsm = ble_ll_conn_find_active_conn(handle); + connsm = ble_ll_conn_find_by_handle(handle); if (!connsm) { rc = BLE_ERR_UNK_CONN_ID; goto done; } - txoctets = le16toh(cmd->tx_octets); - txtime = le16toh(cmd->tx_time); + tx_octets = le16toh(cmd->tx_octets); + tx_time = le16toh(cmd->tx_time); - /* Make sure it is valid */ - if (!ble_ll_chk_txrx_octets(txoctets) || - !ble_ll_chk_txrx_time(txtime)) { + if (!ble_ll_hci_check_dle(tx_octets, tx_time)) { rc = BLE_ERR_INV_HCI_CMD_PARMS; goto done; } -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) - /* - * Keep original value requested by host since we may want to recalculate - * MaxTxTime after PHY changes between coded and uncoded. - */ - connsm->host_req_max_tx_time = txtime; - - /* If peer does not support coded, we cannot use value larger than 2120us */ - if (!(connsm->remote_features[0] & (BLE_LL_FEAT_LE_CODED_PHY >> 8))) { - txtime = min(txtime, BLE_LL_CONN_SUPP_TIME_MAX_UNCODED); - } -#endif - - rc = BLE_ERR_SUCCESS; - if (connsm->max_tx_time != txtime || - connsm->max_tx_octets != txoctets) { - - connsm->max_tx_time = txtime; - connsm->max_tx_octets = txoctets; - - ble_ll_ctrl_initiate_dle(connsm); - } + rc = ble_ll_conn_set_data_len(connsm, tx_octets, tx_time, 0, 0); done: rsp->conn_handle = htole16(handle); *rsplen = sizeof(*rsp); + return rc; } #endif @@ -1419,11 +1569,13 @@ ble_ll_conn_hci_le_start_encrypt(const uint8_t *cmdbuf, uint8_t len) return BLE_ERR_INV_HCI_CMD_PARMS; } - connsm = ble_ll_conn_find_active_conn(le16toh(cmd->conn_handle)); + connsm = ble_ll_conn_find_by_handle(le16toh(cmd->conn_handle)); if (!connsm) { rc = BLE_ERR_UNK_CONN_ID; - } else if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) { +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) + } else if (connsm->conn_role == BLE_LL_CONN_ROLE_PERIPHERAL) { rc = BLE_ERR_UNSPECIFIED; +#endif } else if (connsm->cur_ctrl_proc == BLE_LL_CTRL_PROC_ENCRYPT) { /* * The specification does not say what to do here but the host should @@ -1470,17 +1622,19 @@ ble_ll_conn_hci_le_ltk_reply(const uint8_t *cmdbuf, uint8_t len, /* Find connection handle */ handle = le16toh(cmd->conn_handle); - connsm = ble_ll_conn_find_active_conn(handle); + connsm = ble_ll_conn_find_by_handle(handle); if (!connsm) { rc = BLE_ERR_UNK_CONN_ID; goto ltk_key_cmd_complete; } - /* Should never get this if we are a master! */ - if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + /* Should never get this if we are a central! */ + if (connsm->conn_role == BLE_LL_CONN_ROLE_CENTRAL) { rc = BLE_ERR_UNSPECIFIED; goto ltk_key_cmd_complete; } +#endif /* The connection should be awaiting a reply. If not, just discard */ if (connsm->enc_data.enc_state != CONN_ENC_S_LTK_REQ_WAIT) { @@ -1527,17 +1681,19 @@ ble_ll_conn_hci_le_ltk_neg_reply(const uint8_t *cmdbuf, uint8_t len, /* Find connection handle */ handle = le16toh(cmd->conn_handle); - connsm = ble_ll_conn_find_active_conn(handle); + connsm = ble_ll_conn_find_by_handle(handle); if (!connsm) { rc = BLE_ERR_UNK_CONN_ID; goto ltk_key_cmd_complete; } - /* Should never get this if we are a master! */ - if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + /* Should never get this if we are a central! */ + if (connsm->conn_role == BLE_LL_CONN_ROLE_CENTRAL) { rc = BLE_ERR_UNSPECIFIED; goto ltk_key_cmd_complete; } +#endif /* The connection should be awaiting a reply. If not, just discard */ if (connsm->enc_data.enc_state != CONN_ENC_S_LTK_REQ_WAIT) { @@ -1545,9 +1701,19 @@ ble_ll_conn_hci_le_ltk_neg_reply(const uint8_t *cmdbuf, uint8_t len, goto ltk_key_cmd_complete; } - /* We received a negative reply! Send REJECT_IND */ - ble_ll_ctrl_reject_ind_send(connsm, BLE_LL_CTRL_ENC_REQ, - BLE_ERR_PINKEY_MISSING); + /* Core 6.1 | Vol 6, Part B | 5.1.3.1 + * If this procedure is being performed after a Pause Encryption procedure, and the + * Peripheral's Host does not provide a Long Term Key, the Peripheral shall perform the + * ACL Termination procedure with the error code PIN or Key Missing (0x06). + */ + if (connsm->flags.encrypt_paused) { + connsm->disconnect_reason = BLE_ERR_PINKEY_MISSING; + ble_ll_ctrl_terminate_start(connsm); + } else { + /* We received a negative reply! Send REJECT_IND */ + ble_ll_ctrl_reject_ind_send(connsm, BLE_LL_CTRL_ENC_REQ, BLE_ERR_PINKEY_MISSING); + } + connsm->enc_data.enc_state = CONN_ENC_S_LTK_NEG_REPLY; rc = BLE_ERR_SUCCESS; @@ -1568,12 +1734,12 @@ ble_ll_conn_req_peer_sca(const uint8_t *cmdbuf, uint8_t len, const struct ble_hci_le_request_peer_sca_cp *params = (const void *)cmdbuf; struct ble_ll_conn_sm *connsm; - connsm = ble_ll_conn_find_active_conn(params->conn_handle); + connsm = ble_ll_conn_find_by_handle(le16toh(params->conn_handle)); if (!connsm) { return BLE_ERR_UNK_CONN_ID; } - if (!(connsm->remote_features[2] & (BLE_LL_FEAT_SCA_UPDATE >> 24))) { + if (!ble_ll_conn_rem_feature_check(connsm, BLE_LL_FEAT_SCA_UPDATE)) { return BLE_ERR_UNSUPP_REM_FEATURE; } @@ -1588,6 +1754,102 @@ ble_ll_conn_req_peer_sca(const uint8_t *cmdbuf, uint8_t len, } #endif +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE) +int +ble_ll_conn_hci_set_default_subrate(const uint8_t *cmdbuf, uint8_t len, + uint8_t *rspbuf, uint8_t *rsplen) +{ + const struct ble_hci_le_set_default_subrate_cp *cp = (const void *)cmdbuf; + struct ble_ll_conn_global_params *gcp = &g_ble_ll_conn_params; + uint16_t subrate_min; + uint16_t subrate_max; + uint16_t max_latency; + uint16_t cont_num; + uint16_t supervision_tmo; + + subrate_min = le16toh(cp->subrate_min); + subrate_max = le16toh(cp->subrate_max); + max_latency = le16toh(cp->max_latency); + cont_num = le16toh(cp->cont_num); + supervision_tmo = le16toh(cp->supervision_tmo); + + if ((subrate_min < 0x0001) || (subrate_min > 0x01f4) || + (subrate_max < 0x0001) || (subrate_max > 0x01f4) || + (max_latency > 0x01f3) || (cont_num > 0x01f3) || + (supervision_tmo < 0x000a) || (supervision_tmo > 0x0c80)) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + if (subrate_max * (max_latency + 1) > 500) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + if (subrate_max < subrate_min) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + if (cont_num >= subrate_max) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + gcp->acc_subrate_min = subrate_min; + gcp->acc_subrate_max = subrate_max; + gcp->acc_max_latency = max_latency; + gcp->acc_cont_num = cont_num; + gcp->acc_supervision_tmo = supervision_tmo; + + return 0; +} + +int +ble_ll_conn_hci_subrate_req(const uint8_t *cmdbuf, uint8_t len, + uint8_t *rspbuf, uint8_t *rsplen) +{ + const struct ble_hci_le_subrate_req_cp *cp = (const void *)cmdbuf; + struct ble_ll_conn_subrate_req_params srp; + struct ble_ll_conn_sm *connsm; + uint16_t conn_handle; + int rc; + + conn_handle = le16toh(cp->conn_handle); + srp.subrate_min = le16toh(cp->subrate_min); + srp.subrate_max = le16toh(cp->subrate_max); + srp.max_latency = le16toh(cp->max_latency); + srp.cont_num = le16toh(cp->cont_num); + srp.supervision_tmo = le16toh(cp->supervision_tmo); + + connsm = ble_ll_conn_find_by_handle(conn_handle); + if (!connsm) { + return BLE_ERR_UNK_CONN_ID; + } + + rc = ble_ll_conn_subrate_req_hci(connsm, &srp); + if (rc < 0) { + if (rc == -EINVAL) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } else if (rc == -EBUSY) { + return BLE_ERR_CTLR_BUSY; + } else if (rc == -ENOTSUP) { + return BLE_ERR_UNSUPP_REM_FEATURE; + } else { + return BLE_ERR_UNSPECIFIED; + } + } + +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + if (connsm->conn_role == BLE_LL_CONN_ROLE_CENTRAL) { + connsm->acc_subrate_min = srp.subrate_min; + connsm->acc_subrate_min = srp.subrate_max; + connsm->acc_max_latency = srp.max_latency; + connsm->acc_cont_num = srp.cont_num; + connsm->acc_supervision_tmo = srp.supervision_tmo; + } +#endif + + return 0; +} +#endif + #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_PING) /** * Read authenticated payload timeout (OGF=3, OCF==0x007B) @@ -1613,7 +1875,7 @@ ble_ll_conn_hci_rd_auth_pyld_tmo(const uint8_t *cmdbuf, uint8_t len, } handle = le16toh(cmd->conn_handle); - connsm = ble_ll_conn_find_active_conn(handle); + connsm = ble_ll_conn_find_by_handle(handle); if (!connsm) { rc = BLE_ERR_UNK_CONN_ID; rsp->tmo = 0; @@ -1656,21 +1918,24 @@ ble_ll_conn_hci_wr_auth_pyld_tmo(const uint8_t *cmdbuf, uint8_t len, handle = le16toh(cmd->conn_handle); - connsm = ble_ll_conn_find_active_conn(handle); + connsm = ble_ll_conn_find_by_handle(handle); if (!connsm) { rc = BLE_ERR_UNK_CONN_ID; } else { /* * The timeout is in units of 10 msecs. We need to make sure that the - * timeout is greater than or equal to connItvl * (1 + slaveLatency) + * timeout is greater than or equal to connItvl * (1 + peripheralLatency) */ tmo = le16toh(cmd->tmo); min_tmo = (uint32_t)connsm->conn_itvl * BLE_LL_CONN_ITVL_USECS; - min_tmo *= (connsm->slave_latency + 1); +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE) + min_tmo *= connsm->subrate_factor; +#endif + min_tmo *= (connsm->periph_latency + 1); min_tmo /= 10000; if (tmo < min_tmo) { - rc = BLE_ERR_INV_HCI_CMD_PARMS; + rc = BLE_ERR_CMD_DISALLOWED; } else { connsm->auth_pyld_tmo = tmo; if (ble_npl_callout_is_active(&connsm->auth_pyld_timer)) { @@ -1685,7 +1950,40 @@ ble_ll_conn_hci_wr_auth_pyld_tmo(const uint8_t *cmdbuf, uint8_t len, } #endif -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) +int +ble_ll_conn_hci_cb_read_tx_pwr(const uint8_t *cmdbuf, uint8_t len, + uint8_t *rspbuf, uint8_t *rsplen) +{ + const struct ble_hci_cb_read_tx_pwr_cp *cmd = (const void *)cmdbuf; + struct ble_hci_cb_read_tx_pwr_rp *rsp = (void *)rspbuf; + struct ble_ll_conn_sm *connsm; + uint16_t handle; + + if (len != sizeof(*cmd)) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + if (cmd->type != 0x01) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + handle = le16toh(cmd->conn_handle); + connsm = ble_ll_conn_find_by_handle(handle); + if (!connsm) { + return BLE_ERR_UNK_CONN_ID; + } + + rsp->conn_handle = cmd->conn_handle; + rsp->tx_level = g_ble_ll_tx_power; + + *rsplen = sizeof(*rsp); + + return BLE_ERR_SUCCESS; +} +#endif + +#if MYNEWT_VAL(BLE_LL_PHY) /** * Read current phy for connection (OGF=8, OCF==0x0030) * @@ -1709,7 +2007,7 @@ ble_ll_conn_hci_le_rd_phy(const uint8_t *cmdbuf, uint8_t len, } handle = le16toh(cmd->conn_handle); - connsm = ble_ll_conn_find_active_conn(handle); + connsm = ble_ll_conn_find_by_handle(handle); if (!connsm) { rsp->tx_phy = 0; rsp->rx_phy = 0; @@ -1749,7 +2047,7 @@ ble_ll_conn_hci_le_set_phy(const uint8_t *cmdbuf, uint8_t len) } handle = le16toh(cmd->conn_handle); - connsm = ble_ll_conn_find_active_conn(handle); + connsm = ble_ll_conn_find_by_handle(handle); if (!connsm) { return BLE_ERR_UNK_CONN_ID; } @@ -1758,7 +2056,7 @@ ble_ll_conn_hci_le_set_phy(const uint8_t *cmdbuf, uint8_t len) * If host has requested a PHY update and we are not finished do * not allow another one */ - if (CONN_F_HOST_PHY_UPDATE(connsm)) { + if (connsm->flags.phy_update_host_initiated) { return BLE_ERR_CMD_DISALLOWED; } @@ -1774,9 +2072,9 @@ ble_ll_conn_hci_le_set_phy(const uint8_t *cmdbuf, uint8_t len) goto phy_cmd_param_err; } - connsm->phy_data.phy_options = phy_options & 0x03; - connsm->phy_data.host_pref_tx_phys_mask = tx_phys, - connsm->phy_data.host_pref_rx_phys_mask = rx_phys; + connsm->phy_data.pref_opts = phy_options & 0x03; + connsm->phy_data.pref_mask_tx = tx_phys, + connsm->phy_data.pref_mask_rx = rx_phys; /* * The host preferences override the default phy preferences. Currently, @@ -1787,9 +2085,9 @@ ble_ll_conn_hci_le_set_phy(const uint8_t *cmdbuf, uint8_t len) */ if (IS_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_PHY_UPDATE)) { if (connsm->cur_ctrl_proc != BLE_LL_CTRL_PROC_PHY_UPDATE) { - CONN_F_CTRLR_PHY_UPDATE(connsm) = 0; + connsm->flags.phy_update_self_initiated = 0; } - CONN_F_HOST_PHY_UPDATE(connsm) = 1; + connsm->flags.phy_update_host_initiated = 1; } else { /* * We could be doing a peer-initiated PHY update procedure. If this @@ -1797,20 +2095,20 @@ ble_ll_conn_hci_le_set_phy(const uint8_t *cmdbuf, uint8_t len) * we are not done with a peer-initiated procedure we just set the * pending bit but do not start the control procedure. */ - if (CONN_F_PEER_PHY_UPDATE(connsm)) { + if (connsm->flags.phy_update_peer_initiated) { connsm->pending_ctrl_procs |= (1 << BLE_LL_CTRL_PROC_PHY_UPDATE); - CONN_F_HOST_PHY_UPDATE(connsm) = 1; + connsm->flags.phy_update_host_initiated = 1; } else { /* Check if we should start phy update procedure */ - if (!ble_ll_conn_chk_phy_upd_start(connsm)) { - CONN_F_HOST_PHY_UPDATE(connsm) = 1; + if (!ble_ll_conn_phy_update_if_needed(connsm)) { + connsm->flags.phy_update_host_initiated = 1; } else { /* * Set flag to send a PHY update complete event. We set flag * even if we do not do an update procedure since we have to * inform the host even if we decide not to change anything. */ - CONN_F_PHY_UPDATE_EVENT(connsm) = 1; + connsm->flags.phy_update_host_w4event = 1; } } } @@ -1837,7 +2135,21 @@ ble_ll_set_sync_transfer_params(const uint8_t *cmdbuf, uint8_t len, goto done; } - if (cmd->mode > 0x02) { + if (MYNEWT_VAL(BLE_VERSION) >= 53) { + if (cmd->mode > 0x03) { + rc = BLE_ERR_INV_HCI_CMD_PARMS; + goto done; + } + + if ((cmd->mode == 0x03) && + !MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_ADI_SUPPORT)) { + /* We do not support ADI in periodic advertising thus cannot enable + * duplicate filtering. + */ + rc = BLE_ERR_UNSUPPORTED; + goto done; + } + } else if (cmd->mode > 0x02) { rc = BLE_ERR_INV_HCI_CMD_PARMS; goto done; } @@ -1860,7 +2172,7 @@ ble_ll_set_sync_transfer_params(const uint8_t *cmdbuf, uint8_t len, goto done; } - connsm = ble_ll_conn_find_active_conn(le16toh(cmd->conn_handle)); + connsm = ble_ll_conn_find_by_handle(le16toh(cmd->conn_handle)); if (!connsm) { rc = BLE_ERR_UNK_CONN_ID; goto done; @@ -1890,7 +2202,19 @@ ble_ll_set_default_sync_transfer_params(const uint8_t *cmdbuf, uint8_t len) return BLE_ERR_INV_HCI_CMD_PARMS; } - if (cmd->mode > 0x02) { + if (MYNEWT_VAL(BLE_VERSION) >= 53) { + if (cmd->mode > 0x03) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + if ((cmd->mode == 0x03) && + !MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_ADI_SUPPORT)) { + /* We do not support ADI in periodic advertising thus cannot enable + * duplicate filtering. + */ + return BLE_ERR_UNSUPPORTED; + } + } else if (cmd->mode > 0x02) { return BLE_ERR_INV_HCI_CMD_PARMS; } @@ -1917,3 +2241,4 @@ ble_ll_set_default_sync_transfer_params(const uint8_t *cmdbuf, uint8_t len) return BLE_ERR_SUCCESS; } #endif +#endif diff --git a/nimble/controller/src/ble_ll_conn_priv.h b/nimble/controller/src/ble_ll_conn_priv.h index 915a4d2a62..460a836ff0 100644 --- a/nimble/controller/src/ble_ll_conn_priv.h +++ b/nimble/controller/src/ble_ll_conn_priv.h @@ -47,7 +47,7 @@ extern "C" { #define BLE_LL_CONN_TX_OFF_USECS (1250) #define BLE_LL_CONN_CE_USECS (625) #define BLE_LL_CONN_TX_WIN_MIN (1) /* in tx win units */ -#define BLE_LL_CONN_SLAVE_LATENCY_MAX (499) +#define BLE_LL_CONN_PERIPH_LATENCY_MAX (499) /* Connection handle range */ #define BLE_LL_CONN_MAX_CONN_HANDLE (0x0EFF) @@ -59,11 +59,14 @@ extern "C" { #define BLE_LL_CONN_DEF_AUTH_PYLD_TMO (3000) #define BLE_LL_CONN_AUTH_PYLD_OS_TMO(x) ble_npl_time_ms_to_ticks32((x) * 10) +#if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) +#define BLE_LL_CONN_CSS_NO_SLOT (UINT16_MAX) +#endif + /* Global Link Layer connection parameters */ struct ble_ll_conn_global_params { - uint8_t master_chan_map[BLE_LL_CONN_CHMAP_LEN]; - uint8_t num_used_chans; +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) || MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) uint8_t supp_max_tx_octets; uint8_t supp_max_rx_octets; uint8_t conn_init_max_tx_octets; @@ -74,6 +77,14 @@ struct ble_ll_conn_global_params uint16_t conn_init_max_tx_time_coded; uint16_t supp_max_tx_time; uint16_t supp_max_rx_time; +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE) + uint16_t acc_subrate_min; + uint16_t acc_subrate_max; + uint16_t acc_max_latency; + uint16_t acc_cont_num; + uint16_t acc_supervision_tmo; +#endif +#endif }; extern struct ble_ll_conn_global_params g_ble_ll_conn_params; @@ -93,8 +104,44 @@ STAILQ_HEAD(ble_ll_conn_free_list, ble_ll_conn_sm); extern struct ble_ll_conn_active_list g_ble_ll_conn_active_list; extern struct ble_ll_conn_free_list g_ble_ll_conn_free_list; -/* Pointer to connection state machine we are trying to create */ -extern struct ble_ll_conn_sm *g_ble_ll_conn_create_sm; +#if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) +SLIST_HEAD(ble_ll_conn_css_list, ble_ll_conn_sm); +extern struct ble_ll_conn_css_list g_ble_ll_conn_css_list; +#endif + +struct ble_ll_conn_create_scan { + uint8_t filter_policy; + uint8_t own_addr_type; + uint8_t peer_addr_type; + uint8_t peer_addr[BLE_DEV_ADDR_LEN]; +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) + uint8_t init_phy_mask; +#endif + struct { + uint16_t itvl; + uint16_t window; + } scan_params[2]; +}; + +struct ble_ll_conn_create_params { + uint32_t conn_itvl; + uint32_t conn_itvl_ticks; + uint8_t conn_itvl_usecs; + uint16_t conn_latency; + uint16_t supervision_timeout; + uint16_t min_ce_len; + uint16_t max_ce_len; +}; + +struct ble_ll_conn_create_sm { + struct ble_ll_conn_sm *connsm; +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) + struct ble_ll_conn_create_params params[3]; +#endif +}; + +extern struct ble_ll_conn_create_sm g_ble_ll_conn_create_sm; +extern struct ble_ll_conn_sm *g_ble_ll_conn_css_ref; /* Generic interface */ struct ble_ll_len_req; @@ -122,58 +169,42 @@ void ble_ll_conn_end(struct ble_ll_conn_sm *connsm, uint8_t ble_err); void ble_ll_conn_enqueue_pkt(struct ble_ll_conn_sm *connsm, struct os_mbuf *om, uint8_t hdr_byte, uint16_t length); struct ble_ll_conn_sm *ble_ll_conn_sm_get(void); -void ble_ll_conn_master_init(struct ble_ll_conn_sm *connsm, - struct hci_create_conn *hcc); -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -void ble_ll_conn_ext_master_init(struct ble_ll_conn_sm *connsm, - struct hci_ext_create_conn *hcc); - -void ble_ll_conn_ext_set_params(struct ble_ll_conn_sm *connsm, - struct hci_ext_conn_params *hcc_params, - int phy); -#endif +void ble_ll_conn_central_init(struct ble_ll_conn_sm *connsm, + struct ble_ll_conn_create_scan *cc_scan, + struct ble_ll_conn_create_params *cc_params); -struct ble_ll_conn_sm *ble_ll_conn_find_active_conn(uint16_t handle); +struct ble_ll_conn_sm *ble_ll_conn_find_by_handle(uint16_t handle); void ble_ll_conn_update_eff_data_len(struct ble_ll_conn_sm *connsm); /* Advertising interface */ -int ble_ll_conn_slave_start(uint8_t *rxbuf, uint8_t pat, - struct ble_mbuf_hdr *rxhdr, bool force_csa2); +int ble_ll_conn_periph_start(uint8_t *rxbuf, uint8_t pat, + struct ble_mbuf_hdr *rxhdr, bool force_csa2); /* Link Layer interface */ void ble_ll_conn_module_init(void); -void ble_ll_conn_set_global_chanmap(uint8_t num_used_chans, const uint8_t *chanmap); void ble_ll_conn_module_reset(void); void ble_ll_conn_tx_pkt_in(struct os_mbuf *om, uint16_t handle, uint16_t len); int ble_ll_conn_rx_isr_start(struct ble_mbuf_hdr *rxhdr, uint32_t aa); int ble_ll_conn_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr); void ble_ll_conn_rx_data_pdu(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *hdr); -void ble_ll_init_rx_pkt_in(uint8_t pdu_type, uint8_t *rxbuf, - struct ble_mbuf_hdr *ble_hdr); -int ble_ll_init_rx_isr_start(uint8_t pdu_type, struct ble_mbuf_hdr *ble_hdr); -int ble_ll_init_rx_isr_end(uint8_t *rxbuf, uint8_t crcok, - struct ble_mbuf_hdr *ble_hdr); void ble_ll_conn_wfr_timer_exp(void); -void ble_ll_conn_init_wfr_timer_exp(void); int ble_ll_conn_is_lru(struct ble_ll_conn_sm *s1, struct ble_ll_conn_sm *s2); uint32_t ble_ll_conn_get_ce_end_time(void); void ble_ll_conn_event_halt(void); -void ble_ll_conn_reset_pending_aux_conn_rsp(void); -bool ble_ll_conn_init_pending_aux_conn_rsp(void); /* HCI */ void ble_ll_disconn_comp_event_send(struct ble_ll_conn_sm *connsm, uint8_t reason); void ble_ll_auth_pyld_tmo_event_send(struct ble_ll_conn_sm *connsm); int ble_ll_conn_hci_disconnect_cmd(const struct ble_hci_lc_disconnect_cp *cmd); int ble_ll_conn_hci_rd_rem_ver_cmd(const uint8_t *cmdbuf, uint8_t len); -int ble_ll_conn_create(const uint8_t *cmdbuf, uint8_t len); +int ble_ll_conn_hci_create(const uint8_t *cmdbuf, uint8_t len); int ble_ll_conn_hci_update(const uint8_t *cmdbuf, uint8_t len); int ble_ll_conn_hci_set_chan_class(const uint8_t *cmdbuf, uint8_t len); int ble_ll_conn_hci_param_rr(const uint8_t *cmdbuf, uint8_t len, uint8_t *rspbuf, uint8_t *rsplen); int ble_ll_conn_hci_param_nrr(const uint8_t *cmdbuf, uint8_t len, uint8_t *rspbuf, uint8_t *rsplen); -int ble_ll_conn_create_cancel(ble_ll_hci_post_cmd_complete_cb *post_cmd_cb); +int ble_ll_conn_create_cancel(void); void ble_ll_conn_num_comp_pkts_event_send(struct ble_ll_conn_sm *connsm); void ble_ll_conn_comp_event_send(struct ble_ll_conn_sm *connsm, uint8_t status, uint8_t *evbuf, struct ble_ll_adv_sm *advsm); @@ -196,13 +227,23 @@ int ble_ll_conn_hci_wr_auth_pyld_tmo(const uint8_t *cmdbuf, uint8_t len, uint8_t *rspbuf, uint8_t *rsplen); int ble_ll_conn_hci_rd_auth_pyld_tmo(const uint8_t *cmdbuf, uint8_t len, uint8_t *rspbuf, uint8_t *rsplen); +int ble_ll_conn_hci_cb_read_tx_pwr(const uint8_t *cmdbuf, uint8_t len, + uint8_t *rspbuf, uint8_t *rsplen); + #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_SCA_UPDATE) int ble_ll_conn_req_peer_sca(const uint8_t *cmdbuf, uint8_t len, uint8_t *rspbuf, uint8_t *rsplen); #endif +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE) +int ble_ll_conn_hci_set_default_subrate(const uint8_t *cmdbuf, uint8_t len, + uint8_t *rspbuf, uint8_t *rsplen); +int ble_ll_conn_hci_subrate_req(const uint8_t *cmdbuf, uint8_t len, + uint8_t *rspbuf, uint8_t *rsplen); +#endif #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_PING) void ble_ll_conn_auth_pyld_timer_start(struct ble_ll_conn_sm *connsm); +void ble_ll_conn_auth_pyld_timer_cb(struct ble_npl_event *ev); #else #define ble_ll_conn_auth_pyld_timer_start(x) #endif @@ -213,15 +254,21 @@ bool ble_ll_conn_cth_flow_enable(bool enabled); void ble_ll_conn_cth_flow_process_cmd(const uint8_t *cmdbuf); #endif -int ble_ll_hci_cmd_rx(uint8_t *cmd, void *arg); -int ble_ll_hci_acl_rx(struct os_mbuf *om, void *arg); +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_DATA_LEN_EXT) +int ble_ll_conn_set_data_len(struct ble_ll_conn_sm *connsm, + uint16_t tx_octets, uint16_t tx_time, + uint16_t rx_octets, uint16_t rx_time); +#endif + +void ble_ll_conn_itvl_to_ticks(uint32_t itvl, + uint32_t *itvl_ticks, uint8_t *itvl_usecs); int ble_ll_conn_hci_le_rd_phy(const uint8_t *cmdbuf, uint8_t len, uint8_t *rsp, uint8_t *rsplen); int ble_ll_conn_hci_le_set_phy(const uint8_t *cmdbuf, uint8_t len); -int ble_ll_conn_chk_phy_upd_start(struct ble_ll_conn_sm *connsm); +int ble_ll_conn_phy_update_if_needed(struct ble_ll_conn_sm *connsm); #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -int ble_ll_ext_conn_create(const uint8_t *cmdbuf, uint8_t cmdlen); +int ble_ll_conn_hci_ext_create(const uint8_t *cmdbuf, uint8_t len); #endif #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER) @@ -230,6 +277,14 @@ int ble_ll_set_sync_transfer_params(const uint8_t *cmdbuf, uint8_t len, int ble_ll_set_default_sync_transfer_params(const uint8_t *cmdbuf, uint8_t len); #endif +#if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) +void ble_ll_conn_css_set_next_slot(uint16_t slot_idx); +uint16_t ble_ll_conn_css_get_next_slot(void); +int ble_ll_conn_css_is_slot_busy(uint16_t slot_idx); +int ble_ll_conn_css_move(struct ble_ll_conn_sm *connsm, uint16_t slot_idx); + +#endif + #ifdef __cplusplus } #endif diff --git a/nimble/controller/src/ble_ll_crypto.c b/nimble/controller/src/ble_ll_crypto.c new file mode 100644 index 0000000000..be3e1be3b6 --- /dev/null +++ b/nimble/controller/src/ble_ll_crypto.c @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#include +#include +#include + +int +ble_ll_crypto_cmac(const uint8_t *key, const uint8_t *in, int len, + uint8_t *out) +{ + struct tc_aes_key_sched_struct sched; + struct tc_cmac_struct state; + + if (tc_cmac_setup(&state, key, &sched) == TC_CRYPTO_FAIL) { + return -1; + } + + if (tc_cmac_update(&state, in, len) == TC_CRYPTO_FAIL) { + return -1; + } + + if (tc_cmac_final(out, &state) == TC_CRYPTO_FAIL) { + return -1; + } + + return 0; +} + +int +ble_ll_crypto_h8(const uint8_t *k, const uint8_t *s, const uint8_t *key_id, + uint8_t *out) +{ + uint8_t ik[16]; + int rc; + + rc = ble_ll_crypto_cmac(s, k, 16, ik); + if (rc) { + return rc; + } + + return ble_ll_crypto_cmac(ik, key_id, 4, out); +} diff --git a/nimble/controller/src/ble_ll_cs.c b/nimble/controller/src/ble_ll_cs.c new file mode 100644 index 0000000000..a9a181a849 --- /dev/null +++ b/nimble/controller/src/ble_ll_cs.c @@ -0,0 +1,119 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#if MYNEWT_VAL(BLE_LL_CHANNEL_SOUNDING) +#include +#include "nimble/hci_common.h" +#include "controller/ble_ll_utils.h" +#include "controller/ble_ll.h" +#include "controller/ble_ll_conn.h" +#include "controller/ble_ll_hci.h" +#include "controller/ble_ll_cs.h" + +int +ble_ll_cs_hci_rd_loc_supp_cap(uint8_t *rspbuf, uint8_t *rsplen) +{ + return BLE_ERR_UNSUPPORTED; +} + +int +ble_ll_cs_hci_rd_rem_supp_cap(const uint8_t *cmdbuf, uint8_t cmdlen) +{ + return BLE_ERR_UNSUPPORTED; +} + +int +ble_ll_cs_hci_wr_cached_rem_supp_cap(const uint8_t *cmdbuf, uint8_t cmdlen, + uint8_t *rspbuf, uint8_t *rsplen) +{ + return BLE_ERR_UNSUPPORTED; +} + +int +ble_ll_cs_hci_sec_enable(const uint8_t *cmdbuf, uint8_t cmdlen) +{ + return BLE_ERR_UNSUPPORTED; +} + +int +ble_ll_cs_hci_set_def_settings(const uint8_t *cmdbuf, uint8_t cmdlen, + uint8_t *rspbuf, uint8_t *rsplen) +{ + return BLE_ERR_UNSUPPORTED; +} + +int +ble_ll_cs_hci_rd_rem_fae(const uint8_t *cmdbuf, uint8_t cmdlen) +{ + return BLE_ERR_UNSUPPORTED; +} + +int +ble_ll_cs_hci_wr_cached_rem_fae(const uint8_t *cmdbuf, uint8_t cmdlen, + uint8_t *rspbuf, uint8_t *rsplen) +{ + return BLE_ERR_UNSUPPORTED; +} + +int +ble_ll_cs_hci_create_config(const uint8_t *cmdbuf, uint8_t cmdlen) +{ + return BLE_ERR_UNSUPPORTED; +} + +int +ble_ll_cs_hci_remove_config(const uint8_t *cmdbuf, uint8_t cmdlen) +{ + return BLE_ERR_UNSUPPORTED; +} + +int +ble_ll_cs_hci_set_chan_class(const uint8_t *cmdbuf, uint8_t cmdlen) +{ + return BLE_ERR_UNSUPPORTED; +} + +int +ble_ll_cs_hci_set_proc_params(const uint8_t *cmdbuf, uint8_t cmdlen, + uint8_t *rspbuf, uint8_t *rsplen) +{ + return BLE_ERR_UNSUPPORTED; +} + +int +ble_ll_cs_hci_proc_enable(const uint8_t *cmdbuf, uint8_t cmdlen) +{ + return BLE_ERR_UNSUPPORTED; +} + +int +ble_ll_cs_hci_test(const uint8_t *cmdbuf, uint8_t cmdlen, + uint8_t *rspbuf, uint8_t *rsplen) +{ + return BLE_ERR_UNSUPPORTED; +} + +int +ble_ll_cs_hci_test_end(void) +{ + return BLE_ERR_UNSUPPORTED; +} + +#endif /* BLE_LL_CHANNEL_SOUNDING */ diff --git a/nimble/controller/src/ble_ll_ctrl.c b/nimble/controller/src/ble_ll_ctrl.c index c4ac6504c9..5d6e3bcea9 100644 --- a/nimble/controller/src/ble_ll_ctrl.c +++ b/nimble/controller/src/ble_ll_ctrl.c @@ -19,18 +19,23 @@ #include #include #include +#include #include "syscfg/syscfg.h" #include "nimble/ble.h" #include "nimble/nimble_opt.h" #include "nimble/hci_common.h" +#include "controller/ble_ll_utils.h" #include "controller/ble_ll.h" #include "controller/ble_ll_hci.h" #include "controller/ble_ll_ctrl.h" #include "controller/ble_ll_trace.h" #include "controller/ble_hw.h" #include "controller/ble_ll_sync.h" +#include "controller/ble_ll_tmr.h" #include "ble_ll_conn_priv.h" +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + /* To use spec sample data for testing */ #undef BLE_LL_ENCRYPT_USE_TEST_DATA @@ -95,7 +100,7 @@ const uint8_t g_ble_ll_ctrl_pkt_lengths[BLE_LL_CTRL_OPCODES] = BLE_LL_CTRL_PAUSE_ENC_RSP_LEN, BLE_LL_CTRL_VERSION_IND_LEN, BLE_LL_CTRL_REJ_IND_LEN, - BLE_LL_CTRL_SLAVE_FEATURE_REQ_LEN, + BLE_LL_CTRL_PERIPH_FEATURE_REQ_LEN, BLE_LL_CTRL_CONN_PARAMS_LEN, BLE_LL_CTRL_CONN_PARAMS_LEN, BLE_LL_CTRL_REJECT_IND_EXT_LEN, @@ -115,7 +120,14 @@ const uint8_t g_ble_ll_ctrl_pkt_lengths[BLE_LL_CTRL_OPCODES] = BLE_LL_CTRL_CIS_REQ_LEN, BLE_LL_CTRL_CIS_RSP_LEN, BLE_LL_CTRL_CIS_IND_LEN, - BLE_LL_CTRL_CIS_TERMINATE_LEN + BLE_LL_CTRL_CIS_TERMINATE_LEN, + BLE_LL_CTRL_POWER_CONTROL_REQ_LEN, + BLE_LL_CTRL_POWER_CONTROL_RSP_LEN, + BLE_LL_CTRL_POWER_CHANGE_IND_LEN, + BLE_LL_CTRL_SUBRATE_REQ_LEN, + BLE_LL_CTRL_SUBRATE_IND_LEN, + BLE_LL_CTRL_CHAN_REPORTING_IND_LEN, + BLE_LL_CTRL_CHAN_STATUS_IND_LEN, }; /** @@ -172,7 +184,7 @@ ble_ll_ctrl_rej_ext_ind_make(uint8_t rej_opcode, uint8_t err, uint8_t *ctrdata) ctrdata[1] = err; } -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) +#if MYNEWT_VAL(BLE_LL_PHY) /** * Called to cancel a phy update procedure. * @@ -186,13 +198,13 @@ ble_ll_ctrl_phy_update_cancel(struct ble_ll_conn_sm *connsm, uint8_t ble_err) CLR_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_PHY_UPDATE); /* Check if the host wants an event */ - if (CONN_F_HOST_PHY_UPDATE(connsm)) { + if (connsm->flags.phy_update_host_initiated) { ble_ll_hci_ev_phy_update(connsm, ble_err); - CONN_F_HOST_PHY_UPDATE(connsm) = 0; + connsm->flags.phy_update_host_initiated = 0; } /* Clear any bits for phy updates that might be in progress */ - CONN_F_CTRLR_PHY_UPDATE(connsm) = 0; + connsm->flags.phy_update_self_initiated = 0; } #endif @@ -279,8 +291,26 @@ ble_ll_ctrl_conn_param_pdu_proc(struct ble_ll_conn_sm *connsm, uint8_t *dptr, req->offset4 = get_le16(dptr + 19); req->offset5 = get_le16(dptr + 21); - /* Check if parameters are valid */ ble_err = BLE_ERR_SUCCESS; + +#if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) + /* Allow to change connection parameters only if conn_itvl can stay unchanged + * and anchor point change is not requested */ + if (ble_ll_sched_css_is_enabled()) { + if (connsm->conn_role == BLE_LL_CONN_ROLE_CENTRAL && + ((connsm->conn_itvl < le16toh(req->interval_min)) || + (connsm->conn_itvl > le16toh(req->interval_max)) || + (le16toh(req->offset0) != 0xffff))) { + ble_err = BLE_ERR_INV_LMP_LL_PARM; + goto conn_param_pdu_exit; + } + + req->interval_min = connsm->conn_itvl; + req->interval_max = connsm->conn_itvl; + } +#endif + + /* Check if parameters are valid */ rc = ble_ll_conn_hci_chk_conn_params(req->interval_min, req->interval_max, req->latency, @@ -301,7 +331,7 @@ ble_ll_ctrl_conn_param_pdu_proc(struct ble_ll_conn_sm *connsm, uint8_t *dptr, if ((connsm->conn_itvl >= req->interval_min) && (connsm->conn_itvl <= req->interval_max) && (connsm->supervision_tmo == req->timeout) && - (connsm->slave_latency == req->latency)) { + (connsm->periph_latency == req->latency)) { indicate = 0; goto conn_parm_req_do_indicate; } @@ -309,15 +339,14 @@ ble_ll_ctrl_conn_param_pdu_proc(struct ble_ll_conn_sm *connsm, uint8_t *dptr, /* * A change has been requested. Is it within the values specified by - * the host? Note that for a master we will not be processing a - * connect param request from a slave if we are currently trying to + * the host? Note that for a central we will not be processing a + * connect param request from a peripheral if we are currently trying to * update the connection parameters. This means that the previous - * check is all we need for a master (when receiving a request). + * check is all we need for a central (when receiving a request). */ - if ((connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) || - (opcode == BLE_LL_CTRL_CONN_PARM_RSP)) { + if (CONN_IS_PERIPHERAL(connsm) || (opcode == BLE_LL_CTRL_CONN_PARM_RSP)) { /* - * Not sure what to do about the slave. It is possible that the + * Not sure what to do about the peripheral. It is possible that the * current connection parameters are not the same ones as the local host * has provided? Not sure what to do here. Do we need to remember what * host sent us? For now, I will assume that we need to remember what @@ -356,7 +385,7 @@ ble_ll_ctrl_conn_param_pdu_proc(struct ble_ll_conn_sm *connsm, uint8_t *dptr, */ ble_ll_hci_ev_rem_conn_parm_req(connsm, req); connsm->host_reply_opcode = opcode; - connsm->csmflags.cfbit.awaiting_host_reply = 1; + connsm->flags.conn_update_host_w4reply = 1; rsp_opcode = 255; } else { /* Create reply to connection request */ @@ -369,21 +398,39 @@ ble_ll_ctrl_conn_param_pdu_proc(struct ble_ll_conn_sm *connsm, uint8_t *dptr, rspbuf[1] = opcode; rspbuf[2] = ble_err; } + +#if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) + if (!ble_err) { + connsm->css_slot_idx_pending = connsm->css_slot_idx; + } +#endif + return rsp_opcode; } -/** - * Called to make a connection update request LL control PDU - * - * Context: Link Layer - * - * @param connsm - * @param rsp - */ static void -ble_ll_ctrl_conn_upd_make(struct ble_ll_conn_sm *connsm, uint8_t *pyld, - struct ble_ll_conn_params *cp) +ble_ll_ctrl_conn_update_init_proc(struct ble_ll_conn_sm *connsm, + struct ble_ll_conn_params *cp) { + /* This only stores conn params, if any. The caller will enqueue LL Control + * PDU and we will calculate its contents when dequeued so we know that + * instant is in the future. + */ + + connsm->flags.conn_update_sched = 0; + connsm->flags.conn_update_use_cp = (cp != NULL); + + if (cp) { + connsm->conn_cp = *cp; + } +} + +static void +ble_ll_ctrl_conn_update_make_ind_pdu(struct ble_ll_conn_sm *connsm, + uint8_t *ctrdata) +{ + struct ble_ll_conn_params *cp = NULL; + struct ble_ll_conn_params offset_cp = { }; uint16_t instant; uint32_t dt; uint32_t num_old_ce; @@ -392,14 +439,35 @@ ble_ll_ctrl_conn_upd_make(struct ble_ll_conn_sm *connsm, uint8_t *pyld, struct hci_conn_update *hcu; struct ble_ll_conn_upd_req *req; + if (connsm->flags.conn_update_use_cp) { + cp = &connsm->conn_cp; + } + /* * Set instant. We set the instant to the current event counter plus - * the amount of slave latency as the slave may not be listening + * the amount of peripheral latency as the peripheral may not be listening * at every connection interval and we are not sure when the connect * request will actually get sent. We add one more event plus the * minimum as per the spec of 6 connection events. */ - instant = connsm->event_cntr + connsm->slave_latency + 6 + 1; +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE) + instant = connsm->subrate_base_event + 6 * connsm->subrate_factor * + (connsm->periph_latency + 1); +#else + instant = connsm->event_cntr + connsm->periph_latency + 6 + 1; +#endif + + /* Check if this is a move anchor request and configure proper connection + * parameters */ + if (connsm->conn_update_anchor_offset_req) { + offset_cp.interval_min = connsm->conn_itvl; + offset_cp.interval_max = connsm->conn_itvl; + offset_cp.latency = connsm->periph_latency; + offset_cp.timeout = connsm->supervision_tmo; + offset_cp.offset0 = connsm->conn_update_anchor_offset_req; + connsm->conn_update_anchor_offset_req = 0; + cp = &offset_cp; + } /* * XXX: This should change in the future, but for now we will just @@ -446,15 +514,12 @@ ble_ll_ctrl_conn_upd_make(struct ble_ll_conn_sm *connsm, uint8_t *pyld, req->instant = instant; /* XXX: make sure this works for the connection parameter request proc. */ - pyld[0] = req->winsize; - put_le16(pyld + 1, req->winoffset); - put_le16(pyld + 3, req->interval); - put_le16(pyld + 5, req->latency); - put_le16(pyld + 7, req->timeout); - put_le16(pyld + 9, instant); - - /* Set flag in state machine to denote we have scheduled an update */ - connsm->csmflags.cfbit.conn_update_sched = 1; + ctrdata[0] = req->winsize; + put_le16(ctrdata + 1, req->winoffset); + put_le16(ctrdata + 3, req->interval); + put_le16(ctrdata + 5, req->latency); + put_le16(ctrdata + 7, req->timeout); + put_le16(ctrdata + 9, instant); } /** @@ -482,17 +547,19 @@ ble_ll_ctrl_proc_unk_rsp(struct ble_ll_conn_sm *connsm, uint8_t *dptr, uint8_t * case BLE_LL_CTRL_CONN_UPDATE_IND: ctrl_proc = BLE_LL_CTRL_PROC_CONN_UPDATE; break; - case BLE_LL_CTRL_SLAVE_FEATURE_REQ: + case BLE_LL_CTRL_PERIPH_FEATURE_REQ: ctrl_proc = BLE_LL_CTRL_PROC_FEATURE_XCHG; - BLE_LL_CONN_CLEAR_FEATURE(connsm, BLE_LL_FEAT_SLAVE_INIT); + BLE_LL_CONN_CLEAR_FEATURE(connsm, BLE_LL_FEAT_PERIPH_INIT); break; case BLE_LL_CTRL_CONN_PARM_REQ: BLE_LL_CONN_CLEAR_FEATURE(connsm, BLE_LL_FEAT_CONN_PARM_REQ); - if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { - ble_ll_ctrl_conn_upd_make(connsm, rspdata, NULL); +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + if (connsm->conn_role == BLE_LL_CONN_ROLE_CENTRAL) { + ble_ll_ctrl_conn_update_init_proc(connsm, NULL); connsm->reject_reason = BLE_ERR_SUCCESS; return BLE_LL_CTRL_CONN_UPDATE_IND; } +#endif /* note: fall-through intentional */ case BLE_LL_CTRL_CONN_PARM_RSP: ctrl_proc = BLE_LL_CTRL_PROC_CONN_PARAM_REQ; @@ -504,7 +571,7 @@ ble_ll_ctrl_proc_unk_rsp(struct ble_ll_conn_sm *connsm, uint8_t *dptr, uint8_t * ctrl_proc = BLE_LL_CTRL_PROC_LE_PING; BLE_LL_CONN_CLEAR_FEATURE(connsm, BLE_LL_FEAT_LE_PING); break; -#if (BLE_LL_BT5_PHY_SUPPORTED ==1) +#if MYNEWT_VAL(BLE_LL_PHY) case BLE_LL_CTRL_PHY_REQ: ble_ll_ctrl_phy_update_cancel(connsm, BLE_ERR_UNSUPP_REM_FEATURE); ctrl_proc = BLE_LL_CTRL_PROC_PHY_UPDATE; @@ -528,11 +595,11 @@ ble_ll_ctrl_proc_unk_rsp(struct ble_ll_conn_sm *connsm, uint8_t *dptr, uint8_t * if (ctrl_proc == BLE_LL_CTRL_PROC_CONN_PARAM_REQ) { ble_ll_hci_ev_conn_update(connsm, BLE_ERR_UNSUPP_REM_FEATURE); } else if (ctrl_proc == BLE_LL_CTRL_PROC_FEATURE_XCHG) { - if (connsm->csmflags.cfbit.pending_hci_rd_features) { + if (connsm->flags.features_host_req) { ble_ll_hci_ev_rd_rem_used_feat(connsm, BLE_ERR_UNSUPP_REM_FEATURE); } - connsm->csmflags.cfbit.pending_hci_rd_features = 0; + connsm->flags.features_host_req = 0; } } @@ -559,11 +626,6 @@ ble_ll_ctrl_proc_rsp_timer_cb(struct ble_npl_event *ev) static void ble_ll_ctrl_start_rsp_timer(struct ble_ll_conn_sm *connsm) { - ble_npl_callout_init(&connsm->ctrl_proc_rsp_timer, - &g_ble_ll_data.ll_evq, - ble_ll_ctrl_proc_rsp_timer_cb, - connsm); - /* Re-start timer. Control procedure timeout is 40 seconds */ ble_npl_callout_reset(&connsm->ctrl_proc_rsp_timer, ble_npl_time_ms_to_ticks32(BLE_LL_CTRL_PROC_TIMEOUT_MS)); @@ -588,6 +650,11 @@ ble_ll_ctrl_phy_from_phy_mask(uint8_t phy_mask) { uint8_t phy; + /* One and only one bit shall be set */ + if (__builtin_popcount(phy_mask) != 1) { + return 0; + } + /* * NOTE: wipe out unsupported PHYs. There should not be an unsupported * in this mask if the other side is working correctly. @@ -619,7 +686,7 @@ ble_ll_ctrl_phy_from_phy_mask(uint8_t phy_mask) return phy; } -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) +#if MYNEWT_VAL(BLE_LL_PHY) uint8_t ble_ll_ctrl_phy_tx_transition_get(uint8_t phy_mask) { @@ -650,24 +717,24 @@ ble_ll_ctrl_phy_update_proc_complete(struct ble_ll_conn_sm *connsm) connsm->phy_tx_transition = 0; - if (CONN_F_PEER_PHY_UPDATE(connsm)) { - CONN_F_PEER_PHY_UPDATE(connsm) = 0; - } else if (CONN_F_CTRLR_PHY_UPDATE(connsm)) { - CONN_F_CTRLR_PHY_UPDATE(connsm) = 0; + if (connsm->flags.phy_update_peer_initiated) { + connsm->flags.phy_update_peer_initiated = 0; + } else if (connsm->flags.phy_update_self_initiated) { + connsm->flags.phy_update_self_initiated = 0; } else { /* Must be a host-initiated update */ - CONN_F_HOST_PHY_UPDATE(connsm) = 0; + connsm->flags.phy_update_host_initiated = 0; chk_host_phy = 0; - if (CONN_F_PHY_UPDATE_EVENT(connsm) == 0) { + if (connsm->flags.phy_update_host_w4event == 0) { ble_ll_hci_ev_phy_update(connsm, BLE_ERR_SUCCESS); } } /* Must check if we need to start host procedure */ if (chk_host_phy) { - if (CONN_F_HOST_PHY_UPDATE(connsm)) { - if (ble_ll_conn_chk_phy_upd_start(connsm)) { - CONN_F_HOST_PHY_UPDATE(connsm) = 0; + if (connsm->flags.phy_update_host_initiated) { + if (ble_ll_conn_phy_update_if_needed(connsm)) { + connsm->flags.phy_update_host_initiated = 0; } else { chk_proc_stop = 0; } @@ -679,6 +746,7 @@ ble_ll_ctrl_phy_update_proc_complete(struct ble_ll_conn_sm *connsm) } } +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) /** * * There is probably a better way for the controller to choose which PHY use. @@ -716,48 +784,50 @@ ble_ll_ctrl_find_new_phy(uint8_t phy_mask_prefs) * @param connsm Pointer to connection state machine * @param dptr Pointer to PHY_REQ or PHY_RSP data. * @param ctrdata: Pointer to where CtrData of UPDATE_IND pdu starts - * @param slave_req flag denoting if slave requested this. 0: no 1:yes + * @param periph_req flag denoting if peripheral requested this. 0: no 1:yes */ + static void ble_ll_ctrl_phy_update_ind_make(struct ble_ll_conn_sm *connsm, uint8_t *dptr, - uint8_t *ctrdata, int slave_req) + uint8_t *ctrdata, int periph_req) { uint8_t m_to_s; uint8_t s_to_m; uint8_t tx_phys; uint8_t rx_phys; - uint16_t instant; - uint8_t is_slave_sym = 0; + uint8_t is_periph_sym = 0; /* Get preferences from PDU */ tx_phys = dptr[0]; rx_phys = dptr[1]; - /* If we are master, check if slave requested symmetric PHY */ - if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { - is_slave_sym = tx_phys == rx_phys; - is_slave_sym &= __builtin_popcount(tx_phys) == 1; + /* If we are central, check if peripheral requested symmetric PHY */ +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + if (connsm->conn_role == BLE_LL_CONN_ROLE_CENTRAL) { + is_periph_sym = tx_phys == rx_phys; + is_periph_sym &= __builtin_popcount(tx_phys) == 1; } +#endif /* Get m_to_s and s_to_m masks */ - if (slave_req) { - m_to_s = connsm->phy_data.host_pref_tx_phys_mask & rx_phys; - s_to_m = connsm->phy_data.host_pref_rx_phys_mask & tx_phys; + if (periph_req) { + m_to_s = connsm->phy_data.pref_mask_tx & rx_phys; + s_to_m = connsm->phy_data.pref_mask_rx & tx_phys; } else { - m_to_s = connsm->phy_data.req_pref_tx_phys_mask & rx_phys; - s_to_m = connsm->phy_data.req_pref_rx_phys_mask & tx_phys; + m_to_s = connsm->phy_data.pref_mask_tx_req & rx_phys; + s_to_m = connsm->phy_data.pref_mask_rx_req & tx_phys; } - if (is_slave_sym) { + if (is_periph_sym) { /* * If either s_to_m or m_to_s is 0, it means for at least one direction * requested PHY is not our preferred one so make sure we keep current * PHY in both directions * * Core 5.2, Vol 6, PartB, 5.1.10 - * If the slave specified a single PHY in both the TX_PHYS and - * RX_PHYS fields and both fields are the same, the master shall - * either select the PHY specified by the slave for both directions + * If the peripheral specified a single PHY in both the TX_PHYS and + * RX_PHYS fields and both fields are the same, the central shall + * either select the PHY specified by the peripheral for both directions * or shall leave both directions unchanged. */ if ((s_to_m == 0) || (m_to_s == 0)) { @@ -788,23 +858,17 @@ ble_ll_ctrl_phy_update_ind_make(struct ble_ll_conn_sm *connsm, uint8_t *dptr, * one running. */ if ((m_to_s == 0) && (s_to_m == 0)) { - if (CONN_F_PEER_PHY_UPDATE(connsm)) { - CONN_F_PEER_PHY_UPDATE(connsm) = 0; - } else if (CONN_F_CTRLR_PHY_UPDATE(connsm)) { - CONN_F_CTRLR_PHY_UPDATE(connsm) = 0; + if (connsm->flags.phy_update_peer_initiated) { + connsm->flags.phy_update_peer_initiated = 0; + } else if (connsm->flags.phy_update_self_initiated) { + connsm->flags.phy_update_self_initiated = 0; ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_PHY_UPDATE); } else { ble_ll_hci_ev_phy_update(connsm, BLE_ERR_SUCCESS); - CONN_F_HOST_PHY_UPDATE(connsm) = 0; + connsm->flags.phy_update_host_initiated = 0; ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_PHY_UPDATE); } - instant = 0; } else { - /* Determine instant we will use. 6 more is minimum */ - instant = connsm->event_cntr + connsm->slave_latency + 6 + 1; - connsm->phy_instant = instant; - CONN_F_PHY_UPDATE_SCHED(connsm) = 1; - /* Set new phys to use when instant occurs */ connsm->phy_data.new_tx_phy = m_to_s; connsm->phy_data.new_rx_phy = s_to_m; @@ -821,8 +885,35 @@ ble_ll_ctrl_phy_update_ind_make(struct ble_ll_conn_sm *connsm, uint8_t *dptr, ctrdata[0] = m_to_s; ctrdata[1] = s_to_m; +} +#endif + +#if MYNEWT_VAL(BLE_LL_PHY) +static bool +ble_ll_ctrl_phy_update_ind_instant(struct ble_ll_conn_sm *connsm, uint8_t *ctrdata) +{ + uint16_t instant; + uint8_t m_to_s; + uint8_t s_to_m; + bool schedule = false; + + m_to_s = ctrdata[0]; + s_to_m = ctrdata[1]; + + if ((m_to_s == 0) && (s_to_m == 0)) { + instant = 0; + } else { + /* Determine instant we will use. 6 more is minimum */ + instant = connsm->event_cntr + connsm->periph_latency + 6 + 1; + connsm->phy_instant = instant; + schedule = true; + } + put_le16(ctrdata + 2, instant); + + return schedule; } +#endif /** * Create a LL_PHY_REQ or LL_PHY_RSP pdu @@ -833,17 +924,8 @@ ble_ll_ctrl_phy_update_ind_make(struct ble_ll_conn_sm *connsm, uint8_t *dptr, static void ble_ll_ctrl_phy_req_rsp_make(struct ble_ll_conn_sm *connsm, uint8_t *ctrdata) { - /* If no preference we use current phy */ - if (connsm->phy_data.host_pref_tx_phys_mask == 0) { - ctrdata[0] = CONN_CUR_TX_PHY_MASK(connsm); - } else { - ctrdata[0] = connsm->phy_data.host_pref_tx_phys_mask; - } - if (connsm->phy_data.host_pref_rx_phys_mask == 0) { - ctrdata[1] = CONN_CUR_RX_PHY_MASK(connsm); - } else { - ctrdata[1] = connsm->phy_data.host_pref_rx_phys_mask; - } + ctrdata[0] = connsm->phy_data.pref_mask_tx; + ctrdata[1] = connsm->phy_data.pref_mask_rx; } #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_SCA_UPDATE) @@ -877,7 +959,9 @@ ble_ll_ctrl_rx_phy_req(struct ble_ll_conn_sm *connsm, uint8_t *req, err = ble_ll_ctrl_proc_with_instant_initiated(connsm, BLE_LL_CTRL_PROC_PHY_UPDATE); - if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { + switch (connsm->conn_role) { +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + case BLE_LL_CONN_ROLE_CENTRAL: if (err) { ble_ll_ctrl_rej_ext_ind_make(BLE_LL_CTRL_PHY_REQ, err, rsp); rsp_opcode = BLE_LL_CTRL_REJECT_IND_EXT; @@ -886,11 +970,14 @@ ble_ll_ctrl_rx_phy_req(struct ble_ll_conn_sm *connsm, uint8_t *req, * NOTE: do not change order of these two lines as the call to * make the LL_PHY_UPDATE_IND pdu might clear the flag. */ - CONN_F_PEER_PHY_UPDATE(connsm) = 1; + connsm->flags.phy_update_peer_initiated = 1; ble_ll_ctrl_phy_update_ind_make(connsm, req, rsp, 1); rsp_opcode = BLE_LL_CTRL_PHY_UPDATE_IND; } - } else { + break; +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) + case BLE_LL_CONN_ROLE_PERIPHERAL: /* XXX: deal with other control procedures that we need to stop */ if (err) { if (connsm->cur_ctrl_proc == BLE_LL_CTRL_PROC_PHY_UPDATE) { @@ -902,14 +989,14 @@ ble_ll_ctrl_rx_phy_req(struct ble_ll_conn_sm *connsm, uint8_t *req, ble_ll_ctrl_phy_update_cancel(connsm, err); /* XXX: ? Should not be any phy update events */ - CONN_F_PHY_UPDATE_EVENT(connsm) = 0; + connsm->flags.phy_update_host_w4event = 0; } /* XXX: TODO: if we started another procedure with an instant * why are we doing this? Need to look into this.*/ - /* Respond to master's phy update procedure */ - CONN_F_PEER_PHY_UPDATE(connsm) = 1; + /* Respond to central's phy update procedure */ + connsm->flags.phy_update_peer_initiated = 1; ble_ll_ctrl_phy_req_rsp_make(connsm, rsp); rsp_opcode = BLE_LL_CTRL_PHY_RSP; @@ -918,7 +1005,13 @@ ble_ll_ctrl_rx_phy_req(struct ble_ll_conn_sm *connsm, uint8_t *req, /* Start response timer */ connsm->cur_ctrl_proc = BLE_LL_CTRL_PROC_PHY_UPDATE; ble_ll_ctrl_start_rsp_timer(connsm); + break; +#endif + default: + BLE_LL_ASSERT(0); + break; } + return rsp_opcode; } @@ -938,7 +1031,10 @@ ble_ll_ctrl_rx_phy_rsp(struct ble_ll_conn_sm *connsm, uint8_t *dptr, uint8_t rsp_opcode; rsp_opcode = BLE_ERR_MAX; - if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { + + switch (connsm->conn_role) { +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + case BLE_LL_CONN_ROLE_CENTRAL: if (connsm->cur_ctrl_proc == BLE_LL_CTRL_PROC_PHY_UPDATE) { ble_ll_ctrl_phy_update_ind_make(connsm, dptr, rsp, 0); ble_npl_callout_stop(&connsm->ctrl_proc_rsp_timer); @@ -951,11 +1047,19 @@ ble_ll_ctrl_rx_phy_rsp(struct ble_ll_conn_sm *connsm, uint8_t *dptr, * * XXX: TODO count some stat? */ - } else { + break; +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) + case BLE_LL_CONN_ROLE_PERIPHERAL: rsp_opcode = BLE_LL_CTRL_UNKNOWN_RSP; + break; +#endif + default: + BLE_LL_ASSERT(0); + break; } - /* NOTE: slave should never receive one of these */ + /* NOTE: peripheral should never receive one of these */ return rsp_opcode; } @@ -963,7 +1067,7 @@ ble_ll_ctrl_rx_phy_rsp(struct ble_ll_conn_sm *connsm, uint8_t *dptr, /** * Called when a LL_PHY_UPDATE_IND pdu is received * - * NOTE: slave is the only device that should receive this. + * NOTE: peripheral is the only device that should receive this. * * @param connsm * @param dptr @@ -981,9 +1085,11 @@ ble_ll_ctrl_rx_phy_update_ind(struct ble_ll_conn_sm *connsm, uint8_t *dptr) uint16_t instant; uint16_t delta; - if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + if (connsm->conn_role == BLE_LL_CONN_ROLE_CENTRAL) { return BLE_LL_CTRL_UNKNOWN_RSP; } +#endif /* * Reception stops the procedure response timer but does not @@ -1009,8 +1115,8 @@ ble_ll_ctrl_rx_phy_update_ind(struct ble_ll_conn_sm *connsm, uint8_t *dptr) } else { no_change = 0; /* - * NOTE: from the slaves perspective, the m to s phy is the one - * that the slave will receive on; s to m is the one it will + * NOTE: from the peripherals perspective, the m to s phy is the one + * that the peripheral will receive on; s to m is the one it will * transmit on */ new_rx_phy = ble_ll_ctrl_phy_from_phy_mask(new_m_to_s_mask); @@ -1036,7 +1142,7 @@ ble_ll_ctrl_rx_phy_update_ind(struct ble_ll_conn_sm *connsm, uint8_t *dptr) connsm->phy_data.new_tx_phy = new_tx_phy; connsm->phy_data.new_rx_phy = new_rx_phy; connsm->phy_instant = instant; - CONN_F_PHY_UPDATE_SCHED(connsm) = 1; + connsm->flags.phy_update_sched = 1; } return BLE_ERR_MAX; } @@ -1059,11 +1165,9 @@ ble_ll_ctrl_rx_phy_update_ind(struct ble_ll_conn_sm *connsm, uint8_t *dptr) static uint8_t ble_ll_ctrl_rx_periodic_sync_ind(struct ble_ll_conn_sm *connsm, uint8_t *dptr) { - if (connsm->sync_transfer_mode) { - ble_ll_sync_periodic_ind(connsm, dptr, connsm->sync_transfer_mode == 1, - connsm->sync_transfer_skip, - connsm->sync_transfer_sync_timeout); - } + ble_ll_sync_periodic_ind(connsm, dptr, connsm->sync_transfer_mode, + connsm->sync_transfer_skip, + connsm->sync_transfer_sync_timeout); return BLE_ERR_MAX; } #endif @@ -1082,7 +1186,12 @@ static uint8_t ble_ll_ctrl_rx_sca_req(struct ble_ll_conn_sm *connsm, uint8_t *dptr, uint8_t *rsp) { + if (connsm->conn_role == BLE_LL_CONN_ROLE_PERIPHERAL) { + connsm->central_sca = dptr[0]; + } + ble_ll_ctrl_sca_req_rsp_make(connsm, rsp); + return BLE_LL_CTRL_CLOCK_ACCURACY_RSP; } @@ -1100,34 +1209,140 @@ ble_ll_ctrl_rx_sca_rsp(struct ble_ll_conn_sm *connsm, uint8_t *dptr) if (connsm->cur_ctrl_proc != BLE_LL_CTRL_PROC_SCA_UPDATE) { return BLE_LL_CTRL_UNKNOWN_RSP; } + + if (connsm->conn_role == BLE_LL_CONN_ROLE_PERIPHERAL) { + connsm->central_sca = dptr[0]; + } + ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_SCA_UPDATE); ble_ll_hci_ev_sca_update(connsm, BLE_ERR_SUCCESS, dptr[0]); + return BLE_ERR_MAX; } #endif -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ISO) -static uint8_t -ble_ll_ctrl_rx_cis_req(struct ble_ll_conn_sm *connsm, uint8_t *dptr, - uint8_t *rspdata) +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE) +static void +ble_ll_ctrl_subrate_req_make(struct ble_ll_conn_sm *connsm, uint8_t *pyld, + struct ble_ll_conn_subrate_req_params *srp) { - return BLE_LL_CTRL_UNKNOWN_RSP; + put_le16(pyld + 0, srp->subrate_min); + put_le16(pyld + 2, srp->subrate_max); + put_le16(pyld + 4, srp->max_latency); + put_le16(pyld + 6, srp->cont_num); + put_le16(pyld + 8, srp->supervision_tmo); +} + +static void +ble_ll_ctrl_subrate_ind_make(struct ble_ll_conn_sm *connsm, uint8_t *pyld, + struct ble_ll_conn_subrate_params *sp) +{ + put_le16(pyld + 0, sp->subrate_factor); + put_le16(pyld + 2, sp->subrate_base_event); + put_le16(pyld + 4, sp->periph_latency); + put_le16(pyld + 6, sp->cont_num); + put_le16(pyld + 8, sp->supervision_tmo); } static uint8_t -ble_ll_ctrl_rx_cis_rsp(struct ble_ll_conn_sm *connsm, uint8_t *dptr, - uint8_t *rspdata) +ble_ll_ctrl_rx_subrate_req(struct ble_ll_conn_sm *connsm, uint8_t *req, + uint8_t *rsp) { - return BLE_LL_CTRL_UNKNOWN_RSP; + struct ble_ll_conn_subrate_req_params params; + struct ble_ll_conn_subrate_req_params *srp = ¶ms; + uint8_t err; + int rc; + +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) + if (connsm->conn_role == BLE_LL_CONN_ROLE_PERIPHERAL) { + return BLE_LL_CTRL_UNKNOWN_RSP; + } +#endif + + if ((ble_ll_read_supp_features() & BLE_LL_FEAT_CONN_SUBRATING_HOST) == 0) { + ble_ll_ctrl_rej_ext_ind_make(BLE_LL_CTRL_SUBRATE_REQ, + BLE_ERR_UNSUPP_REM_FEATURE, rsp); + return BLE_LL_CTRL_REJECT_IND_EXT; + } + + srp->subrate_min = get_le16(req + 0); + srp->subrate_max = get_le16(req + 2); + srp->max_latency = get_le16(req + 4); + srp->cont_num = get_le16(req + 6); + srp->supervision_tmo = get_le16(req + 8); + + rc = ble_ll_conn_subrate_req_llcp(connsm, srp); + if (rc < 0) { + if (rc == -EINVAL) { + err = BLE_ERR_INV_LMP_LL_PARM; + } else if (rc == -ENOTSUP) { + err = BLE_ERR_UNSUPP_REM_FEATURE; + } else if (rc == -EBUSY) { + err = BLE_ERR_DIFF_TRANS_COLL; + } else { + err = BLE_ERR_UNSPECIFIED; + } + + ble_ll_ctrl_rej_ext_ind_make(BLE_LL_CTRL_SUBRATE_REQ, err, rsp); + + return BLE_LL_CTRL_REJECT_IND_EXT; + } + + return BLE_ERR_MAX; } static uint8_t -ble_ll_ctrl_rx_cis_ind(struct ble_ll_conn_sm *connsm, uint8_t *dptr) +ble_ll_ctrl_rx_subrate_ind(struct ble_ll_conn_sm *connsm, uint8_t *req, + uint8_t *rsp) { - return BLE_LL_CTRL_UNKNOWN_RSP; + struct ble_ll_conn_subrate_params params; + struct ble_ll_conn_subrate_params *sp = ¶ms; + uint32_t t1, t2; + +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + if (connsm->conn_role == BLE_LL_CONN_ROLE_CENTRAL) { + return BLE_LL_CTRL_UNKNOWN_RSP; + } +#endif + + sp->subrate_factor = get_le16(req + 0); + sp->subrate_base_event = get_le16(req + 2); + sp->periph_latency = get_le16(req + 4); + sp->cont_num = get_le16(req + 6); + sp->supervision_tmo = get_le16(req + 8); + + /* This is probably not really useful since we shall apply new parameters + * immediately after receiving LL_SUBRATE_IND and central shall apply those + * parameters after receiving ack which it already did, so it's too late + * here to do anything useful. Let's just send LL_REJECT_EXT_IND anyway just + * for debugging purposes and reset to subrate factor of 1 and no latency, + * perhaps we can find some connection event from central and send our PDU. + */ + t1 = connsm->conn_itvl * sp->subrate_factor * (sp->periph_latency + 1) * + BLE_LL_CONN_ITVL_USECS; + t2 = sp->supervision_tmo * BLE_HCI_CONN_SPVN_TMO_UNITS * 1000 / 2; + if ((sp->subrate_factor < 1) || (sp->subrate_factor > 500) || + (sp->cont_num > sp->subrate_factor - 1) || + (sp->subrate_factor * (sp->periph_latency + 1) > 500) || (t1 >= t2)) { + + sp->subrate_factor = 1; + sp->subrate_base_event = connsm->event_cntr; + sp->periph_latency = 0; + sp->cont_num = 0; + sp->supervision_tmo = connsm->supervision_tmo; + + return BLE_ERR_MAX; + } + + ble_ll_conn_subrate_set(connsm, sp); + ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_SUBRATE_REQ); + connsm->flags.subrate_host_req = 0; + + return BLE_ERR_MAX; } #endif + /** * Create a link layer length request or length response PDU. * @@ -1193,7 +1408,7 @@ ble_ll_calc_session_key(struct ble_ll_conn_sm *connsm) * XXX: the current code may actually allow some control pdu's to be sent * in states where they shouldnt. I dont expect those states to occur so I * dont try to check for them but we could do more... for example there are - * different PDUs allowed for master/slave and TX/RX + * different PDUs allowed for central/peripheral and TX/RX * * @param llid * @param opcode @@ -1236,11 +1451,13 @@ ble_ll_ctrl_enc_allowed_pdu(uint8_t llid, uint8_t len, uint8_t opcode) } int -ble_ll_ctrl_enc_allowed_pdu_rx(struct os_mbuf *rxpdu) +ble_ll_ctrl_enc_allowed_pdu_rx(struct ble_ll_conn_sm *connsm, struct os_mbuf *rxpdu) { uint8_t llid; uint8_t len; uint8_t opcode; + uint8_t state; + int allowed; llid = rxpdu->om_data[0] & BLE_LL_DATA_HDR_LLID_MASK; len = rxpdu->om_data[1]; @@ -1250,7 +1467,47 @@ ble_ll_ctrl_enc_allowed_pdu_rx(struct os_mbuf *rxpdu) opcode = 0; } - return ble_ll_ctrl_enc_allowed_pdu(llid, len, opcode); + allowed = 0; + state = connsm->enc_data.enc_state; + + switch (llid) { + case BLE_LL_LLID_CTRL: + switch (opcode) { + case BLE_LL_CTRL_REJECT_IND: + case BLE_LL_CTRL_REJECT_IND_EXT: + allowed = state == CONN_ENC_S_ENC_RSP_WAIT || + state == CONN_ENC_S_START_ENC_REQ_WAIT; + break; + case BLE_LL_CTRL_START_ENC_RSP: + allowed = state == CONN_ENC_S_START_ENC_RSP_WAIT; + break; + case BLE_LL_CTRL_START_ENC_REQ: + allowed = state == CONN_ENC_S_START_ENC_REQ_WAIT; + break; + case BLE_LL_CTRL_ENC_REQ: + allowed = state == CONN_ENC_S_ENCRYPTED || state == CONN_ENC_S_PAUSED; + break; + case BLE_LL_CTRL_ENC_RSP: + allowed = state == CONN_ENC_S_ENC_RSP_WAIT; + break; + case BLE_LL_CTRL_PAUSE_ENC_REQ: + allowed = state == CONN_ENC_S_ENCRYPTED; + break; + case BLE_LL_CTRL_PAUSE_ENC_RSP: + allowed = state == CONN_ENC_S_PAUSE_ENC_RSP_WAIT; + break; + case BLE_LL_CTRL_TERMINATE_IND: + allowed = 1; + break; + } + break; + case BLE_LL_LLID_DATA_FRAG: + /* Empty PDUs are allowed */ + allowed = len == 0; + break; + } + + return allowed; } int @@ -1333,15 +1590,6 @@ ble_ll_ctrl_start_enc_send(struct ble_ll_conn_sm *connsm) return rc; } -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ISO) -static void -ble_ll_ctrl_cis_create(struct ble_ll_conn_sm *connsm, uint8_t *dptr) -{ - /* TODO Implement */ - return; -} -#endif - /** * Create a link layer control "encrypt request" PDU. * @@ -1352,7 +1600,7 @@ ble_ll_ctrl_cis_create(struct ble_ll_conn_sm *connsm, uint8_t *dptr) * IVm (4) * * The random number and encrypted diversifier come from the host command. - * Controller generates master portion of SDK and IV. + * Controller generates central portion of SDK and IV. * * NOTE: this function does not set the LL data pdu header nor does it * set the opcode in the buffer. @@ -1382,7 +1630,7 @@ ble_ll_ctrl_enc_req_make(struct ble_ll_conn_sm *connsm, uint8_t *dptr) } /** - * Called when LL_ENC_RSP is received by the master. + * Called when LL_ENC_RSP is received by the central. * * Context: Link Layer Task. * @@ -1390,7 +1638,7 @@ ble_ll_ctrl_enc_req_make(struct ble_ll_conn_sm *connsm, uint8_t *dptr) * SKDs (8) * IVs (4) * - * The master now has the long term key (from the start encrypt command) + * The central now has the long term key (from the start encrypt command) * and the SKD (stored in the plain text encryption block). From this the * sessionKey is generated. * @@ -1416,7 +1664,7 @@ ble_ll_ctrl_rx_enc_rsp(struct ble_ll_conn_sm *connsm, uint8_t *dptr) /** * Called when we have received a LL control encryption request PDU. This - * should only be received by a slave. + * should only be received by a peripheral. * * The LL_ENC_REQ PDU format is: * Rand (8) @@ -1428,7 +1676,7 @@ ble_ll_ctrl_rx_enc_rsp(struct ble_ll_conn_sm *connsm, uint8_t *dptr) * but it could be a reject ind. Note that the caller of this function * will send the REJECT_IND_EXT if supported by remote. * - * NOTE: if this is received by a master we will silently discard the PDU + * NOTE: if this is received by a central we will silently discard the PDU * (denoted by return BLE_ERR_MAX). * * @param connsm @@ -1439,9 +1687,11 @@ static uint8_t ble_ll_ctrl_rx_enc_req(struct ble_ll_conn_sm *connsm, uint8_t *dptr, uint8_t *rspdata) { - if (connsm->conn_role != BLE_LL_CONN_ROLE_SLAVE) { +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + if (connsm->conn_role == BLE_LL_CONN_ROLE_CENTRAL) { return BLE_LL_CTRL_UNKNOWN_RSP; } +#endif connsm->enc_data.enc_state = CONN_ENC_S_ENC_RSP_TO_BE_SENT; @@ -1482,17 +1732,29 @@ ble_ll_ctrl_rx_start_enc_req(struct ble_ll_conn_sm *connsm) { int rc; - /* Only master should receive start enc request */ + /* Only central should receive start enc request */ rc = BLE_ERR_MAX; - if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { + + switch (connsm->conn_role) { +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + case BLE_LL_CONN_ROLE_CENTRAL: /* We only want to send a START_ENC_RSP if we havent yet */ if (connsm->enc_data.enc_state == CONN_ENC_S_START_ENC_REQ_WAIT) { connsm->enc_data.enc_state = CONN_ENC_S_START_ENC_RSP_WAIT; rc = BLE_LL_CTRL_START_ENC_RSP; } - } else { + break; +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) + case BLE_LL_CONN_ROLE_PERIPHERAL: rc = BLE_LL_CTRL_UNKNOWN_RSP; + break; +#endif + default: + BLE_LL_ASSERT(0); + break; } + return rc; } @@ -1507,7 +1769,7 @@ ble_ll_ctrl_rx_pause_enc_req(struct ble_ll_conn_sm *connsm) * ignore it... */ rc = BLE_ERR_MAX; - if ((connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) && + if (CONN_IS_PERIPHERAL(connsm) && (connsm->enc_data.enc_state == CONN_ENC_S_ENCRYPTED)) { rc = BLE_LL_CTRL_PAUSE_ENC_RSP; } else { @@ -1528,18 +1790,30 @@ ble_ll_ctrl_rx_pause_enc_req(struct ble_ll_conn_sm *connsm) static uint8_t ble_ll_ctrl_rx_pause_enc_rsp(struct ble_ll_conn_sm *connsm) { - int rc; + int rc = 0; - if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { + switch (connsm->conn_role) { +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + case BLE_LL_CONN_ROLE_CENTRAL: rc = BLE_LL_CTRL_PAUSE_ENC_RSP; - } else if (connsm->enc_data.enc_state == CONN_ENC_S_PAUSE_ENC_RSP_WAIT) { - /* Master sends back unencrypted LL_PAUSE_ENC_RSP. - * From this moment encryption is paused. - */ - rc = BLE_ERR_MAX; - connsm->enc_data.enc_state = CONN_ENC_S_PAUSED; - } else { - rc = BLE_LL_CTRL_UNKNOWN_RSP; + break; +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) + case BLE_LL_CONN_ROLE_PERIPHERAL: + if (connsm->enc_data.enc_state == CONN_ENC_S_PAUSE_ENC_RSP_WAIT) { + /* Master sends back unencrypted LL_PAUSE_ENC_RSP. + * From this moment encryption is paused. + */ + rc = BLE_ERR_MAX; + connsm->enc_data.enc_state = CONN_ENC_S_PAUSED; + } else { + rc = BLE_LL_CTRL_UNKNOWN_RSP; + } + break; +#endif + default: + BLE_LL_ASSERT(0); + break; } return rc; @@ -1557,37 +1831,46 @@ ble_ll_ctrl_rx_pause_enc_rsp(struct ble_ll_conn_sm *connsm) static uint8_t ble_ll_ctrl_rx_start_enc_rsp(struct ble_ll_conn_sm *connsm) { - int rc; + int rc = 0; /* Not in proper state. Discard */ if (connsm->enc_data.enc_state != CONN_ENC_S_START_ENC_RSP_WAIT) { return BLE_ERR_MAX; } - /* If master, we are done. Stop control procedure and sent event to host */ - if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { - + switch (connsm->conn_role) { +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + case BLE_LL_CONN_ROLE_CENTRAL: ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_ENCRYPT); /* We are encrypted */ connsm->enc_data.enc_state = CONN_ENC_S_ENCRYPTED; + connsm->flags.encrypt_paused = 0; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_PING) ble_ll_conn_auth_pyld_timer_start(connsm); #endif rc = BLE_ERR_MAX; - } else { - /* Procedure has completed but slave needs to send START_ENC_RSP */ + break; +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) + case BLE_LL_CONN_ROLE_PERIPHERAL: + /* Procedure has completed but peripheral needs to send START_ENC_RSP */ rc = BLE_LL_CTRL_START_ENC_RSP; /* Stop timer if it was started when sending START_ENC_REQ */ if (connsm->cur_ctrl_proc == BLE_LL_CTRL_PROC_ENCRYPT) { ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_ENCRYPT); } + break; +#endif + default: + BLE_LL_ASSERT(0); + break; } /* * XXX: for now, a Slave sends this event when it receivest the - * START_ENC_RSP from the master. It might be technically incorrect + * START_ENC_RSP from the central. It might be technically incorrect * to send it before we transmit our own START_ENC_RSP. */ ble_ll_hci_ev_encrypt_chg(connsm, BLE_ERR_SUCCESS); @@ -1652,11 +1935,11 @@ static void ble_ll_ctrl_version_ind_make(struct ble_ll_conn_sm *connsm, uint8_t *pyld) { /* Set flag to denote we have sent/received this */ - connsm->csmflags.cfbit.version_ind_sent = 1; + connsm->flags.version_ind_txd = 1; /* Fill out response */ pyld[0] = BLE_HCI_VER_BCS; - put_le16(pyld + 1, MYNEWT_VAL(BLE_LL_MFRG_ID)); + put_le16(pyld + 1, MYNEWT_VAL(BLE_LL_MANUFACTURER_ID)); put_le16(pyld + 3, BLE_LL_SUB_VERS_NR); } @@ -1670,15 +1953,18 @@ static void ble_ll_ctrl_chanmap_req_make(struct ble_ll_conn_sm *connsm, uint8_t *pyld) { /* Copy channel map that host desires into request */ - memcpy(pyld, g_ble_ll_conn_params.master_chan_map, BLE_LL_CONN_CHMAP_LEN); - memcpy(connsm->req_chanmap, pyld, BLE_LL_CONN_CHMAP_LEN); + memcpy(pyld, g_ble_ll_data.chan_map, BLE_LL_CHAN_MAP_LEN); + memcpy(connsm->req_chanmap, pyld, BLE_LL_CHAN_MAP_LEN); - /* Place instant into request */ - connsm->chanmap_instant = connsm->event_cntr + connsm->slave_latency + 6 + 1; - put_le16(pyld + BLE_LL_CONN_CHMAP_LEN, connsm->chanmap_instant); + /* Instant is placed in ble_ll_ctrl_chanmap_req_instant()*/ +} - /* Set scheduled flag */ - connsm->csmflags.cfbit.chanmap_update_scheduled = 1; +static void +ble_ll_ctrl_chanmap_req_instant(struct ble_ll_conn_sm *connsm, uint8_t *pyld) +{ + /* Place instant into request */ + connsm->chanmap_instant = connsm->event_cntr + connsm->periph_latency + 6 + 1; + put_le16(pyld + BLE_LL_CHAN_MAP_LEN, connsm->chanmap_instant); } /** @@ -1695,16 +1981,25 @@ uint8_t ble_ll_ctrl_conn_param_reply(struct ble_ll_conn_sm *connsm, uint8_t *rsp, struct ble_ll_conn_params *req) { - uint8_t rsp_opcode; + uint8_t rsp_opcode = 0; - if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) { + switch (connsm->conn_role) { +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + case BLE_LL_CONN_ROLE_CENTRAL: + ble_ll_ctrl_conn_update_init_proc(connsm, req); + rsp_opcode = BLE_LL_CTRL_CONN_UPDATE_IND; + break; +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) + case BLE_LL_CONN_ROLE_PERIPHERAL: /* Create a connection parameter response */ ble_ll_ctrl_conn_param_pdu_make(connsm, rsp + 1, req); rsp_opcode = BLE_LL_CTRL_CONN_PARM_RSP; - } else { - /* Create a connection update pdu */ - ble_ll_ctrl_conn_upd_make(connsm, rsp + 1, req); - rsp_opcode = BLE_LL_CTRL_CONN_UPDATE_IND; + break; +#endif + default: + BLE_LL_ASSERT(0); + break; } return rsp_opcode; @@ -1732,19 +2027,32 @@ ble_ll_ctrl_rx_reject_ind(struct ble_ll_conn_sm *connsm, uint8_t *dptr, ble_error = dptr[1]; } + /* Suppress unused-but-set if not used by following code (due to syscfg) */ + (void)ble_error; + /* XXX: should I check to make sure the rejected opcode is sane if we receive ind ext? */ switch (connsm->cur_ctrl_proc) { case BLE_LL_CTRL_PROC_CONN_PARAM_REQ: if (opcode == BLE_LL_CTRL_REJECT_IND_EXT) { - /* As a master we should send connection update indication in this point */ - if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { + switch (connsm->conn_role) { + #if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + case BLE_LL_CONN_ROLE_CENTRAL: + /* As a central we should send connection update indication in this point */ rsp_opcode = BLE_LL_CTRL_CONN_UPDATE_IND; - ble_ll_ctrl_conn_upd_make(connsm, rspdata, NULL); + ble_ll_ctrl_conn_update_init_proc(connsm, NULL); connsm->reject_reason = BLE_ERR_SUCCESS; - } else { + break; + #endif + #if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) + case BLE_LL_CONN_ROLE_PERIPHERAL: ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_CONN_PARAM_REQ); ble_ll_hci_ev_conn_update(connsm, ble_error); + break; + #endif + default: + BLE_LL_ASSERT(0); + break; } } break; @@ -1755,7 +2063,7 @@ ble_ll_ctrl_rx_reject_ind(struct ble_ll_conn_sm *connsm, uint8_t *dptr, connsm->enc_data.enc_state = CONN_ENC_S_UNENCRYPTED; break; #endif -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) +#if MYNEWT_VAL(BLE_LL_PHY) case BLE_LL_CTRL_PROC_PHY_UPDATE: ble_ll_ctrl_phy_update_cancel(connsm, ble_error); ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_PHY_UPDATE); @@ -1774,6 +2082,13 @@ ble_ll_ctrl_rx_reject_ind(struct ble_ll_conn_sm *connsm, uint8_t *dptr, ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_SCA_UPDATE); break; #endif +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE) + case BLE_LL_CTRL_PROC_SUBRATE_REQ: + ble_ll_hci_ev_subrate_change(connsm, ble_error); + ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_SUBRATE_UPDATE); + break; +#endif + default: break; } @@ -1796,10 +2111,12 @@ ble_ll_ctrl_rx_conn_update(struct ble_ll_conn_sm *connsm, uint8_t *dptr) uint16_t conn_events; struct ble_ll_conn_upd_req *reqdata; - /* Only a slave should receive this */ - if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { + /* Only a peripheral should receive this */ +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + if (connsm->conn_role == BLE_LL_CONN_ROLE_CENTRAL) { return BLE_LL_CTRL_UNKNOWN_RSP; } +#endif /* Retrieve parameters */ reqdata = &connsm->conn_update_req; @@ -1819,7 +2136,7 @@ ble_ll_ctrl_rx_conn_update(struct ble_ll_conn_sm *connsm, uint8_t *dptr) if (conn_events >= 32767) { ble_ll_conn_timeout(connsm, BLE_ERR_INSTANT_PASSED); } else { - connsm->csmflags.cfbit.conn_update_sched = 1; + connsm->flags.conn_update_sched = 1; /* * Errata says that receiving a connection update when the event @@ -1841,7 +2158,7 @@ ble_ll_ctrl_rx_conn_update(struct ble_ll_conn_sm *connsm, uint8_t *dptr) } void -ble_ll_ctrl_initiate_dle(struct ble_ll_conn_sm *connsm) +ble_ll_ctrl_initiate_dle(struct ble_ll_conn_sm *connsm, bool initial) { if (!(connsm->conn_features & BLE_LL_FEAT_DATA_LEN_EXT)) { return; @@ -1850,12 +2167,15 @@ ble_ll_ctrl_initiate_dle(struct ble_ll_conn_sm *connsm) /* * Section 4.5.10 Vol 6 PART B. If the max tx/rx time or octets * exceeds the minimum, data length procedure needs to occur + * "at the earliest practical opportunity". */ - if ((connsm->max_tx_octets <= BLE_LL_CONN_SUPP_BYTES_MIN) && - (connsm->max_rx_octets <= BLE_LL_CONN_SUPP_BYTES_MIN) && - (connsm->max_tx_time <= BLE_LL_CONN_SUPP_TIME_MIN) && - (connsm->max_rx_time <= BLE_LL_CONN_SUPP_TIME_MIN)) { - return; + if (initial) { + if ((connsm->max_tx_octets <= BLE_LL_CONN_SUPP_BYTES_MIN) && + (connsm->max_rx_octets <= BLE_LL_CONN_SUPP_BYTES_MIN) && + (connsm->max_tx_time <= BLE_LL_CONN_SUPP_TIME_MIN) && + (connsm->max_rx_time <= BLE_LL_CONN_SUPP_TIME_MIN)) { + return; + } } ble_ll_ctrl_proc_start(connsm, BLE_LL_CTRL_PROC_DATA_LEN_UPD); @@ -1868,7 +2188,7 @@ ble_ll_ctrl_update_features(struct ble_ll_conn_sm *connsm, uint8_t *feat) memcpy(connsm->remote_features, feat + 1, 7); /* If we received peer's features for the 1st time, we should try DLE */ - if (!connsm->csmflags.cfbit.rxd_features) { + if (!connsm->flags.features_rxd) { #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) /* * If connection was established on uncoded PHY, by default we use @@ -1877,24 +2197,32 @@ ble_ll_ctrl_update_features(struct ble_ll_conn_sm *connsm, uint8_t *feat) * LE Coded PHY. However, once we know that peer does support it we can * update those values to ones applicable for coded PHY. */ - if (connsm->remote_features[0] & (BLE_LL_FEAT_LE_CODED_PHY >> 8)) { + if (ble_ll_conn_rem_feature_check(connsm, BLE_LL_FEAT_LE_CODED_PHY)) { if (connsm->host_req_max_tx_time) { - connsm->max_tx_time = max(connsm->max_tx_time, + connsm->max_tx_time = MAX(connsm->max_tx_time, connsm->host_req_max_tx_time); } else { connsm->max_tx_time = g_ble_ll_conn_params.conn_init_max_tx_time_coded; } - connsm->max_rx_time = BLE_LL_CONN_SUPP_TIME_MAX_CODED; + if (connsm->host_req_max_rx_time) { + connsm->max_rx_time = MAX(connsm->max_rx_time, + connsm->host_req_max_rx_time); + } else { + connsm->max_rx_time = BLE_LL_CONN_SUPP_TIME_MAX_CODED; + } } #endif - connsm->csmflags.cfbit.pending_initiate_dle = 1; - connsm->csmflags.cfbit.rxd_features = 1; +#if MYNEWT_VAL(BLE_LL_CONN_INIT_AUTO_DLE) + connsm->flags.pending_initiate_dle = 1; +#endif + + connsm->flags.features_rxd = 1; } } /** - * Called when we receive a feature request or a slave initiated feature + * Called when we receive a feature request or a peripheral initiated feature * request. * * @@ -1914,16 +2242,16 @@ ble_ll_ctrl_rx_feature_req(struct ble_ll_conn_sm *connsm, uint8_t *dptr, uint64_t our_feat; /* - * Only accept slave feature requests if we are a master and feature - * requests if we are a slave. + * Only accept peripheral feature requests if we are a central and feature + * requests if we are a peripheral. */ - if (opcode == BLE_LL_CTRL_SLAVE_FEATURE_REQ) { - if (connsm->conn_role != BLE_LL_CONN_ROLE_MASTER) { + if (opcode == BLE_LL_CTRL_PERIPH_FEATURE_REQ) { + if (!CONN_IS_CENTRAL(connsm)) { return BLE_LL_CTRL_UNKNOWN_RSP; } } else { /* XXX: not sure this is correct but do it anyway */ - if (connsm->conn_role != BLE_LL_CONN_ROLE_SLAVE) { + if (!CONN_IS_PERIPHERAL(connsm)) { return BLE_LL_CTRL_UNKNOWN_RSP; } } @@ -1969,9 +2297,9 @@ ble_ll_ctrl_rx_feature_rsp(struct ble_ll_conn_sm *connsm, uint8_t *dptr) } /* Send event to host if pending features read */ - if (connsm->csmflags.cfbit.pending_hci_rd_features) { + if (connsm->flags.features_host_req) { ble_ll_hci_ev_rd_rem_used_feat(connsm, BLE_ERR_SUCCESS); - connsm->csmflags.cfbit.pending_hci_rd_features = 0; + connsm->flags.features_host_req = 0; } } @@ -2000,11 +2328,11 @@ ble_ll_ctrl_rx_conn_param_req(struct ble_ll_conn_sm *connsm, uint8_t *dptr, * well. This is not expected to happen anyway. A return of BLE_ERR_MAX * means that we will simply discard the connection parameter request */ - if (connsm->csmflags.cfbit.awaiting_host_reply) { + if (connsm->flags.conn_update_host_w4reply) { return BLE_ERR_MAX; } - /* XXX: remember to deal with this on the master: if the slave has + /* XXX: remember to deal with this on the central: if the peripheral has * initiated a procedure we may have received its connection parameter * update request and have signaled the host with an event. If that * is the case, we will need to drop the host command when we get it @@ -2014,38 +2342,49 @@ ble_ll_ctrl_rx_conn_param_req(struct ble_ll_conn_sm *connsm, uint8_t *dptr, * be pending (a connection update) that will cause collisions and the behavior below. */ /* - * Check for procedure collision (Vol 6 PartB 5.3). If we are a slave - * and we receive a request we "consider the slave initiated + * Check for procedure collision (Vol 6 PartB 5.3). If we are a peripheral + * and we receive a request we "consider the peripheral initiated * procedure as complete". This means send a connection update complete * event (with error). * - * If a master, we send reject with a + * If a central, we send reject with a * transaction collision error code. */ if (IS_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_CONN_PARAM_REQ)) { - if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) { - ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_CONN_PARAM_REQ); - ble_ll_hci_ev_conn_update(connsm, BLE_ERR_LMP_COLLISION); - } else { - /* The master sends reject ind ext w/error code 0x23 */ + switch (connsm->conn_role) { +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + case BLE_LL_CONN_ROLE_CENTRAL: + /* The central sends reject ind ext w/error code 0x23 */ rsp_opcode = BLE_LL_CTRL_REJECT_IND_EXT; rspbuf[1] = BLE_LL_CTRL_CONN_PARM_REQ; rspbuf[2] = BLE_ERR_LMP_COLLISION; return rsp_opcode; +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) + case BLE_LL_CONN_ROLE_PERIPHERAL: + ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_CONN_PARAM_REQ); + ble_ll_hci_ev_conn_update(connsm, BLE_ERR_LMP_COLLISION); + break; +#endif + default: + BLE_LL_ASSERT(0); + break; } } /* - * If we are a master and we currently performing a channel map + * If we are a central and we currently performing a channel map * update procedure we need to return an error */ - if ((connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) && - (connsm->csmflags.cfbit.chanmap_update_scheduled)) { +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + if ((connsm->conn_role == BLE_LL_CONN_ROLE_CENTRAL) && + (connsm->flags.chanmap_update_sched)) { rsp_opcode = BLE_LL_CTRL_REJECT_IND_EXT; rspbuf[1] = BLE_LL_CTRL_CONN_PARM_REQ; rspbuf[2] = BLE_ERR_DIFF_TRANS_COLL; return rsp_opcode; } +#endif /* Process the received connection parameter request */ rsp_opcode = ble_ll_ctrl_conn_param_pdu_proc(connsm, dptr, rspbuf, @@ -2059,19 +2398,21 @@ ble_ll_ctrl_rx_conn_param_rsp(struct ble_ll_conn_sm *connsm, uint8_t *dptr, { uint8_t rsp_opcode; - /* A slave should never receive this response */ - if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) { + /* A peripheral should never receive this response */ +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) + if (connsm->conn_role == BLE_LL_CONN_ROLE_PERIPHERAL) { return BLE_LL_CTRL_UNKNOWN_RSP; } +#endif /* - * This case should never happen! It means that the slave initiated a - * procedure and the master initiated one as well. If we do get in this - * state just clear the awaiting reply. The slave will hopefully stop its + * This case should never happen! It means that the peripheral initiated a + * procedure and the central initiated one as well. If we do get in this + * state just clear the awaiting reply. The peripheral will hopefully stop its * procedure when we reply. */ - if (connsm->csmflags.cfbit.awaiting_host_reply) { - connsm->csmflags.cfbit.awaiting_host_reply = 0; + if (connsm->flags.conn_update_host_w4reply) { + connsm->flags.conn_update_host_w4reply = 0; } /* If we receive a response and no procedure is pending, just leave */ @@ -2106,10 +2447,10 @@ ble_ll_ctrl_rx_version_ind(struct ble_ll_conn_sm *connsm, uint8_t *dptr, connsm->vers_nr = dptr[0]; connsm->comp_id = get_le16(dptr + 1); connsm->sub_vers_nr = get_le16(dptr + 3); - connsm->csmflags.cfbit.rxd_version_ind = 1; + connsm->flags.version_ind_rxd = 1; rsp_opcode = BLE_ERR_MAX; - if (!connsm->csmflags.cfbit.version_ind_sent) { + if (!connsm->flags.version_ind_txd) { rsp_opcode = BLE_LL_CTRL_VERSION_IND; ble_ll_ctrl_version_ind_make(connsm, rspbuf); } @@ -2136,19 +2477,21 @@ ble_ll_ctrl_rx_chanmap_req(struct ble_ll_conn_sm *connsm, uint8_t *dptr) uint16_t instant; uint16_t conn_events; - if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + if (connsm->conn_role == BLE_LL_CONN_ROLE_CENTRAL) { return BLE_LL_CTRL_UNKNOWN_RSP; } +#endif /* If instant is in the past, we have to end the connection */ - instant = get_le16(dptr + BLE_LL_CONN_CHMAP_LEN); + instant = get_le16(dptr + BLE_LL_CHAN_MAP_LEN); conn_events = (instant - connsm->event_cntr) & 0xFFFF; if (conn_events >= 32767) { ble_ll_conn_timeout(connsm, BLE_ERR_INSTANT_PASSED); } else { connsm->chanmap_instant = instant; - memcpy(connsm->req_chanmap, dptr, BLE_LL_CONN_CHMAP_LEN); - connsm->csmflags.cfbit.chanmap_update_scheduled = 1; + memcpy(connsm->req_chanmap, dptr, BLE_LL_CHAN_MAP_LEN); + connsm->flags.chanmap_update_sched = 1; } return BLE_ERR_MAX; @@ -2170,7 +2513,7 @@ static struct os_mbuf * ble_ll_ctrl_proc_init(struct ble_ll_conn_sm *connsm, int ctrl_proc) { uint8_t len; - uint8_t opcode; + uint8_t opcode = 0; uint8_t *dptr; uint8_t *ctrdata; struct os_mbuf *om; @@ -2186,17 +2529,27 @@ ble_ll_ctrl_proc_init(struct ble_ll_conn_sm *connsm, int ctrl_proc) switch (ctrl_proc) { case BLE_LL_CTRL_PROC_CONN_UPDATE: opcode = BLE_LL_CTRL_CONN_UPDATE_IND; - ble_ll_ctrl_conn_upd_make(connsm, ctrdata, NULL); + ble_ll_ctrl_conn_update_init_proc(connsm, NULL); break; case BLE_LL_CTRL_PROC_CHAN_MAP_UPD: opcode = BLE_LL_CTRL_CHANNEL_MAP_REQ; ble_ll_ctrl_chanmap_req_make(connsm, ctrdata); break; case BLE_LL_CTRL_PROC_FEATURE_XCHG: - if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { + switch (connsm->conn_role) { +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + case BLE_LL_CONN_ROLE_CENTRAL: opcode = BLE_LL_CTRL_FEATURE_REQ; - } else { - opcode = BLE_LL_CTRL_SLAVE_FEATURE_REQ; + break; +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) + case BLE_LL_CONN_ROLE_PERIPHERAL: + opcode = BLE_LL_CTRL_PERIPH_FEATURE_REQ; + break; +#endif + default: + BLE_LL_ASSERT(0); + break; } put_le64(ctrdata, ble_ll_read_supp_features()); break; @@ -2231,7 +2584,7 @@ ble_ll_ctrl_proc_init(struct ble_ll_conn_sm *connsm, int ctrl_proc) } break; #endif -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) +#if MYNEWT_VAL(BLE_LL_PHY) case BLE_LL_CTRL_PROC_PHY_UPDATE: opcode = BLE_LL_CTRL_PHY_REQ; ble_ll_ctrl_phy_req_rsp_make(connsm, ctrdata); @@ -2243,11 +2596,20 @@ ble_ll_ctrl_proc_init(struct ble_ll_conn_sm *connsm, int ctrl_proc) ble_ll_ctrl_sca_req_rsp_make(connsm, ctrdata); break; #endif -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ISO) - case BLE_LL_CTRL_PROC_CIS_CREATE: - opcode = BLE_LL_CTRL_CIS_REQ; - ble_ll_ctrl_cis_create(connsm, ctrdata); +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE) +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) + case BLE_LL_CTRL_PROC_SUBRATE_REQ: + opcode = BLE_LL_CTRL_SUBRATE_REQ; + ble_ll_ctrl_subrate_req_make(connsm, ctrdata, &connsm->subrate_req); break; +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + case BLE_LL_CTRL_PROC_SUBRATE_UPDATE: + opcode = BLE_LL_CTRL_SUBRATE_IND; + ble_ll_ctrl_subrate_ind_make(connsm, ctrdata, + &connsm->subrate_trans); + break; +#endif #endif default: BLE_LL_ASSERT(0); @@ -2327,12 +2689,11 @@ ble_ll_ctrl_terminate_start(struct ble_ll_conn_sm *connsm) ctrl_proc = BLE_LL_CTRL_PROC_TERMINATE; om = ble_ll_ctrl_proc_init(connsm, ctrl_proc); if (om) { - CONN_F_TERMINATE_STARTED(connsm) = 1; + connsm->flags.terminate_started = 1; /* Set terminate "timeout" */ usecs = connsm->supervision_tmo * BLE_HCI_CONN_SPVN_TMO_UNITS * 1000; - connsm->terminate_timeout = os_cputime_get32() + - os_cputime_usecs_to_ticks(usecs); + connsm->terminate_timeout = ble_ll_tmr_get() + ble_ll_tmr_u2t(usecs); } } @@ -2382,6 +2743,9 @@ ble_ll_ctrl_proc_start(struct ble_ll_conn_sm *connsm, int ctrl_proc) void ble_ll_ctrl_chk_proc_start(struct ble_ll_conn_sm *connsm) { +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) + struct os_mbuf *om; +#endif int i; /* XXX: TODO new rules! Cannot start certain control procedures if other @@ -2393,7 +2757,7 @@ ble_ll_ctrl_chk_proc_start(struct ble_ll_conn_sm *connsm) * terminate if needed */ if (connsm->disconnect_reason) { - if (!CONN_F_TERMINATE_STARTED(connsm)) { + if (!connsm->flags.terminate_started) { /* * If the terminate procedure has not started it means we were not * able to start it right away (no control pdu was available). @@ -2404,6 +2768,22 @@ ble_ll_ctrl_chk_proc_start(struct ble_ll_conn_sm *connsm) return; } +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) + if (connsm->flags.pending_encrypt_restart) { + /* This flag should only be set after LL_PAUSE_ENC_RSP was txd from + * central and there should be already active encryption procedure + * ongoing. We need to restart encryption to complete key refresh. + */ + BLE_LL_ASSERT(connsm->cur_ctrl_proc == BLE_LL_CTRL_PROC_ENCRYPT); + BLE_LL_ASSERT(IS_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_ENCRYPT)); + + om = ble_ll_ctrl_proc_init(connsm, BLE_LL_CTRL_PROC_ENCRYPT); + if (om) { + connsm->flags.pending_encrypt_restart = 0; + } + } +#endif + /* If there is a running procedure or no pending, do nothing */ if ((connsm->cur_ctrl_proc == BLE_LL_CTRL_PROC_IDLE) && (connsm->pending_ctrl_procs != 0)) { @@ -2418,7 +2798,7 @@ ble_ll_ctrl_chk_proc_start(struct ble_ll_conn_sm *connsm) * received the information dont start it. */ if ((i == BLE_LL_CTRL_PROC_VERSION_XCHG) && - (connsm->csmflags.cfbit.rxd_version_ind)) { + (connsm->flags.version_ind_rxd)) { ble_ll_hci_ev_rd_rem_ver(connsm, BLE_ERR_SUCCESS); CLR_PENDING_CTRL_PROC(connsm, i); } else { @@ -2436,7 +2816,7 @@ ble_ll_ctrl_chk_proc_start(struct ble_ll_conn_sm *connsm) * NOTE: this function uses the received PDU for the response in some cases. If * the received PDU is not used it needs to be freed here. * - * XXX: may want to check, for both master and slave, whether the control + * XXX: may want to check, for both central and peripheral, whether the control * pdu should be received by that role. Might make for less code... * Context: Link Layer * @@ -2446,18 +2826,15 @@ ble_ll_ctrl_chk_proc_start(struct ble_ll_conn_sm *connsm) int ble_ll_ctrl_rx_pdu(struct ble_ll_conn_sm *connsm, struct os_mbuf *om) { - uint32_t features; - uint32_t feature; + uint64_t features; + uint64_t feature; uint8_t len; uint8_t opcode; - uint8_t rsp_opcode; uint8_t *dptr; uint8_t *rspbuf; uint8_t *rspdata; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - int restart_encryption; -#endif int rc = 0; + uint8_t rsp_opcode = 0; /* XXX: where do we validate length received and packet header length? * do this in LL task when received. Someplace!!! What I mean @@ -2473,6 +2850,12 @@ ble_ll_ctrl_rx_pdu(struct ble_ll_conn_sm *connsm, struct os_mbuf *om) len = dptr[1]; opcode = dptr[2]; +#if MYNEWT_VAL(BLE_LL_HCI_LLCP_TRACE) + ble_ll_hci_ev_send_vs_llcp_trace(0x03, connsm->conn_handle, + connsm->event_cntr, + &dptr[2], len); +#endif + /* * rspbuf points to first byte of response. The response buffer does not * contain the Data Channel PDU. Thus, the first byte of rspbuf is the @@ -2494,10 +2877,6 @@ ble_ll_ctrl_rx_pdu(struct ble_ll_conn_sm *connsm, struct os_mbuf *om) ble_ll_trace_u32x2(BLE_LL_TRACE_ID_CTRL_RX, opcode, len); -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - restart_encryption = 0; -#endif - /* If opcode comes from reserved value or CtrlData fields is invalid * we shall respond with LL_UNKNOWN_RSP */ @@ -2513,8 +2892,8 @@ ble_ll_ctrl_rx_pdu(struct ble_ll_conn_sm *connsm, struct os_mbuf *om) case BLE_LL_CTRL_LENGTH_REQ: feature = BLE_LL_FEAT_DATA_LEN_EXT; break; - case BLE_LL_CTRL_SLAVE_FEATURE_REQ: - feature = BLE_LL_FEAT_SLAVE_INIT; + case BLE_LL_CTRL_PERIPH_FEATURE_REQ: + feature = BLE_LL_FEAT_PERIPH_INIT; break; case BLE_LL_CTRL_CONN_PARM_REQ: case BLE_LL_CTRL_CONN_PARM_RSP: @@ -2537,6 +2916,10 @@ ble_ll_ctrl_rx_pdu(struct ble_ll_conn_sm *connsm, struct os_mbuf *om) case BLE_LL_CTRL_PERIODIC_SYNC_IND: feature = BLE_LL_FEAT_SYNC_TRANS_RECV; break; + case BLE_LL_CTRL_SUBRATE_REQ: + case BLE_LL_CTRL_SUBRATE_IND: + feature = BLE_LL_FEAT_CONN_SUBRATING; + break; default: feature = 0; break; @@ -2623,7 +3006,7 @@ ble_ll_ctrl_rx_pdu(struct ble_ll_conn_sm *connsm, struct os_mbuf *om) case BLE_LL_CTRL_VERSION_IND: rsp_opcode = ble_ll_ctrl_rx_version_ind(connsm, dptr, rspdata); break; - case BLE_LL_CTRL_SLAVE_FEATURE_REQ: + case BLE_LL_CTRL_PERIPH_FEATURE_REQ: rsp_opcode = ble_ll_ctrl_rx_feature_req(connsm, dptr, rspbuf, opcode); break; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) @@ -2644,9 +3027,6 @@ ble_ll_ctrl_rx_pdu(struct ble_ll_conn_sm *connsm, struct os_mbuf *om) break; case BLE_LL_CTRL_PAUSE_ENC_RSP: rsp_opcode = ble_ll_ctrl_rx_pause_enc_rsp(connsm); - if (rsp_opcode == BLE_LL_CTRL_PAUSE_ENC_RSP) { - restart_encryption = 1; - } break; #endif case BLE_LL_CTRL_PING_REQ: @@ -2667,7 +3047,7 @@ ble_ll_ctrl_rx_pdu(struct ble_ll_conn_sm *connsm, struct os_mbuf *om) /* Sometimes reject triggers sending other LL CTRL msg */ rsp_opcode = ble_ll_ctrl_rx_reject_ind(connsm, dptr, opcode, rspdata); break; -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) +#if MYNEWT_VAL(BLE_LL_PHY) case BLE_LL_CTRL_PHY_REQ: rsp_opcode = ble_ll_ctrl_rx_phy_req(connsm, dptr, rspdata); break; @@ -2687,21 +3067,18 @@ ble_ll_ctrl_rx_pdu(struct ble_ll_conn_sm *connsm, struct os_mbuf *om) break; #endif -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ISO) - case BLE_LL_CTRL_CIS_REQ: - rsp_opcode = ble_ll_ctrl_rx_cis_req(connsm, dptr, rspdata); - break; - case BLE_LL_CTRL_CIS_RSP: - rsp_opcode = ble_ll_ctrl_rx_cis_rsp(connsm, dptr, rspdata); - break; - case BLE_LL_CTRL_CIS_IND: - rsp_opcode = ble_ll_ctrl_rx_cis_ind(connsm, dptr); - break; -#endif #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER) case BLE_LL_CTRL_PERIODIC_SYNC_IND: rsp_opcode = ble_ll_ctrl_rx_periodic_sync_ind(connsm, dptr); break; +#endif +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE) + case BLE_LL_CTRL_SUBRATE_REQ: + rsp_opcode = ble_ll_ctrl_rx_subrate_req(connsm, dptr, rspdata); + break; + case BLE_LL_CTRL_SUBRATE_IND: + rsp_opcode = ble_ll_ctrl_rx_subrate_ind(connsm, dptr, rspdata); + break; #endif default: /* Nothing to do here */ @@ -2723,19 +3100,14 @@ ble_ll_ctrl_rx_pdu(struct ble_ll_conn_sm *connsm, struct os_mbuf *om) } len = g_ble_ll_ctrl_pkt_lengths[rsp_opcode] + 1; ble_ll_conn_enqueue_pkt(connsm, om, BLE_LL_LLID_CTRL, len); -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - if (restart_encryption) { - /* XXX: what happens if this fails? Meaning we cant allocate - mbuf? */ - ble_ll_ctrl_proc_init(connsm, BLE_LL_CTRL_PROC_ENCRYPT); - } -#endif } - if (connsm->csmflags.cfbit.pending_initiate_dle) { - connsm->csmflags.cfbit.pending_initiate_dle = 0; - ble_ll_ctrl_initiate_dle(connsm); +#if MYNEWT_VAL(BLE_LL_CONN_INIT_AUTO_DLE) + if (connsm->flags.pending_initiate_dle) { + connsm->flags.pending_initiate_dle = 0; + ble_ll_ctrl_initiate_dle(connsm, true); } +#endif return rc; } @@ -2786,6 +3158,41 @@ ble_ll_ctrl_reject_ind_send(struct ble_ll_conn_sm *connsm, uint8_t rej_opcode, return rc; } +int +ble_ll_ctrl_tx_start(struct ble_ll_conn_sm *connsm, struct os_mbuf *txpdu) +{ + uint8_t opcode; + uint8_t *ctrdata; + + opcode = txpdu->om_data[0]; + ctrdata = &txpdu->om_data[1]; + + switch (opcode) { + case BLE_LL_CTRL_CONN_UPDATE_IND: + ble_ll_ctrl_conn_update_make_ind_pdu(connsm, ctrdata); + connsm->flags.conn_update_sched = 1; + break; + case BLE_LL_CTRL_CHANNEL_MAP_REQ: + ble_ll_ctrl_chanmap_req_instant(connsm, ctrdata); + connsm->flags.chanmap_update_sched = 1; + break; +#if MYNEWT_VAL(BLE_LL_PHY) + case BLE_LL_CTRL_PHY_UPDATE_IND: + if (ble_ll_ctrl_phy_update_ind_instant(connsm, ctrdata)) { + connsm->flags.phy_update_sched = 1; + } + break; +#endif +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE) + case BLE_LL_CTRL_SUBRATE_IND: + connsm->flags.subrate_trans = 1; + break; +#endif + } + + return 0; +} + /** * Called when a Link Layer Control pdu has been transmitted successfully. * This is called when we have a received a PDU during the ISR. @@ -2802,23 +3209,29 @@ ble_ll_ctrl_tx_done(struct os_mbuf *txpdu, struct ble_ll_conn_sm *connsm) int rc; uint8_t opcode; +#if MYNEWT_VAL(BLE_LL_HCI_LLCP_TRACE) + ble_ll_hci_ev_send_vs_llcp_trace(0x04, connsm->conn_handle, + connsm->event_cntr, + txpdu->om_data, txpdu->om_len); +#endif + rc = 0; opcode = txpdu->om_data[0]; switch (opcode) { case BLE_LL_CTRL_TERMINATE_IND: - connsm->csmflags.cfbit.terminate_ind_txd = 1; + connsm->flags.terminate_ind_txd = 1; rc = -1; break; case BLE_LL_CTRL_REJECT_IND_EXT: if (connsm->cur_ctrl_proc == BLE_LL_CTRL_PROC_CONN_PARAM_REQ) { /* If rejecting opcode is BLE_LL_CTRL_PROC_CONN_PARAM_REQ and - * reason is LMP collision that means we are master on the link and + * reason is LMP collision that means we are central on the link and * peer wanted to start procedure which we already started. * Let's wait for response and do not close procedure. */ if (txpdu->om_data[1] == BLE_LL_CTRL_CONN_PARM_REQ && txpdu->om_data[2] != BLE_ERR_LMP_COLLISION) { connsm->reject_reason = txpdu->om_data[2]; - connsm->csmflags.cfbit.host_expects_upd_event = 1; + connsm->flags.conn_update_host_w4event = 1; } } #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) @@ -2834,38 +3247,63 @@ ble_ll_ctrl_tx_done(struct os_mbuf *txpdu, struct ble_ll_conn_sm *connsm) break; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) case BLE_LL_CTRL_PAUSE_ENC_REQ: + connsm->flags.encrypt_paused = 1; /* note: fall-through intentional */ case BLE_LL_CTRL_ENC_REQ: connsm->enc_data.enc_state = CONN_ENC_S_ENC_RSP_WAIT; break; case BLE_LL_CTRL_ENC_RSP: connsm->enc_data.enc_state = CONN_ENC_S_LTK_REQ_WAIT; - connsm->csmflags.cfbit.send_ltk_req = 1; + connsm->flags.encrypt_ltk_req = 1; break; +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) case BLE_LL_CTRL_START_ENC_RSP: - if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) { + if (connsm->conn_role == BLE_LL_CONN_ROLE_PERIPHERAL) { connsm->enc_data.enc_state = CONN_ENC_S_ENCRYPTED; - if (CONN_F_LE_PING_SUPP(connsm)) { + connsm->flags.encrypt_paused = 0; + if (connsm->flags.le_ping_supp) { ble_ll_conn_auth_pyld_timer_start(connsm); } } break; case BLE_LL_CTRL_PAUSE_ENC_RSP: - if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) { + if (connsm->conn_role == BLE_LL_CONN_ROLE_PERIPHERAL) { connsm->enc_data.enc_state = CONN_ENC_S_PAUSE_ENC_RSP_WAIT; + connsm->flags.encrypt_paused = 1; + } else { + connsm->flags.pending_encrypt_restart = 1; } break; +#else + case BLE_LL_CTRL_PAUSE_ENC_RSP: + BLE_LL_ASSERT(connsm->conn_role == BLE_LL_CONN_ROLE_CENTRAL); + connsm->flags.pending_encrypt_restart = 1; + break; #endif -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) +#endif +#if MYNEWT_VAL(BLE_LL_PHY) +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) case BLE_LL_CTRL_PHY_REQ: - connsm->phy_tx_transition = - ble_ll_ctrl_phy_tx_transition_get(connsm->phy_data.req_pref_tx_phys_mask); + if (connsm->conn_role == BLE_LL_CONN_ROLE_PERIPHERAL) { + connsm->phy_tx_transition = + ble_ll_ctrl_phy_tx_transition_get( + connsm->phy_data.pref_mask_tx_req); + } break; +#endif case BLE_LL_CTRL_PHY_UPDATE_IND: connsm->phy_tx_transition = ble_ll_ctrl_phy_tx_transition_get(txpdu->om_data[2]); break; #endif +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE) +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + case BLE_LL_CTRL_SUBRATE_IND: + connsm->flags.subrate_trans = 0; + connsm->flags.subrate_ind_txd = 1; + break; +#endif /* BLE_LL_CTRL_SUBRATE_IND */ +#endif /* BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE */ default: break; } @@ -2873,3 +3311,16 @@ ble_ll_ctrl_tx_done(struct os_mbuf *txpdu, struct ble_ll_conn_sm *connsm) os_mbuf_free_chain(txpdu); return rc; } + +void +ble_ll_ctrl_init_conn_sm(struct ble_ll_conn_sm *connsm) +{ + ble_npl_callout_init(&connsm->ctrl_proc_rsp_timer, &g_ble_ll_data.ll_evq, + ble_ll_ctrl_proc_rsp_timer_cb, connsm); + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_PING) + ble_npl_callout_init(&connsm->auth_pyld_timer, &g_ble_ll_data.ll_evq, + ble_ll_conn_auth_pyld_timer_cb, connsm); +#endif +} +#endif diff --git a/nimble/transport/dialog_cmac/cmac_driver/include/cmac_driver/cmac_host.h b/nimble/controller/src/ble_ll_ctrl_priv.h similarity index 82% rename from nimble/transport/dialog_cmac/cmac_driver/include/cmac_driver/cmac_host.h rename to nimble/controller/src/ble_ll_ctrl_priv.h index 50d8675524..ca1c83d390 100644 --- a/nimble/transport/dialog_cmac/cmac_driver/include/cmac_driver/cmac_host.h +++ b/nimble/controller/src/ble_ll_ctrl_priv.h @@ -17,19 +17,19 @@ * under the License. */ -#ifndef __DA1469X_CMAC_V2_H_ -#define __DA1469X_CMAC_V2_H_ +#ifndef H_BLE_LL_CTRL_PRIV_ +#define H_BLE_LL_CTRL_PRIV_ + +#include "controller/ble_ll_conn.h" #ifdef __cplusplus extern "C" { #endif -void cmac_host_init(void); -void cmac_host_signal2cmac(void); -void cmac_host_rf_calibrate(void); +void ble_ll_ctrl_init_conn_sm(struct ble_ll_conn_sm *connsm); #ifdef __cplusplus } #endif -#endif /* __DA1469X_CMAC_V2_H_ */ +#endif /* H_BLE_LL_CTRL_PRIV_ */ diff --git a/nimble/controller/src/ble_ll_dtm.c b/nimble/controller/src/ble_ll_dtm.c index de3b168b22..c7823e0f1a 100644 --- a/nimble/controller/src/ble_ll_dtm.c +++ b/nimble/controller/src/ble_ll_dtm.c @@ -26,10 +26,13 @@ #include "os/os.h" #include "stats/stats.h" #include "controller/ble_ll.h" +#include "controller/ble_ll_pdu.h" #include "controller/ble_phy.h" #include "controller/ble_ll_sched.h" #include "controller/ble_ll_rfmgmt.h" +#include "controller/ble_ll_tmr.h" #include "ble_ll_dtm_priv.h" +#include "ble_ll_priv.h" STATS_SECT_START(ble_ll_dtm_stats) STATS_SECT_ENTRY(rx_count) @@ -153,11 +156,8 @@ ble_ll_dtm_set_next(struct dtm_ctx *ctx) struct ble_ll_sched_item *sch = &ctx->sch; ctx->pdu_start_ticks += ctx->itvl_ticks; - ctx->pdu_start_usecs += ctx->itvl_rem_usec; - if (ctx->pdu_start_usecs >= 31) { - ctx->pdu_start_ticks++; - ctx->pdu_start_usecs -= 31; - } + ble_ll_tmr_add_u(&ctx->pdu_start_ticks, &ctx->pdu_start_usecs, + ctx->itvl_rem_usec); sch->start_time = ctx->pdu_start_ticks; sch->remainder = ctx->pdu_start_usecs; @@ -196,16 +196,6 @@ ble_ll_dtm_ev_tx_resched_cb(struct ble_npl_event *evt) { BLE_LL_ASSERT(rc == 0); } -static int ble_ll_dtm_rx_start(void); - -static void -ble_ll_dtm_ev_rx_restart_cb(struct ble_npl_event *evt) { - if (ble_ll_dtm_rx_start() != 0) { - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &g_ble_ll_dtm_ctx.evt); - STATS_INC(ble_ll_dtm_stats, rx_failed); - } -} - static void ble_ll_dtm_tx_done(void *arg) { @@ -219,7 +209,7 @@ ble_ll_dtm_tx_done(void *arg) g_ble_ll_dtm_ctx.num_of_packets++; /* Reschedule event in LL context */ - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &ctx->evt); + ble_ll_event_add(&ctx->evt); ble_ll_state_set(BLE_LL_STATE_STANDBY); } @@ -245,7 +235,7 @@ ble_ll_dtm_tx_sched_cb(struct ble_ll_sched_item *sch) ble_phy_mode_set(ctx->phy_mode, ctx->phy_mode); #endif ble_phy_set_txend_cb(ble_ll_dtm_tx_done, ctx); - ble_phy_txpwr_set(0); + ble_ll_tx_power_set(g_ble_ll_tx_power); sch->start_time += g_ble_ll_sched_offset_ticks; @@ -261,11 +251,11 @@ ble_ll_dtm_tx_sched_cb(struct ble_ll_sched_item *sch) ble_ll_state_set(BLE_LL_STATE_DTM); - return BLE_LL_SCHED_STATE_DONE; + return BLE_LL_SCHED_STATE_RUNNING; resched: /* Reschedule from LL task if late for this PDU */ - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &ctx->evt); + ble_ll_event_add(&ctx->evt); STATS_INC(ble_ll_dtm_stats, tx_failed); @@ -278,10 +268,9 @@ ble_ll_dtm_calculate_itvl(struct dtm_ctx *ctx, uint8_t len, { uint32_t l; uint32_t itvl_usec; - uint32_t itvl_ticks; /* Calculate interval as per spec Bluetooth 5.0 Vol 6. Part F, 4.1.6 */ - l = ble_ll_pdu_tx_time_get(len + BLE_LL_PDU_HDR_LEN, phy_mode); + l = ble_ll_pdu_us(len, phy_mode); itvl_usec = ((l + 249 + 624) / 625) * 625; #if MYNEWT_VAL(BLE_LL_DTM_EXTENSIONS) @@ -290,13 +279,7 @@ ble_ll_dtm_calculate_itvl(struct dtm_ctx *ctx, uint8_t len, } #endif - itvl_ticks = os_cputime_usecs_to_ticks(itvl_usec); - ctx->itvl_rem_usec = (itvl_usec - os_cputime_ticks_to_usecs(itvl_ticks)); - if (ctx->itvl_rem_usec == 31) { - ctx->itvl_rem_usec = 0; - ++itvl_ticks; - } - ctx->itvl_ticks = itvl_ticks; + ctx->itvl_ticks = ble_ll_tmr_u2t_r(itvl_usec, &ctx->itvl_rem_usec); } static int @@ -325,7 +308,7 @@ ble_ll_dtm_tx_create_ctx(uint8_t packet_payload, uint8_t len, /* Set BLE transmit header */ ble_hdr = BLE_MBUF_HDR_PTR(m); - ble_hdr->txinfo.flags = 0; + ble_hdr->txinfo.num_data_pkt = 0; ble_hdr->txinfo.offset = 0; ble_hdr->txinfo.pyld_len = len; ble_hdr->txinfo.hdr_byte = packet_payload; @@ -359,6 +342,18 @@ ble_ll_dtm_tx_create_ctx(uint8_t packet_payload, uint8_t len, case 0x07: byte_pattern = 0xAA; break; +#if MYNEWT_VAL(BLE_LL_DTM_EXTENSIONS) + case 0xff: + ble_ll_tx_power_set(g_ble_ll_tx_power); + rc = ble_phy_dtm_carrier(channel_rf_to_index[rf_channel]); + if (rc) { + return 1; + } + + /* this is special as it doesn't involve scheduling */ + g_ble_ll_dtm_ctx.active = 1; + return 0; +#endif default: return 1; } @@ -410,7 +405,7 @@ ble_ll_dtm_rx_start(void) #endif OS_ENTER_CRITICAL(sr); - rc = ble_phy_rx_set_start_time(os_cputime_get32(), 0); + rc = ble_phy_rx_set_start_time(ble_ll_rfmgmt_enable_now(), 0); OS_EXIT_CRITICAL(sr); if (rc && rc != BLE_PHY_ERR_RX_LATE) { return rc; @@ -421,21 +416,9 @@ ble_ll_dtm_rx_start(void) return 0; } -static int -ble_ll_dtm_rx_sched_cb(struct ble_ll_sched_item *sch) -{ - if (ble_ll_dtm_rx_start() != 0) { - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &g_ble_ll_dtm_ctx.evt); - STATS_INC(ble_ll_dtm_stats, rx_failed); - } - - return BLE_LL_SCHED_STATE_DONE; -} - static int ble_ll_dtm_rx_create_ctx(uint8_t rf_channel, uint8_t phy_mode) { - struct ble_ll_sched_item *sch = &g_ble_ll_dtm_ctx.sch; int rc; g_ble_ll_dtm_ctx.phy_mode = phy_mode; @@ -443,16 +426,8 @@ ble_ll_dtm_rx_create_ctx(uint8_t rf_channel, uint8_t phy_mode) STATS_CLEAR(ble_ll_dtm_stats, rx_count); - ble_npl_event_init(&g_ble_ll_dtm_ctx.evt, ble_ll_dtm_ev_rx_restart_cb, - NULL); - - sch->sched_cb = ble_ll_dtm_rx_sched_cb; - sch->cb_arg = &g_ble_ll_dtm_ctx; - sch->sched_type = BLE_LL_SCHED_TYPE_DTM; - sch->start_time = ble_ll_rfmgmt_enable_now(); - - rc = ble_ll_sched_dtm(sch); - BLE_LL_ASSERT(rc == 0); + rc = ble_ll_dtm_rx_start(); + assert(rc == 0); ble_phy_enable_dtm(); @@ -472,7 +447,7 @@ ble_ll_dtm_ctx_free(struct dtm_ctx * ctx) } ble_ll_sched_rmv_elem(&ctx->sch); - ble_npl_eventq_remove(&g_ble_ll_data.ll_evq, &g_ble_ll_dtm_ctx.evt); + ble_ll_event_remove(&g_ble_ll_dtm_ctx.evt); ble_phy_disable(); ble_phy_disable_dtm(); @@ -490,7 +465,7 @@ ble_ll_dtm_tx_test(uint8_t tx_chan, uint8_t len, uint8_t packet_payload, { uint8_t phy_mode; - if (g_ble_ll_dtm_ctx.active) { + if (g_ble_ll_dtm_ctx.active || ble_ll_is_busy(0)) { return BLE_ERR_CTLR_BUSY; } @@ -515,8 +490,18 @@ ble_ll_dtm_tx_test(uint8_t tx_chan, uint8_t len, uint8_t packet_payload, return BLE_ERR_INV_HCI_CMD_PARMS; } - if (tx_chan > 0x27 || packet_payload > 0x07) { + if (tx_chan > 0x27) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + if (packet_payload > 0x07) { +#if MYNEWT_VAL(BLE_LL_DTM_EXTENSIONS) + if (packet_payload != 255) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } +#else return BLE_ERR_INV_HCI_CMD_PARMS; +#endif } if (ble_ll_dtm_tx_create_ctx(packet_payload, len, tx_chan, phy_mode, @@ -592,7 +577,7 @@ ble_ll_dtm_rx_test(uint8_t rx_chan, uint8_t hci_phy) { uint8_t phy_mode; - if (g_ble_ll_dtm_ctx.active) { + if (g_ble_ll_dtm_ctx.active || ble_ll_is_busy(0)) { return BLE_ERR_CTLR_BUSY; } @@ -672,10 +657,7 @@ ble_ll_dtm_rx_pkt_in(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *hdr) STATS_INC(ble_ll_dtm_stats, rx_count); } - if (ble_ll_dtm_rx_start() != 0) { - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &g_ble_ll_dtm_ctx.evt); - STATS_INC(ble_ll_dtm_stats, rx_failed); - } + ble_phy_restart_rx(); } int @@ -712,6 +694,12 @@ ble_ll_dtm_reset(void) ble_ll_dtm_ctx_free(&g_ble_ll_dtm_ctx); } +int +ble_ll_dtm_enabled(void) +{ + return g_ble_ll_dtm_ctx.active; +} + void ble_ll_dtm_init(void) { diff --git a/nimble/controller/src/ble_ll_dtm_priv.h b/nimble/controller/src/ble_ll_dtm_priv.h index e04af07beb..1e0e2c6fd0 100644 --- a/nimble/controller/src/ble_ll_dtm_priv.h +++ b/nimble/controller/src/ble_ll_dtm_priv.h @@ -37,4 +37,5 @@ int ble_ll_dtm_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr); void ble_ll_dtm_rx_pkt_in(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *hdr); void ble_ll_dtm_wfr_timer_exp(void); void ble_ll_dtm_reset(void); +int ble_ll_dtm_enabled(void); #endif diff --git a/nimble/controller/src/ble_ll_hci.c b/nimble/controller/src/ble_ll_hci.c index 7cd3621c6d..07b0aec1c5 100644 --- a/nimble/controller/src/ble_ll_hci.c +++ b/nimble/controller/src/ble_ll_hci.c @@ -24,7 +24,7 @@ #include "nimble/ble.h" #include "nimble/nimble_opt.h" #include "nimble/hci_common.h" -#include "nimble/ble_hci_trans.h" +#include "controller/ble_ll_utils.h" #include "controller/ble_hw.h" #include "controller/ble_ll_adv.h" #include "controller/ble_ll_scan.h" @@ -33,9 +33,14 @@ #include "controller/ble_ll_whitelist.h" #include "controller/ble_ll_resolv.h" #include "controller/ble_ll_sync.h" +#include +#include "controller/ble_ll_isoal.h" #include "controller/ble_ll_iso.h" +#include "controller/ble_ll_iso_big.h" +#include "controller/ble_ll_cs.h" #include "ble_ll_priv.h" #include "ble_ll_conn_priv.h" +#include "ble_ll_hci_priv.h" #if MYNEWT_VAL(BLE_LL_DTM) #include "ble_ll_dtm_priv.h" @@ -54,6 +59,9 @@ static uint64_t g_ble_ll_hci_event_mask2; static int16_t rx_path_pwr_compensation; static int16_t tx_path_pwr_compensation; +static ble_ll_hci_post_cmd_complete_cb hci_cmd_post_cb = NULL; +static void *hci_cmd_post_cb_user_data = NULL; + #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) static enum { ADV_MODE_ANY, @@ -107,7 +115,7 @@ ble_ll_hci_event_send(struct ble_hci_ev *hci_ev) STATS_INC(ble_ll_stats, hci_events_sent); /* Send the event to the host */ - rc = ble_hci_trans_ll_evt_tx((uint8_t *)hci_ev); + rc = ble_transport_to_hs_evt(hci_ev); BLE_LL_DEBUG_GPIO(HCI_EV, 0); @@ -124,7 +132,7 @@ ble_ll_hci_send_noop(void) struct ble_hci_ev_command_complete_nop *ev; struct ble_hci_ev *hci_ev; - hci_ev = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); + hci_ev = ble_transport_alloc_evt(0); if (hci_ev) { /* Create a command complete event with a NO-OP opcode */ hci_ev->opcode = BLE_HCI_EVCODE_COMMAND_COMPLETE; @@ -211,7 +219,7 @@ ble_ll_hci_rd_local_version(uint8_t *rspbuf, uint8_t *rsplen) rsp->hci_ver = BLE_HCI_VER_BCS; rsp->hci_rev = 0; rsp->lmp_ver = BLE_LMP_VER_BCS; - rsp->manufacturer = htole16(MYNEWT_VAL(BLE_LL_MFRG_ID)); + rsp->manufacturer = htole16(MYNEWT_VAL(BLE_LL_MANUFACTURER_ID)); rsp->lmp_subver = 0; *rsplen = sizeof(*rsp); @@ -255,8 +263,7 @@ ble_ll_hci_rd_local_supp_cmd(uint8_t *rspbuf, uint8_t *rsplen) { struct ble_hci_ip_rd_loc_supp_cmd_rp *rsp = (void *) rspbuf; - memset(rsp->commands, 0, sizeof(rsp->commands)); - memcpy(rsp->commands, g_ble_ll_supp_cmds, sizeof(g_ble_ll_supp_cmds)); + ble_ll_hci_supp_cmd_get(rsp->commands); *rsplen = sizeof(*rsp); return BLE_ERR_SUCCESS; @@ -321,14 +328,20 @@ ble_ll_hci_le_read_bufsize(uint8_t *rspbuf, uint8_t *rsplen) { struct ble_hci_le_rd_buf_size_rp *rp = (void *) rspbuf; +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) || MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) rp->data_len = htole16(g_ble_ll_data.ll_acl_pkt_size); rp->data_packets = g_ble_ll_data.ll_num_acl_pkts; +#else + /* TODO check if can just not support this command */ + rp->data_len = 0; + rp->data_packets = 0; +#endif *rsplen = sizeof(*rp); return BLE_ERR_SUCCESS; } -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ISO) +#if MYNEWT_VAL(BLE_LL_ISO) /** * HCI read buffer size v2 command. Returns the ACL and ISO data packet length and * num data packets. @@ -343,17 +356,23 @@ ble_ll_hci_le_read_bufsize_v2(uint8_t *rspbuf, uint8_t *rsplen) { struct ble_hci_le_rd_buf_size_v2_rp *rp = (void *) rspbuf; + +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) || MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) rp->data_len = htole16(g_ble_ll_data.ll_acl_pkt_size); rp->data_packets = g_ble_ll_data.ll_num_acl_pkts; - rp->iso_data_len = 0; - rp->iso_data_packets = 0; +#else + rp->data_len = 0; + rp->data_packets = 0; +#endif + rp->iso_data_len = htole16(g_ble_ll_data.ll_iso_pkt_size); + rp->iso_data_packets = g_ble_ll_data.ll_num_iso_pkts; *rsplen = sizeof(*rp); return BLE_ERR_SUCCESS; } #endif -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) +#if MYNEWT_VAL(BLE_LL_PHY) /** * Checks the preferred phy masks for validity and places the preferred masks * in the input phy masks @@ -409,6 +428,7 @@ ble_ll_hci_chk_phy_masks(uint8_t all_phys, uint8_t tx_phys, uint8_t rx_phys, * * @return int */ +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) static int ble_ll_hci_le_set_def_phy(const uint8_t *cmdbuf, uint8_t len) { @@ -425,8 +445,18 @@ ble_ll_hci_le_set_def_phy(const uint8_t *cmdbuf, uint8_t len) return rc; } #endif +#endif #if MYNEWT_VAL(BLE_LL_CFG_FEAT_DATA_LEN_EXT) +int +ble_ll_hci_check_dle(uint16_t max_octets, uint16_t max_time) +{ + return (max_octets >= BLE_LL_CONN_SUPP_BYTES_MIN) && + (max_octets <= BLE_LL_CONN_SUPP_BYTES_MAX) && + (max_time >= BLE_LL_CONN_SUPP_TIME_MIN) && + (max_time <= BLE_LL_CONN_SUPP_TIME_MAX); +} + /** * HCI write suggested default data length command. * @@ -445,51 +475,47 @@ ble_ll_hci_le_set_def_phy(const uint8_t *cmdbuf, uint8_t len) static int ble_ll_hci_le_wr_sugg_data_len(const uint8_t *cmdbuf, uint8_t len) { - const struct ble_hci_le_wr_sugg_def_data_len_cp *cmd = (const void*) cmdbuf; - uint16_t tx_oct; + const struct ble_hci_le_wr_sugg_def_data_len_cp *cmd = (const void *)cmdbuf; + uint16_t tx_octets; uint16_t tx_time; - int rc; if (len != sizeof(*cmd)) { return BLE_ERR_INV_HCI_CMD_PARMS; } /* Get suggested octets and time */ - tx_oct = le16toh(cmd->max_tx_octets); + tx_octets = le16toh(cmd->max_tx_octets); tx_time = le16toh(cmd->max_tx_time); - /* If valid, write into suggested and change connection initial times */ - if (ble_ll_chk_txrx_octets(tx_oct) && ble_ll_chk_txrx_time(tx_time)) { - g_ble_ll_conn_params.sugg_tx_octets = (uint8_t)tx_oct; - g_ble_ll_conn_params.sugg_tx_time = tx_time; + if (!ble_ll_hci_check_dle(tx_octets, tx_time)) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } - /* - * We can disregard host suggestion, but we are a nice controller so - * let's use host suggestion, unless they exceed max supported values - * in which case we just use our max. - */ - g_ble_ll_conn_params.conn_init_max_tx_octets = - min(tx_oct, g_ble_ll_conn_params.supp_max_tx_octets); - g_ble_ll_conn_params.conn_init_max_tx_time = - min(tx_time, g_ble_ll_conn_params.supp_max_tx_time); + g_ble_ll_conn_params.sugg_tx_octets = tx_octets; + g_ble_ll_conn_params.sugg_tx_time = tx_time; - /* - * Use the same for coded and uncoded defaults. These are used when PHY - * parameters are initialized and we want to use values overridden by - * host. Make sure we do not exceed max supported time on uncoded. - */ - g_ble_ll_conn_params.conn_init_max_tx_time_uncoded = - min(BLE_LL_CONN_SUPP_TIME_MAX_UNCODED, - g_ble_ll_conn_params.conn_init_max_tx_time); - g_ble_ll_conn_params.conn_init_max_tx_time_coded = - g_ble_ll_conn_params.conn_init_max_tx_time; + /* + * We can disregard host suggestion, but we are a nice controller so + * let's use host suggestion, unless they exceed max supported values + * in which case we just use our max. + */ + g_ble_ll_conn_params.conn_init_max_tx_octets = + MIN(tx_octets, g_ble_ll_conn_params.supp_max_tx_octets); + g_ble_ll_conn_params.conn_init_max_tx_time = + MIN(tx_time, g_ble_ll_conn_params.supp_max_tx_time); - rc = BLE_ERR_SUCCESS; - } else { - rc = BLE_ERR_INV_HCI_CMD_PARMS; - } + /* + * Use the same for coded and uncoded defaults. These are used when PHY + * parameters are initialized and we want to use values overridden by + * host. Make sure we do not exceed max supported time on uncoded. + */ + g_ble_ll_conn_params.conn_init_max_tx_time_uncoded = + MIN(BLE_LL_CONN_SUPP_TIME_MAX_UNCODED, + g_ble_ll_conn_params.conn_init_max_tx_time); + g_ble_ll_conn_params.conn_init_max_tx_time_coded = + g_ble_ll_conn_params.conn_init_max_tx_time; - return rc; + return 0; } /** @@ -644,9 +670,15 @@ ble_ll_hci_le_cmd_send_cmd_status(uint16_t ocf) case BLE_HCI_OCF_LE_GEN_DHKEY: case BLE_HCI_OCF_LE_SET_PHY: case BLE_HCI_OCF_LE_PERIODIC_ADV_CREATE_SYNC: +#if MYNEWT_VAL(BLE_LL_ISO_BROADCASTER) + case BLE_HCI_OCF_LE_CREATE_BIG: + case BLE_HCI_OCF_LE_CREATE_BIG_TEST: + case BLE_HCI_OCF_LE_TERMINATE_BIG: +#endif #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_SCA_UPDATE) case BLE_HCI_OCF_LE_REQ_PEER_SCA: #endif + case BLE_HCI_OCF_LE_SUBRATE_REQ: rc = 1; break; default: @@ -657,6 +689,7 @@ ble_ll_hci_le_cmd_send_cmd_status(uint16_t ocf) } #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) +#if MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) /** HCI LE read maximum advertising data length command. Returns the controllers * max supported advertising data length; * @@ -694,6 +727,7 @@ ble_ll_adv_rd_sup_adv_sets(uint8_t *rspbuf, uint8_t *rsplen) *rsplen = sizeof(*rsp); return BLE_ERR_SUCCESS; } +#endif static bool ble_ll_is_valid_adv_mode(uint8_t ocf) @@ -745,6 +779,9 @@ ble_ll_is_valid_adv_mode(uint8_t ocf) #if MYNEWT_VAL(BLE_VERSION) >= 51 case BLE_HCI_OCF_LE_PERIODIC_ADV_RECEIVE_ENABLE: #endif +#if MYNEWT_VAL(BLE_VERSION) >= 54 + case BLE_HCI_OCF_LE_SET_EXT_ADV_PARAM_V2: +#endif #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER) case BLE_HCI_OCF_LE_PERIODIC_ADV_SYNC_TRANSFER: case BLE_HCI_OCF_LE_PERIODIC_ADV_SET_INFO_TRANSFER: @@ -770,8 +807,8 @@ ble_ll_read_tx_power(uint8_t *rspbuf, uint8_t *rsplen) { struct ble_hci_le_rd_transmit_power_rp *rsp = (void *) rspbuf; - rsp->min_tx_power = ble_phy_txpower_round(-127); - rsp->max_tx_power = ble_phy_txpower_round(126); + rsp->min_tx_power = ble_ll_tx_power_round(-127); + rsp->max_tx_power = ble_ll_tx_power_round(126); *rsplen = sizeof(*rsp); return BLE_ERR_SUCCESS; @@ -785,7 +822,7 @@ ble_ll_read_rf_path_compensation(uint8_t *rspbuf, uint8_t *rsplen) rsp->rx_path_compensation = htole16(rx_path_pwr_compensation); rsp->tx_path_compensation = htole16(tx_path_pwr_compensation); - *rsplen = sizeof(*rsp);; + *rsplen = sizeof(*rsp); return BLE_ERR_SUCCESS; } @@ -810,15 +847,43 @@ ble_ll_write_rf_path_compensation(const uint8_t *cmdbuf, uint8_t len) tx_path_pwr_compensation = tx; rx_path_pwr_compensation = rx; - ble_phy_set_rx_pwr_compensation(rx_path_pwr_compensation / 10); + g_ble_ll_tx_power_compensation = tx / 10; + g_ble_ll_rx_power_compensation = rx / 10; return BLE_ERR_SUCCESS; } -int8_t -ble_ll_get_tx_pwr_compensation(void) +static int +ble_ll_hci_le_set_host_chan_class(const uint8_t *cmdbuf, uint8_t len) { - return tx_path_pwr_compensation / 10; + const struct ble_hci_le_set_host_chan_class_cp *cmd = (const void *)cmdbuf; + uint8_t chan_map_used; + + if (len != sizeof(*cmd)) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + /* HCI command allows only single channel to be enabled, but LL needs at + * least 2 channels to work so let's reject in such case. + */ + chan_map_used = ble_ll_utils_chan_map_used_get(cmd->chan_map); + if ((chan_map_used < 2) || (cmd->chan_map[4] & 0xe0)) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + if (!memcmp(g_ble_ll_data.chan_map, cmd->chan_map, BLE_LL_CHAN_MAP_LEN)) { + return BLE_ERR_SUCCESS; + } + + memcpy(g_ble_ll_data.chan_map, cmd->chan_map, BLE_LL_CHAN_MAP_LEN); + g_ble_ll_data.chan_map_used = chan_map_used; + + ble_ll_conn_chan_map_update(); +#if MYNEWT_VAL(BLE_LL_ISO_BROADCASTER) + ble_ll_iso_big_chan_map_update(); +#endif + + return BLE_ERR_SUCCESS; } /** @@ -837,8 +902,7 @@ ble_ll_get_tx_pwr_compensation(void) */ static int ble_ll_hci_le_cmd_proc(const uint8_t *cmdbuf, uint8_t len, uint16_t ocf, - uint8_t *rspbuf, uint8_t *rsplen, - ble_ll_hci_post_cmd_complete_cb *cb) + uint8_t *rspbuf, uint8_t *rsplen) { int rc; @@ -886,6 +950,7 @@ ble_ll_hci_le_cmd_proc(const uint8_t *cmdbuf, uint8_t len, uint16_t ocf, rc = ble_ll_set_random_addr(cmdbuf, len, false); #endif break; +#if MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) case BLE_HCI_OCF_LE_SET_ADV_PARAMS: rc = ble_ll_adv_set_adv_params(cmdbuf, len); break; @@ -903,20 +968,25 @@ ble_ll_hci_le_cmd_proc(const uint8_t *cmdbuf, uint8_t len, uint16_t ocf, case BLE_HCI_OCF_LE_SET_ADV_ENABLE: rc = ble_ll_hci_adv_set_enable(cmdbuf, len); break; +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) case BLE_HCI_OCF_LE_SET_SCAN_PARAMS: - rc = ble_ll_scan_set_scan_params(cmdbuf, len); + rc = ble_ll_scan_hci_set_params(cmdbuf, len); break; case BLE_HCI_OCF_LE_SET_SCAN_ENABLE: - rc = ble_ll_hci_scan_set_enable(cmdbuf, len); + rc = ble_ll_scan_hci_set_enable(cmdbuf, len); break; +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) case BLE_HCI_OCF_LE_CREATE_CONN: - rc = ble_ll_conn_create(cmdbuf, len); + rc = ble_ll_conn_hci_create(cmdbuf, len); break; case BLE_HCI_OCF_LE_CREATE_CONN_CANCEL: if (len == 0) { - rc = ble_ll_conn_create_cancel(cb); + rc = ble_ll_conn_create_cancel(); } break; +#endif +#endif case BLE_HCI_OCF_LE_RD_WHITE_LIST_SIZE: if (len == 0) { rc = ble_ll_whitelist_read_size(rspbuf, rsplen); @@ -933,18 +1003,22 @@ ble_ll_hci_le_cmd_proc(const uint8_t *cmdbuf, uint8_t len, uint16_t ocf, case BLE_HCI_OCF_LE_RMV_WHITE_LIST: rc = ble_ll_whitelist_rmv(cmdbuf, len); break; +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) case BLE_HCI_OCF_LE_CONN_UPDATE: rc = ble_ll_conn_hci_update(cmdbuf, len); break; +#endif case BLE_HCI_OCF_LE_SET_HOST_CHAN_CLASS: - rc = ble_ll_conn_hci_set_chan_class(cmdbuf, len); + rc = ble_ll_hci_le_set_host_chan_class(cmdbuf, len); break; +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) case BLE_HCI_OCF_LE_RD_CHAN_MAP: rc = ble_ll_conn_hci_rd_chan_map(cmdbuf, len, rspbuf, rsplen); break; case BLE_HCI_OCF_LE_RD_REM_FEAT: rc = ble_ll_conn_hci_read_rem_features(cmdbuf, len); break; +#endif #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) case BLE_HCI_OCF_LE_ENCRYPT: rc = ble_ll_hci_le_encrypt(cmdbuf, len, rspbuf, rsplen); @@ -956,15 +1030,19 @@ ble_ll_hci_le_cmd_proc(const uint8_t *cmdbuf, uint8_t len, uint16_t ocf, } break; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) case BLE_HCI_OCF_LE_START_ENCRYPT: rc = ble_ll_conn_hci_le_start_encrypt(cmdbuf, len); break; +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) case BLE_HCI_OCF_LE_LT_KEY_REQ_REPLY: rc = ble_ll_conn_hci_le_ltk_reply(cmdbuf, len, rspbuf, rsplen); break; case BLE_HCI_OCF_LE_LT_KEY_REQ_NEG_REPLY: rc = ble_ll_conn_hci_le_ltk_neg_reply(cmdbuf, len, rspbuf, rsplen); break; +#endif #endif case BLE_HCI_OCF_LE_RD_SUPP_STATES : if (len == 0) { @@ -984,12 +1062,14 @@ ble_ll_hci_le_cmd_proc(const uint8_t *cmdbuf, uint8_t len, uint16_t ocf, } break; #endif +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) case BLE_HCI_OCF_LE_REM_CONN_PARAM_RR: rc = ble_ll_conn_hci_param_rr(cmdbuf, len, rspbuf, rsplen); break; case BLE_HCI_OCF_LE_REM_CONN_PARAM_NRR: rc = ble_ll_conn_hci_param_nrr(cmdbuf, len, rspbuf, rsplen); break; +#endif #if MYNEWT_VAL(BLE_LL_CFG_FEAT_DATA_LEN_EXT) case BLE_HCI_OCF_LE_SET_DATA_LEN: rc = ble_ll_conn_hci_set_data_len(cmdbuf, len, rspbuf, rsplen); @@ -1040,7 +1120,8 @@ ble_ll_hci_le_cmd_proc(const uint8_t *cmdbuf, uint8_t len, uint16_t ocf, } break; #endif -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) +#if MYNEWT_VAL(BLE_LL_PHY) +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) case BLE_HCI_OCF_LE_RD_PHY: rc = ble_ll_conn_hci_le_rd_phy(cmdbuf, len, rspbuf, rsplen); break; @@ -1051,6 +1132,7 @@ ble_ll_hci_le_cmd_proc(const uint8_t *cmdbuf, uint8_t len, uint16_t ocf, rc = ble_ll_conn_hci_le_set_phy(cmdbuf, len); break; #endif +#endif #if MYNEWT_VAL(BLE_LL_DTM) case BLE_HCI_OCF_LE_RX_TEST_V2: rc = ble_ll_hci_dtm_rx_test_v2(cmdbuf, len); @@ -1059,6 +1141,7 @@ ble_ll_hci_le_cmd_proc(const uint8_t *cmdbuf, uint8_t len, uint16_t ocf, rc = ble_ll_hci_dtm_tx_test_v2(cmdbuf, len); break; #endif +#if MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) case BLE_HCI_OCF_LE_SET_ADV_SET_RND_ADDR: rc = ble_ll_adv_hci_set_random_addr(cmdbuf, len); @@ -1105,24 +1188,28 @@ ble_ll_hci_le_cmd_proc(const uint8_t *cmdbuf, uint8_t len, uint16_t ocf, break; #endif #endif +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) case BLE_HCI_OCF_LE_SET_EXT_SCAN_PARAM: - rc = ble_ll_set_ext_scan_params(cmdbuf, len); + rc = ble_ll_scan_hci_set_ext_params(cmdbuf, len); break; case BLE_HCI_OCF_LE_SET_EXT_SCAN_ENABLE: - rc = ble_ll_hci_ext_scan_set_enable(cmdbuf, len); + rc = ble_ll_scan_hci_set_ext_enable(cmdbuf, len); break; +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) case BLE_HCI_OCF_LE_EXT_CREATE_CONN: - rc = ble_ll_ext_conn_create(cmdbuf, len); + rc = ble_ll_conn_hci_ext_create(cmdbuf, len); break; #endif +#endif #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) case BLE_HCI_OCF_LE_PERIODIC_ADV_CREATE_SYNC: rc = ble_ll_sync_create(cmdbuf, len); break; case BLE_HCI_OCF_LE_PERIODIC_ADV_CREATE_SYNC_CANCEL: if (len == 0) { - rc = ble_ll_sync_cancel(cb); + rc = ble_ll_sync_cancel(); } break; case BLE_HCI_OCF_LE_PERIODIC_ADV_TERM_SYNC: @@ -1149,12 +1236,17 @@ ble_ll_hci_le_cmd_proc(const uint8_t *cmdbuf, uint8_t len, uint16_t ocf, rc = ble_ll_sync_receive_enable(cmdbuf, len); break; #endif +#endif #endif case BLE_HCI_OCF_LE_RD_TRANSMIT_POWER: - rc = ble_ll_read_tx_power(rspbuf, rsplen); + if (len == 0) { + rc = ble_ll_read_tx_power(rspbuf, rsplen); + } break; case BLE_HCI_OCF_LE_RD_RF_PATH_COMPENSATION: - rc = ble_ll_read_rf_path_compensation(rspbuf, rsplen); + if (len == 0) { + rc = ble_ll_read_rf_path_compensation(rspbuf, rsplen); + } break; case BLE_HCI_OCF_LE_WR_RF_PATH_COMPENSATION: rc = ble_ll_write_rf_path_compensation(cmdbuf, len); @@ -1165,12 +1257,16 @@ ble_ll_hci_le_cmd_proc(const uint8_t *cmdbuf, uint8_t len, uint16_t ocf, break; #endif #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER) +#if MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) case BLE_HCI_OCF_LE_PERIODIC_ADV_SYNC_TRANSFER: rc = ble_ll_sync_transfer(cmdbuf, len, rspbuf, rsplen); break; +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) case BLE_HCI_OCF_LE_PERIODIC_ADV_SET_INFO_TRANSFER: rc = ble_ll_adv_periodic_set_info_transfer(cmdbuf, len, rspbuf, rsplen); break; +#endif case BLE_HCI_OCF_LE_PERIODIC_ADV_SYNC_TRANSFER_PARAMS: rc = ble_ll_set_sync_transfer_params(cmdbuf, len, rspbuf, rsplen); break; @@ -1178,76 +1274,109 @@ ble_ll_hci_le_cmd_proc(const uint8_t *cmdbuf, uint8_t len, uint16_t ocf, rc = ble_ll_set_default_sync_transfer_params(cmdbuf, len); break; #endif -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ISO) - case BLE_HCI_OCF_LE_READ_ISO_TX_SYNC: - rc = ble_ll_iso_read_tx_sync(cmdbuf, len); +#if MYNEWT_VAL(BLE_LL_ISO_BROADCASTER) + case BLE_HCI_OCF_LE_CREATE_BIG: + rc = ble_ll_iso_big_hci_create(cmdbuf, len); break; - case BLE_HCI_OCF_LE_SET_CIG_PARAM: - rc = ble_ll_iso_set_cig_param(cmdbuf, len, rspbuf, rsplen); + case BLE_HCI_OCF_LE_CREATE_BIG_TEST: + rc = ble_ll_iso_big_hci_create_test(cmdbuf, len); break; - case BLE_HCI_OCF_LE_CREATE_CIS: - rc = ble_ll_iso_create_cis(cmdbuf, len); + case BLE_HCI_OCF_LE_TERMINATE_BIG: + rc = ble_ll_iso_big_hci_terminate(cmdbuf, len); break; - case BLE_HCI_OCF_LE_REMOVE_CIG: - rc = ble_ll_iso_remove_cig(cmdbuf, len, rspbuf, rsplen); + case BLE_HCI_OCF_LE_ISO_TRANSMIT_TEST: + rc = ble_ll_iso_transmit_test(cmdbuf, len, rspbuf, rsplen); break; - case BLE_HCI_OCF_LE_ACCEPT_CIS_REQ: - rc = ble_ll_iso_accept_cis_req(cmdbuf, len); +#endif /* BLE_LL_ISO_BROADCASTER */ +#if MYNEWT_VAL(BLE_LL_ISO) + case BLE_HCI_OCF_LE_SETUP_ISO_DATA_PATH: + rc = ble_ll_iso_setup_iso_data_path(cmdbuf, len, rspbuf, rsplen); break; - case BLE_HCI_OCF_LE_REJECT_CIS_REQ: - rc = ble_ll_iso_reject_cis_req(cmdbuf, len); + case BLE_HCI_OCF_LE_REMOVE_ISO_DATA_PATH: + rc = ble_ll_iso_remove_iso_data_path(cmdbuf, len, rspbuf, rsplen); break; - case BLE_HCI_OCF_LE_CREATE_BIG: - rc = ble_ll_iso_create_big(cmdbuf, len); + case BLE_HCI_OCF_LE_ISO_TEST_END: + rc = ble_ll_iso_end_test(cmdbuf, len, rspbuf, rsplen); break; - case BLE_HCI_OCF_LE_TERMINATE_BIG: - rc = ble_ll_iso_terminate_big(cmdbuf, len); + case BLE_HCI_OCF_LE_READ_ISO_TX_SYNC: + rc = ble_ll_iso_read_tx_sync(cmdbuf, len, rspbuf, rsplen); break; - case BLE_HCI_OCF_LE_BIG_CREATE_SYNC: - rc = ble_ll_iso_big_create_sync(cmdbuf, len); + case BLE_HCI_OCF_LE_RD_BUF_SIZE_V2: + if (len == 0) { + rc = ble_ll_hci_le_read_bufsize_v2(rspbuf, rsplen); + } break; - case BLE_HCI_OCF_LE_BIG_TERMINATE_SYNC: - rc = ble_ll_iso_big_terminate_sync(cmdbuf,len); +#endif /* BLE_LL_ISO */ +#if BLE_LL_HOST_CONTROLLED_FEATURES + case BLE_HCI_OCF_LE_SET_HOST_FEATURE: + rc = ble_ll_set_host_feat(cmdbuf, len); break; - case BLE_HCI_OCF_LE_SETUP_ISO_DATA_PATH: - rc = ble_ll_iso_setup_iso_data_path(cmdbuf, len); +#endif +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_SCA_UPDATE) + case BLE_HCI_OCF_LE_REQ_PEER_SCA: + rc = ble_ll_conn_req_peer_sca(cmdbuf, len, + rspbuf, rsplen); break; - case BLE_HCI_OCF_LE_REMOVE_ISO_DATA_PATH: - rc = ble_ll_iso_remove_iso_data_path(cmdbuf, len); +#endif +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE) + case BLE_HCI_OCF_LE_SET_DEFAULT_SUBRATE: + rc = ble_ll_conn_hci_set_default_subrate(cmdbuf, len, rspbuf, rsplen); break; - case BLE_HCI_OCF_LE_RD_BUF_SIZE_V2: - rc = ble_ll_hci_le_read_bufsize_v2(rspbuf, rsplen); + case BLE_HCI_OCF_LE_SUBRATE_REQ: + rc = ble_ll_conn_hci_subrate_req(cmdbuf, len, rspbuf, rsplen); break; #endif -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ISO_TEST) - case BLE_HCI_OCF_LE_SET_CIG_PARAM_TEST: - rc = ble_ll_iso_set_cig_param_test(cmdbuf, len, rspbuf, rsplen); - break; - case BLE_HCI_OCF_LE_CREATE_BIG_TEST: - rc = ble_ll_iso_create_big_test(cmdbuf, len); +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) +#if MYNEWT_VAL(BLE_VERSION) >= 54 + case BLE_HCI_OCF_LE_SET_EXT_ADV_PARAM_V2: + rc = ble_ll_adv_ext_set_param_v2(cmdbuf, len, rspbuf, rsplen); break; - case BLE_HCI_OCF_LE_ISO_TRANSMIT_TEST: - rc = ble_ll_iso_transmit_test(cmdbuf, len); +#endif +#endif +#if MYNEWT_VAL(BLE_LL_CHANNEL_SOUNDING) + case BLE_HCI_OCF_LE_CS_RD_LOC_SUPP_CAP: + rc = ble_ll_cs_hci_rd_loc_supp_cap(rspbuf, rsplen); break; - case BLE_HCI_OCF_LE_ISO_RECEIVE_TEST: - rc = ble_ll_iso_receive_test(cmdbuf, len); + case BLE_HCI_OCF_LE_CS_RD_REM_SUPP_CAP: + rc = ble_ll_cs_hci_rd_rem_supp_cap(cmdbuf, len); break; - case BLE_HCI_OCF_LE_ISO_READ_TEST_COUNTERS: - rc = ble_ll_iso_read_counters_test(cmdbuf, len); + case BLE_HCI_OCF_LE_CS_WR_CACHED_REM_SUPP_CAP: + rc = ble_ll_cs_hci_wr_cached_rem_supp_cap(cmdbuf, len, rspbuf, rsplen); break; - case BLE_HCI_OCF_LE_ISO_TEST_END: - rc = ble_ll_iso_end_test(cmdbuf, len); +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + case BLE_HCI_OCF_LE_CS_SEC_ENABLE: + rc = ble_ll_cs_hci_sec_enable(cmdbuf, len); break; #endif -#if MYNEWT_VAL(BLE_VERSION) >= 52 - case BLE_HCI_OCF_LE_SET_HOST_FEAT: - rc = ble_ll_set_host_feat(cmdbuf, len); + case BLE_HCI_OCF_LE_CS_SET_DEF_SETTINGS: + rc = ble_ll_cs_hci_set_def_settings(cmdbuf, len, rspbuf, rsplen); break; -#endif -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_SCA_UPDATE) - case BLE_HCI_OCF_LE_REQ_PEER_SCA: - rc = ble_ll_conn_req_peer_sca(cmdbuf, len, - rspbuf, rsplen); + case BLE_HCI_OCF_LE_CS_RD_REM_FAE: + rc = ble_ll_cs_hci_rd_rem_fae(cmdbuf, len); + break; + case BLE_HCI_OCF_LE_CS_WR_CACHED_REM_FAE: + rc = ble_ll_cs_hci_wr_cached_rem_fae(cmdbuf, len, rspbuf, rsplen); + break; + case BLE_HCI_OCF_LE_CS_CREATE_CONFIG: + rc = ble_ll_cs_hci_create_config(cmdbuf, len); + break; + case BLE_HCI_OCF_LE_CS_REMOVE_CONFIG: + rc = ble_ll_cs_hci_remove_config(cmdbuf, len); + break; + case BLE_HCI_OCF_LE_CS_SET_CHAN_CLASS: + rc = ble_ll_cs_hci_set_chan_class(cmdbuf, len); + break; + case BLE_HCI_OCF_LE_CS_SET_PROC_PARAMS: + rc = ble_ll_cs_hci_set_proc_params(cmdbuf, len, rspbuf, rsplen); + break; + case BLE_HCI_OCF_LE_CS_PROC_ENABLE: + rc = ble_ll_cs_hci_proc_enable(cmdbuf, len); + break; + case BLE_HCI_OCF_LE_CS_TEST: + rc = ble_ll_cs_hci_test(cmdbuf, len, rspbuf, rsplen); + break; + case BLE_HCI_OCF_LE_CS_TEST_END: + rc = ble_ll_cs_hci_test_end(); break; #endif default: @@ -1259,17 +1388,15 @@ ble_ll_hci_le_cmd_proc(const uint8_t *cmdbuf, uint8_t len, uint16_t ocf, * This code is here because we add 256 to the return code to denote * that the reply to this command should be command status (as opposed to * command complete). - * - * For unknown HCI command let us return always command status as per - * specification Bluetooth 5, Vol. 2, Chapter 4.4 */ - if (ble_ll_hci_le_cmd_send_cmd_status(ocf) || rc == BLE_ERR_UNKNOWN_HCI_CMD) { + if (ble_ll_hci_le_cmd_send_cmd_status(ocf)) { rc += (BLE_ERR_MAX + 1); } return rc; } +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) || MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) static int ble_ll_hci_disconnect(const uint8_t *cmdbuf, uint8_t len) { @@ -1281,14 +1408,9 @@ ble_ll_hci_disconnect(const uint8_t *cmdbuf, uint8_t len) return BLE_ERR_INV_HCI_CMD_PARMS; } -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ISO) - if (le16toh(cmd->conn_handle) >= BLE_LL_CONN_HANDLE_ISO_OFFSET) { - return ble_ll_iso_disconnect_cmd(cmd); - } -#endif - return ble_ll_conn_hci_disconnect_cmd(cmd); } +#endif /** * Process a link control command sent from the host to the controller. The HCI @@ -1309,18 +1431,18 @@ ble_ll_hci_link_ctrl_cmd_proc(const uint8_t *cmdbuf, uint8_t len, uint16_t ocf) int rc; switch (ocf) { +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) || MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) case BLE_HCI_OCF_DISCONNECT_CMD: rc = ble_ll_hci_disconnect(cmdbuf, len); /* Send command status instead of command complete */ rc += (BLE_ERR_MAX + 1); break; - case BLE_HCI_OCF_RD_REM_VER_INFO: rc = ble_ll_conn_hci_rd_rem_ver_cmd(cmdbuf, len); /* Send command status instead of command complete */ rc += (BLE_ERR_MAX + 1); break; - +#endif default: rc = BLE_ERR_UNKNOWN_HCI_CMD; break; @@ -1381,17 +1503,9 @@ ble_ll_hci_cb_host_buf_size(const uint8_t *cmdbuf, uint8_t len) return BLE_ERR_INV_HCI_CMD_PARMS; } - /* - * Core 5.2 Vol 4 Part E section 7.3.39 states that "Both the Host and the - * Controller shall support command and event packets, where the data portion - * (excluding header) contained in the packets is 255 octets in size.". - * This means we can basically accept any allowed value since LL does not - * reassemble incoming data thus will not send more than 255 octets in single - * data packet. - */ acl_num = le16toh(cmd->acl_num); acl_data_len = le16toh(cmd->acl_data_len); - if (acl_data_len < 255) { + if ((acl_num < 1) || (acl_data_len < 1)) { return BLE_ERR_INV_HCI_CMD_PARMS; } @@ -1433,6 +1547,11 @@ ble_ll_hci_ctlr_bb_cmd_proc(const uint8_t *cmdbuf, uint8_t len, uint16_t ocf, rc = ble_ll_reset(); } break; +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + case BLE_HCI_OCF_CB_READ_TX_PWR: + rc = ble_ll_conn_hci_cb_read_tx_pwr(cmdbuf, len, rspbuf, rsplen); + break; +#endif #if MYNEWT_VAL(BLE_LL_CFG_FEAT_CTRL_TO_HOST_FLOW_CONTROL) case BLE_HCI_OCF_CB_SET_CTLR_TO_HOST_FC: rc = ble_ll_hci_cb_set_ctrlr_to_host_fc(cmdbuf, len); @@ -1452,7 +1571,8 @@ ble_ll_hci_ctlr_bb_cmd_proc(const uint8_t *cmdbuf, uint8_t len, uint16_t ocf, case BLE_HCI_OCF_CB_SET_EVENT_MASK2: rc = ble_ll_hci_cb_set_event_mask2(cmdbuf, len); break; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_PING) +#if (MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL)) \ + && MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_PING) case BLE_HCI_OCF_CB_RD_AUTH_PYLD_TMO: rc = ble_ll_conn_hci_rd_auth_pyld_tmo(cmdbuf, len, rspbuf, rsplen); break; @@ -1514,9 +1634,11 @@ ble_ll_hci_status_params_cmd_proc(const uint8_t *cmdbuf, uint8_t len, int rc; switch (ocf) { +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) case BLE_HCI_OCF_RD_RSSI: rc = ble_ll_conn_hci_rd_rssi(cmdbuf, len, rspbuf, rsplen); break; +#endif default: rc = BLE_ERR_UNKNOWN_HCI_CMD; break; @@ -1525,47 +1647,154 @@ ble_ll_hci_status_params_cmd_proc(const uint8_t *cmdbuf, uint8_t len, return rc; } -#if MYNEWT_VAL(BLE_HCI_VS) -static int -ble_ll_hci_vs_rd_static_addr(uint8_t *rspbuf, uint8_t *rsplen) +#if MYNEWT_VAL(BLE_LL_HBD_FAKE_DUAL_MODE) +static void +ble_ll_hci_cmd_fake_dual_mode_inquiry_complete(struct ble_npl_event *ev) { - struct ble_hci_vs_rd_static_addr_rp *rsp = (void *) rspbuf; - ble_addr_t addr; + struct ble_hci_ev *hci_ev; - if (ble_hw_get_static_addr(&addr) < 0) { - return BLE_ERR_UNSPECIFIED; + hci_ev = ble_transport_alloc_evt(1); + if (!hci_ev) { + return; } - memcpy(rsp->addr, addr.val, sizeof(rsp->addr)); + hci_ev->opcode = BLE_HCI_EVCODE_INQUIRY_CMP; + hci_ev->length = 1; + hci_ev->data[0] = 0; - *rsplen = sizeof(*rsp); - return BLE_ERR_SUCCESS; + ble_ll_hci_event_send(hci_ev); +} + +static void +ble_ll_hci_cmd_fake_dual_mode_inquiry(uint32_t length) +{ + static struct ble_npl_callout inquiry_timer; + static bool init; + + if (!init) { + ble_npl_callout_init(&inquiry_timer, &g_ble_ll_data.ll_evq, + ble_ll_hci_cmd_fake_dual_mode_inquiry_complete, + NULL); + } + + if (length) { + ble_npl_callout_reset(&inquiry_timer, + ble_npl_time_ms_to_ticks32(length * 1280)); + } else { + ble_npl_callout_stop(&inquiry_timer); + } } static int -ble_ll_hci_vs_cmd_proc(const uint8_t *cmdbuf, uint8_t len, uint16_t ocf, - uint8_t *rspbuf, uint8_t *rsplen) +ble_ll_hci_cmd_fake_dual_mode(uint16_t opcode, uint8_t *cmdbuf, uint8_t len, + uint8_t *rspbuf, uint8_t *rsplen) { int rc; - /* Assume error; if all pass rc gets set to 0 */ - rc = BLE_ERR_INV_HCI_CMD_PARMS; - - switch (ocf) { - case BLE_HCI_OCF_VS_RD_STATIC_ADDR: - if (len == 0) { - rc = ble_ll_hci_vs_rd_static_addr(rspbuf, rsplen); + switch (opcode) { + case BLE_HCI_OP(BLE_HCI_OGF_LINK_CTRL, 0x01): /* Inquiry */ + ble_ll_hci_cmd_fake_dual_mode_inquiry(cmdbuf[3]); + rc = BLE_ERR_MAX + 1; + break; + case BLE_HCI_OP(BLE_HCI_OGF_LINK_CTRL, 0x02): /* Inquiry Cancel */ + ble_ll_hci_cmd_fake_dual_mode_inquiry(0); + rc = 0; + break; + case BLE_HCI_OP(BLE_HCI_OGF_CTLR_BASEBAND, 0x05): /* Set Event Filter */ + case BLE_HCI_OP(BLE_HCI_OGF_CTLR_BASEBAND, 0x13): /* Write Local Name */ + case BLE_HCI_OP(BLE_HCI_OGF_CTLR_BASEBAND, 0x16): /* Write Connection Accept Timeout */ + case BLE_HCI_OP(BLE_HCI_OGF_CTLR_BASEBAND, 0x18): /* Write Page Timeout */ + case BLE_HCI_OP(BLE_HCI_OGF_CTLR_BASEBAND, 0x1a): /* Write Scan Enable */ + case BLE_HCI_OP(BLE_HCI_OGF_CTLR_BASEBAND, 0x1c): /* Write Page Scan Activity */ + case BLE_HCI_OP(BLE_HCI_OGF_CTLR_BASEBAND, 0x1e): /* Write Inquiry Scan Activity */ + case BLE_HCI_OP(BLE_HCI_OGF_CTLR_BASEBAND, 0x20): /* Write Authentication Enable */ + case BLE_HCI_OP(BLE_HCI_OGF_CTLR_BASEBAND, 0x24): /* Write Class Of Device */ + case BLE_HCI_OP(BLE_HCI_OGF_CTLR_BASEBAND, 0x33): /* Host Buffer Size */ + case BLE_HCI_OP(BLE_HCI_OGF_CTLR_BASEBAND, 0x45): /* Write Inquiry Mode */ + case BLE_HCI_OP(BLE_HCI_OGF_CTLR_BASEBAND, 0x52): /* Write Extended Inquiry Response */ + case BLE_HCI_OP(BLE_HCI_OGF_CTLR_BASEBAND, 0x56): /* Write Simple Pairing Mode */ + case BLE_HCI_OP(BLE_HCI_OGF_CTLR_BASEBAND, 0x6d): /* Write LE Host Support */ + rc = 0; + break; + case BLE_HCI_OP(BLE_HCI_OGF_CTLR_BASEBAND, 0x14): /* Read Local Name */ + memset(rspbuf, 0, 248); + strcpy((char *)rspbuf, "NimBLE"); + *rsplen = 248; + rc = 0; + break; + case BLE_HCI_OP(BLE_HCI_OGF_CTLR_BASEBAND, 0x23): /* Read Class Of Device */ + put_le24(rspbuf, 0); + *rsplen = 3; + rc = 0; + break; + case BLE_HCI_OP(BLE_HCI_OGF_CTLR_BASEBAND, 0x25): /* Read Voice Settings */ + put_le16(rspbuf, 0); + *rsplen = 2; + rc = 0; + break; + case BLE_HCI_OP(BLE_HCI_OGF_CTLR_BASEBAND, 0x38): /* Read Number Of Supported IAC */ + rspbuf[0] = 1; + *rsplen = 1; + rc = 0; + break; + case BLE_HCI_OP(BLE_HCI_OGF_CTLR_BASEBAND, 0x39): /* Read Current IAC LAP */ + rspbuf[0] = 1; + put_le24(&rspbuf[1], 0x9e8b33); + *rsplen = 4; + rc = 0; + break; + case BLE_HCI_OP(BLE_HCI_OGF_CTLR_BASEBAND, 0x58): /* Read Inquiry Response Transmit Power Level */ + rspbuf[0] = 0x04; + *rsplen = 1; + rc = 0; + break; + case BLE_HCI_OP(BLE_HCI_OGF_INFO_PARAMS, BLE_HCI_OCF_IP_RD_LOC_SUPP_FEAT): + put_le64(rspbuf, 0x077bffdbfe0ffebf); + *rsplen = 8; + rc = 0; + break; + case BLE_HCI_OP(BLE_HCI_OGF_INFO_PARAMS, 0x04): /* Read Local Extended Features */ + rspbuf[0] = cmdbuf[0]; + rspbuf[1] = 0; + if (rspbuf[0] == 0) { + put_le64(&rspbuf[2], 0x077bffdbfe0ffebf); + rc = 0; + } else { + put_le64(&rspbuf[2], 0); + rc = BLE_ERR_INV_HCI_CMD_PARMS; } + *rsplen = 10; + break; + case BLE_HCI_OP(BLE_HCI_OGF_INFO_PARAMS, BLE_HCI_OCF_IP_RD_BUF_SIZE): + put_le16(rspbuf, 255); + rspbuf[2] = 0; + put_le16(rspbuf + 3, 4); + put_le16(rspbuf + 5, 0); + *rsplen = 7; + rc = 0; break; - default: - rc = BLE_ERR_UNKNOWN_HCI_CMD; + case BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_RD_SUPP_STATES): + put_le64(rspbuf, 0x000003ffffffffff); + *rsplen = 8; + rc = 0; break; + default: + rc = -1; } return rc; } #endif + +void +ble_ll_hci_post_cmd_cb_set(ble_ll_hci_post_cmd_complete_cb cb, void *user_data) +{ + BLE_LL_ASSERT(hci_cmd_post_cb == NULL); + hci_cmd_post_cb = cb; + hci_cmd_post_cb_user_data = user_data; +} + /** * Called to process an HCI command from the host. * @@ -1580,7 +1809,6 @@ ble_ll_hci_cmd_proc(struct ble_npl_event *ev) struct ble_hci_cmd *cmd; uint16_t opcode; uint16_t ocf; - ble_ll_hci_post_cmd_complete_cb post_cb = NULL; struct ble_hci_ev *hci_ev; struct ble_hci_ev_command_status *cmd_status; struct ble_hci_ev_command_complete *cmd_complete; @@ -1609,6 +1837,30 @@ ble_ll_hci_cmd_proc(struct ble_npl_event *ev) /* Assume response length is zero */ rsplen = 0; +#if MYNEWT_VAL(BLE_LL_DTM) + /* if DTM test is enabled disallow any command other than LE Test End or + * HCI Reset + */ + if (ble_ll_dtm_enabled()) { + switch (opcode) { + case BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_TEST_END): + case BLE_HCI_OP(BLE_HCI_OGF_CTLR_BASEBAND, BLE_HCI_OCF_CB_RESET): + break; + default: + rc = BLE_ERR_CMD_DISALLOWED; + goto send_cc_cs; + } + } +#endif + +#if MYNEWT_VAL(BLE_LL_HBD_FAKE_DUAL_MODE) + rc = ble_ll_hci_cmd_fake_dual_mode(opcode, cmd->data, cmd->length, + rspbuf, &rsplen); + if (rc >= 0) { + goto send_cc_cs; + } +#endif + switch (ogf) { case BLE_HCI_OGF_LINK_CTRL: rc = ble_ll_hci_link_ctrl_cmd_proc(cmd->data, cmd->length, ocf); @@ -1623,9 +1875,9 @@ ble_ll_hci_cmd_proc(struct ble_npl_event *ev) rc = ble_ll_hci_status_params_cmd_proc(cmd->data, cmd->length, ocf, rspbuf, &rsplen); break; case BLE_HCI_OGF_LE: - rc = ble_ll_hci_le_cmd_proc(cmd->data, cmd->length, ocf, rspbuf, &rsplen, &post_cb); + rc = ble_ll_hci_le_cmd_proc(cmd->data, cmd->length, ocf, rspbuf, &rsplen); break; -#if MYNEWT_VAL(BLE_HCI_VS) +#if MYNEWT_VAL(BLE_LL_HCI_VS) case BLE_HCI_OGF_VENDOR: rc = ble_ll_hci_vs_cmd_proc(cmd->data, cmd->length, ocf, rspbuf, &rsplen); break; @@ -1636,6 +1888,16 @@ ble_ll_hci_cmd_proc(struct ble_npl_event *ev) break; } + /* We always send command status for unknown command + * ref: Core 5.3, Vol 4, Part E, 4.5 + */ + if (rc == BLE_ERR_UNKNOWN_HCI_CMD) { + rc += (BLE_ERR_MAX + 1); + } + +#if MYNEWT_VAL(BLE_LL_HBD_FAKE_DUAL_MODE) || MYNEWT_VAL(BLE_LL_DTM) +send_cc_cs: +#endif /* If no response is generated, we free the buffers */ BLE_LL_ASSERT(rc >= 0); if (rc <= BLE_ERR_MAX) { @@ -1671,26 +1933,18 @@ ble_ll_hci_cmd_proc(struct ble_npl_event *ev) ble_ll_hci_event_send(hci_ev); /* Call post callback if set by command handler */ - if (post_cb) { - post_cb(); + if (hci_cmd_post_cb) { + hci_cmd_post_cb(hci_cmd_post_cb_user_data); + + hci_cmd_post_cb = NULL; + hci_cmd_post_cb_user_data = NULL; } BLE_LL_DEBUG_GPIO(HCI_CMD, 0); } -/** - * Sends an HCI command to the controller. On success, the supplied buffer is - * relinquished to the controller task. On failure, the caller must free the - * buffer. - * - * @param cmd A flat buffer containing the HCI command to - * send. - * - * @return 0 on success; - * BLE_ERR_MEM_CAPACITY on HCI buffer exhaustion. - */ int -ble_ll_hci_cmd_rx(uint8_t *cmdbuf, void *arg) +ble_ll_hci_cmd_rx(uint8_t *cmdbuf) { struct ble_npl_event *ev; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_CTRL_TO_HOST_FLOW_CONTROL) @@ -1713,7 +1967,7 @@ ble_ll_hci_cmd_rx(uint8_t *cmdbuf, void *arg) if ((ogf == BLE_HCI_OGF_CTLR_BASEBAND) && (ocf == BLE_HCI_OCF_CB_HOST_NUM_COMP_PKTS)) { ble_ll_conn_cth_flow_process_cmd(cmdbuf); - ble_hci_trans_buf_free(cmdbuf); + ble_transport_free(cmdbuf); return 0; } #endif @@ -1726,16 +1980,31 @@ ble_ll_hci_cmd_rx(uint8_t *cmdbuf, void *arg) /* Fill out the event and post to Link Layer */ ble_npl_event_set_arg(ev, cmdbuf); - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, ev); + ble_ll_event_add(ev); return 0; } -/* Send ACL data from host to contoller */ int -ble_ll_hci_acl_rx(struct os_mbuf *om, void *arg) +ble_ll_hci_acl_rx(struct os_mbuf *om) { +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) ble_ll_acl_data_in(om); +#else + /* host should never send ACL in that case but if it does just ignore it */ + os_mbuf_free_chain(om); +#endif + return 0; +} + +int +ble_ll_hci_iso_rx(struct os_mbuf *om) +{ +#if MYNEWT_VAL(BLE_LL_ISO) + ble_ll_iso_data_in(om); +#else + os_mbuf_free_chain(om); +#endif return 0; } diff --git a/nimble/controller/src/ble_ll_hci_ev.c b/nimble/controller/src/ble_ll_hci_ev.c index 0d6da9a01e..8d088d9da8 100644 --- a/nimble/controller/src/ble_ll_hci_ev.c +++ b/nimble/controller/src/ble_ll_hci_ev.c @@ -16,13 +16,15 @@ * specific language governing permissions and limitations * under the License. */ -#include + #include +#include +#include +#include #include #include "syscfg/syscfg.h" #include "nimble/ble.h" #include "nimble/hci_common.h" -#include "nimble/ble_hci_trans.h" #include "controller/ble_ll.h" #include "controller/ble_ll_hci.h" #include "controller/ble_ll_ctrl.h" @@ -44,7 +46,7 @@ ble_ll_hci_ev_datalen_chg(struct ble_ll_conn_sm *connsm) struct ble_hci_ev *hci_ev; if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_DATA_LEN_CHG)) { - hci_ev = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); + hci_ev = ble_transport_alloc_evt(0); if (hci_ev) { hci_ev->opcode = BLE_HCI_EVCODE_LE_META; hci_ev->length = sizeof(*ev); @@ -76,7 +78,7 @@ ble_ll_hci_ev_rem_conn_parm_req(struct ble_ll_conn_sm *connsm, struct ble_hci_ev *hci_ev; if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_REM_CONN_PARM_REQ)) { - hci_ev = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); + hci_ev = ble_transport_alloc_evt(0); if (hci_ev) { hci_ev->opcode = BLE_HCI_EVCODE_LE_META; hci_ev->length = sizeof(*ev); @@ -107,7 +109,7 @@ ble_ll_hci_ev_conn_update(struct ble_ll_conn_sm *connsm, uint8_t status) struct ble_hci_ev *hci_ev; if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_CONN_UPD_COMPLETE)) { - hci_ev = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); + hci_ev = ble_transport_alloc_evt(0); if (hci_ev) { hci_ev->opcode = BLE_HCI_EVCODE_LE_META; hci_ev->length = sizeof(*ev); @@ -117,7 +119,7 @@ ble_ll_hci_ev_conn_update(struct ble_ll_conn_sm *connsm, uint8_t status) ev->status = status; ev->conn_handle = htole16(connsm->conn_handle); ev->conn_itvl = htole16(connsm->conn_itvl); - ev->conn_latency = htole16(connsm->slave_latency); + ev->conn_latency = htole16(connsm->periph_latency); ev->supervision_timeout = htole16(connsm->supervision_tmo); ble_ll_hci_event_send(hci_ev); @@ -133,9 +135,9 @@ ble_ll_hci_ev_encrypt_chg(struct ble_ll_conn_sm *connsm, uint8_t status) struct ble_hci_ev_enrypt_chg *ev_enc_chf; struct ble_hci_ev *hci_ev; - if (CONN_F_ENC_CHANGE_SENT(connsm) == 0) { + if (connsm->flags.encrypt_event_sent == 0) { if (ble_ll_hci_is_event_enabled(BLE_HCI_EVCODE_ENCRYPT_CHG)) { - hci_ev = (void *)ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); + hci_ev = ble_transport_alloc_evt(0); if (hci_ev) { hci_ev->opcode = BLE_HCI_EVCODE_ENCRYPT_CHG; hci_ev->length = sizeof(*ev_enc_chf); @@ -149,12 +151,12 @@ ble_ll_hci_ev_encrypt_chg(struct ble_ll_conn_sm *connsm, uint8_t status) } } - CONN_F_ENC_CHANGE_SENT(connsm) = 1; + connsm->flags.encrypt_event_sent = 1; return; } if (ble_ll_hci_is_event_enabled(BLE_HCI_EVCODE_ENC_KEY_REFRESH)) { - hci_ev = (void *)ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); + hci_ev = ble_transport_alloc_evt(0); if (hci_ev) { hci_ev->opcode = BLE_HCI_EVCODE_ENC_KEY_REFRESH; hci_ev->length = sizeof(*ev_key_refresh); @@ -181,7 +183,7 @@ ble_ll_hci_ev_ltk_req(struct ble_ll_conn_sm *connsm) int rc; if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_LT_KEY_REQ)) { - hci_ev = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); + hci_ev = ble_transport_alloc_evt(0); if (hci_ev) { hci_ev->opcode = BLE_HCI_EVCODE_LE_META; hci_ev->length = sizeof(*ev); @@ -215,7 +217,7 @@ ble_ll_hci_ev_rd_rem_used_feat(struct ble_ll_conn_sm *connsm, uint8_t status) struct ble_hci_ev *hci_ev; if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_RD_REM_USED_FEAT)) { - hci_ev = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); + hci_ev = ble_transport_alloc_evt(0); if (hci_ev) { hci_ev->opcode = BLE_HCI_EVCODE_LE_META; hci_ev->length = sizeof(*ev); @@ -239,7 +241,7 @@ ble_ll_hci_ev_rd_rem_ver(struct ble_ll_conn_sm *connsm, uint8_t status) struct ble_hci_ev *hci_ev; if (ble_ll_hci_is_event_enabled(BLE_HCI_EVCODE_RD_REM_VER_INFO_CMP)) { - hci_ev = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); + hci_ev = ble_transport_alloc_evt(0); if (hci_ev) { hci_ev->opcode = BLE_HCI_EVCODE_RD_REM_VER_INFO_CMP; hci_ev->length = sizeof(*ev); @@ -272,7 +274,7 @@ ble_ll_hci_ev_hw_err(uint8_t hw_err) rc = 0; if (ble_ll_hci_is_event_enabled(BLE_HCI_EVCODE_HW_ERROR)) { - hci_ev = (void *)ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); + hci_ev = ble_transport_alloc_evt(0); if (hci_ev) { hci_ev->opcode = BLE_HCI_EVCODE_HW_ERROR; hci_ev->length = sizeof(*ev); @@ -295,7 +297,7 @@ ble_ll_hci_ev_databuf_overflow(void) struct ble_hci_ev *hci_ev; if (ble_ll_hci_is_event_enabled(BLE_HCI_EVCODE_DATA_BUF_OVERFLOW)) { - hci_ev = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); + hci_ev = ble_transport_alloc_evt(0); if (hci_ev) { hci_ev->opcode = BLE_HCI_EVCODE_DATA_BUF_OVERFLOW; hci_ev->length = sizeof(*ev); @@ -321,7 +323,7 @@ ble_ll_hci_ev_le_csa(struct ble_ll_conn_sm *connsm) struct ble_hci_ev *hci_ev; if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_CHAN_SEL_ALG)) { - hci_ev = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); + hci_ev = ble_transport_alloc_evt(0); if (hci_ev) { hci_ev->opcode = BLE_HCI_EVCODE_LE_META; hci_ev->length = sizeof(*ev); @@ -329,7 +331,7 @@ ble_ll_hci_ev_le_csa(struct ble_ll_conn_sm *connsm) ev->subev_code = BLE_HCI_LE_SUBEV_CHAN_SEL_ALG; ev->conn_handle = htole16(connsm->conn_handle); - ev->csa = connsm->csmflags.cfbit.csa2_supp ? 0x01 : 0x00; + ev->csa = connsm->flags.csa2 ? 0x01 : 0x00; ble_ll_hci_event_send(hci_ev); } @@ -350,7 +352,7 @@ ble_ll_hci_ev_send_scan_req_recv(uint8_t adv_handle, const uint8_t *peer, struct ble_hci_ev *hci_ev; if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_SCAN_REQ_RCVD)) { - hci_ev = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); + hci_ev = ble_transport_alloc_evt(0); if (hci_ev) { hci_ev->opcode = BLE_HCI_EVCODE_LE_META; hci_ev->length = sizeof(*ev); @@ -379,7 +381,7 @@ ble_ll_hci_ev_send_scan_timeout(void) struct ble_hci_ev *hci_ev; if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_SCAN_TIMEOUT)) { - hci_ev = (void *)ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); + hci_ev = ble_transport_alloc_evt(0); if (hci_ev) { hci_ev->opcode = BLE_HCI_EVCODE_LE_META; hci_ev->length = sizeof(*ev); @@ -406,7 +408,7 @@ ble_ll_hci_ev_send_adv_set_terminated(uint8_t status, uint8_t adv_handle, struct ble_hci_ev *hci_ev; if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_ADV_SET_TERMINATED)) { - hci_ev = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); + hci_ev = ble_transport_alloc_evt(0); if (hci_ev) { hci_ev->opcode = BLE_HCI_EVCODE_LE_META; hci_ev->length = sizeof(*ev); @@ -430,7 +432,7 @@ ble_ll_hci_ev_send_adv_set_terminated(uint8_t status, uint8_t adv_handle, * @param connsm Pointer to connection state machine * @param status error status of event */ -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) +#if MYNEWT_VAL(BLE_LL_PHY) int ble_ll_hci_ev_phy_update(struct ble_ll_conn_sm *connsm, uint8_t status) { @@ -440,7 +442,7 @@ ble_ll_hci_ev_phy_update(struct ble_ll_conn_sm *connsm, uint8_t status) rc = 0; if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_PHY_UPDATE_COMPLETE)) { - hci_ev = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); + hci_ev = ble_transport_alloc_evt(0); if (hci_ev) { hci_ev->opcode = BLE_HCI_EVCODE_LE_META; hci_ev->length = sizeof(*ev); @@ -473,7 +475,7 @@ ble_ll_hci_ev_sca_update(struct ble_ll_conn_sm *connsm, uint8_t status, return; } - hci_ev = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); + hci_ev = ble_transport_alloc_evt(0); if (!hci_ev) { return; } @@ -492,10 +494,68 @@ ble_ll_hci_ev_sca_update(struct ble_ll_conn_sm *connsm, uint8_t status, #endif +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE) +void +ble_ll_hci_ev_subrate_change(struct ble_ll_conn_sm *connsm, uint8_t status) +{ + struct ble_hci_ev_le_subev_subrate_change *ev; + struct ble_hci_ev *hci_ev; + + if (!ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_SUBRATE_CHANGE)) { + return; + } + + hci_ev = ble_transport_alloc_evt(0); + if (!hci_ev) { + return; + } + + hci_ev->opcode = BLE_HCI_EVCODE_LE_META; + hci_ev->length = sizeof(*ev); + ev = (void *)hci_ev->data; + + ev->subev_code = BLE_HCI_LE_SUBEV_SUBRATE_CHANGE; + ev->status = status; + ev->conn_handle = htole16(connsm->conn_handle); + ev->subrate_factor = htole16(connsm->subrate_factor); + ev->periph_latency = htole16(connsm->periph_latency); + ev->cont_num = htole16(connsm->cont_num); + ev->supervision_tmo = htole16(connsm->supervision_tmo); + + ble_ll_hci_event_send(hci_ev); +} +#endif + +#if MYNEWT_VAL(BLE_LL_HCI_VS_CONN_STRICT_SCHED) +void +ble_ll_hci_ev_send_vs_css_slot_changed(uint16_t conn_handle, uint16_t slot_idx) +{ + struct ble_hci_ev_vs_css_slot_changed *ev; + struct ble_hci_ev_vs *ev_vs; + struct ble_hci_ev *hci_ev; + + hci_ev = ble_transport_alloc_evt(0); + if (!hci_ev) { + return; + + } + + hci_ev->opcode = BLE_HCI_EVCODE_VS; + hci_ev->length = sizeof(*ev_vs) + sizeof(*ev); + ev_vs = (void *)hci_ev->data; + ev_vs->id = BLE_HCI_VS_SUBEV_ID_CSS_SLOT_CHANGED; + ev = (void *)ev_vs->data; + ev->conn_handle = htole16(conn_handle); + ev->slot_idx = htole16(slot_idx); + + ble_ll_hci_event_send(hci_ev); +} +#endif + void -ble_ll_hci_ev_send_vendor_err(const char *file, uint32_t line) +ble_ll_hci_ev_send_vs_assert(const char *file, uint32_t line) { - struct ble_hci_ev_vendor_debug *ev; + struct ble_hci_ev_vs *ev; struct ble_hci_ev *hci_ev; unsigned int str_len; bool skip = true; @@ -508,14 +568,14 @@ ble_ll_hci_ev_send_vendor_err(const char *file, uint32_t line) */ max_len = BLE_HCI_MAX_DATA_LEN - sizeof(*ev) - 6; - hci_ev = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); + hci_ev = ble_transport_alloc_evt(0); if (hci_ev) { - hci_ev->opcode = BLE_HCI_EVCODE_VENDOR_DEBUG; + hci_ev->opcode = BLE_HCI_EVCODE_VS; hci_ev->length = sizeof(*ev); ev = (void *) hci_ev->data; /* Debug id for future use */ - ev->id = 0x00; + ev->id = BLE_HCI_VS_SUBEV_ID_ASSERT; /* snprintf would be nicer but this is heavy on flash * len = snprintf((char *) ev->data, max_len, "%s:%u", file, line); @@ -528,7 +588,7 @@ ble_ll_hci_ev_send_vendor_err(const char *file, uint32_t line) * hci_ev->length += len; */ str_len = strlen(file); - if (str_len > max_len) { + if (str_len > (unsigned int)max_len) { str_len = max_len; } @@ -551,3 +611,60 @@ ble_ll_hci_ev_send_vendor_err(const char *file, uint32_t line) ble_ll_hci_event_send(hci_ev); } } + +void +ble_ll_hci_ev_send_vs_printf(uint8_t id, const char *fmt, ...) +{ + struct ble_hci_ev_vs *ev; + struct ble_hci_ev *hci_ev; + va_list ap; + int len; + + hci_ev = ble_transport_alloc_evt(1); + if (!hci_ev) { + return; + } + + hci_ev->opcode = BLE_HCI_EVCODE_VS; + hci_ev->length = sizeof(*ev); + + ev = (void *) hci_ev->data; + ev->id = id; + + va_start(ap, fmt); + len = vsnprintf((void *)ev->data, BLE_HCI_MAX_DATA_LEN - sizeof(*ev), fmt, ap); + va_end(ap); + + ev->data[len] = 0; + hci_ev->length += len + 1; + + ble_ll_hci_event_send(hci_ev); +} + +#if MYNEWT_VAL(BLE_LL_HCI_LLCP_TRACE) +void +ble_ll_hci_ev_send_vs_llcp_trace(uint8_t type, uint16_t handle, uint16_t count, + void *pdu, size_t length) +{ + struct ble_hci_ev_vs *ev; + struct ble_hci_ev *hci_ev; + + hci_ev = ble_transport_alloc_evt(1); + if (hci_ev) { + hci_ev->opcode = BLE_HCI_EVCODE_VS; + hci_ev->length = sizeof(*ev) + 8 + length; + ev = (void *) hci_ev->data; + + ev->id = BLE_HCI_VS_SUBEV_ID_LLCP_TRACE; + ev->data[0] = type; + put_le16(&ev->data[1], handle); + put_le16(&ev->data[3], count); + ev->data[5] = 0; + ev->data[6] = 0; + ev->data[7] = 0; + memcpy(&ev->data[8], pdu, length); + + ble_ll_hci_event_send(hci_ev); + } +} +#endif diff --git a/nimble/controller/src/ble_ll_hci_priv.h b/nimble/controller/src/ble_ll_hci_priv.h new file mode 100644 index 0000000000..af67e0a1a3 --- /dev/null +++ b/nimble/controller/src/ble_ll_hci_priv.h @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_BLE_LL_HCI_PRIV_ +#define H_BLE_LL_HCI_PRIV_ + +#ifdef __cplusplus +extern "C" { +#endif + +#if MYNEWT_VAL(BLE_LL_HCI_VS) +void ble_ll_hci_vs_init(void); +int ble_ll_hci_vs_cmd_proc(const uint8_t *cmdbuf, uint8_t cmdlen, uint16_t ocf, + uint8_t *rspbuf, uint8_t *rsplen); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* H_BLE_LL_HCI_ */ diff --git a/nimble/controller/src/ble_ll_hci_supp_cmd.c b/nimble/controller/src/ble_ll_hci_supp_cmd.c new file mode 100644 index 0000000000..31edf1c2aa --- /dev/null +++ b/nimble/controller/src/ble_ll_hci_supp_cmd.c @@ -0,0 +1,369 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#include +#include + +/* Magic macros */ +#define BIT(n) (1 << (n)) | +#define OCTET(x) (0 | x 0) + +static const uint8_t octet_0 = OCTET( +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + BIT(5) /* HCI Disconnect */ +#endif +); + +static const uint8_t octet_2 = OCTET( +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + BIT(7) /* HCI Read Remote Version Information */ +#endif +); + +static const uint8_t octet_5 = OCTET( + BIT(6) /* HCI Set Event Mask */ + BIT(7) /* HCI Reset */ +); + +static const uint8_t octet_10 = OCTET( +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + BIT(2) /* HCI Read Transmit Power Level */ +#endif +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_CTRL_TO_HOST_FLOW_CONTROL) + BIT(5) /* HCI Set Controller To Host Flow Control */ + BIT(6) /* HCI Host Buffer Size */ + BIT(7) /* HCI Host Number Of Completed Packets */ +#endif +); + +static const uint8_t octet_14 = OCTET( + BIT(3) /* HCI Read Local Version Information */ + BIT(5) /* HCI Read Local Supported Features */ +); + +static const uint8_t octet_15 = OCTET( + BIT(1) /* HCI Read BD ADDR */ +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + BIT(5) /* HCI Read RSSI */ +#endif +); + +static const uint8_t octet_22 = OCTET( + BIT(2) /* HCI Set Event Mask Page 2 */ +); + +static const uint8_t octet_25 = OCTET( + BIT(0) /* HCI LE Set Event Mask */ + BIT(1) /* HCI LE Read Buffer Size [v1] */ + BIT(2) /* HCI LE Read Local Supported Features */ + BIT(4) /* HCI LE Set Random Address */ +#if MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) + BIT(5) /* HCI LE Set Advertising Parameters */ + BIT(6) /* HCI LE Read Advertising Physical Channel Tx Power */ + BIT(7) /* HCI LE Set Advertising Data */ +#endif +); + +static const uint8_t octet_26 = OCTET( +#if MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) + BIT(0) /* HCI LE Set Scan Response Data */ + BIT(1) /* HCI LE Set Advertising Enable */ +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) + BIT(2) /* HCI LE Set Scan Parameters */ + BIT(3) /* HCI LE Set Scan Enable */ +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + BIT(4) /* HCI LE Create Connection */ + BIT(5) /* HCI LE Create Connection Cancel */ +#endif + BIT(6) /* HCI LE Read Filter Accept List Size */ + BIT(7) /* HCI LE Clear Filter Accept List */ +); + +static const uint8_t octet_27 = OCTET( + BIT(0) /* HCI LE Add Device To Filter Accept List */ + BIT(1) /* HCI LE Remove Device From Filter Accept List */ +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + BIT(2) /* HCI LE Connection Update */ +#endif + BIT(3) /* HCI LE Set Host Channel Classification */ +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + BIT(4) /* HCI LE Read Channel Map */ + BIT(5) /* HCI LE Read Remote Features */ +#endif +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) + BIT(6) /* HCI LE Encrypt */ +#endif + BIT(7) /* HCI LE Rand */ +); + +static const uint8_t octet_28 = OCTET( +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + BIT(0) /* HCI LE Enable Encryption */ +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) + BIT(1) /* HCI LE Long Term Key Request Reply */ + BIT(2) /* HCI LE Long Term Key Request Negative Reply */ +#endif +#endif + BIT(3) /* HCI LE Read Supported States */ +#if MYNEWT_VAL(BLE_LL_DTM) + BIT(4) /* HCI LE Receiver Test [v1] */ + BIT(5) /* HCI LE Transmitter Test [v1] */ + BIT(6) /* HCI LE Test End */ +#endif +); + +static const uint8_t octet_32 = OCTET( +#if (MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL)) && \ + MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_PING) + BIT(4) /* HCI Read Authenticated Payload Timeout */ + BIT(5) /* HCI Write Authenticated Payload Timeout */ +#endif +); + +static const uint8_t octet_33 = OCTET( +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + BIT(4) /* HCI LE Remote Connection Parameter Request Reply */ + BIT(5) /* HCI LE Remote Connection Parameter Request Negative Reply */ +#endif +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_DATA_LEN_EXT) + BIT(6) /* HCI LE Set Data Length */ + BIT(7) /* HCI LE Read Suggested Default Data Length */ +#endif +); + +static const uint8_t octet_34 = OCTET( +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_DATA_LEN_EXT) + BIT(0) /* HCI LE Write Suggested Data Length */ +#endif +#endif +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + BIT(3) /* HCI LE Add Device To Resolving List */ + BIT(4) /* HCI LE Remove Device From Resolving List */ + BIT(5) /* HCI LE Clear Resolving List */ + BIT(6) /* HCI LE Read Resolving List Size */ + BIT(7) /* HCI LE Read Peer Resolvable Address */ +#endif +); + +static const uint8_t octet_35 = OCTET( +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + BIT(0) /* HCI LE Read Local Resolvable Address */ + BIT(1) /* HCI LE Set Address Resolution Enable */ + BIT(2) /* HCI LE Set Resolvable Private Address Timeout */ +#endif + BIT(3) /* HCI LE Read Maximum Data Length */ +#if MYNEWT_VAL(BLE_LL_PHY) +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + BIT(4) /* HCI LE Read PHY */ + BIT(5) /* HCI LE Set Default PHY */ + BIT(6) /* HCI LE Set PHY */ +#endif +#endif +#if MYNEWT_VAL(BLE_LL_DTM) + BIT(7) /* HCI LE Receiver Test [v2] */ +#endif +); + +static const uint8_t octet_36 = OCTET( +#if MYNEWT_VAL(BLE_LL_DTM) + BIT(0) /* HCI LE Transmitter Test [v2] */ +#endif +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) && MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) + BIT(1) /* HCI LE Set Advertising Set Random Address */ + BIT(2) /* HCI LE Set Extended Advertising Parameters */ + BIT(3) /* HCI LE Set Extended Advertising Data */ + BIT(4) /* HCI LE Set Extended Scan Response Data */ + BIT(5) /* HCI LE Set Extended Advertising Enable */ + BIT(6) /* HCI LE Read Maximum Advertising Data Length */ + BIT(7) /* HCI LE Read Number of Supported Advertising Sets */ +#endif +); + +static const uint8_t octet_37 = OCTET( +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) && MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) + BIT(0) /* HCI LE Remove Advertising Set */ + BIT(1) /* HCI LE Clear Advertising Sets */ +#endif +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) && MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) + BIT(2) /* HCI LE Set Periodic Advertising Parameters */ + BIT(3) /* HCI LE Set Periodic Advertising Data */ + BIT(4) /* HCI LE Set Periodic Advertising Enable */ +#endif +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) +#if MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) + BIT(5) /* HCI LE Set Extended Scan Parameters */ + BIT(6) /* HCI LE Set Extended Scan Enable */ +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + BIT(7) /* HCI LE Extended Create Connection */ +#endif +#endif +); + +static const uint8_t octet_38 = OCTET( +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) && MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) + BIT(0) /* HCI LE Periodic Advertising Create Sync */ + BIT(1) /* HCI LE Periodic Advertising Create Sync Cancel */ + BIT(2) /* HCI LE Periodic Advertising Terminate Sync */ + BIT(3) /* HCI LE Add Device To Periodic Advertiser List */ + BIT(4) /* HCI LE Remove Device From Periodic Advertiser List */ + BIT(5) /* HCI LE Clear Periodic Advertiser List */ + BIT(6) /* HCI LE Read Periodic Advertiser List Size */ +#endif + BIT(7) /* HCI LE Read Transmit Power */ +); + +static const uint8_t octet_39 = OCTET( + BIT(0) /* HCI LE Read RF Path Compensation */ + BIT(1) /* HCI LE Write RF Path Compensation */ +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + BIT(2) /* HCI LE Set Privacy Mode */ +#endif +); + +static const uint8_t octet_40 = OCTET( +#if MYNEWT_VAL(BLE_VERSION) >= 51 && MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) +#if MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) + BIT(5) /* HCI LE Set Periodic Advertising Receive Enable */ +#endif +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER) +#if MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) + BIT(6) /* HCI LE Periodic Advertising Sync Transfer */ +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) + BIT(7) /* HCI LE Periodic Advertising Set Info Transfer */ +#endif +#endif +#endif +); + +static const uint8_t octet_41 = OCTET( +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER) + BIT(0) /* HCI LE Set Periodic Advertising Sync Transfer Parameters */ + BIT(1) /* HCI LE Set Default Periodic Advertising Sync Transfer Parameters */ +#endif +#if MYNEWT_VAL(BLE_LL_ISO) + BIT(5) /* HCI LE Read Buffer Size [v2] */ + BIT(6) /* HCI LE Read ISO TX Sync */ +#endif +); + +static const uint8_t octet_42 = OCTET( +#if MYNEWT_VAL(BLE_LL_ISO_BROADCASTER) + BIT(5) /* HCI LE Create BIG */ + BIT(6) /* HCI LE Create BIG Test */ + BIT(7) /* HCI LE Terminate BIG */ +#endif +); + +static const uint8_t octet_43 = OCTET( +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_SCA_UPDATE) + BIT(2) /* HCI LE Request Peer SCA */ +#endif +#if MYNEWT_VAL(BLE_LL_ISO) + BIT(3) /* HCI LE Setup ISO Data Path */ + BIT(4) /* HCI LE Remove ISO Data Path */ +#endif +#if MYNEWT_VAL(BLE_LL_ISO_BROADCASTER) + BIT(5) /* HCI LE ISO Transmit Test */ +#endif +); + +static const uint8_t octet_44 = OCTET( +#if MYNEWT_VAL(BLE_LL_ISO) + BIT(0) /* HCI LE ISO Test End */ +#endif +#if BLE_LL_HOST_CONTROLLED_FEATURES + BIT(1) /* HCI LE Set Host Feature */ +#endif +); + +static const uint8_t octet_46 = OCTET( +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE) + BIT(0) /* HCI LE Set Default Subrate */ + BIT(1) /* HCI LE Subrate Request */ +#endif +#if MYNEWT_VAL(BLE_VERSION) >= 54 && MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) + BIT(2) /* HCI LE Set Extended Advertising Parameters [v2] */ +#endif +); + +static const uint8_t g_ble_ll_hci_supp_cmds[64] = { + octet_0, + 0, + octet_2, + 0, + 0, + octet_5, + 0, + 0, + 0, + 0, + octet_10, + 0, + 0, + 0, + octet_14, + octet_15, + 0, + 0, + 0, + 0, + 0, + 0, + octet_22, + 0, + 0, + octet_25, + octet_26, + octet_27, + octet_28, + 0, + 0, + 0, + octet_32, + octet_33, + octet_34, + octet_35, + octet_36, + octet_37, + octet_38, + octet_39, + octet_40, + octet_41, + octet_42, + octet_43, + octet_44, + 0, + octet_46, +}; + +void +ble_ll_hci_supp_cmd_get(uint8_t *buf) +{ + memcpy(buf, g_ble_ll_hci_supp_cmds, sizeof(g_ble_ll_hci_supp_cmds)); +} diff --git a/nimble/controller/src/ble_ll_hci_vs.c b/nimble/controller/src/ble_ll_hci_vs.c new file mode 100644 index 0000000000..2027ce61a6 --- /dev/null +++ b/nimble/controller/src/ble_ll_hci_vs.c @@ -0,0 +1,487 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include "syscfg/syscfg.h" +#include "controller/ble_ll_utils.h" +#include "controller/ble_ll.h" +#include "controller/ble_ll_hci.h" +#include "controller/ble_ll_sync.h" +#include "controller/ble_ll_adv.h" +#include "controller/ble_ll_scan.h" +#include "controller/ble_hw.h" +#include "controller/ble_fem.h" +#include "os/util.h" +#include "ble_ll_conn_priv.h" +#include "ble_ll_priv.h" +#include "controller/ble_ll_resolv.h" + +#if MYNEWT_VAL(BLE_LL_HCI_VS) + +SLIST_HEAD(ble_ll_hci_vs_list, ble_ll_hci_vs_cmd); +static struct ble_ll_hci_vs_list g_ble_ll_hci_vs_list; + +static int +ble_ll_hci_vs_rd_static_addr(uint16_t ocf, + const uint8_t *cmdbuf, uint8_t cmdlen, + uint8_t *rspbuf, uint8_t *rsplen) +{ + struct ble_hci_vs_rd_static_addr_rp *rsp = (void *) rspbuf; + ble_addr_t addr; + + if (cmdlen != 0) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + if (ble_hw_get_static_addr(&addr) < 0) { + return BLE_ERR_UNSPECIFIED; + } + + memcpy(rsp->addr, addr.val, sizeof(rsp->addr)); + + *rsplen = sizeof(*rsp); + + return BLE_ERR_SUCCESS; +} + +static int +ble_ll_hci_vs_set_tx_power(uint16_t ocf, const uint8_t *cmdbuf, uint8_t cmdlen, + uint8_t *rspbuf, uint8_t *rsplen) +{ + const struct ble_hci_vs_set_tx_pwr_cp *cmd = (const void *) cmdbuf; + struct ble_hci_vs_set_tx_pwr_rp *rsp = (void *) rspbuf; + + if (cmdlen != sizeof(*cmd)) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + if (ble_ll_is_busy(0)) { + return BLE_ERR_CMD_DISALLOWED; + } + + if (cmd->tx_power == 127) { + /* restore reset default */ + g_ble_ll_tx_power = ble_ll_tx_power_round(MIN(MYNEWT_VAL(BLE_LL_TX_PWR_DBM), + MYNEWT_VAL(BLE_LL_TX_PWR_MAX_DBM)) - + g_ble_ll_tx_power_compensation); + } else { + g_ble_ll_tx_power = ble_ll_tx_power_round(MIN(cmd->tx_power, + MYNEWT_VAL(BLE_LL_TX_PWR_MAX_DBM)) - + g_ble_ll_tx_power_compensation); + } + + rsp->tx_power = g_ble_ll_tx_power + g_ble_ll_tx_power_compensation; + *rsplen = sizeof(*rsp); + + return BLE_ERR_SUCCESS; +} + + +#if MYNEWT_VAL(BLE_LL_HCI_VS_CONN_STRICT_SCHED) +#if !MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED_FIXED) +static int +ble_ll_hci_vs_css_configure(uint16_t ocf, const uint8_t *cmdbuf, uint8_t cmdlen, + uint8_t *rspbuf, uint8_t *rsplen) +{ + const struct ble_hci_vs_css_configure_cp *cmd = (const void *)cmdbuf; + uint32_t slot_us; + uint32_t period_slots; + + if (cmdlen != sizeof(*cmd)) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + if (ble_ll_sched_css_is_enabled()) { + return BLE_ERR_CMD_DISALLOWED; + } + + slot_us = le32toh(cmd->slot_us); + period_slots = le32toh(cmd->period_slots); + + if (slot_us % BLE_LL_CONN_ITVL_USECS) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + if ((slot_us == 0) || (period_slots == 0)) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + ble_ll_sched_css_set_params(slot_us, period_slots); + + return BLE_ERR_SUCCESS; +} +#endif + +static int +ble_ll_hci_vs_css_enable(uint16_t ocf, const uint8_t *cmdbuf, uint8_t cmdlen, + uint8_t *rspbuf, uint8_t *rsplen) +{ + const struct ble_hci_vs_css_enable_cp *cmd = (const void *)cmdbuf; + + if (cmdlen != sizeof(*cmd)) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + if (!SLIST_EMPTY(&g_ble_ll_conn_active_list)) { + return BLE_ERR_CMD_DISALLOWED; + } + + if (cmd->enable & 0xfe) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + ble_ll_sched_css_set_enabled(cmd->enable); + + return BLE_ERR_SUCCESS; +} + +static int +ble_ll_hci_vs_css_set_next_slot(uint16_t ocf, const uint8_t *cmdbuf, + uint8_t cmdlen, uint8_t *rspbuf, + uint8_t *rsplen) +{ + const struct ble_hci_vs_css_set_next_slot_cp *cmd = (const void *)cmdbuf; + uint16_t slot_idx; + + if (cmdlen != sizeof(*cmd)) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + slot_idx = le16toh(cmd->slot_idx); + if ((slot_idx >= ble_ll_sched_css_get_period_slots()) && + (slot_idx != BLE_LL_CONN_CSS_NO_SLOT)) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + if (ble_ll_conn_css_is_slot_busy(slot_idx)) { + return BLE_ERR_CTLR_BUSY; + } + + ble_ll_conn_css_set_next_slot(slot_idx); + + return BLE_ERR_SUCCESS; +} + +static int +ble_ll_hci_vs_css_set_conn_slot(uint16_t ocf, const uint8_t *cmdbuf, + uint8_t cmdlen, uint8_t *rspbuf, + uint8_t *rsplen) +{ + const struct ble_hci_vs_css_set_conn_slot_cp *cmd = (const void *)cmdbuf; + struct ble_ll_conn_sm *connsm; + uint16_t conn_handle; + uint16_t slot_idx; + + if (cmdlen != sizeof(*cmd)) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + if (!ble_ll_sched_css_is_enabled()) { + return BLE_ERR_CMD_DISALLOWED; + } + + slot_idx = le16toh(cmd->slot_idx); + if ((slot_idx >= ble_ll_sched_css_get_period_slots()) && + (slot_idx != BLE_LL_CONN_CSS_NO_SLOT)) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + if (ble_ll_conn_css_is_slot_busy(slot_idx)) { + return BLE_ERR_CTLR_BUSY; + } + + conn_handle = le16toh(cmd->conn_handle); + connsm = ble_ll_conn_find_by_handle(conn_handle); + if (!connsm) { + return BLE_ERR_UNK_CONN_ID; + } + + if (connsm->css_slot_idx_pending != BLE_LL_CONN_CSS_NO_SLOT) { + return BLE_ERR_DIFF_TRANS_COLL; + } + + if (connsm->css_slot_idx == slot_idx) { + return BLE_ERR_CMD_DISALLOWED; + } + + if (ble_ll_conn_css_move(connsm, slot_idx) < 0) { + return BLE_ERR_CTLR_BUSY; + } + + return BLE_ERR_SUCCESS; +} + +static int +ble_ll_hci_vs_css_read_conn_slot(uint16_t ocf, const uint8_t *cmdbuf, + uint8_t cmdlen, uint8_t *rspbuf, + uint8_t *rsplen) +{ + const struct ble_hci_vs_css_read_conn_slot_cp *cmd = (const void *)cmdbuf; + struct ble_hci_vs_css_read_conn_slot_rp *rsp = (void *)rspbuf; + struct ble_ll_conn_sm *connsm; + uint16_t conn_handle; + + if (cmdlen != sizeof(*cmd)) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + if (!ble_ll_sched_css_is_enabled()) { + return BLE_ERR_CMD_DISALLOWED; + } + + conn_handle = le16toh(cmd->conn_handle); + connsm = ble_ll_conn_find_by_handle(conn_handle); + if (!connsm) { + return BLE_ERR_UNK_CONN_ID; + } + + *rsplen = sizeof(*rsp); + rsp->conn_handle = cmd->conn_handle; + rsp->slot_idx = htole16(connsm->css_slot_idx); + + return BLE_ERR_SUCCESS; +} +#endif + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_DATA_LEN_EXT) +static int +ble_ll_hci_vs_set_data_len(uint16_t ocf, const uint8_t *cmdbuf, uint8_t cmdlen, + uint8_t *rspbuf, uint8_t *rsplen) +{ + const struct ble_hci_vs_set_data_len_cp *cmd = (const void *) cmdbuf; + struct ble_hci_vs_set_data_len_rp *rsp = (void *) rspbuf; + struct ble_ll_conn_sm *connsm; + uint16_t conn_handle; + uint16_t tx_octets; + uint16_t tx_time; + uint16_t rx_octets; + uint16_t rx_time; + int rc; + + if (cmdlen != sizeof(*cmd)) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + conn_handle = le16toh(cmd->conn_handle); + connsm = ble_ll_conn_find_by_handle(conn_handle); + if (!connsm) { + return BLE_ERR_UNK_CONN_ID; + } + + tx_octets = le16toh(cmd->tx_octets); + tx_time = le16toh(cmd->tx_time); + rx_octets = le16toh(cmd->rx_octets); + rx_time = le16toh(cmd->rx_time); + + if (!ble_ll_hci_check_dle(tx_octets, tx_time) || + !ble_ll_hci_check_dle(rx_octets, rx_time)) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + rc = ble_ll_conn_set_data_len(connsm, tx_octets, tx_time, rx_octets, + rx_time); + if (rc) { + return rc; + } + + rsp->conn_handle = htole16(conn_handle); + *rsplen = sizeof(*rsp); + + return 0; +} +#endif + +#if MYNEWT_VAL(BLE_FEM_ANTENNA) +static int +ble_ll_hci_vs_set_antenna(uint16_t ocf, const uint8_t *cmdbuf, uint8_t cmdlen, + uint8_t *rspbuf, uint8_t *rsplen) +{ + const struct ble_hci_vs_set_antenna_cp *cmd = (const void *) cmdbuf; + + if (cmdlen != sizeof(*cmd)) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + if (ble_ll_is_busy(0)) { + return BLE_ERR_CMD_DISALLOWED; + } + + if (ble_fem_antenna(cmd->antenna)) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + return BLE_ERR_SUCCESS; +} +#endif + +#if MYNEWT_VAL(BLE_LL_HCI_VS_LOCAL_IRK) +static int +ble_ll_hci_vs_set_local_irk(uint16_t ocf, const uint8_t *cmdbuf, uint8_t cmdlen, + uint8_t *rspbuf, uint8_t *rsplen) +{ + const struct ble_hci_vs_set_local_irk_cp *cmd = (const void *)cmdbuf; + int rc; + + if (cmdlen != sizeof(*cmd)) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + if (ble_ll_is_busy(BLE_LL_BUSY_EXCLUDE_CONNECTIONS)) { + return BLE_ERR_CMD_DISALLOWED; + } + + rc = ble_ll_resolv_local_irk_set(cmd->own_addr_type, cmd->irk); + if (rc) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + *rsplen = 0; + + return 0; +} +#endif + +#if MYNEWT_VAL(BLE_LL_HCI_VS_SET_SCAN_CFG) +static int +ble_ll_hci_vs_set_scan_cfg(uint16_t ocf, const uint8_t *cmdbuf, uint8_t cmdlen, + uint8_t *rspbuf, uint8_t *rsplen) +{ + const struct ble_hci_vs_set_scan_cfg_cp *cmd = (const void *)cmdbuf; + uint32_t flags; + int rc; + + if (cmdlen != sizeof(*cmd)) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + flags = le32toh(cmd->flags); + + if ((flags & BLE_HCI_VS_SET_SCAN_CFG_FLAG_NO_LEGACY) && + (flags & BLE_HCI_VS_SET_SCAN_CFG_FLAG_NO_EXT)) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + rc = ble_ll_scan_set_vs_config(flags, cmd->rssi_threshold); + if (rc != 0) { + return BLE_ERR_CMD_DISALLOWED; + } + + *rsplen = 0; + + return 0; +} +#endif + +static struct ble_ll_hci_vs_cmd g_ble_ll_hci_vs_cmds[] = { + BLE_LL_HCI_VS_CMD(BLE_HCI_OCF_VS_RD_STATIC_ADDR, + ble_ll_hci_vs_rd_static_addr), + BLE_LL_HCI_VS_CMD(BLE_HCI_OCF_VS_SET_TX_PWR, + ble_ll_hci_vs_set_tx_power), +#if MYNEWT_VAL(BLE_LL_HCI_VS_CONN_STRICT_SCHED) +#if !MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED_FIXED) + BLE_LL_HCI_VS_CMD(BLE_HCI_OCF_VS_CSS_CONFIGURE, + ble_ll_hci_vs_css_configure), +#endif + BLE_LL_HCI_VS_CMD(BLE_HCI_OCF_VS_CSS_ENABLE, + ble_ll_hci_vs_css_enable), + BLE_LL_HCI_VS_CMD(BLE_HCI_OCF_VS_CSS_SET_NEXT_SLOT, + ble_ll_hci_vs_css_set_next_slot), + BLE_LL_HCI_VS_CMD(BLE_HCI_OCF_VS_CSS_SET_CONN_SLOT, + ble_ll_hci_vs_css_set_conn_slot), + BLE_LL_HCI_VS_CMD(BLE_HCI_OCF_VS_CSS_READ_CONN_SLOT, + ble_ll_hci_vs_css_read_conn_slot), +#endif +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_DATA_LEN_EXT) + BLE_LL_HCI_VS_CMD(BLE_HCI_OCF_VS_SET_DATA_LEN, + ble_ll_hci_vs_set_data_len), +#endif +#if MYNEWT_VAL(BLE_FEM_ANTENNA) + BLE_LL_HCI_VS_CMD(BLE_HCI_OCF_VS_SET_ANTENNA, ble_ll_hci_vs_set_antenna), +#endif +#if MYNEWT_VAL(BLE_LL_HCI_VS_LOCAL_IRK) + BLE_LL_HCI_VS_CMD(BLE_HCI_OCF_VS_SET_LOCAL_IRK, + ble_ll_hci_vs_set_local_irk), +#endif +#if MYNEWT_VAL(BLE_LL_HCI_VS_SET_SCAN_CFG) + BLE_LL_HCI_VS_CMD(BLE_HCI_OCF_VS_SET_SCAN_CFG, + ble_ll_hci_vs_set_scan_cfg) +#endif +}; + +static struct ble_ll_hci_vs_cmd * +ble_ll_hci_vs_find_by_ocf(uint16_t ocf) +{ + struct ble_ll_hci_vs_cmd *entry; + + entry = SLIST_FIRST(&g_ble_ll_hci_vs_list); + while (entry) { + if (entry->ocf == ocf) { + return entry; + } + + entry = SLIST_NEXT(entry, link); + } + + return NULL; +} + +int +ble_ll_hci_vs_cmd_proc(const uint8_t *cmdbuf, uint8_t cmdlen, uint16_t ocf, + uint8_t *rspbuf, uint8_t *rsplen) +{ + struct ble_ll_hci_vs_cmd *cmd; + int rc; + + cmd = ble_ll_hci_vs_find_by_ocf(ocf); + if (!cmd) { + rc = BLE_ERR_UNKNOWN_HCI_CMD; + } else { + rc = cmd->cb(ocf, cmdbuf, cmdlen, rspbuf, rsplen); + } + + return rc; +} + +void +ble_ll_hci_vs_register(struct ble_ll_hci_vs_cmd *cmds, uint32_t num_cmds) +{ + uint32_t i; + + /* Assume all cmds are registered early on init, so just assert in case of + * invalid request since it means something is wrong with the code itself. + */ + + for (i = 0; i < num_cmds; i++, cmds++) { + BLE_LL_ASSERT(cmds->cb != NULL); + BLE_LL_ASSERT(ble_ll_hci_vs_find_by_ocf(cmds->ocf) == NULL); + + SLIST_INSERT_HEAD(&g_ble_ll_hci_vs_list, cmds, link); + } +} + +void +ble_ll_hci_vs_init(void) +{ + SLIST_INIT(&g_ble_ll_hci_vs_list); + + ble_ll_hci_vs_register(g_ble_ll_hci_vs_cmds, + ARRAY_SIZE(g_ble_ll_hci_vs_cmds)); +} + +#endif diff --git a/nimble/controller/src/ble_ll_iso.c b/nimble/controller/src/ble_ll_iso.c index a6186fe1a5..03a31d5fab 100644 --- a/nimble/controller/src/ble_ll_iso.c +++ b/nimble/controller/src/ble_ll_iso.c @@ -18,129 +18,420 @@ */ #include -#include "syscfg/syscfg.h" -#include "nimble/ble.h" -#include "nimble/hci_common.h" -#include "controller/ble_ll_iso.h" +#include +#include +#include +#include +#include +#include -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ISO) +#if MYNEWT_VAL(BLE_LL_ISO) -int -ble_ll_iso_read_tx_sync(const uint8_t *cmdbuf, uint8_t len) -{ - return BLE_ERR_UNSUPPORTED; -} +STAILQ_HEAD(ble_ll_iso_conn_q, ble_ll_iso_conn); +struct ble_ll_iso_conn_q ll_iso_conn_q; int -ble_ll_iso_set_cig_param(const uint8_t *cmdbuf, uint8_t len, - uint8_t *rspbuf, uint8_t *rsplen) +ble_ll_iso_setup_iso_data_path(const uint8_t *cmdbuf, uint8_t cmdlen, + uint8_t *rspbuf, uint8_t *rsplen) { - return BLE_ERR_UNSUPPORTED; -} + const struct ble_hci_le_setup_iso_data_path_cp *cmd = (const void *)cmdbuf; + struct ble_hci_le_setup_iso_data_path_rp *rsp = (void *)rspbuf; + struct ble_ll_iso_conn *conn; + uint16_t conn_handle; -int -ble_ll_iso_create_cis(const uint8_t *cmdbuf, uint8_t len) -{ - return BLE_ERR_UNSUPPORTED; -} + conn_handle = le16toh(cmd->conn_handle); -int -ble_ll_iso_disconnect_cmd(const struct ble_hci_lc_disconnect_cp *cmd) -{ - return BLE_ERR_UNSUPPORTED; -} + conn = ble_ll_iso_conn_find_by_handle(conn_handle); + if (!conn) { + return BLE_ERR_UNK_CONN_ID; + } -int -ble_ll_iso_remove_cig(const uint8_t *cmdbuf, uint8_t len, - uint8_t *rspbuf, uint8_t *rsplen) -{ - return BLE_ERR_UNSUPPORTED; + if (conn->mux.bn == 0) { + return BLE_ERR_UNSUPPORTED; + } + + if (conn->data_path.enabled) { + return BLE_ERR_CMD_DISALLOWED; + } + + /* Only input for now since we only support BIS */ + if (cmd->data_path_dir) { + return BLE_ERR_CMD_DISALLOWED; + } + + /* We do not (yet) support any vendor-specific data path */ + if (cmd->data_path_id) { + return BLE_ERR_CMD_DISALLOWED; + } + + conn->data_path.enabled = 1; + conn->data_path.data_path_id = cmd->data_path_id; + + rsp->conn_handle = cmd->conn_handle; + *rsplen = sizeof(*rsp); + + return 0; } int -ble_ll_iso_accept_cis_req(const uint8_t *cmdbuf, uint8_t len) +ble_ll_iso_remove_iso_data_path(const uint8_t *cmdbuf, uint8_t cmdlen, + uint8_t *rspbuf, uint8_t *rsplen) { - return BLE_ERR_UNSUPPORTED; + const struct ble_hci_le_remove_iso_data_path_cp *cmd = (const void *)cmdbuf; + struct ble_hci_le_remove_iso_data_path_rp *rsp = (void *)rspbuf; + struct ble_ll_iso_conn *conn; + uint16_t conn_handle; + + conn_handle = le16toh(cmd->conn_handle); + + conn = ble_ll_iso_conn_find_by_handle(conn_handle); + if (!conn) { + return BLE_ERR_UNK_CONN_ID; + } + + /* Only input for now since we only support BIS */ + if (cmd->data_path_dir) { + return BLE_ERR_CMD_DISALLOWED; + } + + conn->data_path.enabled = 0; + + rsp->conn_handle = cmd->conn_handle; + *rsplen = sizeof(*rsp); + + return 0; } int -ble_ll_iso_reject_cis_req(const uint8_t *cmdbuf, uint8_t len) +ble_ll_iso_read_tx_sync(const uint8_t *cmdbuf, uint8_t cmdlen, + uint8_t *rspbuf, uint8_t *rsplen) { - return BLE_ERR_UNSUPPORTED; + const struct ble_hci_le_read_iso_tx_sync_cp *cmd = (const void *)cmdbuf; + struct ble_hci_le_read_iso_tx_sync_rp *rsp = (void *)rspbuf; + struct ble_ll_iso_conn *iso_conn; + uint16_t handle; + + handle = le16toh(cmd->conn_handle); + iso_conn = ble_ll_iso_conn_find_by_handle(handle); + if (!iso_conn) { + return BLE_ERR_UNK_CONN_ID; + } + + rsp->conn_handle = cmd->conn_handle; + rsp->packet_seq_num = htole16(iso_conn->mux.last_tx_packet_seq_num); + rsp->tx_timestamp = htole32(iso_conn->mux.last_tx_timestamp); + put_le24(rsp->time_offset, 0); + + *rsplen = sizeof(*rsp); + + return 0; } int -ble_ll_iso_setup_iso_data_path(const uint8_t *cmdbuf, uint8_t len) +ble_ll_iso_transmit_test(const uint8_t *cmdbuf, uint8_t cmdlen, uint8_t *rspbuf, uint8_t *rsplen) { - return BLE_ERR_UNSUPPORTED; + const struct ble_hci_le_iso_transmit_test_cp *cmd = (const void *)cmdbuf; + struct ble_hci_le_iso_transmit_test_rp *rsp = (void *)rspbuf; + struct ble_ll_iso_conn *conn; + uint16_t handle; + + handle = le16toh(cmd->conn_handle); + + conn = ble_ll_iso_conn_find_by_handle(handle); + if (!conn) { + return BLE_ERR_UNK_CONN_ID; + } + + if (conn->mux.bn == 0) { + return BLE_ERR_UNSUPPORTED; + } + + if (conn->data_path.enabled) { + return BLE_ERR_CMD_DISALLOWED; + } + + if (cmd->payload_type > BLE_HCI_PAYLOAD_TYPE_MAXIMUM_LENGTH) { + return BLE_ERR_INV_LMP_LL_PARM; + } + + conn->data_path.enabled = 1; + conn->data_path.data_path_id = BLE_HCI_ISO_DATA_PATH_ID_HCI; + conn->test_mode.transmit.enabled = 1; + conn->test_mode.transmit.payload_type = cmd->payload_type; + + rsp->conn_handle = cmd->conn_handle; + + *rsplen = sizeof(*rsp); + + return 0; } int -ble_ll_iso_remove_iso_data_path(const uint8_t *cmdbuf, uint8_t len) +ble_ll_iso_end_test(const uint8_t *cmdbuf, uint8_t len, uint8_t *rspbuf, uint8_t *rsplen) { - /* Nothing to do here for now when HCI is supported */ + const struct ble_hci_le_iso_test_end_cp *cmd = (const void *)cmdbuf; + struct ble_hci_le_iso_test_end_rp *rsp = (void *)rspbuf; + struct ble_ll_iso_conn *iso_conn; + uint16_t handle; + + handle = le16toh(cmd->conn_handle); + iso_conn = ble_ll_iso_conn_find_by_handle(handle); + if (!iso_conn) { + return BLE_ERR_UNK_CONN_ID; + } + + if (!iso_conn->test_mode.transmit.enabled) { + return BLE_ERR_UNSUPPORTED; + } + + iso_conn->data_path.enabled = 0; + iso_conn->test_mode.transmit.enabled = 0; + + rsp->conn_handle = cmd->conn_handle; + rsp->received_sdu_count = 0; + rsp->missed_sdu_count = 0; + rsp->failed_sdu_count = 0; + + *rsplen = sizeof(*rsp); + return 0; } -int -ble_ll_iso_create_big(const uint8_t *cmdbuf, uint8_t len) + +struct ble_ll_iso_conn * +ble_ll_iso_conn_find_by_handle(uint16_t conn_handle) { - return BLE_ERR_UNSUPPORTED; + struct ble_ll_iso_conn *conn; + + STAILQ_FOREACH(conn, &ll_iso_conn_q, iso_conn_q_next) { + if (conn_handle == conn->handle) { + return conn; + } + } + + return NULL; } -int -ble_ll_iso_terminate_big(const uint8_t *cmdbuf, uint8_t len) +void +ble_ll_iso_init(void) { - return BLE_ERR_UNSUPPORTED; + STAILQ_INIT(&ll_iso_conn_q); + ble_ll_isoal_init(); } -int -ble_ll_iso_big_create_sync(const uint8_t *cmdbuf, uint8_t len) +void +ble_ll_iso_reset(void) { - return BLE_ERR_UNSUPPORTED; + STAILQ_INIT(&ll_iso_conn_q); + ble_ll_isoal_reset(); } int -ble_ll_iso_big_terminate_sync(const uint8_t *cmdbuf, uint8_t len) +ble_ll_iso_data_in(struct os_mbuf *om) { - return BLE_ERR_UNSUPPORTED; + struct ble_hci_iso *hci_iso; + struct ble_hci_iso_data *hci_iso_data; + struct ble_ll_iso_conn *conn; + struct ble_mbuf_hdr *blehdr; + uint16_t data_hdr_len; + uint16_t handle; + uint16_t conn_handle; + uint16_t length; + uint16_t pb_flag; + uint16_t ts_flag; + uint32_t timestamp = 0; + + hci_iso = (void *)om->om_data; + + handle = le16toh(hci_iso->handle); + conn_handle = BLE_HCI_ISO_CONN_HANDLE(handle); + pb_flag = BLE_HCI_ISO_PB_FLAG(handle); + ts_flag = BLE_HCI_ISO_TS_FLAG(handle); + length = BLE_HCI_ISO_LENGTH(le16toh(hci_iso->length)); + + conn = ble_ll_iso_conn_find_by_handle(conn_handle); + if (!conn) { + os_mbuf_free_chain(om); + return BLE_ERR_UNK_CONN_ID; + } + + data_hdr_len = 0; + if ((pb_flag == BLE_HCI_ISO_PB_FIRST) || + (pb_flag == BLE_HCI_ISO_PB_COMPLETE)) { + blehdr = BLE_MBUF_HDR_PTR(om); + blehdr->txiso.packet_seq_num = ++conn->mux.sdu_counter; + blehdr->txiso.cpu_timestamp = ble_ll_tmr_get(); + + if (ts_flag) { + timestamp = get_le32(om->om_data + sizeof(*hci_iso)); + data_hdr_len += sizeof(uint32_t); + } + blehdr->txiso.hci_timestamp = timestamp; + + hci_iso_data = (void *)(om->om_data + sizeof(*hci_iso) + data_hdr_len); + data_hdr_len += sizeof(*hci_iso_data); + } + os_mbuf_adj(om, sizeof(*hci_iso) + data_hdr_len); + + if (OS_MBUF_PKTLEN(om) != length - data_hdr_len) { + os_mbuf_free_chain(om); + return BLE_ERR_MEM_CAPACITY; + } + + switch (pb_flag) { + case BLE_HCI_ISO_PB_FIRST: + BLE_LL_ASSERT(!conn->frag); + conn->frag = om; + om = NULL; + break; + case BLE_HCI_ISO_PB_CONTINUATION: + BLE_LL_ASSERT(conn->frag); + os_mbuf_concat(conn->frag, om); + om = NULL; + break; + case BLE_HCI_ISO_PB_COMPLETE: + BLE_LL_ASSERT(!conn->frag); + break; + case BLE_HCI_ISO_PB_LAST: + BLE_LL_ASSERT(conn->frag); + os_mbuf_concat(conn->frag, om); + om = conn->frag; + conn->frag = NULL; + break; + default: + BLE_LL_ASSERT(0); + break; + } + + if (om) { + ble_ll_isoal_mux_sdu_enqueue(&conn->mux, om); + } + + return 0; } -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ISO_TEST) -int -ble_ll_iso_set_cig_param_test(const uint8_t *cmdbuf, uint8_t len, - uint8_t *rspbuf, uint8_t *rsplen) +static int +ble_ll_iso_test_pdu_get(struct ble_ll_iso_conn *conn, uint8_t idx, uint32_t pkt_counter, uint8_t *llid, uint8_t *dptr) { - return BLE_ERR_UNSUPPORTED; + uint32_t payload_len; + uint16_t rem_len; + uint8_t sdu_idx; + uint8_t pdu_idx; + int pdu_len; + + BLE_LL_ASSERT(!conn->mux.framed); + + sdu_idx = idx / conn->mux.pdu_per_sdu; + pdu_idx = idx - sdu_idx * conn->mux.pdu_per_sdu; + + switch (conn->test_mode.transmit.payload_type) { + case BLE_HCI_PAYLOAD_TYPE_ZERO_LENGTH: + *llid = 0b00; + pdu_len = 0; + break; + case BLE_HCI_PAYLOAD_TYPE_VARIABLE_LENGTH: + payload_len = max(conn->test_mode.transmit.rand + (sdu_idx * pdu_idx), 4); + + rem_len = payload_len - pdu_idx * conn->mux.max_pdu; + if (rem_len == 0) { + *llid = 0b01; + pdu_len = 0; + } else { + *llid = rem_len > conn->mux.max_pdu; + pdu_len = min(conn->mux.max_pdu, rem_len); + } + + memset(dptr, 0, pdu_len); + + if (payload_len == rem_len) { + put_le32(dptr, pkt_counter); + } + + break; + case BLE_HCI_PAYLOAD_TYPE_MAXIMUM_LENGTH: + payload_len = conn->max_sdu; + + rem_len = payload_len - pdu_idx * conn->mux.max_pdu; + if (rem_len == 0) { + *llid = 0b01; + pdu_len = 0; + } else { + *llid = rem_len > conn->mux.max_pdu; + pdu_len = min(conn->mux.max_pdu, rem_len); + } + + memset(dptr, 0, pdu_len); + + if (payload_len == rem_len) { + put_le32(dptr, pkt_counter); + } + + break; + default: + BLE_LL_ASSERT(0); + } + + return pdu_len; } int -ble_ll_iso_create_big_test(const uint8_t *cmdbuf, uint8_t len) +ble_ll_iso_pdu_get(struct ble_ll_iso_conn *conn, uint8_t idx, uint32_t pkt_counter, uint8_t *llid, void *dptr) { - return BLE_ERR_UNSUPPORTED; + if (conn->test_mode.transmit.enabled) { + return ble_ll_iso_test_pdu_get(conn, idx, pkt_counter, llid, dptr); + } + + return ble_ll_isoal_mux_pdu_get(&conn->mux, idx, llid, dptr); } -int -ble_ll_iso_transmit_test(const uint8_t *cmdbuf, uint8_t len) +void +ble_ll_iso_conn_init(struct ble_ll_iso_conn *conn, struct ble_ll_iso_conn_init_param *param) { - return BLE_ERR_UNSUPPORTED; + os_sr_t sr; + + memset(conn, 0, sizeof(*conn)); + + conn->handle = param->conn_handle; + conn->max_sdu = param->max_sdu; + + ble_ll_isoal_mux_init(&conn->mux, param->max_pdu, param->iso_interval_us, param->sdu_interval_us, + param->bn, param->pte, BLE_LL_ISOAL_MUX_IS_FRAMED(param->framing), + param->framing == BLE_HCI_ISO_FRAMING_FRAMED_UNSEGMENTED); + + OS_ENTER_CRITICAL(sr); + STAILQ_INSERT_TAIL(&ll_iso_conn_q, conn, iso_conn_q_next); + OS_EXIT_CRITICAL(sr); } -int -ble_ll_iso_receive_test(const uint8_t *cmdbuf, uint8_t len) +void +ble_ll_iso_conn_free(struct ble_ll_iso_conn *conn) { - return BLE_ERR_UNSUPPORTED; + os_sr_t sr; + + OS_ENTER_CRITICAL(sr); + STAILQ_REMOVE(&ll_iso_conn_q, conn, ble_ll_iso_conn, iso_conn_q_next); + OS_EXIT_CRITICAL(sr); + + ble_ll_isoal_mux_free(&conn->mux); } int -ble_ll_iso_read_counters_test(const uint8_t *cmdbuf, uint8_t len) +ble_ll_iso_conn_event_start(struct ble_ll_iso_conn *conn, uint32_t timestamp) { - return BLE_ERR_UNSUPPORTED; + if (conn->test_mode.transmit.enabled) { + conn->test_mode.transmit.rand = ble_ll_rand() % conn->max_sdu; + } + + ble_ll_isoal_mux_event_start(&conn->mux, timestamp); + + return 0; } int -ble_ll_iso_end_test(const uint8_t *cmdbuf, uint8_t len) +ble_ll_iso_conn_event_done(struct ble_ll_iso_conn *conn) { - return BLE_ERR_UNSUPPORTED; + conn->num_completed_pkt += ble_ll_isoal_mux_event_done(&conn->mux); + + return conn->num_completed_pkt; } -#endif -#endif + +#endif /* BLE_LL_ISO */ diff --git a/nimble/controller/src/ble_ll_iso_big.c b/nimble/controller/src/ble_ll_iso_big.c new file mode 100644 index 0000000000..774465315e --- /dev/null +++ b/nimble/controller/src/ble_ll_iso_big.c @@ -0,0 +1,1512 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ble_ll_priv.h" + +#if MYNEWT_VAL(BLE_LL_ISO_BROADCASTER) + +/* XXX make those configurable */ +#define BIG_POOL_SIZE (10) +#define BIS_POOL_SIZE (10) + +#define BIG_HANDLE_INVALID (0xff) + +#define BIG_CONTROL_ACTIVE_CHAN_MAP 1 +#define BIG_CONTROL_ACTIVE_TERM 2 + +struct ble_ll_iso_big; + +struct ble_ll_iso_bis { + struct ble_ll_iso_big *big; + uint8_t num; + + uint32_t aa; + uint32_t crc_init; + uint16_t chan_id; + uint8_t iv[8]; + + struct { + uint16_t prn_sub_lu; + uint16_t remap_idx; + + uint8_t subevent_num; + uint8_t n; + uint8_t g; + } tx; + + struct ble_ll_iso_conn conn; + + STAILQ_ENTRY(ble_ll_iso_bis) bis_q_next; +}; + +STAILQ_HEAD(ble_ll_iso_bis_q, ble_ll_iso_bis); + +struct big_params { + uint8_t nse; /* 1-31 */ + uint8_t bn; /* 1-7, mandatory 1 */ + uint8_t irc; /* 1-15 */ + uint8_t pto; /* 0-15, mandatory 0 */ + uint32_t sdu_interval; + uint16_t iso_interval; + uint16_t max_transport_latency_ms; + uint16_t max_sdu; + uint8_t max_pdu; + uint8_t phy; + uint8_t framing; + uint8_t interleaved : 1; + uint8_t encrypted : 1; + uint8_t broadcast_code[16]; +}; + +struct ble_ll_iso_big { + struct ble_ll_adv_sm *advsm; + + uint8_t handle; + uint8_t num_bis; + uint16_t iso_interval; + uint16_t bis_spacing; + uint16_t sub_interval; + uint8_t phy; + uint8_t max_pdu; + uint16_t max_sdu; + uint16_t mpt; + uint8_t bn; /* 1-7, mandatory 1 */ + uint8_t pto; /* 0-15, mandatory 0 */ + uint8_t irc; /* 1-15 */ + uint8_t nse; /* 1-31 */ + uint8_t interleaved : 1; + uint8_t framed : 1; + uint8_t framing_mode : 1; + uint8_t encrypted : 1; + uint8_t giv[8]; + uint8_t gskd[16]; + uint8_t gsk[16]; + uint8_t iv[8]; + uint8_t gc; + + uint32_t sdu_interval; + + uint32_t ctrl_aa; + uint16_t crc_init; + uint8_t chan_map[BLE_LL_CHAN_MAP_LEN]; + uint8_t chan_map_used; + + uint8_t biginfo[33]; + + uint64_t big_counter; + uint64_t bis_counter; + + uint32_t sync_delay; + uint32_t transport_latency_us; + uint32_t event_start; + uint8_t event_start_us; + uint32_t anchor_base_ticks; + uint8_t anchor_base_rem_us; + uint16_t anchor_offset; + struct ble_ll_sched_item sch; + struct ble_npl_event event_done; + + struct { + uint16_t subevents_rem; + struct ble_ll_iso_bis *bis; + } tx; + + struct ble_ll_iso_bis_q bis_q; + +#if MYNEWT_VAL(BLE_LL_ISO_HCI_FEEDBACK_INTERVAL_MS) + uint32_t last_feedback; +#endif + + uint8_t cstf : 1; + uint8_t cssn : 4; + uint8_t control_active : 3; + uint16_t control_instant; + + uint8_t chan_map_new_pending : 1; + uint8_t chan_map_new[BLE_LL_CHAN_MAP_LEN]; + + uint8_t term_pending : 1; + uint8_t term_reason : 7; +}; + +static struct ble_ll_iso_big big_pool[BIG_POOL_SIZE]; +static struct ble_ll_iso_bis bis_pool[BIS_POOL_SIZE]; +static uint8_t big_pool_free = BIG_POOL_SIZE; +static uint8_t bis_pool_free = BIS_POOL_SIZE; + +static struct ble_ll_iso_big *big_pending; +static struct ble_ll_iso_big *big_active; + +static void +big_sched_set(struct ble_ll_iso_big *big) +{ + uint32_t offset_us; + + big->sch.start_time = big->anchor_base_ticks; + big->sch.remainder = big->anchor_base_rem_us; + + offset_us = big->anchor_offset * big->iso_interval * 1250; + + ble_ll_tmr_add(&big->sch.start_time, &big->sch.remainder, offset_us); + + /* Reset anchor base before anchor offset wraps-around. + * This happens much earlier than possible overflow in calculations. + */ + if (big->anchor_offset == UINT16_MAX) { + big->anchor_base_ticks = big->sch.start_time; + big->anchor_base_rem_us = big->sch.remainder; + big->anchor_offset = 0; + } + + big->sch.end_time = big->sch.start_time + + ble_ll_tmr_u2t_up(big->sync_delay) + 1; + big->sch.start_time -= g_ble_ll_sched_offset_ticks; + + if (big->control_active) { + /* XXX calculate proper time */ + big->sch.end_time += 10; + } +} + +static void +ble_ll_iso_big_biginfo_chanmap_update(struct ble_ll_iso_big *big) +{ + uint8_t *buf; + + buf = &big->biginfo[23]; + + /* chm, phy */ + memcpy(buf, big->chan_map, 5); + buf[4] |= (big->phy - 1) << 5; +} + +static void +ble_ll_iso_big_biginfo_calc(struct ble_ll_iso_big *big, uint32_t seed_aa) +{ + uint8_t *buf; + + buf = big->biginfo; + + /* big_offset, big_offset_units, iso_interval, num_bis */ + put_le32(buf, (big->num_bis << 27) | (big->iso_interval << 15)); + buf += 4; + + /* nse, bn */ + *(uint8_t *)buf = (big->bn << 5) | (big->nse); + buf += 1; + + /* sub_interval, pto */ + put_le24(buf,(big->pto << 20) | (big->sub_interval)); + buf += 3; + + /* bis_spacing, irc */ + put_le24(buf, (big->irc << 20) | (big->bis_spacing)); + buf += 3; + + /* max_pdu, rfu, framing_mode */ + put_le16(buf, big->max_pdu | (big->framing_mode) << 15); + buf += 2; + + /* seed_access_address */ + put_le32(buf, seed_aa); + buf += 4; + + /* sdu_interval, max_sdu */ + put_le32(buf, (big->max_sdu << 20) | (big->sdu_interval)); + buf += 4; + + /* base_crc_init */ + put_le16(buf, big->crc_init); + buf += 2; + + /* chm, phy */ + ble_ll_iso_big_biginfo_chanmap_update(big); + buf += 5; + + /* bis_payload_cnt, framing */ + memset(buf, 0x01, 5); + buf[4] |= (big->framed << 7) & 0x80; +} + +int +ble_ll_iso_big_biginfo_copy(struct ble_ll_iso_big *big, uint8_t *dptr, + uint32_t base_ticks, uint8_t base_rem_us) +{ + uint8_t *dptr_start; + uint32_t event_start; + uint8_t event_start_us; + uint64_t counter; + uint32_t offset_us; + uint32_t offset; + + dptr_start = dptr; + counter = big->bis_counter; + + event_start = big->event_start; + event_start_us = big->event_start_us; + + /* Use next BIG event in case current one is before AUX_SYNC_IND. This can + * happen if AUX_SYNC_IND is scheduled right after BIG event and the BIG + * was not yet advanced to next event. + */ + if (event_start <= base_ticks) { + ble_ll_tmr_add(&event_start, &event_start_us, big->iso_interval * 1250); + counter += big->bn; + } + + /* Drop BIGInfo if BIG event is still before AUX_SYNC_IND. This should not + * happen but better not send invalid offset. + */ + if (event_start <= base_ticks) { + return 0; + } + + offset_us = ble_ll_tmr_t2u(event_start - base_ticks); + offset_us += event_start_us; + offset_us -= base_rem_us; + + if (offset_us <= 600) { + counter += big->bn; + offset_us += big->iso_interval * 1250; + } + if (offset_us >= 491460) { + offset = 0x4000 | (offset_us / 300); + } else { + offset = offset_us / 30; + } + + *dptr++ = ble_ll_iso_big_biginfo_len(big) - 1; + *dptr++ = 0x2c; + + memcpy(dptr, big->biginfo, 33); + put_le32(dptr, get_le32(dptr) | (offset & 0x7fff)); + dptr += 28; + + *dptr++ = counter & 0xff; + *dptr++ = (counter >> 8) & 0xff; + *dptr++ = (counter >> 16) & 0xff; + *dptr++ = (counter >> 24) & 0xff; + *dptr++ = ((counter >> 32) & 0x7f) | ((big->framed << 7) & 0x80); + + if (big->encrypted) { + memcpy(dptr, big->giv, 8); + dptr += 8; + memcpy(dptr, big->gskd, 16); + dptr += 16; + } + + return dptr - dptr_start; +} + +int +ble_ll_iso_big_biginfo_len(struct ble_ll_iso_big *big) +{ + return 2 + sizeof(big->biginfo) + + (big->encrypted ? sizeof(big->giv) + sizeof(big->gskd) : 0); +} + +static void +ble_ll_iso_big_free(struct ble_ll_iso_big *big) +{ + struct ble_ll_iso_bis *bis; + + if (big->handle == BIG_HANDLE_INVALID) { + return; + } + + big->handle = BIG_HANDLE_INVALID; + ble_ll_sched_rmv_elem(&big->sch); + ble_npl_eventq_remove(&g_ble_ll_data.ll_evq, &big->event_done); + + STAILQ_FOREACH(bis, &big->bis_q, bis_q_next) { + ble_ll_iso_conn_free(&bis->conn); + bis->big = NULL; + bis_pool_free++; + } + + big_pool_free++; +} + +static void +ble_ll_iso_big_terminate_complete(struct ble_ll_iso_big *big) +{ + struct ble_hci_ev *hci_ev; + struct ble_hci_ev_le_subev_terminate_big_complete *evt; + uint8_t big_handle; + uint8_t reason; + + big_handle = big->handle; + reason = big->term_reason; + + ble_ll_iso_big_free(big); + + hci_ev = ble_transport_alloc_evt(0); + if (!hci_ev) { + BLE_LL_ASSERT(0); + return; + } + hci_ev->opcode = BLE_HCI_EVCODE_LE_META; + hci_ev->length = sizeof(*evt); + + evt = (void *)hci_ev->data; + memset(evt, 0, hci_ev->length); + evt->subev_code = BLE_HCI_LE_SUBEV_TERMINATE_BIG_COMPLETE; + evt->big_handle = big_handle; + evt->reason = reason; + + ble_transport_to_hs_evt(hci_ev); +} + +static void +ble_ll_iso_big_chan_map_update_complete(struct ble_ll_iso_big *big) +{ + memcpy(big->chan_map, big->chan_map_new, BLE_LL_CHAN_MAP_LEN); + big->chan_map_used = ble_ll_utils_chan_map_used_get(big->chan_map); + + ble_ll_iso_big_biginfo_chanmap_update(big); +} + +static void +ble_ll_iso_big_update_event_start(struct ble_ll_iso_big *big, + uint64_t new_big_counter) +{ + os_sr_t sr; + + OS_ENTER_CRITICAL(sr); + /* This has to be updated atomically to avoid races when copying to BIGInfo */ + big->event_start = big->sch.start_time + g_ble_ll_sched_offset_ticks; + big->event_start_us = big->sch.remainder; + big->bis_counter += (new_big_counter - big->big_counter) * big->bn; + big->big_counter = new_big_counter; + OS_EXIT_CRITICAL(sr); +} + +static void +ble_ll_iso_big_event_done(struct ble_ll_iso_big *big) +{ + struct ble_ll_iso_bis *bis; + struct ble_hci_ev *hci_ev; +#if MYNEWT_VAL(BLE_LL_ISO_HCI_FEEDBACK_INTERVAL_MS) + struct ble_hci_ev *fb_hci_ev = NULL; + struct ble_hci_ev_vs *fb_hci_ev_vs; + struct ble_hci_vs_subev_iso_hci_feedback *fb_hci_subev = NULL; + uint16_t exp; + uint32_t now; +#endif + uint64_t big_counter; + struct ble_hci_ev_num_comp_pkts *hci_ev_ncp = NULL; + int num_completed_pkt; + int idx; + int rc; + + ble_ll_rfmgmt_release(); + + if (big->big_counter == 0) { + BLE_LL_ASSERT(big == big_pending); + ble_ll_iso_big_hci_evt_complete(); + } + + hci_ev = ble_transport_alloc_evt(1); + if (hci_ev) { + hci_ev->opcode = BLE_HCI_EVCODE_NUM_COMP_PKTS; + hci_ev->length = sizeof(*hci_ev_ncp); + hci_ev_ncp = (void *)hci_ev->data; + hci_ev_ncp->count = 0; + } + +#if MYNEWT_VAL(BLE_LL_ISO_HCI_FEEDBACK_INTERVAL_MS) + now = os_time_get(); + if (OS_TIME_TICK_GEQ(now, big->last_feedback + + os_time_ms_to_ticks32(MYNEWT_VAL(BLE_LL_ISO_HCI_FEEDBACK_INTERVAL_MS)))) { + fb_hci_ev = ble_transport_alloc_evt(1); + if (fb_hci_ev) { + fb_hci_ev->opcode = BLE_HCI_EVCODE_VS; + fb_hci_ev->length = sizeof(*fb_hci_ev_vs) + sizeof(*fb_hci_subev); + fb_hci_ev_vs = (void *)fb_hci_ev->data; + fb_hci_ev_vs->id = BLE_HCI_VS_SUBEV_ISO_HCI_FEEDBACK; + fb_hci_subev = (void *)fb_hci_ev_vs->data; + fb_hci_subev->big_handle = big->handle; + fb_hci_subev->count = 0; + } + } +#endif + + STAILQ_FOREACH(bis, &big->bis_q, bis_q_next) { + num_completed_pkt = ble_ll_iso_conn_event_done(&bis->conn); + if (hci_ev && num_completed_pkt) { + idx = hci_ev_ncp->count++; + hci_ev_ncp->completed[idx].handle = htole16(bis->conn.handle); + hci_ev_ncp->completed[idx].packets = htole16(num_completed_pkt); + bis->conn.num_completed_pkt = 0; + } + +#if MYNEWT_VAL(BLE_LL_ISO_HCI_FEEDBACK_INTERVAL_MS) + if (fb_hci_ev) { + /* Expected SDUs in queue after an event -> host should send + * sdu_per_interval SDUs until next event so there are sdu_per_event + * SDUs queued at next event. Feedback value is the difference between + * expected and actual SDUs count. + */ + exp = bis->mux.sdu_per_event - bis->mux.sdu_per_interval; + idx = fb_hci_subev->count++; + fb_hci_subev->feedback[idx].handle = htole16(bis->conn.handle); + fb_hci_subev->feedback[idx].sdu_per_interval = bis->mux.sdu_per_interval; + fb_hci_subev->feedback[idx].diff = (int8_t)(bis->mux.sdu_q_len - exp); + } +#endif + } + + if (hci_ev) { + if (hci_ev_ncp->count) { + hci_ev->length = sizeof(*hci_ev_ncp) + + hci_ev_ncp->count * sizeof(hci_ev_ncp->completed[0]); + ble_transport_to_hs_evt(hci_ev); + } else { + ble_transport_free(hci_ev); + } + } + +#if MYNEWT_VAL(BLE_LL_ISO_HCI_FEEDBACK_INTERVAL_MS) + if (fb_hci_ev) { + fb_hci_ev->length = sizeof(*fb_hci_ev_vs) + sizeof(*fb_hci_subev) + + fb_hci_subev->count * sizeof(fb_hci_subev->feedback[0]); + ble_transport_to_hs_evt(fb_hci_ev); + big->last_feedback = now; + } +#endif + + big->sch.start_time = big->event_start; + big->sch.remainder = big->event_start_us; + big_counter = big->big_counter; + + do { + big_counter++; + + if (big->control_active && + (big->control_instant == (uint16_t)big_counter)) { + switch (big->control_active) { + case BIG_CONTROL_ACTIVE_TERM: + ble_ll_iso_big_terminate_complete(big); + return; + case BIG_CONTROL_ACTIVE_CHAN_MAP: + ble_ll_iso_big_chan_map_update_complete(big); + break; + default: + BLE_LL_ASSERT(0); + break; + } + + big->control_active = 0; + big->cstf = 0; + } + + if (!big->control_active) { + if (big->term_pending) { + big->term_pending = 0; + big->control_active = BIG_CONTROL_ACTIVE_TERM; + } else if (big->chan_map_new_pending) { + memcpy(big->chan_map_new, g_ble_ll_data.chan_map, + BLE_LL_CHAN_MAP_LEN); + big->chan_map_new_pending = 0; + big->control_active = BIG_CONTROL_ACTIVE_CHAN_MAP; + } + + if (big->control_active) { + big->control_instant = big_counter + 6; + big->cstf = 1; + big->cssn += 1; + } + } + + big->anchor_offset++; + big_sched_set(big); + + /* This should always succeed since we preempt anything for now */ + rc = ble_ll_sched_iso_big(&big->sch, 0, 1); + BLE_LL_ASSERT(rc == 0); + } while (rc < 0); + + ble_ll_iso_big_update_event_start(big, big_counter); +} + +static void +ble_ll_iso_big_event_done_ev(struct ble_npl_event *ev) +{ + struct ble_ll_iso_big *big; + + big = ble_npl_event_get_arg(ev); + + ble_ll_iso_big_event_done(big); +} + +static void +ble_ll_iso_big_event_done_to_ll(struct ble_ll_iso_big *big) +{ + big_active = NULL; + ble_ll_state_set(BLE_LL_STATE_STANDBY); + ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &big->event_done); +} + +static uint8_t +ble_ll_iso_big_control_pdu_cb(uint8_t *dptr, void *arg, uint8_t *hdr_byte) +{ + struct ble_ll_iso_big *big; + uint8_t len; + + big = arg; + + /* CSTF shall be set to 0 in Control PDU */ + *hdr_byte = 3 | (big->cssn << 2); + + BLE_LL_ASSERT(big->cstf); + BLE_LL_ASSERT(big->control_active); + + if (big->encrypted) { + ble_phy_encrypt_header_mask_set(BLE_LL_PDU_HEADERMASK_BIS); + ble_phy_encrypt_iv_set(big->iv); + ble_phy_encrypt_counter_set(big->bis_counter, 1); + } + + switch (big->control_active) { + case BIG_CONTROL_ACTIVE_CHAN_MAP: + dptr[0] = 0x00; /* BIG_CHANNEL_MAP_IND */ + memcpy(&dptr[1], big->chan_map_new, BLE_LL_CHAN_MAP_LEN); + put_le16(&dptr[6], big->control_instant); + len = 8; + break; + case BIG_CONTROL_ACTIVE_TERM: + dptr[0] = 0x01; /* BIG_TERMINATE_IND */ + dptr[1] = big->term_reason; + put_le16(&dptr[2], big->control_instant); + len = 4; + break; + default: + BLE_LL_ASSERT(0); + len = 0; + break; + } + + return len; +} + +static void +ble_ll_iso_big_control_txend_cb(void *arg) +{ + struct ble_ll_iso_big *big; + + big = arg; + + ble_ll_iso_big_event_done_to_ll(big); +} + +static int +ble_ll_iso_big_control_tx(struct ble_ll_iso_big *big) +{ + uint16_t chan_idx; + uint16_t chan_id; + uint16_t foo, bar; + int rc; + + chan_id = big->ctrl_aa ^ (big->ctrl_aa >> 16); + + chan_idx = ble_ll_utils_dci_iso_event(big->big_counter, chan_id, + &foo, + big->chan_map_used, + big->chan_map, + &bar); + + ble_phy_set_txend_cb(ble_ll_iso_big_control_txend_cb, big); + ble_phy_setchan(chan_idx, big->ctrl_aa, big->crc_init << 8); + + rc = ble_phy_tx(ble_ll_iso_big_control_pdu_cb, big, BLE_PHY_TRANSITION_NONE); + + return rc; +} + +static uint8_t +ble_ll_iso_big_subevent_pdu_cb(uint8_t *dptr, void *arg, uint8_t *hdr_byte) +{ + struct ble_ll_iso_big *big; + struct ble_ll_iso_bis *bis; + int idx; + uint8_t llid; + uint8_t pdu_len; + + big = arg; + bis = big->tx.bis; + + /* Core 5.3, Vol 6, Part B, 4.4.6.6 */ + if (bis->tx.g < big->irc) { + idx = bis->tx.n; + } else { + idx = big->bn * big->pto * (bis->tx.g - big->irc + 1) + bis->tx.n; + } + + if (big->encrypted) { + ble_phy_encrypt_header_mask_set(BLE_LL_PDU_HEADERMASK_BIS); + ble_phy_encrypt_iv_set(bis->iv); + ble_phy_encrypt_counter_set(big->bis_counter + idx, 1); + } + +#if 1 + pdu_len = ble_ll_iso_pdu_get(&bis->conn, idx, big->bis_counter + idx, &llid, dptr); +#else + llid = 0; + pdu_len = big->max_pdu; + /* XXX dummy data for testing */ + memset(dptr, bis->num | (bis->num << 4), pdu_len); + put_be32(dptr, big->big_counter); + put_be32(&dptr[4], big->bis_counter + idx); + dptr[8] = bis->tx.subevent_num; + dptr[9] = bis->tx.g; + dptr[10] = bis->tx.n; + if (bis->tx.g == 0) { + dptr[11] = 'B'; + } else if (bis->tx.g < big->irc) { + dptr[11] = 'R'; + } else { + dptr[11] = 'P'; + } + dptr[12] = 0xff; +#endif + + *hdr_byte = llid | (big->cssn << 2) | (big->cstf << 5); + + return pdu_len; +} + +static int +ble_ll_iso_big_subevent_tx(struct ble_ll_iso_big *big) +{ + struct ble_ll_iso_bis *bis; + uint16_t chan_idx; + int to_tx; + int rc; + + bis = big->tx.bis; + + if (bis->tx.subevent_num == 1) { + chan_idx = ble_ll_utils_dci_iso_event(big->big_counter, bis->chan_id, + &bis->tx.prn_sub_lu, + big->chan_map_used, + big->chan_map, + &bis->tx.remap_idx); + } else { + chan_idx = ble_ll_utils_dci_iso_subevent(bis->chan_id, + &bis->tx.prn_sub_lu, + big->chan_map_used, + big->chan_map, + &bis->tx.remap_idx); + } + + ble_phy_setchan(chan_idx, bis->aa, bis->crc_init); + + to_tx = (big->tx.subevents_rem > 1) || big->cstf; + + rc = ble_phy_tx(ble_ll_iso_big_subevent_pdu_cb, big, + to_tx ? BLE_PHY_TRANSITION_TX_TX + : BLE_PHY_TRANSITION_NONE); + return rc; +} + +static void +ble_ll_iso_big_subevent_txend_cb(void *arg) +{ + struct ble_ll_iso_big *big; + struct ble_ll_iso_bis *bis; + int rc; + + big = arg; + bis = big->tx.bis; + + bis->tx.n++; + if (bis->tx.n == big->bn) { + bis->tx.n = 0; + bis->tx.g++; + } + + /* Switch to next BIS if interleaved or all subevents for current BIS were + * transmitted. + */ + if (big->interleaved || (bis->tx.subevent_num == big->nse)) { + bis = STAILQ_NEXT(bis, bis_q_next); + if (!bis) { + bis = STAILQ_FIRST(&big->bis_q); + } + big->tx.bis = bis; + } + + bis->tx.subevent_num++; + big->tx.subevents_rem--; + + if (big->tx.subevents_rem > 0) { + rc = ble_ll_iso_big_subevent_tx(big); + if (rc) { + ble_phy_disable(); + ble_ll_iso_big_event_done_to_ll(big); + } + return; + } + + if (big->cstf) { + rc = ble_ll_iso_big_control_tx(big); + if (rc) { + ble_phy_disable(); + ble_ll_iso_big_event_done_to_ll(big); + } + return; + } + + ble_ll_iso_big_event_done_to_ll(big); +} + +static int +ble_ll_iso_big_event_sched_cb(struct ble_ll_sched_item *sch) +{ + struct ble_ll_iso_big *big; + struct ble_ll_iso_bis *bis; +#if MYNEWT_VAL(BLE_LL_PHY) + uint8_t phy_mode; +#endif + int rc; + + big = sch->cb_arg; + + ble_ll_state_set(BLE_LL_STATE_BIG); + big_active = big; + + ble_ll_whitelist_disable(); +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + ble_phy_resolv_list_disable(); +#endif +#if MYNEWT_VAL(BLE_LL_PHY) + phy_mode = ble_ll_phy_to_phy_mode(big->phy, 0); + ble_phy_mode_set(phy_mode, phy_mode); +#endif + + ble_ll_tx_power_set(g_ble_ll_tx_power); + + /* XXX calculate this in advance at the end of previous event? */ + big->tx.subevents_rem = big->num_bis * big->nse; + STAILQ_FOREACH(bis, &big->bis_q, bis_q_next) { + ble_ll_iso_conn_event_start(&bis->conn, (uint64_t)big->event_start * + 1000000 / 32768 + + big->event_start_us); + + bis->tx.subevent_num = 0; + bis->tx.n = 0; + bis->tx.g = 0; + } + + /* Select 1st BIS for transmission */ + big->tx.bis = STAILQ_FIRST(&big->bis_q); + big->tx.bis->tx.subevent_num = 1; + + if (big->interleaved) { + ble_phy_tifs_txtx_set(big->bis_spacing, 0); + } else { + ble_phy_tifs_txtx_set(big->sub_interval, 0); + } + + rc = ble_phy_tx_set_start_time(sch->start_time + g_ble_ll_sched_offset_ticks, + sch->remainder); + if (rc) { + ble_phy_disable(); + ble_ll_iso_big_event_done_to_ll(big); + return BLE_LL_SCHED_STATE_DONE; + } + + ble_phy_set_txend_cb(ble_ll_iso_big_subevent_txend_cb, big); + + if (big->encrypted) { + ble_phy_encrypt_enable(big->gsk); + } else { + ble_phy_encrypt_disable(); + } + + rc = ble_ll_iso_big_subevent_tx(big); + if (rc) { + ble_phy_disable(); + ble_ll_iso_big_event_done_to_ll(big); + return BLE_LL_SCHED_STATE_DONE; + } + + return BLE_LL_SCHED_STATE_RUNNING; +} + +static void +ble_ll_iso_big_calculate_gsk(struct ble_ll_iso_big *big, + const uint8_t *broadcast_code) +{ + static const uint8_t big1[16] = {0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x42, 0x49, 0x47, 0x31}; + static const uint8_t big2[4] = {0x42, 0x49, 0x47, 0x32}; + static const uint8_t big3[4] = {0x42, 0x49, 0x47, 0x33}; + uint8_t code[16]; + uint8_t igltk[16]; + uint8_t gltk[16]; + + /* broadcast code is lsb-first in hci, we need msb-first */ + swap_buf(code, broadcast_code, 16); + + ble_ll_rand_data_get(big->gskd, sizeof(big->gskd)); + + ble_ll_crypto_h7(big1, code, igltk); + ble_ll_crypto_h6(igltk, big2, gltk); + ble_ll_crypto_h8(gltk, big->gskd, big3, big->gsk); + + /* need gskd for biginfo, i.e. lsb-first */ + swap_in_place(big->gskd, 16); +} + +static void +ble_ll_iso_big_calculate_iv(struct ble_ll_iso_big *big) +{ + struct ble_ll_iso_bis *bis; + uint8_t *aa; + + ble_ll_rand_data_get(big->giv, sizeof(big->giv)); + STAILQ_FOREACH(bis, &big->bis_q, bis_q_next) { + memcpy(&bis->iv[4], &big->giv[4], 4); + aa = (uint8_t *)&bis->aa; + bis->iv[0] = big->giv[0] ^ aa[0]; + bis->iv[1] = big->giv[1] ^ aa[1]; + bis->iv[2] = big->giv[2] ^ aa[2]; + bis->iv[3] = big->giv[3] ^ aa[3]; + } + + memcpy(&big->iv[4], &big->giv[4], 4); + aa = (uint8_t *)&big->ctrl_aa; + big->iv[0] = big->giv[0] ^ aa[0]; + big->iv[1] = big->giv[1] ^ aa[1]; + big->iv[2] = big->giv[2] ^ aa[2]; + big->iv[3] = big->giv[3] ^ aa[3]; +} + +static int +ble_ll_iso_big_create(uint8_t big_handle, uint8_t adv_handle, uint8_t num_bis, + struct big_params *bp) +{ + struct ble_ll_iso_conn_init_param conn_init_param = { + .iso_interval_us = bp->iso_interval * 1250, + .sdu_interval_us = bp->sdu_interval, + .max_sdu = bp->max_sdu, + .max_pdu = bp->max_pdu, + .framing = bp->framing, + .bn = bp->bn, + }; + struct ble_ll_iso_big *big = NULL; + struct ble_ll_iso_bis *bis; + struct ble_ll_adv_sm *advsm; + uint32_t seed_aa; + uint8_t gc; + uint8_t idx; + int rc; + + if ((big_pool_free == 0) || (bis_pool_free < num_bis)) { + return -ENOMEM; + } + + /* Find free BIG */ + for (idx = 0; idx < BIG_POOL_SIZE; idx++) { + if (!big && big_pool[idx].handle == BIG_HANDLE_INVALID) { + big = &big_pool[idx]; + } + if (big_pool[idx].handle == big_handle) { + return -EALREADY; + } + } + + BLE_LL_ASSERT(big); + + big_pool_free--; + big->handle = big_handle; + + advsm = ble_ll_adv_sync_get(adv_handle); + if (!advsm) { + ble_ll_iso_big_free(big); + return -ENOENT; + } + + if (ble_ll_adv_sync_big_add(advsm, big) < 0) { + ble_ll_iso_big_free(big); + return -ENOENT; + } + + big->advsm = advsm; + + big->crc_init = ble_ll_rand(); + memcpy(big->chan_map, g_ble_ll_data.chan_map, BLE_LL_CHAN_MAP_LEN); + big->chan_map_used = g_ble_ll_data.chan_map_used; + + big->big_counter = 0; + big->bis_counter = 0; + + big->cstf = 0; + big->cssn = 0; + big->control_active = 0; + big->control_instant = 0; + big->chan_map_new_pending = 0; + big->term_pending = 0; + big->term_reason = 0; + + /* Calculate number of additional events for pre-transmissions */ + /* Core 5.3, Vol 6, Part B, 4.4.6.6 */ + gc = bp->nse / bp->bn; + if (bp->irc == gc) { + conn_init_param.pte = 0; + } else { + conn_init_param.pte = bp->pto * (gc - bp->irc); + } + + /* Allocate BISes */ + STAILQ_INIT(&big->bis_q); + big->num_bis = 0; + for (idx = 0; (big->num_bis < num_bis) && (idx < BIS_POOL_SIZE); idx++) { + bis = &bis_pool[idx]; + if (bis->big) { + continue; + } + + big->num_bis++; + STAILQ_INSERT_TAIL(&big->bis_q, bis, bis_q_next); + + bis->big = big; + bis->num = big->num_bis; + bis->crc_init = (big->crc_init << 8) | (big->num_bis); + + conn_init_param.conn_handle = BLE_LL_CONN_HANDLE(BLE_LL_CONN_HANDLE_TYPE_BIS, idx); + + ble_ll_iso_conn_init(&bis->conn, &conn_init_param); + } + + bis_pool_free -= num_bis; + + big->bn = bp->bn; + big->pto = bp->pto; + big->irc = bp->irc; + big->nse = bp->nse; + big->interleaved = bp->interleaved; + big->framed = bp->framing != BLE_HCI_ISO_FRAMING_UNFRAMED; + big->framing_mode = bp->framing == BLE_HCI_ISO_FRAMING_FRAMED_UNSEGMENTED; + big->encrypted = bp->encrypted; + big->sdu_interval = bp->sdu_interval; + big->iso_interval = bp->iso_interval; + big->phy = bp->phy; + big->max_pdu = bp->max_pdu; + big->max_sdu = bp->max_sdu; + /* Core 5.3, Vol 6, Part B, 4.4.6.3 */ + big->mpt = ble_ll_pdu_us(big->max_pdu + (big->encrypted ? 4 : 0), + ble_ll_phy_to_phy_mode(big->phy, + BLE_HCI_LE_PHY_CODED_S8_PREF)); + + /* Core 5.3, Vol 6, Part B, 4.4.6.4 */ + if (big->interleaved) { + big->bis_spacing = big->mpt + BLE_LL_MSS; + big->sub_interval = big->num_bis * big->bis_spacing; + } else { + big->sub_interval = big->mpt + BLE_LL_MSS; + big->bis_spacing = big->nse * big->sub_interval; + } + /* Core 5.3, Vol 6, Part B, 4.4.6.5 */ + big->sync_delay = (big->num_bis - 1) * big->bis_spacing + + (big->nse - 1) * big->sub_interval + big->mpt; + + /* Reset PTO if pre-transmissions won't be used */ + big->gc = gc; + if (big->irc == gc) { + big->pto = 0; + } + + /* Core 6.0, Vol 6, Part G, 3.2.1 and 3.2.2 */ + if (big->framed) { + big->transport_latency_us = big->sync_delay + + (big->pto * (big->nse / big->bn - big->irc) + 1) * + big->iso_interval * 1250 + big->sdu_interval; + } else { + big->transport_latency_us = big->sync_delay + + (big->pto * (big->nse / big->bn - big->irc) + 1) * + big->iso_interval * 1250 - big->sdu_interval; + } + + if (big->transport_latency_us > bp->max_transport_latency_ms * 1000) { + ble_ll_iso_big_free(big); + return -ERANGE; + } + + /* Calculate AA for each BIS and BIG Control. We have to repeat this process + * until all AAs are valid. + */ + do { + rc = 0; + + seed_aa = ble_ll_utils_calc_seed_aa(); + big->ctrl_aa = ble_ll_utils_calc_big_aa(seed_aa, 0); + + if (!ble_ll_utils_verify_aa(big->ctrl_aa)) { + continue; + } + + rc = 1; + + STAILQ_FOREACH(bis, &big->bis_q, bis_q_next) { + bis->aa = ble_ll_utils_calc_big_aa(seed_aa, bis->num); + if (!ble_ll_utils_verify_aa(bis->aa)) { + rc = 0; + break; + } + bis->chan_id = bis->aa ^ (bis->aa >> 16); + } + } while (rc == 0); + + ble_ll_iso_big_biginfo_calc(big, seed_aa); + + if (big->encrypted) { + ble_ll_iso_big_calculate_gsk(big, bp->broadcast_code); + ble_ll_iso_big_calculate_iv(big); + } + + /* For now we will schedule complete event as single item. This allows for + * shortest possible subevent space (150us) but can create sequence of long + * events that will block scheduler from other activities. To mitigate this + * we use preempt_none strategy so scheudling is opportunistic and depending + * on other activities this may create gaps in stream. + * Eventually we should allow for some more robust scheduling, e.g. per-BIS + * for sequential arrangement or per-subevent for interleaved, or event + * per-BIS-subevent but this requires larger subevent space since 150us is + * not enough for some phys to run scheduler item. + */ + + uint32_t padv_start_time, big_start_time; + uint32_t sync_delay_ticks = ble_ll_tmr_u2t_up(big->sync_delay); + int big_event_fixed; + + rc = ble_ll_adv_padv_event_start_get(big->advsm, &padv_start_time, NULL); + if (rc) { + /* 1st event will be moved by 1 interval before scheduling so this will + * be always in the future */ + big_start_time = ble_ll_tmr_get(); + big_event_fixed = 0; + } else { + /* Set 1st BIG event directly before periodic advertising event, this + * way it will not overlap it even if periodic advertising data changes. + * Make sure it's in the future. + */ + big_start_time = padv_start_time - g_ble_ll_sched_offset_ticks - + sync_delay_ticks - 1; + big_event_fixed = 1; + } + + big->anchor_base_ticks = big_start_time; + big->anchor_base_rem_us = 0; + big->anchor_offset = 0; + + do { + big->anchor_offset++; + big_sched_set(big); + + if (LL_TMR_LEQ(big->sch.start_time, ble_ll_tmr_get())) { + rc = -1; + } else { + rc = ble_ll_sched_iso_big(&big->sch, 1, big_event_fixed); + } + } while (rc < 0); + + ble_ll_iso_big_update_event_start(big, big->big_counter); + + big_pending = big; + + return 0; +} + +static int +ble_ll_iso_big_terminate(uint8_t big_handle, uint8_t reason) +{ + struct ble_ll_iso_big *big = NULL; + unsigned idx; + + for (idx = 0; idx < BIG_POOL_SIZE; idx++) { + if (big_pool[idx].handle == big_handle) { + big = &big_pool[idx]; + break; + } + } + + if (!big) { + return -ENOENT; + } + + /* Not sure if this is correct, but let's remove BIGInfo now since there's + * no point for peer to syncing to a BIG that will be disconnected soon. + */ + ble_ll_adv_sync_big_remove(big->advsm, big); + + big->term_reason = reason; + big->term_pending = 1; + + return 0; +} + +void +ble_ll_iso_big_chan_map_update(void) +{ + struct ble_ll_iso_big *big; + int idx; + + for (idx = 0; idx < BIG_POOL_SIZE; idx++) { + big = &big_pool[idx]; + + if (big->handle == BIG_HANDLE_INVALID) { + continue; + } + + big->chan_map_new_pending = 1; + } +} + +void +ble_ll_iso_big_halt(void) +{ + if (big_active) { + ble_ll_iso_big_event_done_to_ll(big_active); + } +} + +void +ble_ll_iso_big_hci_evt_complete(void) +{ + struct ble_ll_iso_big *big; + struct ble_ll_iso_bis *bis; + struct ble_hci_ev_le_subev_create_big_complete *evt; + struct ble_hci_ev *hci_ev; + uint8_t idx; + + big = big_pending; + big_pending = NULL; + + if (!big) { + return; + } + + hci_ev = ble_transport_alloc_evt(0); + if (!hci_ev) { + BLE_LL_ASSERT(0); + /* XXX should we retry later? */ + return; + } + hci_ev->opcode = BLE_HCI_EVCODE_LE_META; + hci_ev->length = sizeof(*evt) + big->num_bis * sizeof(evt->conn_handle[0]); + + evt = (void *)hci_ev->data; + memset(evt, 0, hci_ev->length); + evt->subev_code = BLE_HCI_LE_SUBEV_CREATE_BIG_COMPLETE; + evt->status = 0x00; + + evt->big_handle = big->handle; + put_le24(evt->big_sync_delay, big->sync_delay); + /* Core 5.3, Vol 6, Part G, 3.2.2 */ + put_le24(evt->transport_latency_big, big->transport_latency_us); + evt->phy = big->phy; + evt->nse = big->nse; + evt->bn = big->bn; + evt->pto = big->pto; + evt->irc = big->irc; + evt->max_pdu = htole16(big->max_pdu); + evt->iso_interval = htole16(big->iso_interval); + evt->num_bis = big->num_bis; + + idx = 0; + STAILQ_FOREACH(bis, &big->bis_q, bis_q_next) { + evt->conn_handle[idx] = htole16(bis->conn.handle); + idx++; + } + + ble_ll_hci_event_send(hci_ev); +} + +int +ble_ll_iso_big_hci_create(const uint8_t *cmdbuf, uint8_t len) +{ + const struct ble_hci_le_create_big_cp *cmd = (void *)cmdbuf; + struct big_params bp; + uint8_t valid_phys; + int rc; + + if (len != sizeof(*cmd)) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + if (!IN_RANGE(cmd->big_handle, 0x00, 0xef) || + !IN_RANGE(cmd->adv_handle, 0x00, 0xef) || + !IN_RANGE(cmd->num_bis, 0x01, 0x1f) || + !IN_RANGE(get_le24(cmd->sdu_interval), 0x0000ff, 0x0fffff) || + !IN_RANGE(le16toh(cmd->max_sdu), 0x0001, 0x0fff) || + !IN_RANGE(le16toh(cmd->max_transport_latency), 0x0005, 0x0fa0) || + !IN_RANGE(cmd->rtn, 0x00, 0x1e) || + (cmd->packing > 1) || (cmd->framing > 2) || (cmd->encryption) > 1) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + valid_phys = BLE_HCI_LE_PHY_1M_PREF_MASK; +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY) + valid_phys |= BLE_HCI_LE_PHY_2M_PREF_MASK; +#endif +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) + valid_phys |= BLE_HCI_LE_PHY_CODED_PREF_MASK; +#endif + + if (cmd->phy & ~valid_phys) { + return BLE_ERR_UNSUPPORTED; + } + + bp.sdu_interval = get_le24(cmd->sdu_interval); + bp.max_transport_latency_ms = le16toh(cmd->max_transport_latency); + bp.max_sdu = le16toh(cmd->max_sdu); + if (cmd->phy & BLE_HCI_LE_PHY_2M_PREF_MASK) { + bp.phy = BLE_PHY_2M; + } else if (cmd->phy & BLE_HCI_LE_PHY_1M_PREF_MASK) { + bp.phy = BLE_PHY_1M; + } else { + bp.phy = BLE_PHY_CODED; + } + bp.interleaved = cmd->packing; + bp.encrypted = cmd->encryption; + memcpy(bp.broadcast_code, cmd->broadcast_code, 16); + + /* FIXME for now we only care about retransmissions, so set both NSE and IRC + * to RTN + */ + bp.nse = MIN(cmd->rtn + 1, 0x0f);; + bp.irc = MIN(cmd->rtn + 1, 0x0f); + bp.pto = 0; + + uint32_t iso_interval = bp.sdu_interval / 1250; + if (bp.sdu_interval > iso_interval * 1250) { + /* The requirements for using Unframed PDUs are not met */ + bp.framing = BLE_HCI_ISO_FRAMING_FRAMED_SEGMENTABLE; + bp.iso_interval = iso_interval + 1; + bp.bn = 2; + bp.max_pdu = bp.max_sdu + 5; + } else { + bp.framing = cmd->framing; + bp.iso_interval = iso_interval; + bp.bn = 1; + if (cmd->framing == BLE_HCI_ISO_FRAMING_UNFRAMED) { + bp.max_pdu = bp.max_sdu; + } else { + /** + * XXX: The requirements for using Unframed PDUs are met but the user + * requested Framed PDUs explicitly. Ensure the PDU fits the Segmentation Header. + */ + bp.max_pdu = bp.max_sdu + 5; + } + } + + rc = ble_ll_iso_big_create(cmd->big_handle, cmd->adv_handle, cmd->num_bis, + &bp); + switch (rc) { + case 0: + break; + case -EALREADY: + return BLE_ERR_CMD_DISALLOWED; + case -EINVAL: + return BLE_ERR_INV_HCI_CMD_PARMS; + case -ENOMEM: + return BLE_ERR_CONN_REJ_RESOURCES; + case -ENOENT: + return BLE_ERR_UNK_ADV_INDENT; + case -ERANGE: + return BLE_ERR_UNSUPPORTED; + default: + return BLE_ERR_UNSPECIFIED; + } + + return 0; +} + +int +ble_ll_iso_big_hci_create_test(const uint8_t *cmdbuf, uint8_t len) +{ + const struct ble_hci_le_create_big_test_cp *cmd = (void *)cmdbuf; + struct big_params bp; + uint32_t iso_interval_us; + int rc; + + if (len != sizeof(*cmd)) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + if (!IN_RANGE(cmd->big_handle, 0x00, 0xef) || + !IN_RANGE(cmd->adv_handle, 0x00, 0xef) || + !IN_RANGE(cmd->num_bis, 0x01, 0x1f) || + !IN_RANGE(get_le24(cmd->sdu_interval), 0x0000ff, 0x0fffff) || + !IN_RANGE(le16toh(cmd->iso_interval), 0x0004, 0x0c80) || + !IN_RANGE(cmd->nse, 0x01, 0x1f) || + !IN_RANGE(le16toh(cmd->max_sdu), 0x0001, 0x0fff) || + !IN_RANGE(le16toh(cmd->max_pdu), 0x0001, 0x00fb) || + /* phy */ + (cmd->packing > 1) || (cmd->framing > 1) || + !IN_RANGE(cmd->bn, 0x01, 0x07) || + !IN_RANGE(cmd->irc, 0x01, 0x0f) || + !IN_RANGE(cmd->pto, 0x00, 0x0f) || + (cmd->encryption) > 1) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + bp.nse = cmd->nse; + bp.bn = cmd->bn; + bp.irc = cmd->irc; + bp.pto = cmd->pto; + bp.sdu_interval = get_le24(cmd->sdu_interval); + bp.iso_interval = le16toh(cmd->iso_interval); + bp.max_transport_latency_ms = 0x0fa0; /* max_transport_latency for HCI LE Create BIG */ + bp.max_sdu = le16toh(cmd->max_sdu); + bp.max_pdu = le16toh(cmd->max_pdu); + /* TODO verify phy */ + if (cmd->phy & BLE_HCI_LE_PHY_2M_PREF_MASK) { + bp.phy = BLE_PHY_2M; + } else if (cmd->phy & BLE_HCI_LE_PHY_1M_PREF_MASK) { + bp.phy = BLE_PHY_1M; + } else { + bp.phy = BLE_PHY_CODED; + } + bp.interleaved = cmd->packing; + bp.framing = cmd->framing; + bp.encrypted = cmd->encryption; + memcpy(bp.broadcast_code, cmd->broadcast_code, 16); + + if (bp.nse % bp.bn) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + iso_interval_us = bp.iso_interval * 1250; + + if (bp.framing == BLE_HCI_ISO_FRAMING_UNFRAMED) { + /* sdu_interval shall be an integer multiple of iso_interval */ + if (iso_interval_us % bp.sdu_interval) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + /* bn shall be an integer multiple of (iso_interval / sdu_interval) */ + if (bp.bn % (iso_interval_us / bp.sdu_interval)) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + } + + rc = ble_ll_iso_big_create(cmd->big_handle, cmd->adv_handle, cmd->num_bis, + &bp); + switch (rc) { + case 0: + break; + case -EALREADY: + return BLE_ERR_CMD_DISALLOWED; + case -EINVAL: + return BLE_ERR_INV_HCI_CMD_PARMS; + case -ENOMEM: + return BLE_ERR_CONN_REJ_RESOURCES; + case -ENOENT: + return BLE_ERR_UNK_ADV_INDENT; + case -ERANGE: + return BLE_ERR_UNSUPPORTED; + default: + return BLE_ERR_UNSPECIFIED; + } + + return 0; +} + +int +ble_ll_iso_big_hci_terminate(const uint8_t *cmdbuf, uint8_t len) +{ + const struct ble_hci_le_terminate_big_cp *cmd = (void *)cmdbuf; + int err; + + err = ble_ll_iso_big_terminate(cmd->big_handle, cmd->reason); + switch (err) { + case 0: + break; + case -ENOENT: + return BLE_ERR_UNK_ADV_INDENT; + default: + return BLE_ERR_UNSPECIFIED; + } + + return 0; +} + +void +ble_ll_iso_big_init(void) +{ + struct ble_ll_iso_big *big; + uint8_t idx; + + memset(big_pool, 0, sizeof(big_pool)); + memset(bis_pool, 0, sizeof(bis_pool)); + + for (idx = 0; idx < BIG_POOL_SIZE; idx++) { + big = &big_pool[idx]; + + big->handle = BIG_HANDLE_INVALID; + + big->sch.sched_type = BLE_LL_SCHED_TYPE_BIG; + big->sch.sched_cb = ble_ll_iso_big_event_sched_cb; + big->sch.cb_arg = big; + + ble_npl_event_init(&big->event_done, ble_ll_iso_big_event_done_ev, big); + } + + big_pool_free = ARRAY_SIZE(big_pool); + bis_pool_free = ARRAY_SIZE(bis_pool); +} + +void +ble_ll_iso_big_reset(void) +{ + struct ble_ll_iso_big *big; + int idx; + + for (idx = 0; idx < BIG_POOL_SIZE; idx++) { + big = &big_pool[idx]; + ble_ll_iso_big_free(big); + } + + ble_ll_iso_big_init(); +} + +#endif /* BLE_LL_ISO_BROADCASTER */ diff --git a/nimble/controller/src/ble_ll_isoal.c b/nimble/controller/src/ble_ll_isoal.c new file mode 100644 index 0000000000..2cb842aa4f --- /dev/null +++ b/nimble/controller/src/ble_ll_isoal.c @@ -0,0 +1,488 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#include + +#ifndef min +#define min(a, b) ((a) < (b) ? (a) : (b)) +#endif + +#if MYNEWT_VAL(BLE_LL_ISO) + +void +ble_ll_isoal_mux_init(struct ble_ll_isoal_mux *mux, uint8_t max_pdu, + uint32_t iso_interval_us, uint32_t sdu_interval_us, + uint8_t bn, uint8_t pte, bool framed, uint8_t framing_mode) +{ + memset(mux, 0, sizeof(*mux)); + + mux->max_pdu = max_pdu; + /* Core 5.3, Vol 6, Part G, 2.1 */ + mux->sdu_per_interval = iso_interval_us / sdu_interval_us; + + if (framed) { + /* TODO */ + } else { + mux->pdu_per_sdu = bn / mux->sdu_per_interval; + } + + mux->sdu_per_event = (1 + pte) * mux->sdu_per_interval; + + mux->bn = bn; + + STAILQ_INIT(&mux->sdu_q); + mux->sdu_q_len = 0; + + mux->framed = framed; + mux->framing_mode = framing_mode; +} + +void +ble_ll_isoal_mux_free(struct ble_ll_isoal_mux *mux) +{ + struct os_mbuf_pkthdr *pkthdr; + struct os_mbuf *om; + struct os_mbuf *om_next; + + pkthdr = STAILQ_FIRST(&mux->sdu_q); + while (pkthdr) { + om = OS_MBUF_PKTHDR_TO_MBUF(pkthdr); + + while (om) { + om_next = SLIST_NEXT(om, om_next); + os_mbuf_free(om); + om = om_next; + } + + STAILQ_REMOVE_HEAD(&mux->sdu_q, omp_next); + pkthdr = STAILQ_FIRST(&mux->sdu_q); + } + + STAILQ_INIT(&mux->sdu_q); +} + +void +ble_ll_isoal_mux_sdu_enqueue(struct ble_ll_isoal_mux *mux, struct os_mbuf *om) +{ + struct os_mbuf_pkthdr *pkthdr; + os_sr_t sr; + + BLE_LL_ASSERT(mux); + + OS_ENTER_CRITICAL(sr); + pkthdr = OS_MBUF_PKTHDR(om); + STAILQ_INSERT_TAIL(&mux->sdu_q, pkthdr, omp_next); + mux->sdu_q_len++; +#if MYNEWT_VAL(BLE_LL_ISOAL_MUX_PREFILL) + if (mux->sdu_q_len >= mux->sdu_per_event) { + mux->active = 1; + } +#endif + OS_EXIT_CRITICAL(sr); +} + +int +ble_ll_isoal_mux_event_start(struct ble_ll_isoal_mux *mux, uint32_t timestamp) +{ +#if MYNEWT_VAL(BLE_LL_ISOAL_MUX_PREFILL) + /* If prefill is enabled, we always expect to have required number of SDUs + * in queue, otherwise we disable mux until enough SDUs are queued again. + */ + if (mux->sdu_per_event > mux->sdu_q_len) { + mux->active = 0; + } + if (mux->active && mux->framed) { + mux->sdu_in_event = mux->sdu_q_len; + } else if (mux->active) { + mux->sdu_in_event = mux->sdu_per_event; + } else { + mux->sdu_in_event = 0; + } +#else + if (mux->framed) { + mux->sdu_in_event = mux->sdu_q_len; + } else { + mux->sdu_in_event = min(mux->sdu_q_len, mux->sdu_per_event); + } +#endif + mux->event_tx_timestamp = timestamp; + + return mux->sdu_in_event; +} + +static int +ble_ll_isoal_mux_unframed_event_done(struct ble_ll_isoal_mux *mux) +{ + struct os_mbuf_pkthdr *pkthdr; + struct os_mbuf *om; + struct os_mbuf *om_next; + uint8_t num_sdu; + int pkt_freed = 0; + os_sr_t sr; + + num_sdu = min(mux->sdu_in_event, mux->sdu_per_interval); + +#if MYNEWT_VAL(BLE_LL_ISO_HCI_DISCARD_THRESHOLD) + /* Drop queued SDUs if number of queued SDUs exceeds defined threshold. + * Threshold is defined as number of ISO events. If number of queued SDUs + * exceeds number of SDUs required for single event (i.e. including pt) + * and number of subsequent ISO events defined by threshold value, we'll + * drop any excessive SDUs and notify host as if they were sent. + */ + uint32_t thr = MYNEWT_VAL(BLE_LL_ISO_HCI_DISCARD_THRESHOLD); + if (mux->sdu_q_len > mux->sdu_per_event + thr * mux->sdu_per_interval) { + num_sdu = mux->sdu_q_len - mux->sdu_per_event - + thr * mux->sdu_per_interval; + } +#endif + + pkthdr = STAILQ_FIRST(&mux->sdu_q); + while (pkthdr && num_sdu--) { + OS_ENTER_CRITICAL(sr); + STAILQ_REMOVE_HEAD(&mux->sdu_q, omp_next); + BLE_LL_ASSERT(mux->sdu_q_len > 0); + mux->sdu_q_len--; + OS_EXIT_CRITICAL(sr); + + om = OS_MBUF_PKTHDR_TO_MBUF(pkthdr); + while (om) { + om_next = SLIST_NEXT(om, om_next); + os_mbuf_free(om); + pkt_freed++; + om = om_next; + } + + pkthdr = STAILQ_FIRST(&mux->sdu_q); + } + + mux->sdu_in_event = 0; + + return pkt_freed; +} + +static int +ble_ll_isoal_mux_framed_event_done(struct ble_ll_isoal_mux *mux) +{ + struct os_mbuf_pkthdr *pkthdr; + struct os_mbuf *om; + struct os_mbuf *om_next; + uint8_t num_sdu; + uint8_t num_pdu; + uint8_t pdu_offset = 0; + uint8_t frag_len = 0; + uint8_t rem_len = 0; + uint8_t hdr_len = 0; + int pkt_freed = 0; + bool sc = mux->sc; + os_sr_t sr; + + num_sdu = mux->sdu_in_event; + if (num_sdu == 0) { + return 0; + } + + num_pdu = mux->bn; + +#if MYNEWT_VAL(BLE_LL_ISO_HCI_DISCARD_THRESHOLD) + /* Drop queued SDUs if number of queued SDUs exceeds defined threshold. + * Threshold is defined as number of ISO events. If number of queued SDUs + * exceeds number of SDUs required for single event (i.e. including pt) + * and number of subsequent ISO events defined by threshold value, we'll + * drop any excessive SDUs and notify host as if they were sent. + */ + uint32_t thr = MYNEWT_VAL(BLE_LL_ISO_HCI_DISCARD_THRESHOLD); + if (mux->sdu_q_len > mux->sdu_per_event + thr * mux->sdu_per_interval) { + num_sdu = mux->sdu_q_len - mux->sdu_per_event - + thr * mux->sdu_per_interval; + } +#endif + + /* Drop num_pdu PDUs */ + pkthdr = STAILQ_FIRST(&mux->sdu_q); + while (pkthdr && num_sdu--) { + om = OS_MBUF_PKTHDR_TO_MBUF(pkthdr); + + while (om && num_pdu > 0) { + rem_len = om->om_len; + hdr_len = sc ? 2 /* Segmentation Header */ + : 5 /* Segmentation Header + TimeOffset */; + + if (mux->max_pdu <= hdr_len + pdu_offset) { + /* Advance to next PDU */ + pdu_offset = 0; + num_pdu--; + continue; + } + + frag_len = min(rem_len, mux->max_pdu - hdr_len - pdu_offset); + + pdu_offset += hdr_len + frag_len; + + os_mbuf_adj(om, frag_len); + + if (frag_len == rem_len) { + om_next = SLIST_NEXT(om, om_next); + os_mbuf_free(om); + pkt_freed++; + om = om_next; + } else { + sc = 1; + } + } + + if (num_pdu == 0) { + break; + } + + OS_ENTER_CRITICAL(sr); + STAILQ_REMOVE_HEAD(&mux->sdu_q, omp_next); + BLE_LL_ASSERT(mux->sdu_q_len > 0); + mux->sdu_q_len--; + OS_EXIT_CRITICAL(sr); + + sc = 0; + pkthdr = STAILQ_FIRST(&mux->sdu_q); + } + + mux->sdu_in_event = 0; + mux->sc = sc; + + return pkt_freed; +} + +int +ble_ll_isoal_mux_event_done(struct ble_ll_isoal_mux *mux) +{ + struct os_mbuf_pkthdr *pkthdr; + struct ble_mbuf_hdr *blehdr; + struct os_mbuf *om; + + pkthdr = STAILQ_FIRST(&mux->sdu_q); + if (pkthdr) { + om = OS_MBUF_PKTHDR_TO_MBUF(pkthdr); + blehdr = BLE_MBUF_HDR_PTR(om); + mux->last_tx_timestamp = mux->event_tx_timestamp; + mux->last_tx_packet_seq_num = blehdr->txiso.packet_seq_num; + } + + if (mux->framed) { + return ble_ll_isoal_mux_framed_event_done(mux); + } + + return ble_ll_isoal_mux_unframed_event_done(mux); +} + +static int +ble_ll_isoal_mux_unframed_get(struct ble_ll_isoal_mux *mux, uint8_t idx, + uint8_t *llid, void *dptr) +{ + struct os_mbuf_pkthdr *pkthdr; + struct os_mbuf *om; + int32_t rem_len; + uint8_t sdu_idx; + uint8_t pdu_idx; + uint16_t sdu_offset; + uint8_t pdu_len; + + sdu_idx = idx / mux->pdu_per_sdu; + pdu_idx = idx - sdu_idx * mux->pdu_per_sdu; + + if (sdu_idx >= mux->sdu_in_event) { + *llid = 0; + return 0; + } + + pkthdr = STAILQ_FIRST(&mux->sdu_q); + while (pkthdr && sdu_idx--) { + pkthdr = STAILQ_NEXT(pkthdr, omp_next); + } + + if (!pkthdr) { + *llid = 0; + return 0; + } + + om = OS_MBUF_PKTHDR_TO_MBUF(pkthdr); + sdu_offset = pdu_idx * mux->max_pdu; + rem_len = OS_MBUF_PKTLEN(om) - sdu_offset; + + if (OS_MBUF_PKTLEN(om) == 0) { + /* LLID = 0b00: Zero-Length SDU (complete SDU) */ + *llid = 0; + pdu_len = 0; + } else if (rem_len <= 0) { + /* LLID = 0b01: ISO Data PDU used as padding */ + *llid = 1; + pdu_len = 0; + } else { + /* LLID = 0b00: Data remaining fits the ISO Data PDU size, + * it's end fragment of an SDU or complete SDU. + * LLID = 0b01: Data remaining exceeds the ISO Data PDU size, + * it's start or continuation fragment of an SDU. + */ + *llid = rem_len > mux->max_pdu; + pdu_len = min(mux->max_pdu, rem_len); + } + + os_mbuf_copydata(om, sdu_offset, pdu_len, dptr); + + return pdu_len; +} + +static int +ble_ll_isoal_mux_framed_get(struct ble_ll_isoal_mux *mux, uint8_t idx, + uint8_t *llid, uint8_t *dptr) +{ + struct ble_mbuf_hdr *blehdr; + struct os_mbuf_pkthdr *pkthdr; + struct os_mbuf *om; + uint32_t time_offset; + uint16_t seghdr; + uint16_t rem_len = 0; + uint16_t sdu_offset = 0; + uint8_t num_sdu; + uint8_t num_pdu; + uint8_t frag_len; + uint8_t pdu_offset = 0; + bool sc = mux->sc; + uint8_t hdr_len = 0; + + *llid = 0b10; + + num_sdu = mux->sdu_in_event; + if (num_sdu == 0) { + return 0; + } + + num_pdu = idx; + + /* Skip the idx PDUs */ + pkthdr = STAILQ_FIRST(&mux->sdu_q); + while (pkthdr && num_sdu > 0 && num_pdu > 0) { + om = OS_MBUF_PKTHDR_TO_MBUF(pkthdr); + + rem_len = OS_MBUF_PKTLEN(om) - sdu_offset; + hdr_len = sc ? 2 /* Segmentation Header */ + : 5 /* Segmentation Header + TimeOffset */; + + if (mux->max_pdu <= hdr_len + pdu_offset) { + /* Advance to next PDU */ + pdu_offset = 0; + num_pdu--; + continue; + } + + frag_len = min(rem_len, mux->max_pdu - hdr_len - pdu_offset); + + pdu_offset += hdr_len + frag_len; + + if (frag_len == rem_len) { + /* Process next SDU */ + sdu_offset = 0; + num_sdu--; + pkthdr = STAILQ_NEXT(pkthdr, omp_next); + + sc = 0; + } else { + sdu_offset += frag_len; + + sc = 1; + } + } + + if (num_pdu > 0) { + return 0; + } + + BLE_LL_ASSERT(pdu_offset == 0); + + while (pkthdr && num_sdu > 0) { + om = OS_MBUF_PKTHDR_TO_MBUF(pkthdr); + + rem_len = OS_MBUF_PKTLEN(om) - sdu_offset; + hdr_len = sc ? 2 /* Segmentation Header */ + : 5 /* Segmentation Header + TimeOffset */; + + if (mux->max_pdu <= hdr_len + pdu_offset) { + break; + } + + frag_len = min(rem_len, mux->max_pdu - hdr_len - pdu_offset); + + /* Segmentation Header */ + seghdr = BLE_LL_ISOAL_SEGHDR(sc, frag_len == rem_len, frag_len + hdr_len - 2); + put_le16(dptr + pdu_offset, seghdr); + pdu_offset += 2; + + /* Time Offset */ + if (hdr_len > 2) { + blehdr = BLE_MBUF_HDR_PTR(om); + + time_offset = mux->event_tx_timestamp - + blehdr->txiso.cpu_timestamp; + put_le24(dptr + pdu_offset, time_offset); + pdu_offset += 3; + } + + /* ISO Data Fragment */ + os_mbuf_copydata(om, sdu_offset, frag_len, dptr + pdu_offset); + pdu_offset += frag_len; + + if (frag_len == rem_len) { + /* Process next SDU */ + sdu_offset = 0; + num_sdu--; + pkthdr = STAILQ_NEXT(pkthdr, omp_next); + + sc = 0; + } else { + sdu_offset += frag_len; + + sc = 1; + } + } + + return pdu_offset; +} + +int +ble_ll_isoal_mux_pdu_get(struct ble_ll_isoal_mux *mux, uint8_t idx, + uint8_t *llid, void *dptr) +{ + if (mux->framed) { + return ble_ll_isoal_mux_framed_get(mux, idx, llid, dptr); + } + + return ble_ll_isoal_mux_unframed_get(mux, idx, llid, dptr); +} + +void +ble_ll_isoal_init(void) +{ +} + +void +ble_ll_isoal_reset(void) +{ +} + +#endif /* BLE_LL_ISO */ diff --git a/nimble/controller/src/ble_ll_pdu.c b/nimble/controller/src/ble_ll_pdu.c new file mode 100644 index 0000000000..bcbb5ff06b --- /dev/null +++ b/nimble/controller/src/ble_ll_pdu.c @@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include + +static const uint16_t syncword_len[] = { + [BLE_PHY_MODE_1M] = (BLE_LL_PDU_PREAMBLE_1M_LEN + BLE_LL_PDU_AA_LEN) * 8, + [BLE_PHY_MODE_2M] = (BLE_LL_PDU_PREAMBLE_2M_LEN + BLE_LL_PDU_AA_LEN) * 4, + [BLE_PHY_MODE_CODED_125KBPS] = 80 + 256 + 16 + 24, + [BLE_PHY_MODE_CODED_500KBPS] = 80 + 256 + 16 + 24, +}; + +static const uint16_t payload0_len[] = { + [BLE_PHY_MODE_1M] = (BLE_LL_PDU_PREAMBLE_1M_LEN + BLE_LL_PDU_AA_LEN + + BLE_LL_PDU_HEADER_LEN + BLE_LL_PDU_CRC_LEN) * 8, + [BLE_PHY_MODE_2M] = (BLE_LL_PDU_PREAMBLE_2M_LEN + BLE_LL_PDU_AA_LEN + + BLE_LL_PDU_HEADER_LEN + BLE_LL_PDU_CRC_LEN) * 4, + [BLE_PHY_MODE_CODED_125KBPS] = 80 + 256 + 16 + 24 + + 8 * (BLE_LL_PDU_HEADER_LEN * 8 + 24 + 3), + [BLE_PHY_MODE_CODED_500KBPS] = 80 + 256 + 16 + 24 + + 2 * (BLE_LL_PDU_HEADER_LEN * 8 + 24 + 3), +}; + +static const uint8_t us_per_octet[] = { + [BLE_PHY_MODE_1M] = 8, + [BLE_PHY_MODE_2M] = 4, + [BLE_PHY_MODE_CODED_125KBPS] = 64, + [BLE_PHY_MODE_CODED_500KBPS] = 16, +}; + +uint32_t +ble_ll_pdu_syncword_us(uint8_t phy_mode) +{ + return syncword_len[phy_mode]; +} + +uint32_t +ble_ll_pdu_us(uint8_t payload_len, uint8_t phy_mode) +{ + return payload0_len[phy_mode] + (payload_len * us_per_octet[phy_mode]); +} diff --git a/nimble/controller/src/ble_ll_priv.h b/nimble/controller/src/ble_ll_priv.h index 900950ef64..f0498fea8a 100644 --- a/nimble/controller/src/ble_ll_priv.h +++ b/nimble/controller/src/ble_ll_priv.h @@ -24,6 +24,36 @@ extern "C" { #endif +extern int8_t g_ble_ll_tx_power; +extern int8_t g_ble_ll_tx_power_compensation; +extern int8_t g_ble_ll_rx_power_compensation; + +int ble_ll_tx_power_round(int tx_power); +void ble_ll_tx_power_set(int tx_power); + +static inline int +ble_ll_rx_gain(void) +{ + int gain = g_ble_ll_rx_power_compensation; + +#if MYNEWT_VAL(BLE_FEM_LNA) +#if MYNEWT_VAL(BLE_FEM_LNA_GAIN_TUNABLE) + gain += ble_fem_lna_rx_gain(); +#else + gain += MYNEWT_VAL(BLE_FEM_LNA_GAIN); +#endif +#endif + + return gain; +} + +/* if there is any radio related activity enabled + * (scanning, advertising, connection etc) + */ +#define BLE_LL_BUSY_EXCLUDE_CONNECTIONS 0x01 + +int ble_ll_is_busy(unsigned int flags); + #ifdef MYNEWT #include "syscfg/syscfg.h" diff --git a/nimble/controller/src/ble_ll_rand.c b/nimble/controller/src/ble_ll_rand.c index 8aa7127160..fc7febcf48 100644 --- a/nimble/controller/src/ble_ll_rand.c +++ b/nimble/controller/src/ble_ll_rand.c @@ -33,6 +33,14 @@ #include "trng/trng.h" #endif +#ifdef RIOT_VERSION +#include "random.h" +#endif + +#if BABBLESIM +extern void tm_tick(void); +#endif + #if MYNEWT_VAL(TRNG) static struct trng_dev *g_trng; #else @@ -116,6 +124,9 @@ ble_ll_rand_data_get(uint8_t *buf, uint8_t len) while ((g_ble_ll_rnum_data.rnd_size < len) && (g_ble_ll_rnum_data.rnd_size < MYNEWT_VAL(BLE_LL_RNG_BUFSIZE))) { /* Spin here */ +#if BABBLESIM + tm_tick(); +#endif } } } @@ -127,6 +138,7 @@ ble_ll_rand_data_get(uint8_t *buf, uint8_t len) uint32_t ble_ll_rand(void) { +#ifndef RIOT_VERSION static unsigned short xsubi[3]; static bool init = true; @@ -136,6 +148,9 @@ ble_ll_rand(void) } return (uint32_t) jrand48(xsubi); +#else + return random_uint32(); +#endif } /** diff --git a/nimble/controller/src/ble_ll_resolv.c b/nimble/controller/src/ble_ll_resolv.c index 02af93040a..3566876e09 100644 --- a/nimble/controller/src/ble_ll_resolv.c +++ b/nimble/controller/src/ble_ll_resolv.c @@ -31,6 +31,7 @@ #include "controller/ble_ll_sync.h" #include "controller/ble_hw.h" #include "ble_ll_conn_priv.h" +#include "ble_ll_priv.h" #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) struct ble_ll_resolv_data @@ -47,18 +48,16 @@ struct ble_ll_resolv_data g_ble_ll_resolv_data; __attribute__((aligned(4))) struct ble_ll_resolv_entry g_ble_ll_resolv_list[MYNEWT_VAL(BLE_LL_RESOLV_LIST_SIZE)]; -static int -ble_ll_is_controller_busy(void) -{ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) - if (ble_ll_sync_enabled()) { - return 1; - } +#if MYNEWT_VAL(BLE_LL_HCI_VS_LOCAL_IRK) +struct local_irk_data { + uint8_t is_set; + uint8_t irk[16]; + uint8_t rpa[6]; +}; +/* 0 is for public, 1 is for static address */ +static struct local_irk_data g_local_irk[2]; #endif - return ble_ll_adv_enabled() || ble_ll_scan_enabled() || - g_ble_ll_conn_create_sm; -} /** * Called to determine if a change is allowed to the resolving list at this * time. We are not allowed to modify the resolving list if address translation @@ -73,7 +72,7 @@ ble_ll_resolv_list_chg_allowed(void) int rc; if (g_ble_ll_resolv_data.addr_res_enabled && - ble_ll_is_controller_busy()) { + ble_ll_is_busy(BLE_LL_BUSY_EXCLUDE_CONNECTIONS)) { rc = 0; } else { rc = 1; @@ -81,6 +80,30 @@ ble_ll_resolv_list_chg_allowed(void) return rc; } +static void +generate_rpa(const uint8_t *irk, uint8_t *rpa) +{ + uint8_t *prand; + struct ble_encryption_block ecb; + + /* Get prand */ + prand = rpa + 3; + ble_ll_rand_prand_get(prand); + + /* Calculate hash, hash = ah(local IRK, prand) */ + memcpy(ecb.key, irk, 16); + memset(ecb.plain_text, 0, 13); + ecb.plain_text[13] = prand[2]; + ecb.plain_text[14] = prand[1]; + ecb.plain_text[15] = prand[0]; + + /* Calculate hash */ + ble_hw_encrypt_block(&ecb); + + rpa[0] = ecb.cipher_text[15]; + rpa[1] = ecb.cipher_text[14]; + rpa[2] = ecb.cipher_text[13]; +} /** * Called to generate a resolvable private address in rl structure @@ -92,8 +115,6 @@ static void ble_ll_resolv_gen_priv_addr(struct ble_ll_resolv_entry *rl, int local) { uint8_t *irk; - uint8_t *prand; - struct ble_encryption_block ecb; uint8_t *addr; BLE_LL_ASSERT(rl != NULL); @@ -106,23 +127,7 @@ ble_ll_resolv_gen_priv_addr(struct ble_ll_resolv_entry *rl, int local) irk = rl->rl_peer_irk; } - /* Get prand */ - prand = addr + 3; - ble_ll_rand_prand_get(prand); - - /* Calculate hash, hash = ah(local IRK, prand) */ - memcpy(ecb.key, irk, 16); - memset(ecb.plain_text, 0, 13); - ecb.plain_text[13] = prand[2]; - ecb.plain_text[14] = prand[1]; - ecb.plain_text[15] = prand[0]; - - /* Calculate hash */ - ble_hw_encrypt_block(&ecb); - - addr[0] = ecb.cipher_text[15]; - addr[1] = ecb.cipher_text[14]; - addr[2] = ecb.cipher_text[13]; + generate_rpa(irk, addr); } /** @@ -135,6 +140,10 @@ ble_ll_resolv_rpa_timer_cb(struct ble_npl_event *ev) int i; os_sr_t sr; struct ble_ll_resolv_entry *rl; +#if MYNEWT_VAL(BLE_LL_HCI_VS_LOCAL_IRK) + struct local_irk_data *irk_data; + uint8_t rpa[6]; +#endif rl = &g_ble_ll_resolv_list[0]; for (i = 0; i < g_ble_ll_resolv_data.rl_cnt; ++i) { @@ -152,10 +161,24 @@ ble_ll_resolv_rpa_timer_cb(struct ble_npl_event *ev) ++rl; } +#if MYNEWT_VAL(BLE_LL_HCI_VS_LOCAL_IRK) + for (i = 0; i < ARRAY_SIZE(g_local_irk); i++) { + irk_data = &g_local_irk[i]; + if (irk_data->is_set) { + generate_rpa(irk_data->irk, rpa); + OS_ENTER_CRITICAL(sr); + memcpy(irk_data->rpa, rpa, 6); + OS_EXIT_CRITICAL(sr); + } + } +#endif + ble_npl_callout_reset(&g_ble_ll_resolv_data.rpa_timer, g_ble_ll_resolv_data.rpa_tmo); +#if MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) ble_ll_adv_rpa_timeout(); +#endif } /** @@ -437,8 +460,8 @@ ble_ll_resolv_enable_cmd(const uint8_t *cmdbuf, uint8_t len) return BLE_ERR_INV_HCI_CMD_PARMS; } - if (ble_ll_is_controller_busy()) { - return BLE_ERR_CMD_DISALLOWED; + if (ble_ll_is_busy(BLE_LL_BUSY_EXCLUDE_CONNECTIONS)) { + return BLE_ERR_CMD_DISALLOWED; } @@ -455,8 +478,8 @@ int ble_ll_resolv_peer_addr_rd(const uint8_t *cmdbuf, uint8_t len, uint8_t *rspbuf, uint8_t *rsplen) { - const struct ble_hci_le_rd_peer_recolv_addr_cp *cmd = (const void *) cmdbuf; - struct ble_hci_le_rd_peer_recolv_addr_rp *rsp = (void *) rspbuf; + const struct ble_hci_le_rd_peer_resolv_addr_cp *cmd = (const void *) cmdbuf; + struct ble_hci_le_rd_peer_resolv_addr_rp *rsp = (void *) rspbuf; struct ble_ll_resolv_entry *rl; int rc; @@ -481,8 +504,8 @@ int ble_ll_resolv_local_addr_rd(const uint8_t *cmdbuf, uint8_t len, uint8_t *rspbuf, uint8_t *rsplen) { - const struct ble_hci_le_rd_local_recolv_addr_cp *cmd = (const void *) cmdbuf; - struct ble_hci_le_rd_local_recolv_addr_rp *rsp = (void *) rspbuf; + const struct ble_hci_le_rd_local_resolv_addr_cp *cmd = (const void *) cmdbuf; + struct ble_hci_le_rd_local_resolv_addr_rp *rsp = (void *) rspbuf; struct ble_ll_resolv_entry *rl; int rc; @@ -542,7 +565,7 @@ ble_ll_resolve_set_priv_mode(const uint8_t *cmdbuf, uint8_t len) const struct ble_hci_le_set_privacy_mode_cp *cmd = (const void *) cmdbuf; struct ble_ll_resolv_entry *rl; - if (ble_ll_is_controller_busy()) { + if (ble_ll_is_busy(BLE_LL_BUSY_EXCLUDE_CONNECTIONS)) { return BLE_ERR_CMD_DISALLOWED; } @@ -646,6 +669,58 @@ ble_ll_resolv_gen_rpa(uint8_t *addr, uint8_t addr_type, uint8_t *rpa, int local) return 0; } +#if MYNEWT_VAL(BLE_LL_HCI_VS_LOCAL_IRK) +int +ble_ll_resolv_local_irk_set(uint8_t own_addr_type, const uint8_t *irk) +{ + struct local_irk_data *irk_data; + int i; + + if (own_addr_type >= 2) { + return -1; + } + + irk_data = &g_local_irk[own_addr_type]; + + memcpy(irk_data->irk, irk, 16); + + irk_data->is_set = 0; + + for (i = 0; i < 16; i++) { + if (irk[i]) { + irk_data->is_set = 1; + break; + } + } + + if (irk_data->is_set) { + generate_rpa(irk_data->irk, irk_data->rpa); + } + + return 0; +} + +int +ble_ll_resolv_local_rpa_get(uint8_t own_addr_type, uint8_t *rpa) +{ + struct local_irk_data *irk_data; + + if (own_addr_type >= 2) { + return -1; + } + + irk_data = &g_local_irk[own_addr_type]; + + if (!irk_data->is_set) { + return -1; + } + + memcpy(rpa, irk_data->rpa, 6); + + return 0; +} +#endif + /** * Resolve a Resolvable Private Address * @@ -747,6 +822,10 @@ ble_ll_resolv_init(void) &g_ble_ll_data.ll_evq, ble_ll_resolv_rpa_timer_cb, NULL); + +#if MYNEWT_VAL(BLE_LL_HCI_VS_LOCAL_IRK) + memset(&g_local_irk, 0, sizeof(g_local_irk)); +#endif } #endif /* if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) */ diff --git a/nimble/controller/src/ble_ll_rfmgmt.c b/nimble/controller/src/ble_ll_rfmgmt.c index 3bf5d5fae6..a9fd64ecb4 100644 --- a/nimble/controller/src/ble_ll_rfmgmt.c +++ b/nimble/controller/src/ble_ll_rfmgmt.c @@ -20,13 +20,13 @@ #include #include #include -#include #include "syscfg/syscfg.h" -#include "os/os_cputime.h" #include "controller/ble_phy.h" #include "controller/ble_ll.h" #include "controller/ble_ll_sched.h" #include "controller/ble_ll_rfmgmt.h" +#include "controller/ble_ll_tmr.h" +#include "ble_ll_priv.h" #if MYNEWT_VAL(BLE_LL_RFMGMT_ENABLE_TIME) > 0 @@ -40,7 +40,7 @@ struct ble_ll_rfmgmt_data { enum ble_ll_rfmgmt_state state; uint16_t ticks_to_enabled; - struct hal_timer timer; + struct ble_ll_tmr timer; bool timer_scheduled; uint32_t timer_scheduled_at; @@ -63,8 +63,9 @@ ble_ll_rfmgmt_enable(void) if (g_ble_ll_rfmgmt_data.state == RFMGMT_STATE_OFF) { g_ble_ll_rfmgmt_data.state = RFMGMT_STATE_ENABLING; - g_ble_ll_rfmgmt_data.enabled_at = os_cputime_get32(); + g_ble_ll_rfmgmt_data.enabled_at = ble_ll_tmr_get(); ble_phy_rfclk_enable(); + BLE_LL_DEBUG_GPIO(RFMGMT, 1); } } @@ -74,6 +75,7 @@ ble_ll_rfmgmt_disable(void) OS_ASSERT_CRITICAL(); if (g_ble_ll_rfmgmt_data.state != RFMGMT_STATE_OFF) { + BLE_LL_DEBUG_GPIO(RFMGMT, 0); ble_phy_rfclk_disable(); g_ble_ll_rfmgmt_data.state = RFMGMT_STATE_OFF; } @@ -98,7 +100,7 @@ ble_ll_rfmgmt_timer_reschedule(void) enable_at = rfmgmt->enable_sched_at; } else { rfmgmt->timer_scheduled = false; - os_cputime_timer_stop(&rfmgmt->timer); + ble_ll_tmr_stop(&rfmgmt->timer); return; } @@ -115,7 +117,7 @@ ble_ll_rfmgmt_timer_reschedule(void) } rfmgmt->timer_scheduled = false; - os_cputime_timer_stop(&rfmgmt->timer); + ble_ll_tmr_stop(&rfmgmt->timer); } /* @@ -125,14 +127,14 @@ ble_ll_rfmgmt_timer_reschedule(void) * such case it's absolutely harmless since we already have clock enabled * and this will do nothing. */ - if (CPUTIME_LEQ(enable_at, os_cputime_get32())) { + if (CPUTIME_LEQ(enable_at, ble_ll_tmr_get())) { ble_ll_rfmgmt_enable(); return; } rfmgmt->timer_scheduled = true; rfmgmt->timer_scheduled_at = enable_at; - os_cputime_timer_start(&rfmgmt->timer, enable_at); + ble_ll_tmr_start(&rfmgmt->timer, enable_at); } static void @@ -153,7 +155,7 @@ ble_ll_rfmgmt_release_ev(struct ble_npl_event *ev) OS_ENTER_CRITICAL(sr); - now = os_cputime_get32(); + now = ble_ll_tmr_get(); can_disable = true; lls = ble_ll_state_get(); @@ -188,7 +190,7 @@ ble_ll_rfmgmt_ticks_to_enabled(void) rem_ticks = rfmgmt->ticks_to_enabled; break; case RFMGMT_STATE_ENABLING: - now = os_cputime_get32(); + now = ble_ll_tmr_get(); if (CPUTIME_LT(now, rfmgmt->enabled_at + rfmgmt->ticks_to_enabled)) { rem_ticks = rfmgmt->enabled_at + rfmgmt->ticks_to_enabled - now; break; @@ -212,13 +214,15 @@ ble_ll_rfmgmt_init(void) { struct ble_ll_rfmgmt_data *rfmgmt = &g_ble_ll_rfmgmt_data; + BLE_LL_DEBUG_GPIO_INIT(RFMGMT); + rfmgmt->state = RFMGMT_STATE_OFF; rfmgmt->ticks_to_enabled = - ble_ll_usecs_to_ticks_round_up(MYNEWT_VAL(BLE_LL_RFMGMT_ENABLE_TIME)); + ble_ll_tmr_u2t_up(MYNEWT_VAL(BLE_LL_RFMGMT_ENABLE_TIME)); rfmgmt->timer_scheduled = false; - os_cputime_timer_init(&rfmgmt->timer, ble_ll_rfmgmt_timer_exp, NULL); + ble_ll_tmr_init(&rfmgmt->timer, ble_ll_rfmgmt_timer_exp, NULL); ble_npl_event_init(&rfmgmt->release_ev, ble_ll_rfmgmt_release_ev, NULL); } @@ -230,9 +234,9 @@ ble_ll_rfmgmt_reset(void) rfmgmt->timer_scheduled = false; rfmgmt->timer_scheduled_at = 0; - os_cputime_timer_stop(&rfmgmt->timer); + ble_ll_tmr_stop(&rfmgmt->timer); - ble_npl_eventq_remove(&g_ble_ll_data.ll_evq, &rfmgmt->release_ev); + ble_ll_event_remove(&rfmgmt->release_ev); ble_ll_rfmgmt_disable(); @@ -286,10 +290,10 @@ ble_ll_rfmgmt_release(void) OS_ENTER_CRITICAL(sr); - ble_npl_eventq_remove(&g_ble_ll_data.ll_evq, &rfmgmt->release_ev); + ble_ll_event_remove(&rfmgmt->release_ev); if (g_ble_ll_rfmgmt_data.state != RFMGMT_STATE_OFF) { - ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &rfmgmt->release_ev); + ble_ll_event_add(&rfmgmt->release_ev); } OS_EXIT_CRITICAL(sr); @@ -307,7 +311,7 @@ ble_ll_rfmgmt_enable_now(void) ble_ll_rfmgmt_enable(); if (rfmgmt->state == RFMGMT_STATE_ENABLED) { - enabled_at = os_cputime_get32(); + enabled_at = ble_ll_tmr_get(); } else { enabled_at = rfmgmt->enabled_at + rfmgmt->ticks_to_enabled + 1; } diff --git a/nimble/controller/src/ble_ll_scan.c b/nimble/controller/src/ble_ll_scan.c index 7eac16b5ae..0f73fd2e8c 100644 --- a/nimble/controller/src/ble_ll_scan.c +++ b/nimble/controller/src/ble_ll_scan.c @@ -23,17 +23,17 @@ #include #include "syscfg/syscfg.h" #include "os/os.h" -#include "os/os_cputime.h" #include "nimble/ble.h" -#include "nimble/nimble_opt.h" #include "nimble/hci_common.h" -#include "nimble/ble_hci_trans.h" #include "controller/ble_phy.h" #include "controller/ble_hw.h" #include "controller/ble_ll.h" #include "controller/ble_ll_sched.h" -#include "controller/ble_ll_adv.h" #include "controller/ble_ll_scan.h" +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) +#include "controller/ble_ll_scan_aux.h" +#endif +#include "controller/ble_ll_tmr.h" #include "controller/ble_ll_hci.h" #include "controller/ble_ll_whitelist.h" #include "controller/ble_ll_resolv.h" @@ -41,6 +41,9 @@ #include "controller/ble_ll_trace.h" #include "controller/ble_ll_sync.h" #include "ble_ll_conn_priv.h" +#include "ble_ll_priv.h" + +#if MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) /* * XXX: @@ -64,30 +67,17 @@ #define SCAN_VALID_PHY_MASK (BLE_HCI_LE_PHY_1M_PREF_MASK) #endif -/* The scanning parameters set by host */ -static struct ble_ll_scan_params g_ble_ll_scan_params[BLE_LL_SCAN_PHY_NUMBER]; +struct ble_ll_scan_params { + uint8_t own_addr_type; + uint8_t scan_filt_policy; + struct ble_ll_scan_phy scan_phys[BLE_LL_SCAN_PHY_NUMBER]; +}; + +static struct ble_ll_scan_params g_ble_ll_scan_params; /* The scanning state machine global object */ static struct ble_ll_scan_sm g_ble_ll_scan_sm; -struct ble_ll_ext_adv_hdr -{ - uint8_t mode; - uint8_t hdr_len; - uint8_t hdr[0]; -}; - -struct ble_ll_scan_addr_data { - bool adva_present; - uint8_t adva_type; - uint8_t *adva; - uint8_t targeta_type; - uint8_t *targeta; - uint8_t adv_addr_type; - uint8_t *adv_addr; - struct ble_ll_resolv_entry *rl; -}; - /* * Structure used to store advertisers. This is used to limit sending scan * requests to the same advertiser and also to filter duplicate events sent @@ -140,128 +130,15 @@ static struct os_mempool g_scan_dup_pool; static TAILQ_HEAD(ble_ll_scan_dup_list, ble_ll_scan_dup_entry) g_scan_dup_list; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -#if MYNEWT_VAL(BLE_LL_EXT_ADV_AUX_PTR_CNT) != 0 -static os_membuf_t ext_scan_aux_mem[ OS_MEMPOOL_SIZE( - MYNEWT_VAL(BLE_LL_EXT_ADV_AUX_PTR_CNT), - sizeof (struct ble_ll_aux_data)) -]; -#else -#define ext_scan_aux_mem NULL -#endif - -static struct os_mempool ext_scan_aux_pool; - -static int ble_ll_scan_start(struct ble_ll_scan_sm *scansm, - struct ble_ll_sched_item *sch); - -static void -ble_ll_aux_scan_drop_event_cb(struct ble_npl_event *ev) -{ - struct ble_ll_aux_data *aux_data = ble_npl_event_get_arg(ev); - - ble_ll_scan_end_adv_evt(aux_data); - ble_ll_scan_aux_data_unref(aux_data); -} - -static void -ble_ll_aux_scan_drop(struct ble_ll_aux_data *aux_data) -{ - BLE_LL_ASSERT(aux_data); - - STATS_INC(ble_ll_stats, aux_scan_drop); - - ble_npl_event_init(&aux_data->ev, ble_ll_aux_scan_drop_event_cb, aux_data); - ble_ll_event_send(&aux_data->ev); -} - -static int -ble_ll_aux_scan_cb(struct ble_ll_sched_item *sch) -{ - struct ble_ll_scan_sm *scansm = &g_ble_ll_scan_sm; - uint8_t lls = ble_ll_state_get(); - uint32_t wfr_usec; - - STATS_INC(ble_ll_stats, aux_sched_cb); - - /* Drop the scheduled item if scan was disable or there is aux or scan - * response pending - */ - if (!scansm->scan_enabled || scansm->cur_aux_data || - scansm->scan_rsp_pending) { - ble_ll_aux_scan_drop(sch->cb_arg); - sch->cb_arg = NULL; - goto done; - } - - /* Check if there is no aux connect sent. If so drop the sched item */ - if (lls == BLE_LL_STATE_INITIATING && ble_ll_conn_init_pending_aux_conn_rsp()) { - ble_ll_aux_scan_drop(sch->cb_arg); - sch->cb_arg = NULL; - goto done; - } - - /* This function is called only when scanner is running. This can happen - * in 3 states: - * BLE_LL_STATE_SCANNING - * BLE_LL_STATE_INITIATING - * BLE_LL_STATE_STANDBY - */ - if (lls != BLE_LL_STATE_STANDBY) { - ble_phy_disable(); - ble_ll_state_set(BLE_LL_STATE_STANDBY); - } - - /* When doing RX for AUX pkt, cur_aux_data keeps valid aux data */ - scansm->cur_aux_data = sch->cb_arg; - sch->cb_arg = NULL; - BLE_LL_ASSERT(scansm->cur_aux_data != NULL); - scansm->cur_aux_data->scanning = 1; - - if (ble_ll_scan_start(scansm, sch)) { - ble_ll_scan_interrupted(scansm); - goto done; - } - - STATS_INC(ble_ll_stats, aux_fired_for_read); - - wfr_usec = scansm->cur_aux_data->offset_units ? 300 : 30; - ble_phy_wfr_enable(BLE_PHY_WFR_ENABLE_RX, 0, wfr_usec); - -done: - - return BLE_LL_SCHED_STATE_DONE; -} - static int -ble_ll_scan_ext_adv_init(struct ble_ll_aux_data **aux_data) -{ - struct ble_ll_aux_data *e; - - e = os_memblock_get(&ext_scan_aux_pool); - if (!e) { - return -1; - } - - memset(e, 0, sizeof(*e)); - e->sch.sched_cb = ble_ll_aux_scan_cb; - e->sch.sched_type = BLE_LL_SCHED_TYPE_AUX_SCAN; - e->ref_cnt = 1; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - e->rpa_index = -1; -#endif - ble_ll_trace_u32x2(BLE_LL_TRACE_ID_AUX_REF, (uint32_t)e, e->ref_cnt); - - *aux_data = e; - STATS_INC(ble_ll_stats, aux_allocated); +ble_ll_scan_start(struct ble_ll_scan_sm *scansm); - return 0; -} #endif static inline uint32_t ble_ll_scan_time_hci_to_ticks(uint16_t value) { - return os_cputime_usecs_to_ticks(value * BLE_HCI_SCAN_ITVL); + return ble_ll_tmr_u2t(value * BLE_HCI_SCAN_ITVL); } /* See Vol 6 Part B Section 4.4.3.2. Active scanning backoff */ @@ -298,14 +175,14 @@ ble_ll_scan_req_backoff(struct ble_ll_scan_sm *scansm, int success) BLE_LL_ASSERT(scansm->backoff_count <= 256); } -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) +#if MYNEWT_VAL(BLE_LL_SCAN_ACTIVE_SCAN_NRPA) static void ble_ll_scan_refresh_nrpa(struct ble_ll_scan_sm *scansm) { ble_npl_time_t now; now = ble_npl_time_get(); - if (CPUTIME_GEQ(now, scansm->scan_nrpa_timer)) { + if (LL_TMR_GEQ(now, scansm->scan_nrpa_timer)) { /* Generate new NRPA */ ble_ll_rand_data_get(scansm->scan_nrpa, BLE_DEV_ADDR_LEN); scansm->scan_nrpa[5] &= ~0xc0; @@ -316,29 +193,70 @@ ble_ll_scan_refresh_nrpa(struct ble_ll_scan_sm *scansm) } #endif -static void -ble_ll_scan_req_pdu_prepare(struct ble_ll_scan_sm *scansm, - const uint8_t *adv_addr, uint8_t adv_addr_type, - struct ble_ll_resolv_entry *rl) +struct ble_ll_scan_sm * +ble_ll_scan_sm_get(void) +{ + return &g_ble_ll_scan_sm; +} + +uint8_t +ble_ll_scan_get_own_addr_type(void) +{ + return g_ble_ll_scan_sm.own_addr_type; +} + +uint8_t +ble_ll_scan_get_filt_policy(void) +{ + return g_ble_ll_scan_sm.scan_filt_policy; +} + +uint8_t +ble_ll_scan_get_filt_dups(void) +{ + return g_ble_ll_scan_sm.scan_filt_dups; +} + +uint8_t +ble_ll_scan_backoff_kick(void) +{ + struct ble_ll_scan_sm *scansm = &g_ble_ll_scan_sm; + + if (scansm->backoff_count > 0) { + scansm->backoff_count--; + } + + return scansm->backoff_count; +} + +void +ble_ll_scan_backoff_update(int success) +{ + struct ble_ll_scan_sm *scansm = &g_ble_ll_scan_sm; + + ble_ll_scan_req_backoff(scansm, success); +} + +void +ble_ll_scan_make_req_pdu(struct ble_ll_scan_sm *scansm, uint8_t *pdu, + uint8_t *hdr_byte, uint8_t adva_type, + const uint8_t *adva, int rpa_index) { - uint8_t hdr_byte; - struct ble_ll_scan_pdu_data *pdu_data; uint8_t *scana; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + struct ble_ll_resolv_entry *rl; uint8_t rpa[BLE_DEV_ADDR_LEN]; #endif - pdu_data = &scansm->pdu_data; - /* Construct first PDU header byte */ - hdr_byte = BLE_ADV_PDU_TYPE_SCAN_REQ; - if (adv_addr_type) { - hdr_byte |= BLE_ADV_PDU_HDR_RXADD_RAND; + *hdr_byte = BLE_ADV_PDU_TYPE_SCAN_REQ; + if (adva_type) { + *hdr_byte |= BLE_ADV_PDU_HDR_RXADD_RAND; } /* Determine ScanA */ if (scansm->own_addr_type & 0x01) { - hdr_byte |= BLE_ADV_PDU_HDR_TXADD_RAND; + *hdr_byte |= BLE_ADV_PDU_HDR_TXADD_RAND; scana = g_random_addr; } else { scana = g_dev_addr; @@ -346,28 +264,48 @@ ble_ll_scan_req_pdu_prepare(struct ble_ll_scan_sm *scansm, #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) if (scansm->own_addr_type & 0x02) { - /* - * If device is on RL and we have local IRK, we use RPA generated using - * that IRK as ScanA. Otherwise we use NRPA as ScanA to prevent our - * device from being tracked when doing an active scan (Core 5.1, Vol 6, - * Part B, section 6.3) - */ + if (rpa_index >= 0) { + rl = &g_ble_ll_resolv_list[rpa_index]; + } else { + rl = NULL; + } + + /* Check if we should use RPA/NRPA instead of public/random address: + * - use RPA if device is on RL and has local IRK set + * - use RPA generated from local IRK if set + * - use NRPA if allowed by configuration + * */ + if (rl && rl->rl_has_local) { ble_ll_resolv_get_priv_addr(rl, 1, rpa); scana = rpa; } else { - ble_ll_scan_refresh_nrpa(scansm); - scana = scansm->scan_nrpa; + if (ble_ll_resolv_local_rpa_get(scansm->own_addr_type & 0x01, rpa) == 0) { + scana = rpa; + } else { +#if MYNEWT_VAL(BLE_LL_SCAN_ACTIVE_SCAN_NRPA) + ble_ll_scan_refresh_nrpa(scansm); + scana = scansm->scan_nrpa; +#endif + } } - hdr_byte |= BLE_ADV_PDU_HDR_TXADD_RAND; + *hdr_byte |= BLE_ADV_PDU_HDR_TXADD_RAND; } #endif - /* Save scan request data */ - pdu_data->hdr_byte = hdr_byte; - memcpy(pdu_data->scana, scana, BLE_DEV_ADDR_LEN); - memcpy(pdu_data->adva, adv_addr, BLE_DEV_ADDR_LEN); + memcpy(pdu, scana, BLE_DEV_ADDR_LEN); + memcpy(pdu + 6, adva, BLE_DEV_ADDR_LEN); +} + +static void +ble_ll_scan_req_pdu_prepare(struct ble_ll_scan_sm *scansm, + const uint8_t *adv_addr, uint8_t adv_addr_type, + int8_t rpa_index) +{ + ble_ll_scan_make_req_pdu(scansm, scansm->pdu_data.scana, + &scansm->pdu_data.hdr_byte, adv_addr_type, adv_addr, + rpa_index); } static uint8_t @@ -395,7 +333,7 @@ ble_ll_scan_get_ext_adv_report(struct ext_adv_report *copy_from) struct ext_adv_report *report; struct ble_hci_ev *hci_ev; - hci_ev = ( void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_LO); + hci_ev = ble_transport_alloc_evt(1); if (!hci_ev) { return NULL; } @@ -430,100 +368,13 @@ ble_ll_scan_get_ext_adv_report(struct ext_adv_report *copy_from) return hci_ev; } - -static void -ble_ll_scan_send_truncated(struct ble_ll_aux_data *aux_data) -{ - struct ble_hci_ev_le_subev_ext_adv_rpt *ev; - struct ext_adv_report *report; - struct ble_hci_ev *hci_ev; - - if (!ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_EXT_ADV_RPT)) { - return; - } - - BLE_LL_ASSERT(aux_data); - - /* No need to send if we did not send any report or sent truncated already */ - if (!(aux_data->flags_ll & BLE_LL_AUX_FLAG_HCI_SENT_ANY) || - (aux_data->flags_ll & BLE_LL_AUX_FLAG_HCI_SENT_TRUNCATED)) { - return; - } - - BLE_LL_ASSERT(aux_data->evt); - hci_ev = aux_data->evt; - aux_data->evt = NULL; - - hci_ev->length = sizeof(*ev) + sizeof(*report); - - ev = (void *) hci_ev->data; - report = ev->reports; - - report->data_len = 0; - - report->evt_type = aux_data->evt_type; - report->evt_type |= BLE_HCI_ADV_DATA_STATUS_TRUNCATED; - - if (aux_data->flags & BLE_LL_AUX_HAS_ADVA) { - memcpy(report->addr, aux_data->adva, 6); - report->addr_type = aux_data->adva_type; - } - - if (aux_data->flags & BLE_LL_AUX_HAS_TARGETA) { - memcpy(report->dir_addr, aux_data->targeta, 6); - report->dir_addr_type = aux_data->targeta_type; - } - - report->sid = aux_data->adi >> 12; - ble_ll_hci_event_send(hci_ev); - - aux_data->flags_ll |= BLE_LL_AUX_FLAG_SCAN_ERROR; - aux_data->flags_ll |= BLE_LL_AUX_FLAG_HCI_SENT_ANY; - aux_data->flags_ll |= BLE_LL_AUX_FLAG_HCI_SENT_TRUNCATED; -} - -static int -ble_ll_scan_get_adi(struct ble_ll_aux_data *aux_data, uint16_t *adi) -{ - if (!aux_data || !(aux_data->flags & BLE_LL_AUX_HAS_ADI)) { - return -1; - } - - *adi = aux_data->adi; - - return 0; -} - -void -ble_ll_scan_end_adv_evt(struct ble_ll_aux_data *aux_data) -{ - /* Make sure we send report with 'truncated' data state if needed */ - ble_ll_scan_send_truncated(aux_data); -} -#endif - -static void -ble_ll_scan_clean_cur_aux_data(void) -{ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - struct ble_ll_scan_sm *scansm = &g_ble_ll_scan_sm; - - /* If scanner was reading aux ptr, we need to clean it up */ - if (scansm->cur_aux_data) { - ble_ll_scan_end_adv_evt(scansm->cur_aux_data); - ble_ll_scan_aux_data_unref(scansm->cur_aux_data); - scansm->cur_aux_data = NULL; - } #endif -} void ble_ll_scan_halt(void) { struct ble_ll_scan_sm *scansm = &g_ble_ll_scan_sm; - ble_ll_scan_clean_cur_aux_data(); - /* Update backoff if we failed to receive scan response */ if (scansm->scan_rsp_pending) { scansm->scan_rsp_pending = 0; @@ -539,7 +390,7 @@ ble_ll_scan_halt(void) * * @return int 0: have not received a scan response; 1 otherwise. */ -static int +int ble_ll_scan_have_rxd_scan_rsp(uint8_t *addr, uint8_t txadd, uint8_t ext_adv, uint16_t adi) { @@ -583,7 +434,7 @@ ble_ll_scan_have_rxd_scan_rsp(uint8_t *addr, uint8_t txadd, } #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -static void +void ble_ll_scan_add_scan_rsp_adv(uint8_t *addr, uint8_t txadd, uint8_t ext_adv, uint16_t adi) { @@ -592,7 +443,7 @@ ble_ll_scan_add_scan_rsp_adv(uint8_t *addr, uint8_t txadd, /* XXX: for now, if we dont have room, just leave */ num_advs = g_ble_ll_scan_num_rsp_advs; - if (num_advs == MYNEWT_VAL(BLE_LL_NUM_SCAN_RSP_ADVS)) { + if (num_advs >= MYNEWT_VAL(BLE_LL_NUM_SCAN_RSP_ADVS)) { return; } @@ -662,7 +513,7 @@ ble_ll_hci_send_legacy_ext_adv_report(uint8_t evtype, break; default: BLE_LL_ASSERT(0); - ble_hci_trans_buf_free((uint8_t *) hci_ev); + ble_transport_free(hci_ev); return -1; } @@ -707,7 +558,7 @@ ble_ll_hci_send_adv_report(uint8_t evtype, return -1; } - hci_ev = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_LO); + hci_ev = ble_transport_alloc_evt(1); if (!hci_ev) { return -1; } @@ -744,7 +595,7 @@ ble_ll_hci_send_dir_adv_report(const uint8_t *addr, uint8_t addr_type, return -1; } - hci_ev = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_LO); + hci_ev = ble_transport_alloc_evt(1); if (!hci_ev) { return -1; } @@ -852,6 +703,14 @@ ble_ll_scan_send_adv_report(uint8_t pdu_type, } if (BLE_MBUF_HDR_TARGETA_RESOLVED(hdr)) { inita_type += 2; + } else { +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) + if (scansm->ext_scanning) { + if (ble_ll_is_rpa(inita, inita_type)) { + inita_type = 0xfe; + } + } +#endif } #endif @@ -859,20 +718,21 @@ ble_ll_scan_send_adv_report(uint8_t pdu_type, if (scansm->ext_scanning) { rc = ble_ll_hci_send_legacy_ext_adv_report(evtype, adva, adva_type, - hdr->rxinfo.rssi, + hdr->rxinfo.rssi - ble_ll_rx_gain(), adv_data_len, om, inita, inita_type); - goto done; - } +goto done; +} #endif if (subev == BLE_HCI_LE_SUBEV_DIRECT_ADV_RPT) { rc = ble_ll_hci_send_dir_adv_report(adva, adva_type, inita, inita_type, - hdr->rxinfo.rssi); + hdr->rxinfo.rssi - ble_ll_rx_gain()); goto done; } - rc = ble_ll_hci_send_adv_report(evtype, adva, adva_type, hdr->rxinfo.rssi, + rc = ble_ll_hci_send_adv_report(evtype, adva, adva_type, + hdr->rxinfo.rssi - ble_ll_rx_gain(), adv_data_len, om); done: if (!rc && scansm->scan_filt_dups) { @@ -880,27 +740,6 @@ ble_ll_scan_send_adv_report(uint8_t pdu_type, } } -static void -ble_ll_get_chan_to_scan(struct ble_ll_scan_sm *scansm, uint8_t *chan, - int *phy) -{ - struct ble_ll_scan_params *scanp = scansm->scanp; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - struct ble_ll_aux_data *aux_data = scansm->cur_aux_data; - - if (!scansm->ext_scanning || !aux_data || !aux_data->scanning) { - *chan = scanp->scan_chan; - *phy = scanp->phy; - return; - } - - *chan = aux_data->chan; - *phy = aux_data->aux_phy; -#else - *chan = scanp->scan_chan; - *phy = scanp->phy; -#endif -} /** * Called to enable the receiver for scanning. * @@ -911,29 +750,21 @@ ble_ll_get_chan_to_scan(struct ble_ll_scan_sm *scansm, uint8_t *chan, * @return int */ static int -ble_ll_scan_start(struct ble_ll_scan_sm *scansm, struct ble_ll_sched_item *sch) +ble_ll_scan_start(struct ble_ll_scan_sm *scansm) { int rc; - struct ble_ll_scan_params *scanp = scansm->scanp; - uint8_t scan_chan; -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) + struct ble_ll_scan_phy *scanp = scansm->scanp; + uint8_t chan; +#if MYNEWT_VAL(BLE_LL_PHY) uint8_t phy_mode; -#endif int phy; +#endif BLE_LL_ASSERT(scansm->scan_rsp_pending == 0); - ble_ll_get_chan_to_scan(scansm, &scan_chan, &phy); - - /* XXX: right now scheduled item is only present if we schedule for aux - * scan just make sanity check that we have proper combination of - * sch and resulting scan_chan - */ - BLE_LL_ASSERT(!sch || scan_chan < BLE_PHY_ADV_CHAN_START); - BLE_LL_ASSERT(sch || scan_chan >= BLE_PHY_ADV_CHAN_START); - /* Set channel */ - rc = ble_phy_setchan(scan_chan, BLE_ACCESS_ADDR_ADV, BLE_LL_CRCINIT_ADV); + chan = scanp->scan_chan; + rc = ble_phy_setchan(chan, BLE_ACCESS_ADDR_ADV, BLE_LL_CRCINIT_ADV); BLE_LL_ASSERT(rc == 0); /* @@ -954,21 +785,21 @@ ble_ll_scan_start(struct ble_ll_scan_sm *scansm, struct ble_ll_sched_item *sch) } #endif -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) +#if MYNEWT_VAL(BLE_LL_PHY) + phy = scanp->phy; phy_mode = ble_ll_phy_to_phy_mode(phy, BLE_HCI_LE_PHY_CODED_ANY); ble_phy_mode_set(phy_mode, phy_mode); #endif - /* XXX: probably need to make sure hfxo is running too */ - /* XXX: can make this better; want to just start asap. */ - if (sch) { - rc = ble_phy_rx_set_start_time(sch->start_time + - g_ble_ll_sched_offset_ticks, - sch->remainder); - } else { - rc = ble_phy_rx_set_start_time(os_cputime_get32() + - g_ble_ll_sched_offset_ticks, 0); + /* if scan is not passive we need to set tx power as we may end up sending + * package + */ + if (scansm->scanp->scan_type != BLE_SCAN_TYPE_PASSIVE) { + ble_ll_tx_power_set(g_ble_ll_tx_power); } + + rc = ble_phy_rx_set_start_time(ble_ll_tmr_get() + + g_ble_ll_sched_offset_ticks, 0); if (!rc || rc == BLE_PHY_ERR_RX_LATE) { /* If we are late here, it is still OK because we keep scanning. * Clear error @@ -976,18 +807,13 @@ ble_ll_scan_start(struct ble_ll_scan_sm *scansm, struct ble_ll_sched_item *sch) rc = 0; /* Enable/disable whitelisting */ - if (scanp->scan_filt_policy & 1) { + if (scansm->scan_filt_policy & 1) { ble_ll_whitelist_enable(); } else { ble_ll_whitelist_disable(); } - /* Set link layer state to scanning */ - if (scanp->scan_type == BLE_SCAN_TYPE_INITIATE) { - ble_ll_state_set(BLE_LL_STATE_INITIATING); - } else { - ble_ll_state_set(BLE_LL_STATE_SCANNING); - } + ble_ll_state_set(BLE_LL_STATE_SCANNING); } return rc; @@ -1005,7 +831,7 @@ ble_ll_scan_get_next_adv_prim_chan(uint8_t chan) } static uint32_t -ble_ll_scan_move_window_to(struct ble_ll_scan_params *scanp, uint32_t time) +ble_ll_scan_move_window_to(struct ble_ll_scan_phy *scanp, uint32_t time) { uint32_t end_time; @@ -1015,7 +841,7 @@ ble_ll_scan_move_window_to(struct ble_ll_scan_params *scanp, uint32_t time) */ end_time = scanp->timing.start_time + scanp->timing.window; - while (CPUTIME_GEQ(time, end_time)) { + while (LL_TMR_GEQ(time, end_time)) { scanp->timing.start_time += scanp->timing.interval; scanp->scan_chan = ble_ll_scan_get_next_adv_prim_chan(scanp->scan_chan); end_time = scanp->timing.start_time + scanp->timing.window; @@ -1025,7 +851,7 @@ ble_ll_scan_move_window_to(struct ble_ll_scan_params *scanp, uint32_t time) } static bool -ble_ll_scan_is_inside_window(struct ble_ll_scan_params *scanp, uint32_t time) +ble_ll_scan_is_inside_window(struct ble_ll_scan_phy *scanp, uint32_t time) { uint32_t start_time; @@ -1037,80 +863,10 @@ ble_ll_scan_is_inside_window(struct ble_ll_scan_params *scanp, uint32_t time) return true; } - return CPUTIME_GEQ(time, start_time) && - CPUTIME_LT(time, start_time + scanp->timing.window); -} - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -static void -ble_ll_scan_aux_data_free(struct ble_ll_aux_data *aux_data) -{ - if (aux_data) { - if (aux_data->evt) { - ble_hci_trans_buf_free((uint8_t *)aux_data->evt); - aux_data->evt = NULL; - } - os_memblock_put(&ext_scan_aux_pool, aux_data); - STATS_INC(ble_ll_stats, aux_freed); - } -} - -struct ble_ll_aux_data * -ble_ll_scan_aux_data_ref(struct ble_ll_aux_data *aux_data) -{ - os_sr_t sr; - - BLE_LL_ASSERT(aux_data); - - OS_ENTER_CRITICAL(sr); - aux_data->ref_cnt++; - ble_ll_trace_u32x2(BLE_LL_TRACE_ID_AUX_REF, (uint32_t) aux_data, aux_data->ref_cnt); - - OS_EXIT_CRITICAL(sr); - - return aux_data; -} - -void -ble_ll_scan_aux_data_unref(struct ble_ll_aux_data *aux_data) -{ - os_sr_t sr; - - BLE_LL_ASSERT(aux_data); - - OS_ENTER_CRITICAL(sr); - aux_data->ref_cnt--; - ble_ll_trace_u32x2(BLE_LL_TRACE_ID_AUX_UNREF, (uint32_t) aux_data, aux_data->ref_cnt); - - if (aux_data->ref_cnt == 0) { - /* - * Some validation to make sure that we completed scan properly: - * - we either did not send any report or sent completed/truncated - * - we only sent one of completed/truncated - * - in case of error, we wither did not send anything or sent truncated - */ - BLE_LL_ASSERT(!(aux_data->flags_ll & BLE_LL_AUX_FLAG_HCI_SENT_ANY) || - ((aux_data->flags_ll & BLE_LL_AUX_FLAG_HCI_SENT_ANY) && - (aux_data->flags_ll & (BLE_LL_AUX_FLAG_HCI_SENT_COMPLETED | BLE_LL_AUX_FLAG_HCI_SENT_TRUNCATED)))); - BLE_LL_ASSERT(!(aux_data->flags_ll & BLE_LL_AUX_FLAG_HCI_SENT_COMPLETED) || !(aux_data->flags_ll & BLE_LL_AUX_FLAG_HCI_SENT_TRUNCATED)); - BLE_LL_ASSERT(!(aux_data->flags_ll & BLE_LL_AUX_FLAG_SCAN_ERROR) || - !(aux_data->flags_ll & BLE_LL_AUX_FLAG_HCI_SENT_ANY) || - (aux_data->flags_ll & BLE_LL_AUX_FLAG_HCI_SENT_TRUNCATED)); - - ble_ll_scan_aux_data_free(aux_data); - } - - OS_EXIT_CRITICAL(sr); + return LL_TMR_GEQ(time, start_time) && + LL_TMR_LT(time, start_time + scanp->timing.window); } -static void -ble_ll_scan_sched_remove(struct ble_ll_sched_item *sch) -{ - ble_ll_scan_end_adv_evt(sch->cb_arg); - ble_ll_scan_aux_data_unref(sch->cb_arg); - sch->cb_arg = NULL; -} -#endif /** * Stop the scanning state machine */ @@ -1123,15 +879,14 @@ ble_ll_scan_sm_stop(int chk_disable) /* Stop the scanning timer */ scansm = &g_ble_ll_scan_sm; - os_cputime_timer_stop(&scansm->scan_timer); + ble_ll_tmr_stop(&scansm->scan_timer); /* Only set state if we are currently in a scan window */ if (chk_disable) { OS_ENTER_CRITICAL(sr); lls = ble_ll_state_get(); - if ((lls == BLE_LL_STATE_SCANNING) || - (lls == BLE_LL_STATE_INITIATING && chk_disable == 1)) { + if (lls == BLE_LL_STATE_SCANNING) { /* Disable phy */ ble_phy_disable(); @@ -1149,12 +904,15 @@ ble_ll_scan_sm_stop(int chk_disable) #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) if (scansm->ext_scanning) { - ble_ll_scan_clean_cur_aux_data(); - ble_ll_sched_rmv_elem_type(BLE_LL_SCHED_TYPE_AUX_SCAN, ble_ll_scan_sched_remove); + ble_ll_sched_rmv_elem_type(BLE_LL_SCHED_TYPE_SCAN_AUX, ble_ll_scan_aux_sched_remove); scansm->ext_scanning = 0; } #endif +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + scansm->connsm = NULL; +#endif + /* Update backoff if we failed to receive scan response */ if (scansm->scan_rsp_pending) { scansm->scan_rsp_pending = 0; @@ -1175,8 +933,8 @@ ble_ll_scan_sm_stop(int chk_disable) static int ble_ll_scan_sm_start(struct ble_ll_scan_sm *scansm) { - struct ble_ll_scan_params *scanp; - struct ble_ll_scan_params *scanp_next; + struct ble_ll_scan_phy *scanp; + struct ble_ll_scan_phy *scanp_next; if (!ble_ll_is_valid_own_addr_type(scansm->own_addr_type, g_random_addr)) { return BLE_ERR_INV_HCI_CMD_PARMS; @@ -1224,54 +982,24 @@ ble_ll_scan_sm_start(struct ble_ll_scan_sm *scansm) } /* Start scan at 1st window */ - os_cputime_timer_start(&scansm->scan_timer, scanp->timing.start_time); + ble_ll_tmr_start(&scansm->scan_timer, scanp->timing.start_time); return BLE_ERR_SUCCESS; } -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -static void -ble_ll_aux_scan_rsp_failed(struct ble_ll_scan_sm *scansm) -{ - if (!scansm->cur_aux_data) { - return; - } - - STATS_INC(ble_ll_stats, aux_scan_rsp_err); - ble_ll_scan_interrupted(scansm); -} -#endif - static void ble_ll_scan_interrupted_event_cb(struct ble_npl_event *ev) { struct ble_ll_scan_sm *scansm = &g_ble_ll_scan_sm; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - struct ble_ll_aux_data *aux_data; -#endif if (!scansm->scan_enabled) { return; } -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - aux_data = ble_npl_event_get_arg(ev); - - if (aux_data) { - if (scansm->scan_rsp_pending) { - STATS_INC(ble_ll_stats, aux_scan_rsp_err); - } - ble_ll_scan_end_adv_evt(aux_data); - ble_ll_scan_aux_data_unref(aux_data); - ble_npl_event_set_arg(ev, NULL); - STATS_INC(ble_ll_stats, aux_missed_adv); - } -#endif - - /* - * If we timed out waiting for a response, the scan response pending - * flag should be set. Deal with scan backoff. Put device back into rx. - */ + /* + * If we timed out waiting for a response, the scan response pending + * flag should be set. Deal with scan backoff. Put device back into rx. + */ if (scansm->scan_rsp_pending) { scansm->scan_rsp_pending = 0; @@ -1295,10 +1023,10 @@ ble_ll_scan_event_proc(struct ble_npl_event *ev) os_sr_t sr; bool start_scan; bool inside_window; - struct ble_ll_scan_params *scanp; + struct ble_ll_scan_phy *scanp; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) bool inside_window_next; - struct ble_ll_scan_params *scanp_next; + struct ble_ll_scan_phy *scanp_next; #endif uint32_t next_proc_time; uint32_t now; @@ -1314,14 +1042,14 @@ ble_ll_scan_event_proc(struct ble_npl_event *ev) OS_ENTER_CRITICAL(sr); if (!scansm->scan_enabled) { - os_cputime_timer_stop(&scansm->scan_timer); + ble_ll_tmr_stop(&scansm->scan_timer); ble_ll_rfmgmt_scan_changed(false, 0); ble_ll_rfmgmt_release(); OS_EXIT_CRITICAL(sr); return; } - if (scansm->cur_aux_data || scansm->scan_rsp_pending) { + if (scansm->scan_rsp_pending) { /* Aux scan in progress. Wait */ STATS_INC(ble_ll_stats, scan_timer_stopped); scansm->restart_timer_needed = 1; @@ -1329,7 +1057,7 @@ ble_ll_scan_event_proc(struct ble_npl_event *ev) return; } - now = os_cputime_get32(); + now = ble_ll_tmr_get(); inside_window = ble_ll_scan_is_inside_window(scanp, now); @@ -1343,8 +1071,8 @@ ble_ll_scan_event_proc(struct ble_npl_event *ev) * inside window or has next window earlier than current PHY. */ if (!inside_window && - ((inside_window_next || CPUTIME_LEQ(scanp_next->timing.start_time, - scanp->timing.start_time)))) { + ((inside_window_next || LL_TMR_LEQ(scanp_next->timing.start_time, + scanp->timing.start_time)))) { scansm->scanp = scanp_next; scansm->scanp_next = scanp; scanp = scansm->scanp; @@ -1380,20 +1108,31 @@ ble_ll_scan_event_proc(struct ble_npl_event *ev) */ start_scan = inside_window; switch (ble_ll_state_get()) { +#if MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) case BLE_LL_STATE_ADV: + start_scan = false; + break; +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) case BLE_LL_STATE_CONNECTION: + start_scan = false; + break; +#endif +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) case BLE_LL_STATE_SYNC: - start_scan = false; - break; - case BLE_LL_STATE_INITIATING: - /* Must disable PHY since we will move to a new channel */ - ble_phy_disable(); - if (!inside_window) { - ble_ll_state_set(BLE_LL_STATE_STANDBY); - } - /* PHY is disabled - make sure we do not wait for AUX_CONNECT_RSP */ - ble_ll_conn_reset_pending_aux_conn_rsp(); + start_scan = false; + break; +#endif +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) + case BLE_LL_STATE_SCAN_AUX: + start_scan = false; break; +#endif +#if MYNEWT_VAL(BLE_LL_EXT) + case BLE_LL_STATE_EXTERNAL: + start_scan = false; + break; +#endif case BLE_LL_STATE_SCANNING: /* Must disable PHY since we will move to a new channel */ ble_phy_disable(); @@ -1401,6 +1140,11 @@ ble_ll_scan_event_proc(struct ble_npl_event *ev) ble_ll_state_set(BLE_LL_STATE_STANDBY); } break; +#if MYNEWT_VAL(BLE_LL_ISO_BROADCASTER) + case BLE_LL_STATE_BIG: + start_scan = false; + break; +#endif case BLE_LL_STATE_STANDBY: break; default: @@ -1409,13 +1153,13 @@ ble_ll_scan_event_proc(struct ble_npl_event *ev) } if (start_scan) { - ble_ll_scan_start(scansm, NULL); + ble_ll_scan_start(scansm); } else { ble_ll_rfmgmt_release(); } OS_EXIT_CRITICAL(sr); - os_cputime_timer_start(&scansm->scan_timer, next_proc_time); + ble_ll_tmr_start(&scansm->scan_timer, next_proc_time); } /** @@ -1438,7 +1182,7 @@ ble_ll_scan_rx_isr_start(uint8_t pdu_type, uint16_t *rxflags) { int rc; struct ble_ll_scan_sm *scansm; - struct ble_ll_scan_params *scanp; + struct ble_ll_scan_phy *scanp; rc = 0; scansm = &g_ble_ll_scan_sm; @@ -1459,10 +1203,6 @@ ble_ll_scan_rx_isr_start(uint8_t pdu_type, uint16_t *rxflags) } #endif - if (scansm->cur_aux_data && !scansm->scan_rsp_pending ) { - STATS_INC(ble_ll_stats, aux_received); - } - /* * If this is the first PDU after we sent the scan response (as * denoted by the scan rsp pending flag), we set a bit in the ble @@ -1479,9 +1219,6 @@ ble_ll_scan_rx_isr_start(uint8_t pdu_type, uint16_t *rxflags) *rxflags |= BLE_MBUF_HDR_F_SCAN_RSP_RXD; } else { ble_ll_scan_req_backoff(scansm, 0); -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - ble_ll_aux_scan_rsp_failed(scansm); -#endif } } break; @@ -1492,796 +1229,309 @@ ble_ll_scan_rx_isr_start(uint8_t pdu_type, uint16_t *rxflags) } break; #endif - default: - break; - } - - return rc; -} +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + case BLE_SCAN_TYPE_INITIATE: + if ((pdu_type == BLE_ADV_PDU_TYPE_ADV_IND) || + (pdu_type == BLE_ADV_PDU_TYPE_ADV_DIRECT_IND)) { + rc = 1; + } #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -static uint8_t -ble_ll_ext_adv_phy_mode_to_local_phy(uint8_t adv_phy_mode) -{ - switch (adv_phy_mode) { - case 0x00: - return BLE_PHY_1M; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY) - case 0x01: - return BLE_PHY_2M; + if ((pdu_type == BLE_ADV_PDU_TYPE_ADV_EXT_IND && scansm->ext_scanning)) { + *rxflags |= BLE_MBUF_HDR_F_EXT_ADV; + rc = 1; + } #endif -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) - case 0x02: - return BLE_PHY_CODED; + break; #endif + default: + break; } - return 0; + return rc; } -static int -ble_ll_ext_scan_parse_aux_ptr(struct ble_ll_aux_data *aux_data, uint8_t *buf) +static void +ble_ll_scan_get_addr_data_from_legacy(uint8_t pdu_type, uint8_t *rxbuf, + struct ble_ll_scan_addr_data *addrd) { - uint32_t aux_ptr_field = get_le32(buf) & 0x00FFFFFF; - - aux_data->chan = (aux_ptr_field) & 0x3F; - if (aux_data->chan >= BLE_PHY_NUM_DATA_CHANS) { - return -1; - } - - /* TODO use CA aux_ptr_field >> 6 */ - - aux_data->offset = 30 * ((aux_ptr_field >> 8) & 0x1FFF); - - if ((aux_ptr_field >> 7) & 0x01) { - aux_data->offset *= 10; - aux_data->offset_units = 1; - } + BLE_LL_ASSERT(pdu_type < BLE_ADV_PDU_TYPE_ADV_EXT_IND); - if (aux_data->offset < BLE_LL_MAFS) { - return -1; - } + addrd->adva = rxbuf + BLE_LL_PDU_HDR_LEN; + addrd->adva_type = ble_ll_get_addr_type(rxbuf[0] & BLE_ADV_PDU_HDR_TXADD_MASK); - aux_data->aux_phy = - ble_ll_ext_adv_phy_mode_to_local_phy((aux_ptr_field >> 21) & 0x07); - if (aux_data->aux_phy == 0) { - return -1; + if (pdu_type == BLE_ADV_PDU_TYPE_ADV_DIRECT_IND) { + addrd->targeta = rxbuf + BLE_LL_PDU_HDR_LEN + BLE_DEV_ADDR_LEN; + addrd->targeta_type = ble_ll_get_addr_type(rxbuf[0] & BLE_ADV_PDU_HDR_RXADD_MASK); + } else { + addrd->targeta = NULL; + addrd->targeta_type = 0; } - - return 0; } -static void -ble_ll_ext_scan_parse_adv_info(struct ext_adv_report *report, const uint8_t *buf) +int +ble_ll_scan_rx_filter(uint8_t own_addr_type, uint8_t scan_filt_policy, + struct ble_ll_scan_addr_data *addrd, uint8_t *scan_ok) { - uint16_t adv_info = get_le16(buf); +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + struct ble_ll_resolv_entry *rl = NULL; +#endif + bool scan_req_allowed = true; + bool resolved; - /* TODO Use DID */ + /* Note: caller is expected to fill adva, targeta and rpa_index in addrd */ - report->sid = (adv_info >> 12); -} + /* Use AdvA as initial advertiser address, we may change it if resolved */ + addrd->adv_addr = addrd->adva; + addrd->adv_addr_type = addrd->adva_type; -/** - * ble_ll_scan_update_aux_data - * - * Update aux_data stored in ble_hdr.rxinfo.user_data. If no aux_data is present - * (i.e. processing ADV_EXT_IND) this will try to allocate new aux_data. - * - * Context: Interrupt - * - * @param ble_hdr - * @param rxbuf - * - * @return int - * 1: do not scan for next AUX (no AuxPtr or malformed data) - * 0: scan for next AUX (valid AuxPtr found) - * -1: error - */ -int -ble_ll_scan_update_aux_data(struct ble_mbuf_hdr *ble_hdr, uint8_t *rxbuf, - bool *adva_present) -{ - uint8_t pdu_hdr; - uint8_t pdu_len; - uint8_t adv_mode; - uint8_t eh_len; - uint8_t eh_flags; - uint8_t *eh; - struct ble_ll_aux_data *aux_data; - bool is_aux; - - aux_data = ble_hdr->rxinfo.user_data; - /* aux_data is initially not set only for ADV_EXT_IND */ - is_aux = aux_data; - - pdu_hdr = rxbuf[0]; - pdu_len = rxbuf[1]; - - /* PDU without at least Extended Header Length is invalid */ - if (pdu_len == 0) { - return -1; - } +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + addrd->adva_resolved = 0; + addrd->targeta_resolved = 0; - adv_mode = rxbuf[2] >> 6; - eh_len = rxbuf[2] & 0x3f; - eh_flags = rxbuf[3]; - eh = &rxbuf[4]; + BLE_LL_ASSERT((addrd->rpa_index < 0) || + (ble_ll_addr_subtype(addrd->adva, addrd->adva_type) == + BLE_LL_ADDR_SUBTYPE_RPA)); - /* - * PDU without Extended Header is valid in case of last AUX_CHAIN_IND in - * chain so aux_data has to be set and advertising mode has to be 00b, - * otherwise it's an invalid PDU. - */ - if (eh_len == 0) { - if (!aux_data || adv_mode) { - return -1; + switch (ble_ll_addr_subtype(addrd->adva, addrd->adva_type)) { + case BLE_LL_ADDR_SUBTYPE_RPA: + if (addrd->rpa_index >= 0) { + addrd->adva_resolved = 1; + + /* Use resolved identity address as advertiser address */ + rl = &g_ble_ll_resolv_list[addrd->rpa_index]; + addrd->adv_addr = rl->rl_identity_addr; + addrd->adv_addr_type = rl->rl_addr_type; + break; } - aux_data->flags_isr |= BLE_LL_AUX_FLAG_SCAN_COMPLETE; - return 1; - } - /* - * If aux_data is not set, this is ADV_EXT_IND which starts new extended - * advertising event. - */ - if (!aux_data) { - if (ble_ll_scan_ext_adv_init(&aux_data)) { - return -1; + /* fall-through */ + case BLE_LL_ADDR_SUBTYPE_IDENTITY: + /* If AdvA is an identity address, we need to check if that device was + * added to RL in order to use proper privacy mode. + */ + rl = ble_ll_resolv_list_find(addrd->adva, addrd->adva_type); + if (!rl) { + break; } - aux_data->aux_primary_phy = ble_hdr->rxinfo.phy; - } else { - if (aux_data->flags_isr & BLE_LL_AUX_FLAG_AUX_ADV_RECEIVED) { - aux_data->flags_isr |= BLE_LL_AUX_FLAG_AUX_CHAIN_RECEIVED; - } else { - aux_data->flags_isr |= BLE_LL_AUX_FLAG_AUX_ADV_RECEIVED; + /* Ignore device if using network privacy mode and it has IRK */ + if ((rl->rl_priv_mode == BLE_HCI_PRIVACY_NETWORK) && rl->rl_has_peer) { + return -1; } + + addrd->rpa_index = ble_ll_resolv_get_idx(rl); + break; + default: + /* NRPA goes through filtering policy directly */ + break; } - /* Now parse extended header... */ + if (addrd->targeta) { + switch (ble_ll_addr_subtype(addrd->targeta, addrd->targeta_type)) { + case BLE_LL_ADDR_SUBTYPE_RPA: + /* Check if TargetA can be resolved using the same RL entry as AdvA */ + if (rl && ble_ll_resolv_rpa(addrd->targeta, rl->rl_local_irk)) { + addrd->targeta_resolved = 1; + break; + } + + /* Check if scan filter policy allows unresolved RPAs to be processed */ + if (!(scan_filt_policy & 0x02)) { + return -2; + } - if (eh_flags & (1 << BLE_LL_EXT_ADV_ADVA_BIT)) { - aux_data->flags |= BLE_LL_AUX_HAS_ADVA; - memcpy(aux_data->adva, eh, 6); - aux_data->adva_type = !!(pdu_hdr & BLE_ADV_PDU_HDR_TXADD_MASK); - eh += BLE_LL_EXT_ADV_ADVA_SIZE; + /* Do not send scan request even if scan policy allows unresolved + * RPAs - we do not know if this one if directed to us. + */ + scan_req_allowed = false; + break; + case BLE_LL_ADDR_SUBTYPE_IDENTITY: + /* We shall ignore identity in TargetA if we are using RPA */ + if ((own_addr_type & 0x02) && rl && rl->rl_has_local) { + return -1; + } - if (adva_present) { - *adva_present = true; + /* Ignore if not directed to us */ + if ((addrd->targeta_type != (own_addr_type & 0x01)) || + !ble_ll_is_our_devaddr(addrd->targeta, addrd->targeta_type)) { + return -1; + } + break; + default: + /* NRPA goes through filtering policy directly */ + break; } - } else if (adva_present) { - *adva_present = false; } - if (eh_flags & (1 << BLE_LL_EXT_ADV_TARGETA_BIT)) { - aux_data->flags |= BLE_LL_AUX_HAS_TARGETA; - memcpy(aux_data->targeta, eh, 6); - aux_data->targeta_type = !!(pdu_hdr & BLE_ADV_PDU_HDR_RXADD_MASK); - eh += BLE_LL_EXT_ADV_TARGETA_SIZE; + resolved = addrd->adva_resolved; +#else + /* Ignore if not directed to us */ + if (addrd->targeta && + ((addrd->targeta_type != (own_addr_type & 0x01)) || + !ble_ll_is_our_devaddr(addrd->targeta, addrd->targeta_type))) { + return -1; } + resolved = false; +#endif - if (eh_flags & (1 << BLE_LL_EXT_ADV_CTE_INFO_BIT)) { - eh += 1; - } - - if (eh_flags & (1 << BLE_LL_EXT_ADV_DATA_INFO_BIT)) { - aux_data->flags |= BLE_LL_AUX_HAS_ADI; - if (is_aux) { - if (get_le16(eh) != aux_data->adi) { - aux_data->flags_isr |= BLE_LL_AUX_FLAG_SCAN_ERROR; - STATS_INC(ble_ll_stats, aux_chain_err); - } - } else { - aux_data->adi = get_le16(eh); + if (scan_filt_policy & 0x01) { + /* Check on WL if required by scan filter policy */ + if (!ble_ll_whitelist_match(addrd->adv_addr, addrd->adv_addr_type, + resolved)) { + return -2; } - eh += BLE_LL_EXT_ADV_DATA_INFO_SIZE; } - if (eh_flags & (1 << BLE_LL_EXT_ADV_AUX_PTR_BIT)) { - if (ble_ll_ext_scan_parse_aux_ptr(aux_data, eh)) { - aux_data->flags_isr |= BLE_LL_AUX_FLAG_SCAN_ERROR; - } - } else if (!(adv_mode & BLE_LL_EXT_ADV_MODE_SCAN)) { - /* No AuxPtr for scannable PDU is ignored since we can still scan it */ - aux_data->flags_isr |= BLE_LL_AUX_FLAG_SCAN_COMPLETE; + if (scan_ok) { + *scan_ok = scan_req_allowed; } - ble_hdr->rxinfo.user_data = aux_data; - - /* Do not scan for next AUX if either no AuxPtr or malformed data found */ - return !(eh_flags & (1 << BLE_LL_EXT_ADV_AUX_PTR_BIT)) || - (aux_data->flags_isr & BLE_LL_AUX_FLAG_SCAN_ERROR); + return 0; } -/** - * Called when a receive ADV_EXT PDU has ended. - * - * Context: Interrupt - * - * @return int - * < 0 Error - * >= 0: Success (number of bytes left in PDU) - * - */ -static int -ble_ll_scan_parse_ext_hdr(struct os_mbuf *om, - const uint8_t *adva, uint8_t adva_type, - const uint8_t *inita, uint8_t inita_type, - struct ble_mbuf_hdr *ble_hdr, - struct ext_adv_report *report) -{ - uint8_t pdu_len; - uint8_t ext_hdr_len; - uint8_t ext_hdr_flags; - uint8_t *ext_hdr; - uint8_t *rxbuf = om->om_data; - int i = 1; +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) +int +ble_ll_scan_rx_check_init(struct ble_ll_scan_addr_data *addrd) +{ struct ble_ll_scan_sm *scansm; - struct ble_ll_aux_data *aux_data = ble_hdr->rxinfo.user_data; - - BLE_LL_ASSERT(report); + struct ble_ll_conn_sm *connsm; scansm = &g_ble_ll_scan_sm; + connsm = scansm->connsm; + BLE_LL_ASSERT(connsm); - if (!scansm->ext_scanning) { - /* Ignore ext adv if host does not want it*/ - return -1; - } - - pdu_len = rxbuf[1]; - if (pdu_len == 0) { +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + if ((connsm->peer_addr_type > BLE_ADDR_RANDOM) && !addrd->adva_resolved) { return -1; } - - report->evt_type = rxbuf[2] >> 6; - if ( report->evt_type > BLE_LL_EXT_ADV_MODE_SCAN) { +#endif + if ((addrd->adv_addr_type != (connsm->peer_addr_type & 0x01)) || + memcmp(addrd->adv_addr, connsm->peer_addr, 6) != 0) { return -1; } - if (BLE_MBUF_HDR_SCAN_RSP_RXD(ble_hdr)) { - report->evt_type |= BLE_HCI_ADV_SCAN_RSP_MASK; - } - - ext_hdr_len = rxbuf[2] & 0x3F; - os_mbuf_adj(om, 3); - - ext_hdr_flags = rxbuf[3]; - ext_hdr = &rxbuf[4]; - - if (ext_hdr_len) { - i = 0; - if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_ADVA_BIT)) { - i += BLE_LL_EXT_ADV_ADVA_SIZE; - } - - if (adva) { - memcpy(report->addr, adva, 6); - report->addr_type = adva_type; - } - - if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_TARGETA_BIT)) { - i += BLE_LL_EXT_ADV_TARGETA_SIZE; - } + return 0; +} +#endif - if (inita) { - memcpy(report->dir_addr, inita, 6); - report->dir_addr_type = inita_type; - report->evt_type |= BLE_HCI_ADV_DIRECT_MASK; - } +static int +ble_ll_scan_rx_isr_end_on_adv(uint8_t pdu_type, uint8_t *rxbuf, + struct ble_mbuf_hdr *hdr, + struct ble_ll_scan_addr_data *addrd) +{ + struct ble_ll_scan_sm *scansm = &g_ble_ll_scan_sm; + struct ble_ll_scan_phy *scanp = scansm->scanp; + struct ble_mbuf_hdr_rxinfo *rxinfo = &hdr->rxinfo; + uint8_t scan_ok; + int rc; - if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_CTE_INFO_BIT)) { - /* Just skip it for now*/ - i += 1; - } + ble_ll_scan_get_addr_data_from_legacy(pdu_type, rxbuf, addrd); - if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_DATA_INFO_BIT)) { - ble_ll_ext_scan_parse_adv_info(report, (ext_hdr + i)); - i += BLE_LL_EXT_ADV_DATA_INFO_SIZE; - } else if (report->evt_type & BLE_HCI_ADV_SCAN_RSP_MASK) { - report->sid = (aux_data->adi >> 12); - } +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + addrd->rpa_index = ble_hw_resolv_list_match(); +#endif - /* In this point of time we don't want to care about aux ptr */ - if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_AUX_PTR_BIT)) { - i += BLE_LL_EXT_ADV_AUX_PTR_SIZE; - } + rc = ble_ll_scan_rx_filter(scansm->own_addr_type, + scansm->scan_filt_policy, addrd, &scan_ok); + if (rc < 0) { + return 0; + } - if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_SYNC_INFO_BIT)) { - report->periodic_itvl = get_le16(ext_hdr + i + 2); - i += BLE_LL_EXT_ADV_SYNC_INFO_SIZE; +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + if ((scanp->scan_type == BLE_SCAN_TYPE_INITIATE) && + !(scansm->scan_filt_policy & 0x01)) { + rc = ble_ll_scan_rx_check_init(addrd); + if (rc < 0) { + return 0; } + } +#endif - if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_TX_POWER_BIT)) { - report->tx_power = *(ext_hdr + i); - i += BLE_LL_EXT_ADV_TX_POWER_SIZE; - } + rxinfo->flags |= BLE_MBUF_HDR_F_DEVMATCH; +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + rxinfo->rpa_index = addrd->rpa_index; + if (addrd->adva_resolved) { + rxinfo->flags |= BLE_MBUF_HDR_F_RESOLVED; + } + if (addrd->targeta_resolved) { + rxinfo->flags |= BLE_MBUF_HDR_F_TARGETA_RESOLVED; + } +#endif - /* TODO Handle ACAD if needed */ + if (!scan_ok) { + /* Scan request forbidden by filter policy */ + return 0; } - /* In the event we need information on primary and secondary PHY used during - * advertising. + /* Allow responding to all PDUs when initiating since unwanted PDUs were + * already filtered out in isr_start. */ - if (!aux_data) { - report->pri_phy = ble_hdr->rxinfo.phy; - goto done; + if ((scanp->scan_type == BLE_SCAN_TYPE_ACTIVE) && + ((pdu_type == BLE_ADV_PDU_TYPE_ADV_IND) || + (pdu_type == BLE_ADV_PDU_TYPE_ADV_SCAN_IND))) { + return 1; } - report->sec_phy = aux_data->aux_phy; - report->pri_phy = aux_data->aux_primary_phy; - - if (ext_hdr_len) { - /* Adjust mbuf to contain advertising data only */ - os_mbuf_adj(om, ext_hdr_len); +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + if (scanp->scan_type == BLE_SCAN_TYPE_INITIATE) { + return 1; } +#endif - /* Let us first keep update event type in aux data. - * Note that in aux chain and aux scan response packets - * we do miss original event type, which we need for advertising report. - */ - aux_data->evt_type |= report->evt_type; - report->evt_type = aux_data->evt_type; - -done: - return pdu_len - ext_hdr_len - 1; + return 0; } static int -ble_ll_scan_get_addr_from_ext_adv(uint8_t *rxbuf, struct ble_mbuf_hdr *ble_hdr, - uint8_t **addr, uint8_t *addr_type, - uint8_t **inita, uint8_t *inita_type, - int *ext_mode) -{ - uint8_t pdu_len; - uint8_t ext_hdr_len; - uint8_t ext_hdr_flags; - uint8_t *ext_hdr; - bool has_adva = false; - bool has_inita = false; - int i; - struct ble_ll_aux_data *aux_data = ble_hdr->rxinfo.user_data; +ble_ll_scan_rx_isr_end_on_scan_rsp(uint8_t pdu_type, uint8_t *rxbuf, + struct ble_mbuf_hdr *hdr, + struct ble_ll_scan_addr_data *addrd) +{ + struct ble_ll_scan_sm *scansm = &g_ble_ll_scan_sm; + struct ble_mbuf_hdr_rxinfo *rxinfo = &hdr->rxinfo; + uint8_t sreq_adva_type; + uint8_t *sreq_adva; - *addr = NULL; - *inita = NULL; + ble_ll_scan_get_addr_data_from_legacy(pdu_type, rxbuf, addrd); - pdu_len = rxbuf[1]; - if (pdu_len == 0) { + if (!BLE_MBUF_HDR_SCAN_RSP_RXD(hdr)) { + /* + * We were not expecting scan response so just ignore and do not + * update backoff. + */ return -1; } - *ext_mode = rxbuf[2] >> 6; - if (*ext_mode > BLE_LL_EXT_ADV_MODE_SCAN) { + sreq_adva_type = !!(scansm->pdu_data.hdr_byte & BLE_ADV_PDU_HDR_RXADD_MASK); + sreq_adva = scansm->pdu_data.adva; + + /* + * Ignore scan response if AdvA does not match AdvA in request and also + * update backoff as if there was no scan response. + */ + if ((addrd->adva_type != sreq_adva_type) || + memcmp(addrd->adva, sreq_adva, BLE_DEV_ADDR_LEN)) { + ble_ll_scan_req_backoff(scansm, 0); return -1; } - ext_hdr_len = rxbuf[2] & 0x3F; - if (ext_hdr_len == 0) { - goto done; +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + /* + * We are not pushing this one through filters so need to update + * rpa_index here as otherwise pkt_in won't be able to determine + * advertiser address properly. + */ + rxinfo->rpa_index = ble_hw_resolv_list_match(); + if (rxinfo->rpa_index >= 0) { + rxinfo->flags |= BLE_MBUF_HDR_F_RESOLVED; } +#endif - ext_hdr_flags = rxbuf[3]; - ext_hdr = &rxbuf[4]; - - i = 0; - if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_ADVA_BIT)) { - if (ext_hdr_len < BLE_LL_EXT_ADV_ADVA_SIZE) { - return -1; - } - - *addr = ext_hdr + i; - *addr_type = - ble_ll_get_addr_type(rxbuf[0] & BLE_ADV_PDU_HDR_TXADD_MASK); - i += BLE_LL_EXT_ADV_ADVA_SIZE; + rxinfo->flags |= BLE_MBUF_HDR_F_DEVMATCH; - has_adva = true; - } - - if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_TARGETA_BIT)) { - *inita = ext_hdr + i; - *inita_type = - ble_ll_get_addr_type(rxbuf[0] & BLE_ADV_PDU_HDR_RXADD_MASK); - i += BLE_LL_EXT_ADV_TARGETA_SIZE; - - has_inita = true; - } - -done: - /* Check if we had address already. If yes, replace it with new one */ - - if (aux_data) { - /* If address has been provided, we do have it already in aux_data.*/ - if (aux_data->flags & BLE_LL_AUX_HAS_ADVA) { - if (!has_adva) { - *addr = aux_data->adva; - *addr_type = aux_data->adva_type; - } else { - memcpy(aux_data->adva, *addr, 6); - aux_data->adva_type = *addr_type; - } - } - - if (aux_data->flags & BLE_LL_AUX_HAS_TARGETA) { - if (!has_inita) { - *inita = aux_data->targeta; - *inita_type = aux_data->targeta_type; - } else { - memcpy(aux_data->targeta, *inita, 6); - aux_data->targeta_type = *inita_type; - } - } - } - - return 0; -} -#endif - -int -ble_ll_scan_adv_decode_addr(uint8_t pdu_type, uint8_t *rxbuf, - struct ble_mbuf_hdr *ble_hdr, - uint8_t **addr, uint8_t *addr_type, - uint8_t **inita, uint8_t *inita_type, - int *ext_mode) -{ - /* - * XXX this should be only used for legacy advertising, but need to refactor - * code in ble_ll_init first so it does not call this for ext - */ - - if (pdu_type != BLE_ADV_PDU_TYPE_ADV_EXT_IND && - pdu_type != BLE_ADV_PDU_TYPE_AUX_CONNECT_RSP) { - /* Legacy advertising */ - *addr_type = ble_ll_get_addr_type(rxbuf[0] & BLE_ADV_PDU_HDR_TXADD_MASK); - *addr = rxbuf + BLE_LL_PDU_HDR_LEN; - - if (pdu_type != BLE_ADV_PDU_TYPE_ADV_DIRECT_IND) { - *inita = NULL; - *inita_type = 0; - return 0; - } - - *inita = rxbuf + BLE_LL_PDU_HDR_LEN + BLE_DEV_ADDR_LEN; - *inita_type = ble_ll_get_addr_type(rxbuf[0] & BLE_ADV_PDU_HDR_RXADD_MASK); - - return 0; - } - - /* Extended advertising */ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - return ble_ll_scan_get_addr_from_ext_adv(rxbuf, ble_hdr, addr, addr_type, - inita, inita_type, ext_mode); -#else - return -1; -#endif - - return 0; -} - -static void -ble_ll_scan_get_addr_data_from_legacy(uint8_t pdu_type, uint8_t *rxbuf, - struct ble_ll_scan_addr_data *addrd) -{ - BLE_LL_ASSERT(pdu_type < BLE_ADV_PDU_TYPE_ADV_EXT_IND); - - addrd->adva_present = true; - - addrd->adva = rxbuf + BLE_LL_PDU_HDR_LEN; - addrd->adva_type = ble_ll_get_addr_type(rxbuf[0] & BLE_ADV_PDU_HDR_TXADD_MASK); - - if (pdu_type == BLE_ADV_PDU_TYPE_ADV_DIRECT_IND) { - addrd->targeta = rxbuf + BLE_LL_PDU_HDR_LEN + BLE_DEV_ADDR_LEN; - addrd->targeta_type = ble_ll_get_addr_type(rxbuf[0] & BLE_ADV_PDU_HDR_RXADD_MASK); - } else { - addrd->targeta = NULL; - addrd->targeta_type = 0; - } -} - -/* - * Matches incoming PDU using scan filter policy and whitelist, if applicable. - * This will also resolve addresses and update flags/fields in header and - * addr_data as needed. - * - * @return 0 = no match - * 1 = match - * 2 = match, but do not scan - */ -static int -ble_ll_scan_rx_filter(struct ble_mbuf_hdr *hdr, struct ble_ll_scan_addr_data *addrd) -{ - struct ble_ll_scan_sm *scansm = &g_ble_ll_scan_sm; - struct ble_ll_scan_params *scanp = scansm->scanp; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - struct ble_ll_aux_data *aux_data = hdr->rxinfo.user_data; -#endif - struct ble_mbuf_hdr_rxinfo *rxinfo = &hdr->rxinfo; - struct ble_ll_resolv_entry *rl = NULL; -#endif - bool scan_req_allowed = true; - int resolved = 0; - - /* Use AdvA as initial advertiser address, we may try to resolve it later */ - addrd->adv_addr = addrd->adva; - addrd->adv_addr_type = addrd->adva_type; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - /* By default, assume AdvA is not resolved */ - rxinfo->rpa_index = -1; - - switch (ble_ll_addr_subtype(addrd->adva, addrd->adva_type)) { - case BLE_LL_ADDR_SUBTYPE_RPA: - /* - * Only resolve if packet actually contained AdvA. - * In extended advertising PDUs we may use RL index from a PDU that - * already had AdvA (e.g. ADV_EXT_IND in case of AUX_ADV_IND without - * AdvA). In legacy advertising PDUs we always need to resolve AdvA. - */ - if (addrd->adva_present) { - rxinfo->rpa_index = ble_hw_resolv_list_match(); - } else { -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - BLE_LL_ASSERT(aux_data); - rxinfo->rpa_index = aux_data->rpa_index; -#else - BLE_LL_ASSERT(false); - rxinfo->rpa_index = -1; -#endif - } - - if (rxinfo->rpa_index < 0) { - break; - } - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - if (aux_data) { - aux_data->rpa_index = rxinfo->rpa_index; - } -#endif - - /* Use resolved identity address as advertiser address */ - rl = &g_ble_ll_resolv_list[rxinfo->rpa_index]; - addrd->adv_addr = rl->rl_identity_addr; - addrd->adv_addr_type = rl->rl_addr_type; - addrd->rl = rl; - - rxinfo->flags |= BLE_MBUF_HDR_F_RESOLVED; - resolved = 1; - break; - case BLE_LL_ADDR_SUBTYPE_IDENTITY: - /* - * If AdvA is an identity address, we need to check if that device was - * added to RL in order to use proper privacy mode. - */ - rl = ble_ll_resolv_list_find(addrd->adva, addrd->adva_type); - if (!rl) { - break; - } - - addrd->rl = rl; - - /* Ignore device if using network privacy mode and it has IRK */ - if ((rl->rl_priv_mode == BLE_HCI_PRIVACY_NETWORK) && rl->rl_has_peer) { - return 0; - } - break; - default: - /* NRPA goes through filtering policy directly */ - break; - } - - if (addrd->targeta) { - switch (ble_ll_addr_subtype(addrd->targeta, addrd->targeta_type)) { - case BLE_LL_ADDR_SUBTYPE_RPA: - /* Check if TargetA can be resolved using the same RL entry as AdvA */ - if (rl && ble_ll_resolv_rpa(addrd->targeta, rl->rl_local_irk)) { - rxinfo->flags |= BLE_MBUF_HDR_F_TARGETA_RESOLVED; - break; - } - - /* Check if scan filter policy allows unresolved RPAs to be processed */ - if (!(scanp->scan_filt_policy & 0x02)) { - return 0; - } - - /* - * We will notify host as requited by scan policy, but make sure we - * do not send scan request since we do not know if this is directed - * to us. - */ - scan_req_allowed = false; - break; - case BLE_LL_ADDR_SUBTYPE_IDENTITY: - /* We shall ignore identity in TargetA if we are using RPA */ - if ((scanp->own_addr_type & 0x02) && rl && rl->rl_has_local) { - return 0; - } - /* Ignore if not directed to us */ - if (!ble_ll_is_our_devaddr(addrd->targeta, addrd->targeta_type)) { - return 0; - } - break; - default: - /* NRPA goes through filtering policy directly */ - break; - } - } -#else - /* Ignore if not directed to us */ - if (addrd->targeta && - !ble_ll_is_our_devaddr(addrd->targeta, addrd->targeta_type)) { - return 0; - } -#endif - - /* Check on WL if required by scan filter policy */ - if (scanp->scan_filt_policy & 0x01) { - if (!ble_ll_whitelist_match(addrd->adv_addr, addrd->adv_addr_type, resolved)) { - return 0; - } - } - - return scan_req_allowed ? 1 : 2; -} - -static int -ble_ll_scan_rx_isr_on_legacy(uint8_t pdu_type, uint8_t *rxbuf, - struct ble_mbuf_hdr *hdr, - struct ble_ll_scan_addr_data *addrd) -{ - struct ble_ll_scan_sm *scansm = &g_ble_ll_scan_sm; - struct ble_ll_scan_params *scanp = scansm->scanp; - struct ble_mbuf_hdr_rxinfo *rxinfo = &hdr->rxinfo; - uint8_t sreq_adva_type; - uint8_t *sreq_adva; - int rc; - - ble_ll_scan_get_addr_data_from_legacy(pdu_type, rxbuf, addrd); - - if (pdu_type == BLE_ADV_PDU_TYPE_SCAN_RSP) { - if (!BLE_MBUF_HDR_SCAN_RSP_RXD(hdr)) { - /* - * We were not expecting scan response so just ignore and do not - * update backoff. - */ - return -1; - } - - sreq_adva_type = !!(scansm->pdu_data.hdr_byte & BLE_ADV_PDU_HDR_RXADD_MASK); - sreq_adva = scansm->pdu_data.adva; - - /* - * Ignore scan response if AdvA does not match AdvA in request and also - * update backoff as if there was no scan response. - */ - if ((addrd->adva_type != sreq_adva_type) || - memcmp(addrd->adva, sreq_adva, BLE_DEV_ADDR_LEN)) { - ble_ll_scan_req_backoff(scansm, 0); - return -1; - } - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - /* - * We are not pushing this one through filters so need to update - * rpa_index here as otherwise pkt_in won't be able to determine - * advertiser address properly. - */ - rxinfo->rpa_index = ble_hw_resolv_list_match(); - if (rxinfo->rpa_index >= 0) { - rxinfo->flags |= BLE_MBUF_HDR_F_RESOLVED; - } -#endif - - rxinfo->flags |= BLE_MBUF_HDR_F_DEVMATCH; - - return 0; - } - - rc = ble_ll_scan_rx_filter(hdr, addrd); - if (!rc) { - return 0; - } - - rxinfo->flags |= BLE_MBUF_HDR_F_DEVMATCH; - - if (rc == 2) { - /* Scan request forbidden by filter policy */ - return 0; - } - - return (scanp->scan_type == BLE_SCAN_TYPE_ACTIVE) && - ((pdu_type == BLE_ADV_PDU_TYPE_ADV_IND) || - (pdu_type == BLE_ADV_PDU_TYPE_ADV_SCAN_IND)); -} - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -static int -ble_ll_scan_rx_isr_on_aux(uint8_t pdu_type, uint8_t *rxbuf, - struct ble_mbuf_hdr *hdr, - struct ble_ll_scan_addr_data *addrd) -{ - struct ble_ll_scan_sm *scansm = &g_ble_ll_scan_sm; - struct ble_ll_scan_params *scanp = scansm->scanp; - struct ble_mbuf_hdr_rxinfo *rxinfo = &hdr->rxinfo; - struct ble_ll_aux_data *aux_data; - int rc; - - if (!scansm->ext_scanning) { - return -1; - } - - rc = ble_ll_scan_update_aux_data(hdr, rxbuf, &addrd->adva_present); - if (rc < 0) { - rxinfo->flags |= BLE_MBUF_HDR_F_AUX_INVALID; - return -1; - } else if (rc == 0) { - rxinfo->flags |= BLE_MBUF_HDR_F_AUX_PTR_WAIT; - } - - /* Now we can update aux_data from header since it may have just been created */ - aux_data = rxinfo->user_data; - - /* - * Restore proper header flags if filtering was already done successfully on - * some previous PDU in an event. - */ - if (aux_data->flags & BLE_LL_AUX_IS_MATCHED) { - rxinfo->flags |= BLE_MBUF_HDR_F_DEVMATCH; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - rxinfo->rpa_index = aux_data->rpa_index; - if (rxinfo->rpa_index >= 0) { - rxinfo->flags |= BLE_MBUF_HDR_F_RESOLVED; - } - if (aux_data->flags & BLE_LL_AUX_IS_TARGETA_RESOLVED) { - rxinfo->flags |= BLE_MBUF_HDR_F_TARGETA_RESOLVED; - } -#endif - goto done; - } - - if (aux_data->flags & BLE_LL_AUX_HAS_ADVA) { - addrd->adva = aux_data->adva; - addrd->adva_type = aux_data->adva_type; - } else { - /* Accept this PDU and wait for AdvA in aux */ - rxinfo->flags |= BLE_MBUF_HDR_F_DEVMATCH; - return 0; - } - if (aux_data->flags & BLE_LL_AUX_HAS_TARGETA) { - addrd->targeta = aux_data->targeta; - addrd->targeta_type = aux_data->targeta_type; - } else { - addrd->targeta = NULL; - } - - rc = ble_ll_scan_rx_filter(hdr, addrd); - if (!rc) { - return 0; - } - - rxinfo->flags |= BLE_MBUF_HDR_F_DEVMATCH; - - /* - * Once we matched device, there's no need to go through filtering on every - * other PDU in an event so just store info required to restore state for - * subsequent PDUs in aux_data. - */ - aux_data->flags |= BLE_LL_AUX_IS_MATCHED; - if (rxinfo->flags & BLE_MBUF_HDR_F_TARGETA_RESOLVED) { - aux_data->flags |= BLE_LL_AUX_IS_TARGETA_RESOLVED; - /* AdvA state is already stored in rpa_index */ - } - - if (rc == 2) { - /* Scan request forbidden by filter policy */ - return 0; - } - -done: - return (scanp->scan_type == BLE_SCAN_TYPE_ACTIVE) && - ((rxbuf[2] >> 6) == BLE_LL_EXT_ADV_MODE_SCAN); -} -#endif + return 0; +} static bool ble_ll_scan_send_scan_req(uint8_t pdu_type, uint8_t *rxbuf, @@ -2290,23 +1540,11 @@ ble_ll_scan_send_scan_req(uint8_t pdu_type, uint8_t *rxbuf, { struct ble_ll_scan_sm *scansm = &g_ble_ll_scan_sm; struct ble_mbuf_hdr_rxinfo *rxinfo = &hdr->rxinfo; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - struct ble_ll_aux_data *aux_data = rxinfo->user_data; - uint8_t phy_mode; -#endif bool is_ext_adv = false; + int8_t rpa_index; uint16_t adi = 0; int rc; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - if (pdu_type == BLE_ADV_PDU_TYPE_ADV_EXT_IND) { - if (ble_ll_scan_get_adi(aux_data, &adi) < 0) { - return false; - } - is_ext_adv = true; - } -#endif - /* Check if we already scanned this device successfully */ if (ble_ll_scan_have_rxd_scan_rsp(addrd->adv_addr, addrd->adv_addr_type, is_ext_adv, adi)) { @@ -2317,21 +1555,19 @@ ble_ll_scan_send_scan_req(uint8_t pdu_type, uint8_t *rxbuf, BLE_LL_ASSERT(scansm->scan_rsp_pending == 0); /* We want to send a request. See if backoff allows us */ - if (scansm->backoff_count > 0) { - if (--scansm->backoff_count != 0) { - return false; - } - } - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - phy_mode = ble_ll_phy_to_phy_mode(rxinfo->phy, BLE_HCI_LE_PHY_CODED_ANY); - if (ble_ll_sched_scan_req_over_aux_ptr(rxinfo->channel, phy_mode)) { + if (ble_ll_scan_backoff_kick() != 0) { return false; } + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + rpa_index = addrd->rpa_index; +#else + rpa_index = -1; #endif /* Use original AdvA in scan request (Core 5.1, Vol 6, Part B, section 6.3) */ - ble_ll_scan_req_pdu_prepare(scansm, addrd->adva, addrd->adva_type, addrd->rl); + ble_ll_scan_req_pdu_prepare(scansm, addrd->adva, addrd->adva_type, + rpa_index); rc = ble_phy_tx(ble_ll_scan_req_tx_pdu_cb, scansm, BLE_PHY_TRANSITION_TX_RX); if (rc) { @@ -2341,14 +1577,6 @@ ble_ll_scan_send_scan_req(uint8_t pdu_type, uint8_t *rxbuf, scansm->scan_rsp_pending = 1; rxinfo->flags |= BLE_MBUF_HDR_F_SCAN_REQ_TXD; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - if (rxinfo->channel < BLE_PHY_NUM_DATA_CHANS) { - /* Keep aux_data for expected scan response */ - scansm->cur_aux_data = ble_ll_scan_aux_data_ref(aux_data); - STATS_INC(ble_ll_stats, aux_scan_req_tx); - } -#endif - return true; } @@ -2384,48 +1612,47 @@ ble_ll_scan_rx_isr_end(struct os_mbuf *rxpdu, uint8_t crcok) return 0; } - rxbuf = rxpdu->om_data; - pdu_type = rxbuf[0] & BLE_ADV_PDU_HDR_TYPE_MASK; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - /* - * In case aux was expected, copy aux_data for LL to use. Make sure this was - * indeed an aux as otherwise there's no need to process it and just pass to - * LL immediately. - */ - if (scansm->cur_aux_data) { - rxinfo->user_data = scansm->cur_aux_data; - scansm->cur_aux_data = NULL; - if (pdu_type != BLE_ADV_PDU_TYPE_ADV_EXT_IND) { - ble_ll_state_set(BLE_LL_STATE_STANDBY); - return -1; - } + if (!crcok) { + goto scan_rx_isr_ignore; } -#endif - if (!crcok) { + if (!scansm->scan_enabled) { + STATS_INC(ble_ll_stats, rx_pdu_on_scan_disabled); goto scan_rx_isr_ignore; } - /* - * Addresses will be always set in handlers, no need to initialize them. We - * only need to initialize rl which may not be always set, depending on how - * filtering goes. - */ - addrd.rl = NULL; + rxbuf = rxpdu->om_data; + pdu_type = rxbuf[0] & BLE_ADV_PDU_HDR_TYPE_MASK; switch (pdu_type) { case BLE_ADV_PDU_TYPE_ADV_IND: case BLE_ADV_PDU_TYPE_ADV_DIRECT_IND: + rc = ble_ll_scan_rx_isr_end_on_adv(pdu_type, rxbuf, hdr, &addrd); + break; case BLE_ADV_PDU_TYPE_ADV_NONCONN_IND: - case BLE_ADV_PDU_TYPE_SCAN_RSP: case BLE_ADV_PDU_TYPE_ADV_SCAN_IND: - rc = ble_ll_scan_rx_isr_on_legacy(pdu_type, rxbuf, hdr, &addrd); +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + if (scansm->scanp->scan_type == BLE_SCAN_TYPE_INITIATE) { + rc = -1; + break; + } +#endif + rc = ble_ll_scan_rx_isr_end_on_adv(pdu_type, rxbuf, hdr, &addrd); + break; + case BLE_ADV_PDU_TYPE_SCAN_RSP: + rc = ble_ll_scan_rx_isr_end_on_scan_rsp(pdu_type, rxbuf, hdr, &addrd); break; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) case BLE_ADV_PDU_TYPE_ADV_EXT_IND: - rc = ble_ll_scan_rx_isr_on_aux(pdu_type, rxbuf, hdr, &addrd); - break; + rc = ble_ll_scan_aux_rx_isr_end_on_ext(&g_ble_ll_scan_sm, rxpdu); + if (rc < 0) { + rxinfo->flags |= BLE_MBUF_HDR_F_IGNORED; + } + ble_ll_state_set(BLE_LL_STATE_STANDBY); + /* Return here, we do not want any further processing since it's all + * handled in scan_aux. + */ + return -1; #endif default: /* This is not something we would like to process here */ @@ -2435,10 +1662,24 @@ ble_ll_scan_rx_isr_end(struct os_mbuf *rxpdu, uint8_t crcok) if (rc == -1) { goto scan_rx_isr_ignore; - } else if (rc == 1) { - if (ble_ll_scan_send_scan_req(pdu_type, rxbuf, hdr, &addrd)) { - /* Keep PHY active and LL in scanning state */ - return 0; + } + + if (rc == 1) { + switch (scansm->scanp->scan_type) { + case BLE_SCAN_TYPE_ACTIVE: + if (ble_ll_scan_send_scan_req(pdu_type, rxbuf, hdr, &addrd)) { + /* Keep PHY active and LL in scanning state */ + return 0; + } + break; +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + case BLE_SCAN_TYPE_INITIATE: + if (ble_ll_conn_send_connect_req(rxpdu, &addrd, 0) == 0) { + hdr->rxinfo.flags |= BLE_MBUF_HDR_F_CONNECT_IND_TXD; + return 0; + } + break; +#endif } } @@ -2474,381 +1715,64 @@ ble_ll_scan_chk_resume(void) OS_ENTER_CRITICAL(sr); if (scansm->restart_timer_needed) { scansm->restart_timer_needed = 0; - ble_ll_event_send(&scansm->scan_sched_ev); + ble_ll_event_add(&scansm->scan_sched_ev); STATS_INC(ble_ll_stats, scan_timer_restarted); OS_EXIT_CRITICAL(sr); return; } - now = os_cputime_get32(); - if (ble_ll_state_get() == BLE_LL_STATE_STANDBY && - ble_ll_scan_is_inside_window(scansm->scanp, now)) { - /* Turn on the receiver and set state */ - ble_ll_scan_start(scansm, NULL); - } - OS_EXIT_CRITICAL(sr); - } -} - -/** - * Scan timer callback; means that the scan window timeout has been reached - * and we should perform the appropriate actions. - * - * Context: Interrupt (cputimer) - * - * @param arg Pointer to scan state machine. - */ -void -ble_ll_scan_timer_cb(void *arg) -{ - struct ble_ll_scan_sm *scansm; - - scansm = (struct ble_ll_scan_sm *)arg; - ble_ll_event_send(&scansm->scan_sched_ev); -} - -void -ble_ll_scan_interrupted(struct ble_ll_scan_sm *scansm) -{ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - ble_npl_event_set_arg(&scansm->scan_interrupted_ev, scansm->cur_aux_data); - scansm->cur_aux_data = NULL; -#endif - - ble_ll_event_send(&scansm->scan_interrupted_ev); -} - -/** - * Called when the wait for response timer expires while in the scanning - * state. - * - * Context: Interrupt. - */ -void -ble_ll_scan_wfr_timer_exp(void) -{ - struct ble_ll_scan_sm *scansm; - uint8_t chan; - int phy; - int rc; -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) - uint8_t phy_mode; -#endif - uint32_t now; - - scansm = &g_ble_ll_scan_sm; - - /* Update backoff if we failed to receive scan response */ - if (scansm->scan_rsp_pending) { - scansm->scan_rsp_pending = 0; - ble_ll_scan_req_backoff(scansm, 0); - } - - if (scansm->cur_aux_data) { - /* We actually care about interrupted scan only for EXT ADV because only - * then we might consider to send truncated event to the host. - */ - ble_ll_scan_interrupted(scansm); - - /* Need to disable phy since we are going to move to BLE_LL_STATE_STANDBY - * or we will need to change channel to primary one - */ - ble_phy_disable(); - - now = os_cputime_get32(); - if (!ble_ll_scan_is_inside_window(scansm->scanp, now)) { - /* Outside the window scan */ - ble_ll_state_set(BLE_LL_STATE_STANDBY); - return; - } - - ble_ll_get_chan_to_scan(scansm, &chan, &phy); -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) - phy_mode = ble_ll_phy_to_phy_mode(phy, BLE_HCI_LE_PHY_CODED_ANY); - ble_phy_mode_set(phy_mode, phy_mode); -#endif - rc = ble_phy_setchan(chan, BLE_ACCESS_ADDR_ADV, BLE_LL_CRCINIT_ADV); - BLE_LL_ASSERT(rc == 0); - } - - - ble_phy_restart_rx(); -} - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -/* - * Send extended advertising report - * - * @return -1 on error (data truncated or other error) - * 0 on success (data status is "completed") - * 1 on success (data status is not "completed") - */ -static int -ble_ll_hci_send_ext_adv_report(uint8_t ptype, uint8_t *adva, uint8_t adva_type, - uint8_t *inita, uint8_t inita_type, - struct os_mbuf *om, - struct ble_mbuf_hdr *hdr) -{ - struct ble_ll_aux_data *aux_data = hdr->rxinfo.user_data; - struct ble_hci_ev_le_subev_ext_adv_rpt *ev; - struct ext_adv_report *report; - struct ble_hci_ev *hci_ev; - struct ble_hci_ev *hci_ev_next; - int offset; - int datalen; - int rc; - bool need_event; - bool is_scannable_aux; - uint8_t max_data_len; - - if (!ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_EXT_ADV_RPT)) { - rc = -1; - goto done; - } - - /* Just ignore PDU if truncated was already sent. - * This can happen if next PDU in chain was already received before we - * manage to cancel scan on error (which resulted in sending truncated HCI - * event) - */ - if (aux_data && (aux_data->flags_ll & BLE_LL_AUX_FLAG_HCI_SENT_TRUNCATED)) { - rc = -1; - goto done; - } - - /* - * We keep one allocated event in aux_data to be able to truncate chain - * properly in case of error. If there is no event in aux_data it means this - * is the first event for this chain. - */ - if (aux_data && aux_data->evt) { - hci_ev = aux_data->evt; - aux_data->evt = NULL; - - hci_ev->length = sizeof(*ev) + sizeof(*report); - } else { - hci_ev = ble_ll_scan_get_ext_adv_report(NULL); - if (!hci_ev) { - rc = -1; - goto done; - } - } - - ev = (void *) hci_ev->data; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - /* If RPA has been used, make sure we use correct address types - * in the advertising report. - */ - if (BLE_MBUF_HDR_RESOLVED(hdr)) { - adva_type += 2; - } - if (BLE_MBUF_HDR_TARGETA_RESOLVED(hdr)) { - inita_type += 2; - } -#endif - - datalen = ble_ll_scan_parse_ext_hdr(om, adva, adva_type, inita, inita_type, - hdr, ev->reports); - if (datalen < 0) { - rc = -1; - - /* Need to send truncated event if we already sent some reports */ - if (aux_data && (aux_data->flags_ll & BLE_LL_AUX_FLAG_HCI_SENT_ANY)) { - BLE_LL_ASSERT(!(aux_data->flags_ll & BLE_LL_AUX_FLAG_HCI_SENT_COMPLETED)); - - aux_data->flags_ll |= BLE_LL_AUX_FLAG_SCAN_ERROR; - aux_data->flags_ll |= BLE_LL_AUX_FLAG_HCI_SENT_TRUNCATED; - - report = ev->reports; - report->data_len = 0; - report->evt_type |= BLE_HCI_ADV_DATA_STATUS_TRUNCATED; - - ble_ll_hci_event_send(hci_ev); - goto done; - } - - ble_hci_trans_buf_free((uint8_t *)hci_ev); - goto done; - } - - is_scannable_aux = aux_data && - (aux_data->evt_type & BLE_HCI_ADV_SCAN_MASK) && - !(aux_data->evt_type & BLE_HCI_ADV_SCAN_RSP_MASK); - - max_data_len = BLE_LL_MAX_EVT_LEN - sizeof(*hci_ev) - sizeof(*ev) - sizeof(*report); - offset = 0; - - do { - hci_ev_next = NULL; - - ev = (void *) hci_ev->data; - report = ev->reports; - - report->data_len = min(max_data_len, datalen - offset); - - /* adjust event length */ - hci_ev->length += report->data_len; - report->rssi = hdr->rxinfo.rssi; - - os_mbuf_copydata(om, offset, report->data_len, report->data); - offset += report->data_len; - - /* - * We need another event if either there are still some data left to - * send in current PDU or scan is not completed. There are two exceptions - * though: - * - we sent all data from this PDU and there is scan error set already; - * it may be set before entering current function due to failed aux - * scan scheduling - * - this is a scannable event which is not a scan response - */ - need_event = ((offset < datalen) || (aux_data && !(aux_data->flags_ll & BLE_LL_AUX_FLAG_SCAN_COMPLETE))) && - !((offset == datalen) && (aux_data->flags_ll & BLE_LL_AUX_FLAG_SCAN_ERROR)) && - !is_scannable_aux; - - if (need_event) { - /* - * We will need another event so let's try to allocate one now. If - * we cannot do this, need to mark event as truncated. - */ - hci_ev_next = ble_ll_scan_get_ext_adv_report(report); - - if (hci_ev_next) { - report->evt_type |= BLE_HCI_ADV_DATA_STATUS_INCOMPLETE; - rc = 1; - } else { - report->evt_type |= BLE_HCI_ADV_DATA_STATUS_TRUNCATED; - rc = -1; - } - } else if (aux_data && (aux_data->flags_ll & BLE_LL_AUX_FLAG_SCAN_ERROR)) { - report->evt_type |= BLE_HCI_ADV_DATA_STATUS_TRUNCATED; - rc = -1; - } else { - rc = 0; - } - - if ((rc == -1) && aux_data) { - aux_data->flags_ll |= BLE_LL_AUX_FLAG_SCAN_ERROR; - - if (!(aux_data->flags_ll & BLE_LL_AUX_FLAG_HCI_SENT_ANY)) { - ble_hci_trans_buf_free((uint8_t *)hci_ev); - goto done; - } - - aux_data->flags_ll |= BLE_LL_AUX_FLAG_HCI_SENT_TRUNCATED; - } else if (!is_scannable_aux) { - /* - * We do not set 'sent' flags for scannable AUX since we only care - * about scan response that will come next. - */ - aux_data->flags_ll |= BLE_LL_AUX_FLAG_HCI_SENT_ANY; - if (rc == 0) { - aux_data->flags_ll |= BLE_LL_AUX_FLAG_HCI_SENT_COMPLETED; - } - } - - ble_ll_hci_event_send(hci_ev); - - hci_ev = hci_ev_next; - } while ((offset < datalen) && hci_ev); - - BLE_LL_ASSERT(offset <= datalen); - - if (aux_data) { - /* Store any event left for later use */ - aux_data->evt = hci_ev; - } else { - /* If it is empty beacon, evt shall be NULL */ - BLE_LL_ASSERT(!hci_ev); - } - -done: - if (!aux_data) { - return rc; - } - - if (rc == 0) { - if (aux_data->evt_type & BLE_HCI_ADV_SCAN_RSP_MASK) { - /* Complete scan response can be added to duplicates list */ - ble_ll_scan_add_scan_rsp_adv(aux_data->adva, aux_data->adva_type, - 1, aux_data->adi); - } else if (is_scannable_aux) { - /* - * Scannable AUX is marked as incomplete because we do not want to - * add this to duplicates list now, this should happen only after - * we receive complete scan response. The drawback here is that we - * will keep receiving reports for scannable PDUs until complete - * scan response is received. - * - * XXX ^^ extend duplicates list to fix - */ - rc = 1; - } - } else if (rc < 0) { - aux_data->flags_ll |= BLE_LL_AUX_FLAG_SCAN_ERROR; - } - - return rc; -} -#endif - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) -static void -ble_ll_scan_check_periodic_sync(const struct os_mbuf *om, struct ble_mbuf_hdr *rxhdr, - uint8_t *adva, uint8_t adva_type, int rpa_index) -{ - uint8_t pdu_len; - uint8_t ext_hdr_len; - uint8_t ext_hdr_flags; - uint8_t *ext_hdr; - uint8_t *rxbuf = om->om_data; - uint8_t sid; - int i; - - pdu_len = rxbuf[1]; - if (pdu_len == 0) { - return; - } - - ext_hdr_len = rxbuf[2] & 0x3F; - - if (ext_hdr_len) { - ext_hdr_flags = rxbuf[3]; - ext_hdr = &rxbuf[4]; - i = 0; - - if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_ADVA_BIT)) { - i += BLE_LL_EXT_ADV_ADVA_SIZE; - } - - if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_TARGETA_BIT)) { - i += BLE_LL_EXT_ADV_TARGETA_SIZE; + now = ble_ll_tmr_get(); + if (ble_ll_state_get() == BLE_LL_STATE_STANDBY && + ble_ll_scan_is_inside_window(scansm->scanp, now)) { + /* Turn on the receiver and set state */ + ble_ll_scan_start(scansm); } + OS_EXIT_CRITICAL(sr); + } +} - if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_CTE_INFO_BIT)) { - i += 1; - } +/** + * Scan timer callback; means that the scan window timeout has been reached + * and we should perform the appropriate actions. + * + * Context: Interrupt (cputimer) + * + * @param arg Pointer to scan state machine. + */ +void +ble_ll_scan_timer_cb(void *arg) +{ + struct ble_ll_scan_sm *scansm; - if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_DATA_INFO_BIT)) { - sid = (get_le16(ext_hdr + i) >> 12); - i += BLE_LL_EXT_ADV_DATA_INFO_SIZE; - } else { - /* ADI is mandatory */ - return; - } + scansm = (struct ble_ll_scan_sm *)arg; + ble_ll_event_add(&scansm->scan_sched_ev); +} - if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_AUX_PTR_BIT)) { - i += BLE_LL_EXT_ADV_AUX_PTR_SIZE; - } +void +ble_ll_scan_interrupted(struct ble_ll_scan_sm *scansm) +{ + ble_ll_event_add(&scansm->scan_interrupted_ev); +} - if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_SYNC_INFO_BIT)) { - ble_ll_sync_info_event(adva, adva_type, rpa_index, sid, rxhdr, - ext_hdr + i); - } +/** + * Called when the wait for response timer expires while in the scanning + * state. + * + * Context: Interrupt. + */ +void +ble_ll_scan_wfr_timer_exp(void) +{ + struct ble_ll_scan_sm *scansm = &g_ble_ll_scan_sm; + + /* Update backoff if we failed to receive scan response */ + if (scansm->scan_rsp_pending) { + scansm->scan_rsp_pending = 0; + ble_ll_scan_req_backoff(scansm, 0); } + + ble_phy_restart_rx(); } -#endif static inline void ble_ll_scan_dup_move_to_head(struct ble_ll_scan_dup_entry *e) @@ -2915,20 +1839,17 @@ ble_ll_scan_dup_check_legacy(uint8_t addr_type, uint8_t *addr, uint8_t pdu_type) } #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -static int -ble_ll_scan_dup_check_ext(uint8_t addr_type, uint8_t *addr, - struct ble_ll_aux_data *aux_data) +int +ble_ll_scan_dup_check_ext(uint8_t addr_type, uint8_t *addr, bool has_aux, + uint16_t adi) { struct ble_ll_scan_dup_entry *e; - bool has_aux; bool is_anon; - uint16_t adi; uint8_t type; int rc; - has_aux = aux_data != NULL; is_anon = addr == NULL; - adi = has_aux ? aux_data->adi : 0; + adi = has_aux ? adi : 0; type = BLE_LL_SCAN_ENTRY_TYPE_EXT(addr_type, has_aux, is_anon, adi); @@ -2967,19 +1888,16 @@ ble_ll_scan_dup_check_ext(uint8_t addr_type, uint8_t *addr, return rc; } -static int -ble_ll_scan_dup_update_ext(uint8_t addr_type, uint8_t *addr, - struct ble_ll_aux_data *aux_data) +int +ble_ll_scan_dup_update_ext(uint8_t addr_type, uint8_t *addr, bool has_aux, + uint16_t adi) { struct ble_ll_scan_dup_entry *e; - bool has_aux; bool is_anon; - uint16_t adi; uint8_t type; - has_aux = aux_data != NULL; is_anon = addr == NULL; - adi = has_aux ? aux_data->adi : 0; + adi = has_aux ? adi : 0; type = BLE_LL_SCAN_ENTRY_TYPE_EXT(addr_type, has_aux, is_anon, adi); @@ -3011,15 +1929,24 @@ ble_ll_scan_rx_pkt_in_restore_addr_data(struct ble_mbuf_hdr *hdr, addrd->adv_addr_type = addrd->adva_type; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - if (rxinfo->rpa_index >= 0) { + addrd->rpa_index = rxinfo->rpa_index; + + if (hdr->rxinfo.flags & BLE_MBUF_HDR_F_RESOLVED) { + BLE_LL_ASSERT(rxinfo->rpa_index >= 0); rl = &g_ble_ll_resolv_list[rxinfo->rpa_index]; addrd->adv_addr = rl->rl_identity_addr; addrd->adv_addr_type = rl->rl_addr_type; - addrd->rl = rl; + addrd->adva_resolved = 1; + } else { + addrd->adva_resolved = 0; } + if (hdr->rxinfo.flags & BLE_MBUF_HDR_F_TARGETA_RESOLVED) { addrd->targeta = ble_ll_get_our_devaddr(scansm->own_addr_type & 1); addrd->targeta_type = scansm->own_addr_type & 1; + addrd->targeta_resolved = 1; + } else { + addrd->targeta_resolved = 0; } #endif } @@ -3044,6 +1971,13 @@ ble_ll_scan_rx_pkt_in_on_legacy(uint8_t pdu_type, struct os_mbuf *om, ble_ll_scan_get_addr_data_from_legacy(pdu_type, rxbuf, addrd); ble_ll_scan_rx_pkt_in_restore_addr_data(hdr, addrd); +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + if (addrd->adva_resolved) { + BLE_LL_ASSERT(addrd->rpa_index >= 0); + ble_ll_resolv_set_peer_rpa(addrd->rpa_index, addrd->adva); + } +#endif + send_hci_report = !scansm->scan_filt_dups || !ble_ll_scan_dup_check_legacy(addrd->adv_addr_type, addrd->adv_addr, @@ -3061,143 +1995,6 @@ ble_ll_scan_rx_pkt_in_on_legacy(uint8_t pdu_type, struct os_mbuf *om, } } -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -static void -ble_ll_scan_rx_pkt_in_on_aux(uint8_t pdu_type, struct os_mbuf *om, - struct ble_mbuf_hdr *hdr, - struct ble_ll_scan_addr_data *addrd) -{ - struct ble_ll_scan_sm *scansm = &g_ble_ll_scan_sm; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) - uint8_t *rxbuf = om->om_data; -#endif - struct ble_mbuf_hdr_rxinfo *rxinfo = &hdr->rxinfo; - struct ble_ll_aux_data *aux_data = rxinfo->user_data; - bool send_hci_report; - int rc; - - if (aux_data) { - aux_data->flags_ll |= aux_data->flags_isr; - } - - /* - * For every new extended advertising event scanned, rx_isr_end will either - * allocate new aux_data or set 'invalid' flag. This means if no 'invalid' - * flag is set, aux_data is always valid. - */ - - /* Drop on scan error or if we received not what we expected to receive */ - if (!BLE_MBUF_HDR_CRC_OK(hdr) || - BLE_MBUF_HDR_IGNORED(hdr) || - BLE_MBUF_HDR_AUX_INVALID(hdr) || - (aux_data->flags_ll & BLE_LL_AUX_FLAG_SCAN_ERROR) || - (pdu_type != BLE_ADV_PDU_TYPE_ADV_EXT_IND) || - !scansm->scan_enabled) { - if (aux_data) { - ble_ll_scan_end_adv_evt(aux_data); - ble_ll_scan_aux_data_unref(aux_data); - rxinfo->user_data = NULL; - } - return; - } - - BLE_LL_ASSERT(aux_data); - - if (aux_data->flags & BLE_LL_AUX_HAS_ADVA) { - addrd->adva = aux_data->adva; - addrd->adva_type = aux_data->adva_type; - } else { - addrd->adva = NULL; - addrd->adva_type = 0; - } - if (aux_data->flags & BLE_LL_AUX_HAS_TARGETA) { - addrd->targeta = aux_data->targeta; - addrd->targeta_type = aux_data->targeta_type; - } else { - addrd->targeta = NULL; - addrd->targeta_type = 0; - } - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) - /* - * Periodic scan uses own filter list so we need to let it do own filtering - * regardless of scanner filtering. Just make sure we already have AdvA. - */ - if (ble_ll_sync_enabled() && - ((rxbuf[2] >> 6) == BLE_LL_EXT_ADV_MODE_NON_CONN) && addrd->adva && - !(aux_data->flags_ll & BLE_LL_AUX_FLAG_AUX_CHAIN_RECEIVED)) { - ble_ll_scan_check_periodic_sync(om, hdr, addrd->adva, addrd->adva_type, - rxinfo->rpa_index); - } -#endif - - /* Ignore if device was not matched by either whitelist or scan policy */ - if (!BLE_MBUF_HDR_DEVMATCH(hdr)) { - goto scan_continue; - } - - ble_ll_scan_rx_pkt_in_restore_addr_data(hdr, addrd); - - /* - * If there is AuxPtr in this PDU, we should first try to schedule scan for - * subsequent aux. - */ - if (BLE_MBUF_HDR_WAIT_AUX(hdr)) { - if (ble_ll_sched_aux_scan(hdr, scansm, aux_data)) { - rxinfo->flags &= ~BLE_MBUF_HDR_F_AUX_PTR_WAIT; - aux_data->flags_ll |= BLE_LL_AUX_FLAG_SCAN_ERROR; - - /* Silently ignore if no HCI event was sent to host */ - if (!(aux_data->flags_ll & BLE_LL_AUX_FLAG_HCI_SENT_ANY)) { - goto scan_continue; - } - } - - /* Ignore if this was just ADV_EXT_IND with AuxPtr, will process aux */ - if (!(aux_data->flags_ll & BLE_LL_AUX_FLAG_AUX_ADV_RECEIVED)) { - goto scan_continue; - } - - STATS_INC(ble_ll_stats, aux_chain_cnt); - } - - send_hci_report = !scansm->scan_filt_dups || - !ble_ll_scan_dup_check_ext(addrd->adv_addr_type, - addrd->adv_addr, aux_data); - if (send_hci_report) { - rc = ble_ll_hci_send_ext_adv_report(pdu_type, - addrd->adv_addr, addrd->adv_addr_type, - addrd->targeta, addrd->targeta_type, - om, hdr); - if ((rc < 0) && BLE_MBUF_HDR_WAIT_AUX(hdr)) { - /* Data were truncated so stop scanning for subsequent auxes */ - aux_data->flags_ll |= BLE_LL_AUX_FLAG_SCAN_ERROR; - - if (ble_ll_sched_rmv_elem(&aux_data->sch) == 0) { - ble_ll_scan_aux_data_unref(aux_data->sch.cb_arg); - aux_data->sch.cb_arg = NULL; - } - } else if ((rc == 0) && scansm->scan_filt_dups) { - /* Complete data were send so we can update scan_dup list */ - ble_ll_scan_dup_update_ext(addrd->adv_addr_type, addrd->adv_addr, - aux_data); - } - } - - if (BLE_MBUF_HDR_SCAN_RSP_RXD(hdr)) { - /* - * For now assume success if we just received direct scan response, - * don't care about complete aux chain. - */ - ble_ll_scan_req_backoff(scansm, 1); - } - -scan_continue: - ble_ll_scan_aux_data_unref(rxinfo->user_data); - rxinfo->user_data = NULL; -} -#endif - /** * Process a received PDU while in the scanning state. * @@ -3209,32 +2006,92 @@ ble_ll_scan_rx_pkt_in_on_aux(uint8_t pdu_type, struct os_mbuf *om, void ble_ll_scan_rx_pkt_in(uint8_t ptype, struct os_mbuf *om, struct ble_mbuf_hdr *hdr) { -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) || MYNEWT_VAL(BLE_LL_HCI_VS_SET_SCAN_CFG) struct ble_mbuf_hdr_rxinfo *rxinfo = &hdr->rxinfo; - struct ble_ll_aux_data *aux_data = rxinfo->user_data; #endif +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + uint8_t *targeta; +#endif + struct ble_ll_scan_sm *scansm; struct ble_ll_scan_addr_data addrd; + uint8_t max_pdu_type; + + scansm = &g_ble_ll_scan_sm; + + /* Ignore PDUs we do not expect here */ + max_pdu_type = BLE_ADV_PDU_TYPE_ADV_SCAN_IND; +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) + if (scansm->ext_scanning) { + /* Note: We do not expect AUX_CONNECT_RSP here */ + max_pdu_type = BLE_ADV_PDU_TYPE_ADV_EXT_IND; + } +#endif + if (ptype > max_pdu_type) { + ble_ll_scan_chk_resume(); + return; + } + +#if MYNEWT_VAL(BLE_LL_HCI_VS_SET_SCAN_CFG) + if ((scansm->vs_config.ignore_ext) && + (ptype == BLE_ADV_PDU_TYPE_ADV_EXT_IND)) { + ble_ll_scan_chk_resume(); + return; + } + + if ((scansm->vs_config.ignore_legacy) && + (ptype != BLE_ADV_PDU_TYPE_ADV_EXT_IND)) { + ble_ll_scan_chk_resume(); + return; + } + + if ((scansm->vs_config.rssi_filter) && + (rxinfo->rssi < scansm->vs_config.rssi_threshold)) { + ble_ll_scan_chk_resume(); + return; + } +#endif #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - if (aux_data || (ptype == BLE_ADV_PDU_TYPE_ADV_EXT_IND)) { - ble_ll_scan_rx_pkt_in_on_aux(ptype, om, hdr, &addrd); + if (ptype == BLE_ADV_PDU_TYPE_ADV_EXT_IND) { + ble_ll_scan_aux_pkt_in_on_ext(om, hdr); ble_ll_scan_chk_resume(); return; } #endif - ble_ll_scan_rx_pkt_in_on_legacy(ptype, om, hdr, &addrd); + switch (scansm->scanp->scan_type) { +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + case BLE_SCAN_TYPE_INITIATE: + if (rxinfo->flags & BLE_MBUF_HDR_F_CONNECT_IND_TXD) { + /* We need to keep original TargetA in case it was resolved, so rl + * can be updated properly. + */ + ble_ll_scan_get_addr_data_from_legacy(ptype, om->om_data, &addrd); + targeta = addrd.targeta; + ble_ll_scan_rx_pkt_in_restore_addr_data(hdr, &addrd); + + ble_ll_scan_sm_stop(0); + ble_ll_conn_created_on_legacy(om, &addrd, targeta); + return; + } + break; +#endif + default: + ble_ll_scan_rx_pkt_in_on_legacy(ptype, om, hdr, &addrd); + break; + } + ble_ll_scan_chk_resume(); } int -ble_ll_scan_set_scan_params(const uint8_t *cmdbuf, uint8_t len) +ble_ll_scan_hci_set_params(const uint8_t *cmdbuf, uint8_t len) { const struct ble_hci_le_set_scan_params_cp *cmd = (const void *)cmdbuf; uint16_t scan_itvl; uint16_t scan_window; struct ble_ll_scan_sm *scansm; - struct ble_ll_scan_params *scanp; + struct ble_ll_scan_phy *scanp; if (len != sizeof(*cmd)) { return BLE_ERR_INV_HCI_CMD_PARMS; @@ -3276,16 +2133,18 @@ ble_ll_scan_set_scan_params(const uint8_t *cmdbuf, uint8_t len) } /* Store scan parameters */ - scanp = &g_ble_ll_scan_params[PHY_UNCODED]; + g_ble_ll_scan_params.own_addr_type = cmd->own_addr_type; + g_ble_ll_scan_params.scan_filt_policy = cmd->filter_policy; + + scanp = &g_ble_ll_scan_params.scan_phys[PHY_UNCODED]; scanp->configured = 1; scanp->scan_type = cmd->scan_type; scanp->timing.interval = ble_ll_scan_time_hci_to_ticks(scan_itvl); scanp->timing.window = ble_ll_scan_time_hci_to_ticks(scan_window); - scanp->scan_filt_policy = cmd->filter_policy; - scanp->own_addr_type = cmd->own_addr_type; #if (BLE_LL_SCAN_PHY_NUMBER == 2) - g_ble_ll_scan_params[PHY_CODED].configured = 0; + scanp = &g_ble_ll_scan_params.scan_phys[PHY_CODED]; + scanp->configured = 0; #endif return 0; @@ -3293,7 +2152,7 @@ ble_ll_scan_set_scan_params(const uint8_t *cmdbuf, uint8_t len) #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) static int -ble_ll_check_scan_params(uint8_t type, uint16_t itvl, uint16_t window) +ble_ll_scan_check_phy_params(uint8_t type, uint16_t itvl, uint16_t window) { /* Check scan type */ if ((type != BLE_HCI_SCAN_TYPE_PASSIVE) && @@ -3303,9 +2162,9 @@ ble_ll_check_scan_params(uint8_t type, uint16_t itvl, uint16_t window) /* Check interval and window */ if ((itvl < BLE_HCI_SCAN_ITVL_MIN) || - (itvl > BLE_HCI_SCAN_ITVL_MAX) || + (itvl > BLE_HCI_SCAN_ITVL_MAX_EXT) || (window < BLE_HCI_SCAN_WINDOW_MIN) || - (window > BLE_HCI_SCAN_WINDOW_MAX) || + (window > BLE_HCI_SCAN_WINDOW_MAX_EXT) || (itvl < window)) { return BLE_ERR_INV_HCI_CMD_PARMS; } @@ -3314,14 +2173,16 @@ ble_ll_check_scan_params(uint8_t type, uint16_t itvl, uint16_t window) } int -ble_ll_set_ext_scan_params(const uint8_t *cmdbuf, uint8_t len) +ble_ll_scan_hci_set_ext_params(const uint8_t *cmdbuf, uint8_t len) { const struct ble_hci_le_set_ext_scan_params_cp *cmd = (const void *) cmdbuf; const struct scan_params *params = cmd->scans; - struct ble_ll_scan_params new_params[BLE_LL_SCAN_PHY_NUMBER] = { }; - struct ble_ll_scan_params *uncoded = &new_params[PHY_UNCODED]; - struct ble_ll_scan_params *coded = &new_params[PHY_CODED]; + struct ble_ll_scan_phy new_params[BLE_LL_SCAN_PHY_NUMBER] = { }; + struct ble_ll_scan_phy *uncoded = &new_params[PHY_UNCODED]; +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) + struct ble_ll_scan_phy *coded = &new_params[PHY_CODED]; +#endif uint16_t interval; uint16_t window; int rc; @@ -3342,22 +2203,18 @@ ble_ll_set_ext_scan_params(const uint8_t *cmdbuf, uint8_t len) return BLE_ERR_INV_HCI_CMD_PARMS; } - coded->own_addr_type = cmd->own_addr_type; - uncoded->own_addr_type = cmd->own_addr_type; - /* Check scanner filter policy */ if (cmd->filter_policy > BLE_HCI_SCAN_FILT_MAX) { return BLE_ERR_INV_HCI_CMD_PARMS; } - coded->scan_filt_policy = cmd->filter_policy; - uncoded->scan_filt_policy = cmd->filter_policy; + /* Check if valid phy is specified */ + if (cmd->phys & ~SCAN_VALID_PHY_MASK) { + return BLE_ERR_UNSUPPORTED; + } - /* Check if no reserved bits in PHYS are set and that at least one valid PHY - * is set. - */ - if (!(cmd->phys & SCAN_VALID_PHY_MASK) || - (cmd->phys & ~SCAN_VALID_PHY_MASK)) { + /* Check if at least one valid phy is specified */ + if (!(cmd->phys & SCAN_VALID_PHY_MASK)) { return BLE_ERR_INV_HCI_CMD_PARMS; } @@ -3369,7 +2226,7 @@ ble_ll_set_ext_scan_params(const uint8_t *cmdbuf, uint8_t len) interval = le16toh(params->itvl); window = le16toh(params->window); - rc = ble_ll_check_scan_params(params->type, interval, window); + rc = ble_ll_scan_check_phy_params(params->type, interval, window); if (rc) { return rc; } @@ -3393,7 +2250,7 @@ ble_ll_set_ext_scan_params(const uint8_t *cmdbuf, uint8_t len) interval = le16toh(params->itvl); window = le16toh(params->window); - rc = ble_ll_check_scan_params(params->type, interval, window); + rc = ble_ll_scan_check_phy_params(params->type, interval, window); if (rc) { return rc; } @@ -3405,7 +2262,6 @@ ble_ll_set_ext_scan_params(const uint8_t *cmdbuf, uint8_t len) /* That means user wants to use this PHY for scanning */ coded->configured = 1; } -#endif /* if any of PHYs is configured for continuous scan we alter interval to * fit other PHY @@ -3419,14 +2275,39 @@ ble_ll_set_ext_scan_params(const uint8_t *cmdbuf, uint8_t len) uncoded->timing.interval += coded->timing.window; } } +#endif - memcpy(g_ble_ll_scan_params, new_params, sizeof(new_params)); + g_ble_ll_scan_params.own_addr_type = cmd->own_addr_type; + g_ble_ll_scan_params.scan_filt_policy = cmd->filter_policy; + + memcpy(g_ble_ll_scan_params.scan_phys, new_params, sizeof(new_params)); return 0; } #endif +#if MYNEWT_VAL(BLE_LL_HCI_VS_SET_SCAN_CFG) +int +ble_ll_scan_set_vs_config(uint32_t flags, int8_t rssi_threshold) +{ + struct ble_ll_scan_sm *scansm; + + scansm = &g_ble_ll_scan_sm; + + if (scansm->scan_enabled || scansm->connsm) { + return 1; + } + + scansm->vs_config.ignore_legacy = !!(flags & BLE_HCI_VS_SET_SCAN_CFG_FLAG_NO_LEGACY); + scansm->vs_config.ignore_ext = !!(flags & BLE_HCI_VS_SET_SCAN_CFG_FLAG_NO_EXT); + scansm->vs_config.rssi_filter = !!(flags & BLE_HCI_VS_SET_SCAN_CFG_FLAG_RSSI_FILTER); + scansm->vs_config.rssi_threshold = rssi_threshold; + + return 0; +} +#endif + #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) static void ble_ll_scan_duration_period_timers_restart(struct ble_ll_scan_sm *scansm) @@ -3487,8 +2368,8 @@ ble_ll_scan_set_enable(uint8_t enable, uint8_t filter_dups, uint16_t period, { int rc; struct ble_ll_scan_sm *scansm; - struct ble_ll_scan_params *scanp; - struct ble_ll_scan_params *scanp_phy; + struct ble_ll_scan_phy *scanp; + struct ble_ll_scan_phy *scanp_phy; int i; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) ble_npl_time_t period_ticks = 0; @@ -3503,6 +2384,27 @@ ble_ll_scan_set_enable(uint8_t enable, uint8_t filter_dups, uint16_t period, scansm = &g_ble_ll_scan_sm; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) + if (ext) { + /* + * If Enable is set to 0x01 and the Host has not issued the + * HCI_LE_Set_Extended_Scan_Parameters command, the Controller shall + * either use vendor-specified parameters or return the error code + * Command Disallowed (0x0C) + * + * To keep things simple for devices without public address we + * reject in such case. + */ + for (i = 0; i < BLE_LL_SCAN_PHY_NUMBER; i++) { + if (g_ble_ll_scan_params.scan_phys[i].configured) { + break; + } + } + + if (i == BLE_LL_SCAN_PHY_NUMBER) { + return BLE_ERR_CMD_DISALLOWED; + } + } + /* we can do that here since value will never change until reset */ scansm->ext_scanning = ext; @@ -3542,13 +2444,15 @@ ble_ll_scan_set_enable(uint8_t enable, uint8_t filter_dups, uint16_t period, /* if already enable we just need to update parameters */ if (scansm->scan_enabled) { /* Controller does not allow initiating and scanning.*/ +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) for (i = 0; i < BLE_LL_SCAN_PHY_NUMBER; i++) { - scanp_phy = &scansm->scanp_phys[i]; + scanp_phy = &scansm->scan_phys[i]; if (scanp_phy->configured && scanp_phy->scan_type == BLE_SCAN_TYPE_INITIATE) { return BLE_ERR_CMD_DISALLOWED; } } +#endif #if MYNEWT_VAL(BLE_LL_NUM_SCAN_DUP_ADVS) /* update filter policy */ @@ -3575,9 +2479,12 @@ ble_ll_scan_set_enable(uint8_t enable, uint8_t filter_dups, uint16_t period, scansm->scanp = NULL; scansm->scanp_next = NULL; + scansm->own_addr_type = g_ble_ll_scan_params.own_addr_type; + scansm->scan_filt_policy = g_ble_ll_scan_params.scan_filt_policy; + for (i = 0; i < BLE_LL_SCAN_PHY_NUMBER; i++) { - scanp_phy = &scansm->scanp_phys[i]; - scanp = &g_ble_ll_scan_params[i]; + scanp_phy = &scansm->scan_phys[i]; + scanp = &g_ble_ll_scan_params.scan_phys[i]; if (!scanp->configured) { continue; @@ -3586,15 +2493,9 @@ ble_ll_scan_set_enable(uint8_t enable, uint8_t filter_dups, uint16_t period, scanp_phy->configured = scanp->configured; scanp_phy->scan_type = scanp->scan_type; scanp_phy->timing = scanp->timing; - scanp_phy->scan_filt_policy = scanp->scan_filt_policy; - scanp_phy->own_addr_type = scanp->own_addr_type; if (!scansm->scanp) { scansm->scanp = scanp_phy; - /* Take own_addr_type from the first configured PHY. - * Note: All configured PHYs shall have the same own_addr_type - */ - scansm->own_addr_type = scanp_phy->own_addr_type; } else { scansm->scanp_next = scanp_phy; } @@ -3606,8 +2507,9 @@ ble_ll_scan_set_enable(uint8_t enable, uint8_t filter_dups, uint16_t period, * Parameters defaults. */ if (!scansm->scanp) { - scansm->scanp = &scansm->scanp_phys[PHY_UNCODED]; + scansm->scanp = &scansm->scan_phys[PHY_UNCODED]; scansm->own_addr_type = BLE_ADDR_PUBLIC; + scansm->scan_filt_policy = BLE_HCI_SCAN_FILT_NO_WL; scanp_phy = scansm->scanp; scanp_phy->configured = 1; @@ -3616,8 +2518,6 @@ ble_ll_scan_set_enable(uint8_t enable, uint8_t filter_dups, uint16_t period, ble_ll_scan_time_hci_to_ticks(BLE_HCI_SCAN_ITVL_DEF); scanp_phy->timing.window = ble_ll_scan_time_hci_to_ticks(BLE_HCI_SCAN_WINDOW_DEF); - scanp_phy->scan_filt_policy = BLE_HCI_SCAN_FILT_NO_WL; - scanp_phy->own_addr_type = BLE_ADDR_PUBLIC; } rc = ble_ll_scan_sm_start(scansm); @@ -3633,7 +2533,7 @@ ble_ll_scan_set_enable(uint8_t enable, uint8_t filter_dups, uint16_t period, return rc; } -int ble_ll_hci_scan_set_enable(const uint8_t *cmdbuf, uint8_t len) +int ble_ll_scan_hci_set_enable(const uint8_t *cmdbuf, uint8_t len) { const struct ble_hci_le_set_scan_enable_cp *cmd = (const void *) cmdbuf; @@ -3646,7 +2546,7 @@ int ble_ll_hci_scan_set_enable(const uint8_t *cmdbuf, uint8_t len) } #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -int ble_ll_hci_ext_scan_set_enable(const uint8_t *cmdbuf, uint8_t len) +int ble_ll_scan_hci_set_ext_enable(const uint8_t *cmdbuf, uint8_t len) { const struct ble_hci_le_set_ext_scan_enable_cp *cmd = (const void *) cmdbuf; @@ -3671,11 +2571,9 @@ ble_ll_scan_can_chg_whitelist(void) { int rc; struct ble_ll_scan_sm *scansm; - struct ble_ll_scan_params *scanp; scansm = &g_ble_ll_scan_sm; - scanp = scansm->scanp; - if (scansm->scan_enabled && (scanp->scan_filt_policy & 1)) { + if (scansm->scan_enabled && (scansm->scan_filt_policy & 1)) { rc = 0; } else { rc = 1; @@ -3684,83 +2582,61 @@ ble_ll_scan_can_chg_whitelist(void) return rc; } +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) int -ble_ll_scan_initiator_start(struct hci_create_conn *hcc, - struct ble_ll_scan_sm **sm) +ble_ll_scan_initiator_start(struct ble_ll_conn_sm *connsm, uint8_t ext, + struct ble_ll_conn_create_scan *cc_scan) { struct ble_ll_scan_sm *scansm; - struct ble_ll_scan_params *scanp; - int rc; - - scansm = &g_ble_ll_scan_sm; - scansm->own_addr_type = hcc->own_addr_type; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - scansm->ext_scanning = 0; + struct ble_ll_scan_phy *scanp_uncoded; +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) && MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) + struct ble_ll_scan_phy *scanp_coded; #endif - scansm->scanp = &scansm->scanp_phys[PHY_UNCODED]; - scansm->scanp_next = NULL; - - scanp = scansm->scanp; - scanp->scan_filt_policy = hcc->filter_policy; - scanp->timing.interval = ble_ll_scan_time_hci_to_ticks(hcc->scan_itvl); - scanp->timing.window = ble_ll_scan_time_hci_to_ticks(hcc->scan_window); - scanp->scan_type = BLE_SCAN_TYPE_INITIATE; - - rc = ble_ll_scan_sm_start(scansm); - if (sm == NULL) { - return rc; - } - - if (rc == BLE_ERR_SUCCESS) { - *sm = scansm; - } else { - *sm = NULL; - } - - return rc; -} - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -int -ble_ll_scan_ext_initiator_start(struct hci_ext_create_conn *hcc, - struct ble_ll_scan_sm **sm) -{ - struct ble_ll_scan_sm *scansm; - struct ble_ll_scan_params *scanp_uncoded; - struct ble_ll_scan_params *scanp_coded; - struct hci_ext_conn_params *params; + uint8_t init_phy_mask; int rc; scansm = &g_ble_ll_scan_sm; - scansm->own_addr_type = hcc->own_addr_type; + scansm->own_addr_type = cc_scan->own_addr_type; + scansm->scan_filt_policy = cc_scan->filter_policy; scansm->scanp = NULL; scansm->scanp_next = NULL; - scansm->ext_scanning = 1; - - if (hcc->init_phy_mask & BLE_PHY_MASK_1M) { - params = &hcc->params[0]; - scanp_uncoded = &scansm->scanp_phys[PHY_UNCODED]; +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) + scansm->ext_scanning = ext; + init_phy_mask = cc_scan->init_phy_mask; +#else + init_phy_mask = BLE_PHY_MASK_1M; +#endif + scansm->connsm = connsm; - scanp_uncoded->timing.interval = ble_ll_scan_time_hci_to_ticks(params->scan_itvl); - scanp_uncoded->timing.window = ble_ll_scan_time_hci_to_ticks(params->scan_window); + scanp_uncoded = &scansm->scan_phys[PHY_UNCODED]; + if (init_phy_mask & BLE_PHY_MASK_1M) { + scanp_uncoded->configured = 1; + scanp_uncoded->timing.interval = ble_ll_scan_time_hci_to_ticks( + cc_scan->scan_params[PHY_UNCODED].itvl); + scanp_uncoded->timing.window = ble_ll_scan_time_hci_to_ticks( + cc_scan->scan_params[PHY_UNCODED].window); scanp_uncoded->scan_type = BLE_SCAN_TYPE_INITIATE; - scanp_uncoded->scan_filt_policy = hcc->filter_policy; scansm->scanp = scanp_uncoded; + } else { + scanp_uncoded->configured = 0; } - if (hcc->init_phy_mask & BLE_PHY_MASK_CODED) { - params = &hcc->params[2]; - scanp_coded = &scansm->scanp_phys[PHY_CODED]; - - scanp_coded->timing.interval = ble_ll_scan_time_hci_to_ticks(params->scan_itvl); - scanp_coded->timing.window = ble_ll_scan_time_hci_to_ticks(params->scan_window); +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) && MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) + scanp_coded = &scansm->scan_phys[PHY_CODED]; + if (init_phy_mask & BLE_PHY_MASK_CODED) { + scanp_coded->configured = 1; + scanp_coded->timing.interval = ble_ll_scan_time_hci_to_ticks( + cc_scan->scan_params[PHY_CODED].itvl); + scanp_coded->timing.window = ble_ll_scan_time_hci_to_ticks( + cc_scan->scan_params[PHY_CODED].window); scanp_coded->scan_type = BLE_SCAN_TYPE_INITIATE; - scanp_coded->scan_filt_policy = hcc->filter_policy; if (scansm->scanp) { scansm->scanp_next = scanp_coded; } else { scansm->scanp = scanp_coded; } + } else { + scanp_coded->configured = 0; } /* if any of PHYs is configured for continuous scan we alter interval to @@ -3776,16 +2652,11 @@ ble_ll_scan_ext_initiator_start(struct hci_ext_create_conn *hcc, scanp_uncoded->timing.interval += scanp_coded->timing.window; } } +#endif rc = ble_ll_scan_sm_start(scansm); - if (sm == NULL) { - return rc; - } - - if (rc == BLE_ERR_SUCCESS) { - *sm = scansm; - } else { - *sm = NULL; + if (rc == 0) { + g_ble_ll_conn_create_sm.connsm = connsm; } return rc; @@ -3853,18 +2724,11 @@ ble_ll_scan_get_pdu_data(void) return &g_ble_ll_scan_sm.pdu_data; } -/* Returns true if whitelist is enabled for scanning */ -int -ble_ll_scan_whitelist_enabled(void) -{ - return g_ble_ll_scan_sm.scanp->scan_filt_policy & 1; -} - static void ble_ll_scan_common_init(void) { struct ble_ll_scan_sm *scansm; - struct ble_ll_scan_params *scanp; + struct ble_ll_scan_phy *scanp; int i; /* Clear state machine in case re-initialized */ @@ -3872,32 +2736,32 @@ ble_ll_scan_common_init(void) memset(scansm, 0, sizeof(struct ble_ll_scan_sm)); /* Clear scan parameters in case re-initialized */ - memset(g_ble_ll_scan_params, 0, sizeof(g_ble_ll_scan_params)); + memset(&g_ble_ll_scan_params, 0, sizeof(g_ble_ll_scan_params)); /* Initialize scanning window end event */ ble_npl_event_init(&scansm->scan_sched_ev, ble_ll_scan_event_proc, scansm); for (i = 0; i < BLE_LL_SCAN_PHY_NUMBER; i++) { /* Set all non-zero default parameters */ - scanp = &g_ble_ll_scan_params[i]; + scanp = &g_ble_ll_scan_params.scan_phys[i]; scanp->timing.interval = ble_ll_scan_time_hci_to_ticks(BLE_HCI_SCAN_ITVL_DEF); scanp->timing.window = ble_ll_scan_time_hci_to_ticks(BLE_HCI_SCAN_WINDOW_DEF); } - scansm->scanp_phys[PHY_UNCODED].phy = BLE_PHY_1M; + scansm->scan_phys[PHY_UNCODED].phy = BLE_PHY_1M; #if (BLE_LL_SCAN_PHY_NUMBER == 2) - scansm->scanp_phys[PHY_CODED].phy = BLE_PHY_CODED; + scansm->scan_phys[PHY_CODED].phy = BLE_PHY_CODED; #endif -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) +#if MYNEWT_VAL(BLE_LL_SCAN_ACTIVE_SCAN_NRPA) /* Make sure we'll generate new NRPA if necessary */ scansm->scan_nrpa_timer = ble_npl_time_get(); #endif /* Initialize scanning timer */ - os_cputime_timer_init(&scansm->scan_timer, ble_ll_scan_timer_cb, scansm); + ble_ll_tmr_init(&scansm->scan_timer, ble_ll_scan_timer_cb, scansm); /* Initialize extended scan timers */ #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) @@ -3941,13 +2805,11 @@ ble_ll_scan_reset(void) os_mempool_clear(&g_scan_dup_pool); TAILQ_INIT(&g_scan_dup_list); -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - /* clear memory pool for AUX scan results */ - os_mempool_clear(&ext_scan_aux_pool); -#endif - /* Call the common init function again */ ble_ll_scan_common_init(); +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) + ble_ll_scan_aux_init(); +#endif } /** @@ -3961,15 +2823,6 @@ ble_ll_scan_init(void) { os_error_t err; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - err = os_mempool_init(&ext_scan_aux_pool, - MYNEWT_VAL(BLE_LL_EXT_ADV_AUX_PTR_CNT), - sizeof (struct ble_ll_aux_data), - ext_scan_aux_mem, - "ble_ll_aux_scan_pool"); - BLE_LL_ASSERT(err == 0); -#endif - err = os_mempool_init(&g_scan_dup_pool, MYNEWT_VAL(BLE_LL_NUM_SCAN_DUP_ADVS), sizeof(struct ble_ll_scan_dup_entry), @@ -3980,4 +2833,9 @@ ble_ll_scan_init(void) TAILQ_INIT(&g_scan_dup_list); ble_ll_scan_common_init(); +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) + ble_ll_scan_aux_init(); +#endif } + +#endif diff --git a/nimble/controller/src/ble_ll_scan_aux.c b/nimble/controller/src/ble_ll_scan_aux.c new file mode 100644 index 0000000000..0cb734a240 --- /dev/null +++ b/nimble/controller/src/ble_ll_scan_aux.c @@ -0,0 +1,1784 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include + +#if MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) && MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) + +#include +#include +#include +#include +#include "os/os.h" +#include "nimble/ble.h" +#include "nimble/hci_common.h" +#include "controller/ble_ll_utils.h" +#include "controller/ble_phy.h" +#include "controller/ble_hw.h" +#include "controller/ble_ll.h" +#include "controller/ble_ll_pdu.h" +#include "controller/ble_ll_sched.h" +#include "controller/ble_ll_scan.h" +#include "controller/ble_ll_scan_aux.h" +#include "controller/ble_ll_hci.h" +#include "controller/ble_ll_whitelist.h" +#include "controller/ble_ll_resolv.h" +#include "controller/ble_ll_sync.h" +#include "ble_ll_priv.h" + +#define BLE_LL_SCAN_AUX_F_AUX_ADV 0x0001 +#define BLE_LL_SCAN_AUX_F_AUX_CHAIN 0x0002 +#define BLE_LL_SCAN_AUX_F_MATCHED 0x0004 +#define BLE_LL_SCAN_AUX_F_W4_SCAN_RSP 0x0008 +#define BLE_LL_SCAN_AUX_F_SCANNED 0x0010 +#define BLE_LL_SCAN_AUX_F_HAS_ADVA 0x0020 +#define BLE_LL_SCAN_AUX_F_HAS_TARGETA 0x0040 +#define BLE_LL_SCAN_AUX_F_HAS_ADI 0x0080 +#define BLE_LL_SCAN_AUX_F_RESOLVED_ADVA 0x0100 +#define BLE_LL_SCAN_AUX_F_RESOLVED_TARGETA 0x0200 +#define BLE_LL_SCAN_AUX_F_CONNECTABLE 0x0400 +#define BLE_LL_SCAN_AUX_F_W4_CONNECT_RSP 0x0800 + +#define BLE_LL_SCAN_AUX_H_SENT_ANY 0x01 +#define BLE_LL_SCAN_AUX_H_DONE 0x02 +#define BLE_LL_SCAN_AUX_H_TRUNCATED 0x04 + +struct ble_ll_scan_aux_data { + uint16_t flags; + uint8_t hci_state; + + uint8_t scan_type; + + uint8_t pri_phy; + uint8_t sec_phy; + uint8_t chan; + uint16_t wfr_us; + uint32_t aux_ptr; + struct ble_ll_sched_item sch; + struct ble_npl_event break_ev; + struct ble_hci_ev *hci_ev; + + uint16_t adi; + + uint8_t adva[6]; + uint8_t targeta[6]; + uint8_t adva_type : 1; + uint8_t targeta_type : 1; + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + int8_t rpa_index; +#endif +#if MYNEWT_VAL(BLE_LL_ADV_CODING_SELECTION) + uint8_t pri_phy_mode; +#endif +}; + +#define AUX_MEMPOOL_SIZE (OS_MEMPOOL_SIZE( \ + MYNEWT_VAL(BLE_LL_SCAN_AUX_SEGMENT_CNT), \ + sizeof(struct ble_ll_scan_aux_data))) + +static os_membuf_t aux_data_mem[AUX_MEMPOOL_SIZE]; +static struct os_mempool aux_data_pool; + +static struct ble_ll_scan_aux_data *aux_data_current; + +static void ble_ll_hci_ev_send_ext_adv_truncated_report(struct ble_ll_scan_aux_data *aux); + +static inline uint8_t * +ble_ll_scan_aux_get_own_addr(void) +{ + uint8_t own_addr_type; + + own_addr_type = ble_ll_scan_get_own_addr_type() & 1; + + return ble_ll_get_our_devaddr(own_addr_type); +} + +static int +ble_ll_scan_aux_sched_cb(struct ble_ll_sched_item *sch) +{ + struct ble_ll_scan_aux_data *aux = sch->cb_arg; +#if MYNEWT_VAL(BLE_LL_PHY) + uint8_t phy_mode; +#endif + uint8_t lls; + int rc; + + BLE_LL_ASSERT(aux); + + lls = ble_ll_state_get(); + BLE_LL_ASSERT(lls == BLE_LL_STATE_STANDBY); + + rc = ble_phy_setchan(aux->chan, BLE_ACCESS_ADDR_ADV, BLE_LL_CRCINIT_ADV); + BLE_LL_ASSERT(rc == 0); + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) + ble_phy_encrypt_disable(); +#endif + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + if (ble_ll_resolv_enabled()) { + ble_phy_resolv_list_enable(); + } else { + ble_phy_resolv_list_disable(); + } +#endif + +#if MYNEWT_VAL(BLE_LL_PHY) + phy_mode = ble_ll_phy_to_phy_mode(aux->sec_phy, BLE_HCI_LE_PHY_CODED_ANY); + ble_phy_mode_set(phy_mode, phy_mode); +#endif + + /* if scan is not passive we need to set tx power as we may end up sending + * package + */ + /* TODO do this only on first AUX? */ + if (aux->scan_type != BLE_SCAN_TYPE_PASSIVE) { + ble_ll_tx_power_set(g_ble_ll_tx_power); + } + + rc = ble_phy_rx_set_start_time(sch->start_time + g_ble_ll_sched_offset_ticks, + sch->remainder); + if (rc != 0 && rc != BLE_PHY_ERR_RX_LATE) { + ble_ll_scan_aux_break(aux); + return BLE_LL_SCHED_STATE_DONE; + } + + /* Keep listening even if we are late, we may still receive something */ + + if (ble_ll_scan_get_filt_policy() & 1) { + ble_ll_whitelist_enable(); + } else { + ble_ll_whitelist_disable(); + } + + ble_phy_wfr_enable(BLE_PHY_WFR_ENABLE_RX, 0, aux->wfr_us); + + aux_data_current = aux; + + ble_ll_state_set(BLE_LL_STATE_SCAN_AUX); + + return BLE_LL_SCHED_STATE_RUNNING; +} + +static struct ble_ll_scan_aux_data * +ble_ll_scan_aux_alloc(void) +{ + struct ble_ll_scan_aux_data *aux; + + aux = os_memblock_get(&aux_data_pool); + if (!aux) { + return NULL; + } + + memset(aux, 0, sizeof(*aux)); + + aux->sch.sched_cb = ble_ll_scan_aux_sched_cb; + aux->sch.sched_type = BLE_LL_SCHED_TYPE_SCAN_AUX; + aux->sch.cb_arg = aux; +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + aux->rpa_index = -1; +#endif + + return aux; +} + +static void +ble_ll_scan_aux_free(struct ble_ll_scan_aux_data *aux) +{ + BLE_LL_ASSERT(!aux->sch.enqueued); + BLE_LL_ASSERT(aux->hci_ev == NULL); + BLE_LL_ASSERT((aux->hci_state & BLE_LL_SCAN_AUX_H_DONE) || + !(aux->hci_state & BLE_LL_SCAN_AUX_H_SENT_ANY)); + + os_memblock_put(&aux_data_pool, aux); +} + + +static inline bool +ble_ll_scan_aux_need_truncation(struct ble_ll_scan_aux_data *aux) +{ + return (aux->hci_state & BLE_LL_SCAN_AUX_H_SENT_ANY) && + !(aux->hci_state & BLE_LL_SCAN_AUX_H_DONE); +} + +static struct ble_hci_ev * +ble_ll_hci_ev_alloc_ext_adv_report_for_aux(struct ble_mbuf_hdr_rxinfo *rxinfo, + struct ble_ll_scan_addr_data *addrd, + struct ble_ll_scan_aux_data *aux) +{ + struct ble_hci_ev_le_subev_ext_adv_rpt *hci_subev; + struct ext_adv_report *report; + struct ble_hci_ev *hci_ev; + + hci_ev = ble_transport_alloc_evt(1); + if (!hci_ev) { + return NULL; + } + + hci_ev->opcode = BLE_HCI_EVCODE_LE_META; + hci_ev->length = sizeof(*hci_subev) + sizeof(*report); + + hci_subev = (void *)hci_ev->data; + hci_subev->subev_code = BLE_HCI_LE_SUBEV_EXT_ADV_RPT; + hci_subev->num_reports = 1; + + report = hci_subev->reports; + + memset(report, 0, sizeof(*report)); + + report->evt_type = 0; + if (addrd->adva) { + report->addr_type = addrd->adv_addr_type; + memcpy(report->addr, addrd->adv_addr, 6); +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + if (addrd->adva_resolved) { + report->addr_type += 2; + } +#endif + } else { + report->addr_type = 0xff; + } + report->pri_phy = aux->pri_phy; + report->sec_phy = aux->sec_phy; + report->sid = aux->adi >> 12; + report->tx_power = 0x7f; + report->rssi = 0x7f; + report->periodic_itvl = 0; + +#if MYNEWT_VAL(BLE_LL_ADV_CODING_SELECTION) + if (aux->pri_phy_mode == BLE_PHY_MODE_CODED_500KBPS) { + report->pri_phy = 0x04; + } + if (rxinfo->phy_mode == BLE_PHY_MODE_CODED_500KBPS) { + report->sec_phy = 0x04; + } +#endif + + if (addrd->targeta) { + report->evt_type |= BLE_HCI_ADV_DIRECT_MASK; + report->dir_addr_type = addrd->targeta_type; + memcpy(report->dir_addr, addrd->targeta, 6); +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + if (addrd->targeta_resolved) { + report->dir_addr_type += 2; + } else if (ble_ll_is_rpa(addrd->targeta, addrd->targeta_type)) { + report->dir_addr_type = 0xfe; + } +#endif + } + report->data_len = 0; + + return hci_ev; +} + +static struct ble_hci_ev * +ble_ll_hci_ev_dup_ext_adv_report(struct ble_hci_ev *hci_ev_src) +{ + struct ble_hci_ev_le_subev_ext_adv_rpt *hci_subev; + struct ext_adv_report *report; + struct ble_hci_ev *hci_ev; + + hci_ev = ble_transport_alloc_evt(1); + if (!hci_ev) { + return NULL; + } + + memcpy(hci_ev, hci_ev_src, sizeof(*hci_ev) + sizeof(*hci_subev) + + sizeof(*report)); + hci_ev->length = sizeof(*hci_subev) + sizeof(*report); + + hci_subev = (void *)hci_ev->data; + + report = hci_subev->reports; + report->data_len = 0; + + return hci_ev; +} + +static void +ble_ll_hci_ev_update_ext_adv_report_from_aux(struct ble_hci_ev *hci_ev, + struct os_mbuf *rxpdu, + struct ble_mbuf_hdr *rxhdr) +{ + struct ble_hci_ev_le_subev_ext_adv_rpt *hci_subev; + struct ext_adv_report *report; + uint8_t adv_mode; + uint8_t eh_len; + uint8_t eh_flags; + uint8_t *eh_data; + uint8_t *rxbuf; + + hci_subev = (void *)hci_ev->data; + report = hci_subev->reports; + rxbuf = rxpdu->om_data; + + adv_mode = rxbuf[2] >> 6; + eh_len = rxbuf[2] & 0x3f; + eh_flags = rxbuf[3]; + eh_data = &rxbuf[4]; + + report->evt_type |= adv_mode; + if (rxhdr->rxinfo.flags & BLE_MBUF_HDR_F_SCAN_RSP_RXD) { + report->evt_type |= BLE_HCI_ADV_SCAN_MASK | BLE_HCI_ADV_SCAN_RSP_MASK; + } + report->sec_phy = rxhdr->rxinfo.phy; + +#if MYNEWT_VAL(BLE_LL_ADV_CODING_SELECTION) + if (rxhdr->rxinfo.phy_mode == BLE_PHY_MODE_CODED_500KBPS) { + report->sec_phy = 0x04; + } +#endif + + /* Strip PDU header and ext header, leave only AD */ + os_mbuf_adj(rxpdu, 3 + eh_len); + + /* + * We only care about SyncInfo and TxPower so don't bother parsing if they + * are not present, just set to 'unknown' values. + */ + if ((eh_len == 0) || !(eh_flags & ((1 << BLE_LL_EXT_ADV_SYNC_INFO_BIT) | + (1 << BLE_LL_EXT_ADV_TX_POWER_BIT)))) { + report->periodic_itvl = 0; + report->tx_power = 0x7f; + return; + } + /* Now parse extended header... */ + + if (eh_flags & (1 << BLE_LL_EXT_ADV_ADVA_BIT)) { + eh_data += BLE_LL_EXT_ADV_ADVA_SIZE; + } + + if (eh_flags & (1 << BLE_LL_EXT_ADV_TARGETA_BIT)) { + eh_data += BLE_LL_EXT_ADV_TARGETA_SIZE; + } + + if (eh_flags & (1 << BLE_LL_EXT_ADV_CTE_INFO_BIT)) { + eh_data += BLE_LL_EXT_ADV_CTE_INFO_SIZE; + } + + if (eh_flags & (1 << BLE_LL_EXT_ADV_DATA_INFO_BIT)) { + eh_data += BLE_LL_EXT_ADV_DATA_INFO_SIZE; + } + + if (eh_flags & (1 << BLE_LL_EXT_ADV_AUX_PTR_BIT)) { + eh_data += BLE_LL_EXT_ADV_AUX_PTR_SIZE; + } + + if (eh_flags & (1 << BLE_LL_EXT_ADV_SYNC_INFO_BIT)) { + report->periodic_itvl = get_le16(eh_data + 2); + eh_data += BLE_LL_EXT_ADV_SYNC_INFO_SIZE; + } else { + report->periodic_itvl = 0; + } + + if (eh_flags & (1 << BLE_LL_EXT_ADV_TX_POWER_BIT)) { + report->tx_power = *eh_data; + } else { + report->tx_power = 0x7f; + } +} + +static void +ble_ll_hci_ev_update_ext_adv_report_from_ext(struct ble_hci_ev *hci_ev, + struct os_mbuf *rxpdu, + struct ble_mbuf_hdr *rxhdr) +{ + struct ble_mbuf_hdr_rxinfo *rxinfo = &rxhdr->rxinfo; + struct ble_hci_ev_le_subev_ext_adv_rpt *hci_subev; + struct ext_adv_report *report; +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + struct ble_ll_resolv_entry *rl; +#endif + uint8_t pdu_hdr; + uint8_t adv_mode; + uint8_t eh_flags; + uint8_t *eh_data; + uint8_t *rxbuf; + + rxbuf = rxpdu->om_data; + + pdu_hdr = rxbuf[0]; + adv_mode = rxbuf[2] >> 6; + eh_flags = rxbuf[3]; + eh_data = &rxbuf[4]; + + hci_ev->opcode = BLE_HCI_EVCODE_LE_META; + hci_ev->length = sizeof(*hci_subev) + sizeof(*report); + + hci_subev = (void *)hci_ev->data; + hci_subev->subev_code = BLE_HCI_LE_SUBEV_EXT_ADV_RPT; + hci_subev->num_reports = 1; + + report = hci_subev->reports; + + memset(report, 0, sizeof(*report)); + + report->evt_type = adv_mode; + + report->pri_phy = rxinfo->phy; + report->sec_phy = 0; + report->sid = 0xff; + report->rssi = rxhdr->rxinfo.rssi - ble_ll_rx_gain(); + report->periodic_itvl = 0; + report->data_len = 0; + +#if MYNEWT_VAL(BLE_LL_ADV_CODING_SELECTION) + if (rxinfo->phy_mode == BLE_PHY_MODE_CODED_500KBPS) { + report->pri_phy = 0x04; + } +#endif + + /* Now parse extended header... */ + + if (eh_flags & (1 << BLE_LL_EXT_ADV_ADVA_BIT)) { +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + if (rxinfo->flags & BLE_MBUF_HDR_F_RESOLVED) { + rl = &g_ble_ll_resolv_list[rxinfo->rpa_index]; + report->addr_type = rl->rl_addr_type + 2; + memcpy(report->addr, rl->rl_identity_addr, 6); + } else { + report->addr_type = !!(pdu_hdr & BLE_ADV_PDU_HDR_TXADD_MASK); + memcpy(report->addr, eh_data, 6); + } +#else + report->addr_type = !!(pdu_hdr & BLE_ADV_PDU_HDR_TXADD_MASK); + memcpy(report->addr, eh_data, 6); +#endif + eh_data += BLE_LL_EXT_ADV_ADVA_SIZE; + } + + if (eh_flags & (1 << BLE_LL_EXT_ADV_TARGETA_BIT)) { + report->evt_type |= BLE_HCI_ADV_DIRECT_MASK; +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + if (rxinfo->flags & BLE_MBUF_HDR_F_TARGETA_RESOLVED) { + report->dir_addr_type = (ble_ll_scan_get_own_addr_type() & 1) + 2; + memcpy(report->dir_addr, ble_ll_scan_aux_get_own_addr(), 6); + } else { + if (ble_ll_is_rpa(eh_data, pdu_hdr & BLE_ADV_PDU_HDR_RXADD_MASK)) { + report->dir_addr_type = 0xfe; + } else { + report->dir_addr_type = !!(pdu_hdr & + BLE_ADV_PDU_HDR_RXADD_MASK); + } + memcpy(report->dir_addr, eh_data, 6); + } +#else + report->dir_addr_type = !!(pdu_hdr & BLE_ADV_PDU_HDR_RXADD_MASK); + memcpy(report->dir_addr, eh_data, 6); +#endif + eh_data += BLE_LL_EXT_ADV_TARGETA_SIZE; + } + + if (eh_flags & (1 << BLE_LL_EXT_ADV_CTE_INFO_BIT)) { + eh_data += BLE_LL_EXT_ADV_CTE_INFO_SIZE; + } + + if (eh_flags & (1 << BLE_LL_EXT_ADV_DATA_INFO_BIT)) { + eh_data += BLE_LL_EXT_ADV_DATA_INFO_SIZE; + } + + if (eh_flags & (1 << BLE_LL_EXT_ADV_AUX_PTR_BIT)) { + eh_data += BLE_LL_EXT_ADV_AUX_PTR_SIZE; + } + + if (eh_flags & (1 << BLE_LL_EXT_ADV_SYNC_INFO_BIT)) { + eh_data += BLE_LL_EXT_ADV_SYNC_INFO_SIZE; + } + + if (eh_flags & (1 << BLE_LL_EXT_ADV_TX_POWER_BIT)) { + report->tx_power = *eh_data; + } else { + report->tx_power = 0x7f; + } + + /* AdvData in ADV_EXT_IND is RFU so we should ignore it, i.e. we can just + * remove any data left in mbuf + */ + os_mbuf_adj(rxpdu, os_mbuf_len(rxpdu)); + +} + +static void +ble_ll_hci_ev_send_ext_adv_truncated_report(struct ble_ll_scan_aux_data *aux) +{ + struct ble_hci_ev_le_subev_ext_adv_rpt *hci_subev; + struct ext_adv_report *report; + struct ble_hci_ev *hci_ev; + + if (!ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_EXT_ADV_RPT)) { + return; + } + + hci_ev = aux->hci_ev; + aux->hci_ev = NULL; + + BLE_LL_ASSERT(hci_ev); + + hci_subev = (void *)hci_ev->data; + report = hci_subev->reports; + report->evt_type |= BLE_HCI_ADV_DATA_STATUS_TRUNCATED; + + ble_ll_hci_event_send(hci_ev); + + aux->hci_state |= BLE_LL_SCAN_AUX_H_DONE | BLE_LL_SCAN_AUX_H_TRUNCATED; +} + +static int +ble_ll_hci_ev_send_ext_adv_report(struct os_mbuf *rxpdu, + struct ble_mbuf_hdr *rxhdr, + struct ble_hci_ev **hci_ev) +{ + struct ble_mbuf_hdr_rxinfo *rxinfo = &rxhdr->rxinfo; + struct ble_hci_ev_le_subev_ext_adv_rpt *hci_subev; + struct ble_hci_ev *hci_ev_next; + struct ext_adv_report *report; + bool truncated = false; + int max_data_len; + int data_len; + int offset; + + data_len = OS_MBUF_PKTLEN(rxpdu); + max_data_len = BLE_LL_MAX_EVT_LEN - + sizeof(**hci_ev) - sizeof(*hci_subev) - sizeof(*report); + offset = 0; + hci_ev_next = NULL; + + do { + hci_subev = (void *)(*hci_ev)->data; + report = hci_subev->reports; + + report->rssi = rxinfo->rssi - ble_ll_rx_gain(); + + report->data_len = MIN(max_data_len, data_len - offset); + os_mbuf_copydata(rxpdu, offset, report->data_len, report->data); + (*hci_ev)->length += report->data_len; + + offset += report->data_len; + + /* + * We need another event if either there are still some data left in + * this PDU or scan for next aux is scheduled. + */ + if ((offset < data_len) || + (rxinfo->flags & BLE_MBUF_HDR_F_AUX_PTR_WAIT)) { + hci_ev_next = ble_ll_hci_ev_dup_ext_adv_report(*hci_ev); + if (hci_ev_next) { + report->evt_type |= BLE_HCI_ADV_DATA_STATUS_INCOMPLETE; + } else { + report->evt_type |= BLE_HCI_ADV_DATA_STATUS_TRUNCATED; + } + } else if (rxinfo->flags & BLE_MBUF_HDR_F_AUX_PTR_FAILED) { + report->evt_type |= BLE_HCI_ADV_DATA_STATUS_TRUNCATED; + } + + switch (report->evt_type & BLE_HCI_ADV_DATA_STATUS_MASK) { + case BLE_HCI_ADV_DATA_STATUS_TRUNCATED: + truncated = true; + /* no break */ + case BLE_HCI_ADV_DATA_STATUS_COMPLETE: + BLE_LL_ASSERT(!hci_ev_next); + break; + case BLE_HCI_ADV_DATA_STATUS_INCOMPLETE: + BLE_LL_ASSERT(hci_ev_next); + break; + default: + BLE_LL_ASSERT(0); + } + + ble_ll_hci_event_send(*hci_ev); + + *hci_ev = hci_ev_next; + hci_ev_next = NULL; + } while ((offset < data_len) && *hci_ev); + + return truncated ? -1 : 0; +} + + +static int +ble_ll_hci_ev_send_ext_adv_report_for_aux(struct os_mbuf *rxpdu, + struct ble_mbuf_hdr *rxhdr, + struct ble_ll_scan_aux_data *aux, + struct ble_ll_scan_addr_data *addrd) +{ + struct ble_hci_ev *hci_ev; + int rc; + + if (!ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_EXT_ADV_RPT)) { + aux->hci_state = BLE_LL_SCAN_AUX_H_DONE; + return -1; + } + + /* + * We need to always keep one event allocated in aux to be able to truncate + * data properly in case of an error. If there is no event in aux it means + * this is first event and we can silently ignore in case of an error. + */ + if (aux->hci_ev) { + hci_ev = aux->hci_ev; + aux->hci_ev = NULL; + } else { + hci_ev = ble_ll_hci_ev_alloc_ext_adv_report_for_aux(&rxhdr->rxinfo, addrd, aux); + if (!hci_ev) { + aux->hci_state = BLE_LL_SCAN_AUX_H_DONE; + return -1; + } + } + + ble_ll_hci_ev_update_ext_adv_report_from_aux(hci_ev, rxpdu, rxhdr); + + rc = ble_ll_hci_ev_send_ext_adv_report(rxpdu, rxhdr, &hci_ev); + if (rc < 0) { + BLE_LL_ASSERT(!hci_ev); + aux->hci_state = BLE_LL_SCAN_AUX_H_DONE | BLE_LL_SCAN_AUX_H_TRUNCATED; + } else if (hci_ev) { + aux->hci_state = BLE_LL_SCAN_AUX_H_SENT_ANY; + } else { + aux->hci_state = BLE_LL_SCAN_AUX_H_DONE; + } + + aux->hci_ev = hci_ev; + + return rc; +} + +static void +ble_ll_hci_ev_send_ext_adv_report_for_ext(struct os_mbuf *rxpdu, + struct ble_mbuf_hdr *rxhdr) +{ + struct ble_hci_ev *hci_ev; + + if (!ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_EXT_ADV_RPT)) { + return; + } + + hci_ev = ble_transport_alloc_evt(1); + if (!hci_ev) { + return; + } + + ble_ll_hci_ev_update_ext_adv_report_from_ext(hci_ev, rxpdu, rxhdr); + + ble_ll_hci_ev_send_ext_adv_report(rxpdu, rxhdr, &hci_ev); + + BLE_LL_ASSERT(!hci_ev); +} + +static void +ble_ll_scan_aux_break_ev(struct ble_npl_event *ev) +{ + struct ble_ll_scan_aux_data *aux = ble_npl_event_get_arg(ev); + + BLE_LL_ASSERT(aux); + + if (ble_ll_scan_aux_need_truncation(aux)) { + ble_ll_hci_ev_send_ext_adv_truncated_report(aux); + } + + /* Update backoff if we were waiting for scan response */ + if (aux->flags & BLE_LL_SCAN_AUX_F_W4_SCAN_RSP) { + ble_ll_scan_backoff_update(0); + } + + ble_ll_scan_aux_free(aux); + ble_ll_scan_chk_resume(); +} + +void +ble_ll_scan_aux_break(struct ble_ll_scan_aux_data *aux) +{ +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + if (aux->flags & BLE_LL_SCAN_AUX_F_W4_CONNECT_RSP) { + ble_ll_conn_send_connect_req_cancel(); + } +#endif + + ble_npl_event_init(&aux->break_ev, ble_ll_scan_aux_break_ev, aux); + ble_ll_event_add(&aux->break_ev); +} + +static int +ble_ll_scan_aux_phy_to_phy(uint8_t aux_phy, uint8_t *phy) +{ + switch (aux_phy) { + case 0: + *phy = BLE_PHY_1M; + break; +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY) + case 1: + *phy = BLE_PHY_2M; + break; +#endif +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) + case 2: + *phy = BLE_PHY_CODED; + break; +#endif + default: + return -1; + } + + return 0; +} + +int +ble_ll_scan_aux_sched(struct ble_ll_scan_aux_data *aux, uint32_t pdu_ticks, + uint8_t pdu_rem_us, uint32_t aux_ptr) +{ + struct ble_ll_sched_item *sch; + uint32_t aux_offset; + uint8_t offset_unit; + uint8_t aux_phy; + uint8_t chan; + uint8_t ca; + uint8_t phy; + uint32_t offset_us; + uint16_t pdu_rx_us; + uint16_t aux_ww_us; + uint16_t aux_tx_win_us; + + /* Parse AuxPtr */ + chan = aux_ptr & 0x3f; + ca = aux_ptr & 0x40; + offset_unit = aux_ptr & 0x80; + aux_offset = (aux_ptr >> 8) & 0x1fff; + aux_phy = (aux_ptr >> 21) & 0x07; + + if (chan >= BLE_PHY_NUM_DATA_CHANS) { + return -1; + } + + if (ble_ll_scan_aux_phy_to_phy(aux_phy, &phy) < 0) { + return -1; + } + + /* Actual offset */ + offset_us = aux_offset * (offset_unit ? 300 : 30); + /* Time to scan aux PDU */ + pdu_rx_us = ble_ll_pdu_us(MYNEWT_VAL(BLE_LL_SCHED_SCAN_AUX_PDU_LEN), + ble_ll_phy_to_phy_mode(phy, 0)); + /* Transmit window */ + aux_tx_win_us = offset_unit ? 300 : 30; + /* Window widening to include drift due to sleep clock accuracy and jitter */ + aux_ww_us = offset_us * (ca ? 50 : 500) / 1000000 + BLE_LL_JITTER_USECS; + + aux->sec_phy = phy; + aux->chan = chan; + aux->wfr_us = aux_ww_us + aux_tx_win_us; + + sch = &aux->sch; + + sch->start_time = pdu_ticks; + sch->remainder = pdu_rem_us; + ble_ll_tmr_add(&sch->start_time, &sch->remainder, offset_us - aux_ww_us); + + sch->end_time = sch->start_time + + ble_ll_tmr_u2t_up(sch->remainder + 2 * aux_ww_us + + aux_tx_win_us + pdu_rx_us); + + sch->start_time -= g_ble_ll_sched_offset_ticks; + + return ble_ll_sched_scan_aux(&aux->sch); +} + +int +ble_ll_scan_aux_rx_isr_start(uint8_t pdu_type, struct ble_mbuf_hdr *rxhdr) +{ + struct ble_ll_scan_aux_data *aux; + + BLE_LL_ASSERT(aux_data_current); + aux = aux_data_current; + + if (aux->flags & BLE_LL_SCAN_AUX_F_W4_CONNECT_RSP) { + if (pdu_type != BLE_ADV_PDU_TYPE_AUX_CONNECT_RSP) { + aux_data_current = NULL; + ble_ll_scan_aux_break(aux); + ble_ll_state_set(BLE_LL_STATE_STANDBY); + return -1; + } + return 0; + } + + if (pdu_type != BLE_ADV_PDU_TYPE_ADV_EXT_IND) { + aux_data_current = NULL; + ble_ll_scan_aux_break(aux); + ble_ll_state_set(BLE_LL_STATE_STANDBY); + return -1; + } + + /* + * Prepare TX transition when doing active scanning and receiving 1st PDU + * since we may want to send AUX_SCAN_REQ. + */ + if ((aux->scan_type != BLE_SCAN_TYPE_PASSIVE) && + !(aux->flags & BLE_LL_SCAN_AUX_F_AUX_ADV)) { + return 1; + } + + return 0; +} + +static int +ble_ll_scan_aux_parse_to_aux_data(struct ble_ll_scan_aux_data *aux, + uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr) +{ + uint8_t pdu_hdr; + uint8_t pdu_len; + uint8_t adv_mode; + uint8_t eh_len; + uint8_t eh_flags; + uint8_t *eh_data; + + pdu_hdr = rxbuf[0]; + pdu_len = rxbuf[1]; + + /* PDU without at least Extended Header Length is invalid */ + if (pdu_len == 0) { + return -1; + } + + /* Mark as AUX received on 1st PDU, then as CHAIN received on subsequent */ + if (aux->flags & BLE_LL_SCAN_AUX_F_AUX_ADV) { + aux->flags |= BLE_LL_SCAN_AUX_F_AUX_CHAIN; + } else { + aux->flags |= BLE_LL_SCAN_AUX_F_AUX_ADV; + } + + adv_mode = rxbuf[2] >> 6; + eh_len = rxbuf[2] & 0x3f; + + /* Only AUX_CHAIN_IND is valid without Extended Header */ + if (eh_len == 0) { + if (!(aux->flags & BLE_LL_SCAN_AUX_F_AUX_CHAIN) || adv_mode) { + return -1; + } + return 0; + } + + eh_flags = rxbuf[3]; + eh_data = &rxbuf[4]; + + /* Now parse extended header... */ + + /* AdvA is only valid in AUX_ADV_IND if not already present in ADV_EXT_IND */ + if (eh_flags & (1 << BLE_LL_EXT_ADV_ADVA_BIT)) { + if (!(aux->flags & BLE_LL_SCAN_AUX_F_HAS_ADVA) && + !(aux->flags & BLE_LL_SCAN_AUX_F_AUX_CHAIN)) { + memcpy(aux->adva, eh_data, 6); + aux->adva_type = !!(pdu_hdr & BLE_ADV_PDU_HDR_TXADD_MASK); + aux->flags |= BLE_LL_SCAN_AUX_F_HAS_ADVA; +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + aux->rpa_index = ble_hw_resolv_list_match(); +#endif + } + eh_data += BLE_LL_EXT_ADV_ADVA_SIZE; + } + + /* TargetA is only valid in AUX_ADV_IND if not already present in ADV_EXT_IND */ + if (eh_flags & (1 << BLE_LL_EXT_ADV_TARGETA_BIT)) { + if (!(aux->flags & BLE_LL_SCAN_AUX_F_HAS_TARGETA) && + !(aux->flags & BLE_LL_SCAN_AUX_F_AUX_CHAIN)) { + memcpy(aux->targeta, eh_data, 6); + aux->targeta_type = !!(pdu_hdr & BLE_ADV_PDU_HDR_RXADD_MASK); + aux->flags |= BLE_LL_SCAN_AUX_F_HAS_TARGETA; + } + eh_data += BLE_LL_EXT_ADV_TARGETA_SIZE; + } + + if (eh_flags & (1 << BLE_LL_EXT_ADV_CTE_INFO_BIT)) { + eh_data += BLE_LL_EXT_ADV_CTE_INFO_SIZE; + } + + /* + * ADI handling is a bit convoluted.... + * ADI is mandatory in ADV_EXT_IND with AuxPtr and is also mandatory in PDU + * if included in superior PDU. This implies that each AUX_CHAIN shall have + * ADI. However... AUX_SCAN_RSP does not need to have ADI, so if there's no + * ADI in AUX_SCAN_RSP we allow it and clear corresponding flag to skip ADI + * checks on subsequent PDUs. + */ + if (eh_flags & (1 << BLE_LL_EXT_ADV_DATA_INFO_BIT)) { + if (aux->flags & BLE_LL_SCAN_AUX_F_HAS_ADI) { + if (get_le16(eh_data) != aux->adi) { + return -1; + } + } + eh_data += BLE_LL_EXT_ADV_DATA_INFO_SIZE; + } else if (aux->flags & BLE_LL_SCAN_AUX_F_HAS_ADI) { + if (rxhdr->rxinfo.flags & BLE_MBUF_HDR_F_SCAN_RSP_RXD) { + aux->flags &= ~BLE_LL_SCAN_AUX_F_HAS_ADI; + } else { + return -1; + } + } + + /* AuxPtr is RFU if AdvMode!=0 so ignore in such case */ + if ((adv_mode == 0) && (eh_flags & (1 << BLE_LL_EXT_ADV_AUX_PTR_BIT))) { + aux->aux_ptr = get_le24(eh_data); + rxhdr->rxinfo.flags |= BLE_MBUF_HDR_F_AUX_PTR_WAIT; + } + + return 0; +} + +static int +ble_ll_scan_aux_ext_parse(uint8_t *rxbuf, struct ble_ll_scan_addr_data *addrd, + uint16_t *adi, uint32_t *aux_ptr) +{ + uint8_t pdu_hdr; + uint8_t pdu_len; + uint8_t adv_mode; + uint8_t eh_len; + uint8_t eh_flags; + uint8_t *eh_data; + + pdu_hdr = rxbuf[0]; + pdu_len = rxbuf[1]; + + if (pdu_len == 0) { + return -1; + } + + adv_mode = rxbuf[2] >> 6; + eh_len = rxbuf[2] & 0x3f; + + if ((adv_mode == 3) || (eh_len == 0)) { + return -1; + } + + eh_flags = rxbuf[3]; + eh_data = &rxbuf[4]; + + /* ADV_EXT_IND with AuxPtr but without ADI is invalid */ + if ((eh_flags & (1 << BLE_LL_EXT_ADV_AUX_PTR_BIT)) && + !(eh_flags & (1 << BLE_LL_EXT_ADV_DATA_INFO_BIT))) { + return -1; + } + + /* ADV_EXT_IND without either AdvA or AuxPtr is not valid */ + if (!(eh_flags & ((1 << BLE_LL_EXT_ADV_ADVA_BIT) | + (1 << BLE_LL_EXT_ADV_AUX_PTR_BIT)))) { + return -1; + } + + if (eh_flags & (1 << BLE_LL_EXT_ADV_ADVA_BIT)) { + addrd->adva = eh_data; + addrd->adva_type = !!(pdu_hdr & BLE_ADV_PDU_HDR_TXADD_RAND); + eh_data += BLE_LL_EXT_ADV_ADVA_SIZE; + } else { + addrd->adva = NULL; + } + + if (eh_flags & (1 << BLE_LL_EXT_ADV_TARGETA_BIT)) { + addrd->targeta = eh_data; + addrd->targeta_type = !!(pdu_hdr & BLE_ADV_PDU_HDR_RXADD_RAND); + eh_data += BLE_LL_EXT_ADV_TARGETA_SIZE; + } else { + addrd->targeta = NULL; + } + + if (eh_flags & (1 << BLE_LL_EXT_ADV_CTE_INFO_BIT)) { + eh_data += BLE_LL_EXT_ADV_CTE_INFO_SIZE; + } + + if (eh_flags & (1 << BLE_LL_EXT_ADV_DATA_INFO_BIT)) { + *adi = get_le16(eh_data); + eh_data += BLE_LL_EXT_ADV_DATA_INFO_SIZE; + } else { + *adi = 0; + } + + if (eh_flags & (1 << BLE_LL_EXT_ADV_AUX_PTR_BIT)) { + *aux_ptr = get_le24(eh_data); + } else { + *aux_ptr = 0; + } + + return 0; +} + +static void +ble_ll_scan_aux_update_rxinfo_from_addrd(struct ble_ll_scan_addr_data *addrd, + struct ble_mbuf_hdr_rxinfo *rxinfo) +{ +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + rxinfo->rpa_index = addrd->rpa_index; + if (addrd->adva_resolved) { + rxinfo->flags |= BLE_MBUF_HDR_F_RESOLVED; + } + if (addrd->targeta_resolved) { + rxinfo->flags |= BLE_MBUF_HDR_F_TARGETA_RESOLVED; + } +#endif +} + +static void +ble_ll_scan_aux_update_aux_data_from_addrd(struct ble_ll_scan_addr_data *addrd, + struct ble_ll_scan_aux_data *aux) +{ +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + aux->rpa_index = addrd->rpa_index; + if (addrd->adva_resolved) { + aux->flags |= BLE_LL_SCAN_AUX_F_RESOLVED_ADVA; + } + if (addrd->targeta_resolved) { + aux->flags |= BLE_LL_SCAN_AUX_F_RESOLVED_TARGETA; + } +#endif +} + +int +ble_ll_scan_aux_rx_isr_end_on_ext(struct ble_ll_scan_sm *scansm, + struct os_mbuf *rxpdu) +{ + struct ble_mbuf_hdr *rxhdr = BLE_MBUF_HDR_PTR(rxpdu); + struct ble_mbuf_hdr_rxinfo *rxinfo = &rxhdr->rxinfo; + struct ble_ll_scan_addr_data addrd; + struct ble_ll_scan_aux_data *aux; + uint8_t *rxbuf; + uint32_t aux_ptr; + uint16_t adi; + bool do_match; + int rc; + + rxbuf = rxpdu->om_data; + + rc = ble_ll_scan_aux_ext_parse(rxbuf, &addrd, &adi, &aux_ptr); + if (rc < 0) { + return -1; + } + + /* We can filter based on ext PDU alone if both AdvA and TargetA are present + * or there's no AuxPtr. Otherwise, we need to wait for aux PDU to filter. + */ + do_match = !aux_ptr || (addrd.adva && addrd.targeta); + if (do_match) { +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + addrd.rpa_index = ble_hw_resolv_list_match(); +#endif + rc = ble_ll_scan_rx_filter(ble_ll_scan_get_own_addr_type(), + ble_ll_scan_get_filt_policy(), + &addrd, NULL); + if (rc < 0) { + return -1; + } + + /* Don't care about initiator here, there are no AdvA and TargetA + * in connectable ADV_EXT_IND so no filtering to do. + */ + + if (!aux_ptr) { + /* We do not allocate aux_data for ADV_EXT_IND without AuxPtr so + * need to pass match data in rxinfo. + */ + ble_ll_scan_aux_update_rxinfo_from_addrd(&addrd, rxinfo); + } + } + + if (aux_ptr) { + aux = ble_ll_scan_aux_alloc(); + if (!aux) { + return -1; + } + + aux->scan_type = scansm->scanp->scan_type; + + aux->pri_phy = rxinfo->phy; + aux->aux_ptr = aux_ptr; + +#if MYNEWT_VAL(BLE_LL_ADV_CODING_SELECTION) + aux->pri_phy_mode = rxinfo->phy_mode; +#endif + + if (addrd.adva) { + memcpy(aux->adva, addrd.adva, 6); + aux->adva_type = addrd.adva_type; + aux->flags |= BLE_LL_SCAN_AUX_F_HAS_ADVA; + } + + if (addrd.targeta) { + memcpy(aux->targeta, addrd.targeta, 6); + aux->targeta_type = addrd.targeta_type; + aux->flags |= BLE_LL_SCAN_AUX_F_HAS_TARGETA; + } + + aux->adi = adi; + aux->flags |= BLE_LL_SCAN_AUX_F_HAS_ADI; + +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + if (aux->scan_type == BLE_SCAN_TYPE_INITIATE) { + aux->flags |= BLE_LL_SCAN_AUX_F_CONNECTABLE; + } +#endif + + if (do_match) { + aux->flags |= BLE_LL_SCAN_AUX_F_MATCHED; + ble_ll_scan_aux_update_aux_data_from_addrd(&addrd, aux); + } else if (addrd.adva) { +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + /* If ext PDU has AdvA, we need to store rpa_index to be able to + * reuse it for filtering when done on aux PDU. + */ + aux->rpa_index = ble_hw_resolv_list_match(); +#endif + } + + rxinfo->user_data = aux; + } + + return 0; +} + +void +ble_ll_scan_aux_pkt_in_on_ext(struct os_mbuf *rxpdu, + struct ble_mbuf_hdr *rxhdr) +{ + struct ble_mbuf_hdr_rxinfo *rxinfo = &rxhdr->rxinfo; + struct ble_ll_scan_aux_data *aux = rxinfo->user_data; + int rc; + + if (rxinfo->flags & BLE_MBUF_HDR_F_IGNORED) { + BLE_LL_ASSERT(!aux); + return; + } + + if (!aux) { + ble_ll_hci_ev_send_ext_adv_report_for_ext(rxpdu, rxhdr); + return; + } + + BLE_LL_ASSERT(aux->aux_ptr); + + rc = ble_ll_scan_aux_sched(aux, rxhdr->beg_cputime, rxhdr->rem_usecs, + aux->aux_ptr); + if (rc < 0) { + ble_ll_scan_aux_free(aux); + } +} + +static uint8_t +ble_ll_scan_aux_scan_req_tx_pdu_cb(uint8_t *dptr, void *arg, uint8_t *hdr_byte) +{ + struct ble_ll_scan_aux_data *aux = arg; + + ble_ll_scan_make_req_pdu(ble_ll_scan_sm_get(), dptr, hdr_byte, + aux->adva_type, aux->adva, aux->rpa_index); + + return BLE_DEV_ADDR_LEN * 2; +} + +static bool +ble_ll_scan_aux_send_scan_req(struct ble_ll_scan_aux_data *aux, + struct ble_ll_scan_addr_data *addrd) +{ + int rc; + + /* Check if we already scanned this device successfully */ + if (ble_ll_scan_have_rxd_scan_rsp(addrd->adv_addr, addrd->adv_addr_type, + true, aux->adi)) { + return false; + } + + /* We want to send a request, see if backoff allows us */ + if (ble_ll_scan_backoff_kick() != 0) { + return false; + } + + /* TODO perhaps we should check if scan req+rsp won't overlap with scheduler + * item (old code did it), but for now let's just scan and we will be + * interrupted if scheduler kicks in. + */ + + rc = ble_phy_tx(ble_ll_scan_aux_scan_req_tx_pdu_cb, aux, + BLE_PHY_TRANSITION_TX_RX); + if (rc) { + return false; + } + + return true; +} + +int +ble_ll_scan_aux_rx_isr_end(struct os_mbuf *rxpdu, uint8_t crcok) +{ + struct ble_ll_scan_addr_data addrd; + struct ble_mbuf_hdr_rxinfo *rxinfo; + struct ble_ll_scan_aux_data *aux; + struct ble_mbuf_hdr *rxhdr; + uint8_t scan_filt_policy; + uint8_t scan_ok; + uint8_t adv_mode; + uint8_t *rxbuf; + int rc; + + BLE_LL_ASSERT(aux_data_current); + aux = aux_data_current; + aux_data_current = NULL; + + if (rxpdu == NULL) { + ble_ll_scan_aux_break(aux); + goto done; + } + + rxhdr = BLE_MBUF_HDR_PTR(rxpdu); + rxinfo = &rxhdr->rxinfo; + rxinfo->user_data = aux; + + /* It's possible that we received aux while scan was just being disabled in + * LL task. In such case simply ignore aux. + */ + if (!crcok || !ble_ll_scan_enabled()) { + rxinfo->flags |= BLE_MBUF_HDR_F_IGNORED; + goto done; + } + + rxbuf = rxpdu->om_data; + + if (aux->flags & BLE_LL_SCAN_AUX_F_W4_CONNECT_RSP) { + aux->flags &= ~BLE_LL_SCAN_AUX_F_W4_CONNECT_RSP; + rxinfo->flags |= BLE_MBUF_HDR_F_CONNECT_RSP_RXD; + goto done; + } + + if (aux->flags & BLE_LL_SCAN_AUX_F_W4_SCAN_RSP) { + aux->flags &= ~BLE_LL_SCAN_AUX_F_W4_SCAN_RSP; + aux->flags |= BLE_LL_SCAN_AUX_F_SCANNED; + rxinfo->flags |= BLE_MBUF_HDR_F_SCAN_RSP_RXD; + } + + rc = ble_ll_scan_aux_parse_to_aux_data(aux, rxbuf, rxhdr); + if (rc < 0) { + rxinfo->flags |= BLE_MBUF_HDR_F_IGNORED; + goto done; + } + + if (aux->flags & BLE_LL_SCAN_AUX_F_MATCHED) { + goto done; + } + + /* We do filtering on either ADV_EXT_IND or AUX_ADV_IND so we should not be + * here when processing AUX_CHAIN_IND. + */ + BLE_LL_ASSERT(!(aux->flags & BLE_LL_SCAN_AUX_F_AUX_CHAIN)); + + if (aux->flags & BLE_LL_SCAN_AUX_F_HAS_ADVA) { + addrd.adva = aux->adva; + addrd.adva_type = aux->adva_type; + } else { + addrd.adva = NULL; + } + + if (aux->flags & BLE_LL_SCAN_AUX_F_HAS_TARGETA) { + addrd.targeta = aux->targeta; + addrd.targeta_type = aux->targeta_type; + } else { + addrd.targeta = NULL; + } + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + addrd.rpa_index = aux->rpa_index; +#endif + + scan_filt_policy = ble_ll_scan_get_filt_policy(); + + rc = ble_ll_scan_rx_filter(ble_ll_scan_get_own_addr_type(), + scan_filt_policy, &addrd, &scan_ok); + if (rc < 0) { + rxinfo->flags |= BLE_MBUF_HDR_F_IGNORED; + /* + * XXX hack warning + * Even if PDU was not allowed by current scan filter policy, we should + * still allow it to sync if SyncInfo is present. Since we do not use + * F_DEVMATCH in aux code for its intended purpose, let's use it here to + * indicate no match due to scan filter policy. + */ + if (rc == -2) { + rxinfo->flags |= BLE_MBUF_HDR_F_DEVMATCH; + } + goto done; + } + +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + if ((aux->scan_type == BLE_SCAN_TYPE_INITIATE) && + !(scan_filt_policy & 0x01)) { + rc = ble_ll_scan_rx_check_init(&addrd); + if (rc < 0) { + rxinfo->flags |= BLE_MBUF_HDR_F_IGNORED; + goto done; + } + } +#endif + + aux->flags |= BLE_LL_SCAN_AUX_F_MATCHED; + + ble_ll_scan_aux_update_aux_data_from_addrd(&addrd, aux); + + adv_mode = rxbuf[2] >> 6; + + switch (aux->scan_type) { + case BLE_SCAN_TYPE_ACTIVE: + if ((adv_mode == BLE_LL_EXT_ADV_MODE_SCAN) && scan_ok && + ble_ll_scan_aux_send_scan_req(aux, &addrd)) { + /* AUX_SCAN_REQ sent, keep PHY enabled to continue */ + aux->flags |= BLE_LL_SCAN_AUX_F_W4_SCAN_RSP; + rxinfo->flags |= BLE_MBUF_HDR_F_SCAN_REQ_TXD; + aux_data_current = aux; + return 0; + } + break; +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + case BLE_SCAN_TYPE_INITIATE: + if (ble_ll_conn_send_connect_req(rxpdu, &addrd, 1) == 0) { + /* AUX_CONNECT_REQ sent, keep PHY enabled to continue */ + aux->flags |= BLE_LL_SCAN_AUX_F_W4_CONNECT_RSP; + rxinfo->flags |= BLE_MBUF_HDR_F_CONNECT_REQ_TXD; + aux_data_current = aux; + return 0; + } else { + rxinfo->flags |= BLE_MBUF_HDR_F_IGNORED; + } + break; +#endif + default: + break; + } + +done: + /* We are done with this PDU so go to standby and let LL resume if needed */ + ble_ll_state_set(BLE_LL_STATE_STANDBY); + return -1; +} + +static void +ble_ll_scan_aux_init_addrd_from_aux_data(struct ble_ll_scan_aux_data *aux, + struct ble_ll_scan_addr_data *addrd) +{ +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + struct ble_ll_resolv_entry *rl; +#endif + + if (aux->flags & BLE_LL_SCAN_AUX_F_HAS_ADVA) { + addrd->adva = aux->adva; + addrd->adva_type = aux->adva_type; + } else { + addrd->adva = NULL; + addrd->adva_type = 0; + } + + if (aux->flags & BLE_LL_SCAN_AUX_F_HAS_TARGETA) { + addrd->targeta = aux->targeta; + addrd->targeta_type = aux->targeta_type; + } else { + addrd->targeta = NULL; + addrd->targeta_type = 0; + } + + addrd->adv_addr = addrd->adva; + addrd->adv_addr_type = addrd->adva_type; + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + addrd->rpa_index = aux->rpa_index; + + if (aux->flags & BLE_LL_SCAN_AUX_F_RESOLVED_ADVA) { + BLE_LL_ASSERT(aux->rpa_index >= 0); + rl = &g_ble_ll_resolv_list[aux->rpa_index]; + addrd->adv_addr = rl->rl_identity_addr; + addrd->adv_addr_type = rl->rl_addr_type; + addrd->adva_resolved = 1; + } else { + addrd->adva_resolved = 0; + } + + if (aux->flags & BLE_LL_SCAN_AUX_F_RESOLVED_TARGETA) { + addrd->targeta = ble_ll_scan_aux_get_own_addr(); + addrd->targeta_type = ble_ll_scan_get_own_addr_type() & 1; + addrd->targeta_resolved = 1; + } else { + addrd->targeta_resolved = 0; + } +#endif +} + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) +static void +ble_ll_scan_aux_sync_check(struct os_mbuf *rxpdu, + struct ble_ll_scan_addr_data *addrd) +{ + struct ble_mbuf_hdr *rxhdr = BLE_MBUF_HDR_PTR(rxpdu); + uint8_t *rxbuf = rxpdu->om_data; + uint8_t adv_mode; + uint8_t eh_len; + uint8_t eh_flags; + uint8_t *eh_data; + uint8_t sid; + + adv_mode = rxbuf[2] >> 6; + + if (adv_mode != BLE_LL_EXT_ADV_MODE_NON_CONN) { + return; + } + + eh_len = rxbuf[2] & 0x3f; + + if (eh_len == 0) { + return; + } + + eh_flags = rxbuf[3]; + eh_data = &rxbuf[4]; + + /* Need ADI and SyncInfo */ + if (!(eh_flags & (1 << BLE_LL_EXT_ADV_DATA_INFO_BIT)) || + !(eh_flags & (1 << BLE_LL_EXT_ADV_SYNC_INFO_BIT))) { + return; + } + + if (eh_flags & (1 << BLE_LL_EXT_ADV_ADVA_BIT)) { + eh_data += BLE_LL_EXT_ADV_ADVA_SIZE; + } + + if (eh_flags & (1 << BLE_LL_EXT_ADV_TARGETA_BIT)) { + eh_data += BLE_LL_EXT_ADV_TARGETA_SIZE; + } + + if (eh_flags & (1 << BLE_LL_EXT_ADV_CTE_INFO_BIT)) { + eh_data += 1; + } + + sid = get_le16(eh_data) >> 12; + eh_data += BLE_LL_EXT_ADV_DATA_INFO_SIZE; + + if (eh_flags & (1 << BLE_LL_EXT_ADV_AUX_PTR_BIT)) { + eh_data += BLE_LL_EXT_ADV_AUX_PTR_SIZE; + } + + ble_ll_sync_info_event(addrd, sid, rxhdr, eh_data); +} +#endif + +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) +static int +ble_ll_scan_aux_check_connect_rsp(uint8_t *rxbuf, + struct ble_ll_scan_pdu_data *pdu_data, + struct ble_ll_scan_addr_data *addrd) +{ + uint8_t pdu_hdr; + uint8_t pdu_len; + uint8_t adv_mode; + uint8_t eh_len; + uint8_t eh_flags; + uint8_t *eh_data; + uint8_t adva_type; + uint8_t *adva; + uint8_t targeta_type; + uint8_t *targeta; +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + struct ble_ll_resolv_entry *rl = NULL; +#endif + uint8_t match_adva = 1; + + pdu_hdr = rxbuf[0]; + pdu_len = rxbuf[1]; + + if (pdu_len == 0) { + return -1; + } + + adv_mode = rxbuf[2] >> 6; + eh_len = rxbuf[2] & 0x3f; + + if ((adv_mode != 0) || (eh_len == 0)) { + return -1; + } + + eh_flags = rxbuf[3]; + eh_data = &rxbuf[4]; + + /* AUX_CONNECT_RSP without AdvA or TargetA is not valid */ + if (!(eh_flags & ((1 << BLE_LL_EXT_ADV_ADVA_BIT) | + (1 << BLE_LL_EXT_ADV_TARGETA_BIT)))) { + return -1; + } + + adva = eh_data; + adva_type = !!(pdu_hdr & BLE_ADV_PDU_HDR_TXADD_RAND); + eh_data += BLE_LL_EXT_ADV_ADVA_SIZE; + + targeta = eh_data; + targeta_type = !!(pdu_hdr & BLE_ADV_PDU_HDR_RXADD_RAND); + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + /* If AdvA is an RPA and we have peer IRK, we need to check if it resolves + * using that RPA because peer can change RPA between advertising PDU and + * AUX_CONNECT_RSP. In other case, we expect AdvA to be the same as in + * advertising PDU. + */ + if ((addrd->rpa_index >= 0) && ble_ll_is_rpa(adva, adva_type)) { + rl = &g_ble_ll_resolv_list[addrd->rpa_index]; + + if (rl->rl_has_peer) { + if (!ble_ll_resolv_rpa(adva, rl->rl_peer_irk)) { + return -1; + } + + addrd->adva_resolved = 1; + addrd->adva = adva; + addrd->adva_type = adva_type; + + match_adva = 0; + } + } +#endif /* BLE_LL_CFG_FEAT_LL_PRIVACY */ + + if (match_adva && + ((adva_type != !!(pdu_data->hdr_byte & BLE_ADV_PDU_HDR_RXADD_MASK)) || + (memcmp(adva, pdu_data->adva, 6) != 0))) { + return -1; + } + + if ((targeta_type != !!(pdu_data->hdr_byte & BLE_ADV_PDU_HDR_TXADD_MASK)) || + (memcmp(targeta, pdu_data->inita, 6) != 0)) { + return -1; + } + + return 0; +} + +static void +ble_ll_scan_aux_rx_pkt_in_for_initiator(struct os_mbuf *rxpdu, + struct ble_mbuf_hdr *rxhdr) +{ + struct ble_ll_scan_addr_data addrd; + struct ble_mbuf_hdr_rxinfo *rxinfo; + struct ble_ll_scan_aux_data *aux; + + rxinfo = &rxhdr->rxinfo; + aux = rxinfo->user_data; + + if (rxinfo->flags & BLE_MBUF_HDR_F_IGNORED) { + if (aux->flags & BLE_LL_SCAN_AUX_F_W4_CONNECT_RSP) { + ble_ll_conn_send_connect_req_cancel(); + } + ble_ll_scan_aux_free(aux); + ble_ll_scan_chk_resume(); + return; + } + + if (!(rxinfo->flags & BLE_MBUF_HDR_F_CONNECT_RSP_RXD)) { + BLE_LL_ASSERT(rxinfo->flags & BLE_MBUF_HDR_F_CONNECT_REQ_TXD); + /* Waiting for AUX_CONNECT_RSP, do nothing */ + return; + } + + ble_ll_scan_aux_init_addrd_from_aux_data(aux, &addrd); + + if (ble_ll_scan_aux_check_connect_rsp(rxpdu->om_data, + ble_ll_scan_get_pdu_data(), + &addrd) < 0) { + ble_ll_conn_send_connect_req_cancel(); + ble_ll_scan_aux_free(aux); + ble_ll_scan_chk_resume(); + return; + } + + ble_ll_scan_sm_stop(0); + ble_ll_conn_created_on_aux(rxpdu, &addrd, aux->targeta); + ble_ll_scan_aux_free(aux); +} +#endif + +void +ble_ll_scan_aux_rx_pkt_in(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *rxhdr) +{ + struct ble_ll_scan_addr_data addrd; + struct ble_mbuf_hdr_rxinfo *rxinfo; + struct ble_ll_scan_aux_data *aux; + bool scan_duplicate = false; +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) + bool sync_check = false; +#endif + int rc; + + rxinfo = &rxhdr->rxinfo; + aux = rxinfo->user_data; + + BLE_LL_ASSERT(aux); + +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + if (aux->scan_type == BLE_SCAN_TYPE_INITIATE) { + ble_ll_scan_aux_rx_pkt_in_for_initiator(rxpdu, rxhdr); + return; + } +#endif + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) + sync_check = ble_ll_sync_enabled() && + !(aux->flags & BLE_LL_SCAN_AUX_F_AUX_CHAIN); + + /* PDU was not allowed due to scan filter policy, but we can still try to + * sync since separate filter policy is used for this purpose. + */ + if ((rxinfo->flags & BLE_MBUF_HDR_F_DEVMATCH) && sync_check) { + ble_ll_scan_aux_init_addrd_from_aux_data(aux, &addrd); + ble_ll_scan_aux_sync_check(rxpdu, &addrd); + } +#endif + + if (rxinfo->flags & BLE_MBUF_HDR_F_IGNORED) { + if (ble_ll_scan_aux_need_truncation(aux)) { + ble_ll_hci_ev_send_ext_adv_truncated_report(aux); + } else { + aux->hci_state |= BLE_LL_SCAN_AUX_H_DONE; + } + + /* Update backoff if we were waiting for scan response */ + if (aux->flags & BLE_LL_SCAN_AUX_F_W4_SCAN_RSP) { + ble_ll_scan_backoff_update(0); + } + } else if (rxinfo->flags & BLE_MBUF_HDR_F_SCAN_RSP_RXD) { + /* We assume scan success when AUX_SCAN_RSP is received, no need to + * wait for complete chain (Core 5.3, Vol 6, Part B, 4.4.3.1). + */ + ble_ll_scan_backoff_update(1); + } + + if (aux->hci_state & BLE_LL_SCAN_AUX_H_DONE) { + ble_ll_scan_aux_free(aux); + ble_ll_scan_chk_resume(); + return; + } + + /* Try to schedule scan for subsequent aux asap, if needed */ + if (rxinfo->flags & BLE_MBUF_HDR_F_AUX_PTR_WAIT) { + rc = ble_ll_scan_aux_sched(aux, rxhdr->beg_cputime, rxhdr->rem_usecs, + aux->aux_ptr); + if (rc < 0) { + rxinfo->flags &= ~BLE_MBUF_HDR_F_AUX_PTR_WAIT; + rxinfo->flags |= BLE_MBUF_HDR_F_AUX_PTR_FAILED; + } + } + + ble_ll_scan_aux_init_addrd_from_aux_data(aux, &addrd); + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) + if (sync_check) { + ble_ll_scan_aux_sync_check(rxpdu, &addrd); + } +#endif + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + if (addrd.adva_resolved) { + BLE_LL_ASSERT(addrd.rpa_index >= 0); + ble_ll_resolv_set_peer_rpa(addrd.rpa_index, addrd.adva); + } +#endif + + scan_duplicate = ble_ll_scan_get_filt_dups() && + ble_ll_scan_dup_check_ext(addrd.adv_addr_type, + addrd.adv_addr, true, aux->adi); + if (!scan_duplicate) { + rc = ble_ll_hci_ev_send_ext_adv_report_for_aux(rxpdu, rxhdr, aux, + &addrd); + + /* + * Update duplicates list if report was sent successfully and we are + * done with this chain. On error, status is already set to 'done' so + * we will cancel aux scan (if any) and stop further processing. + * However, if we send AUX_SCAN_REQ for this PDU then need to remove + * 'done' as we should continue with scanning after AUX_SCAN_RSP. + */ + + if (rc == 0) { + if (rxinfo->flags & BLE_MBUF_HDR_F_SCAN_REQ_TXD) { + aux->hci_state &= ~BLE_LL_SCAN_AUX_H_DONE; + } else if (aux->hci_state & BLE_LL_SCAN_AUX_H_DONE) { + BLE_LL_ASSERT(!(rxinfo->flags & BLE_MBUF_HDR_F_AUX_PTR_WAIT)); + if (ble_ll_scan_get_filt_dups()) { + ble_ll_scan_dup_update_ext(addrd.adv_addr_type, + addrd.adv_addr, true, aux->adi); + } + if (aux->flags & BLE_LL_SCAN_AUX_F_SCANNED) { + ble_ll_scan_add_scan_rsp_adv(addrd.adv_addr, + addrd.adv_addr_type, + 1, aux->adi); + } + } + } + } else { + /* This is a duplicate, we don't want to scan it anymore */ + aux->hci_state |= BLE_LL_SCAN_AUX_H_DONE; + } + + /* If we are done processing this chain we can remove aux_data now if: + * - we did not send AUX_SCAN_REQ for this PDU + * - there was no aux scan scheduled from this PDU + * - there was aux scan scheduled from this PDU but we removed it + * In other cases, we'll remove aux_data on next pkt_in. + */ + if ((aux->hci_state & BLE_LL_SCAN_AUX_H_DONE) && + !(rxinfo->flags & BLE_MBUF_HDR_F_SCAN_REQ_TXD) && + (!(rxinfo->flags & BLE_MBUF_HDR_F_AUX_PTR_WAIT) || + (ble_ll_sched_rmv_elem(&aux->sch) == 0))) { + ble_ll_scan_aux_free(aux); + } + + ble_ll_scan_chk_resume(); +} + +void +ble_ll_scan_aux_wfr_timer_exp(void) +{ + ble_phy_disable(); + ble_ll_scan_aux_halt(); +} + +void +ble_ll_scan_aux_halt(void) +{ + struct ble_ll_scan_aux_data *aux = aux_data_current; + + BLE_LL_ASSERT(aux); + + aux_data_current = NULL; + + ble_ll_state_set(BLE_LL_STATE_STANDBY); + + ble_ll_scan_aux_break(aux); +} + +void +ble_ll_scan_aux_sched_remove(struct ble_ll_sched_item *sch) +{ + ble_ll_scan_aux_break(sch->cb_arg); +} + +void +ble_ll_scan_aux_init(void) +{ + os_error_t err; + + err = os_mempool_init(&aux_data_pool, + MYNEWT_VAL(BLE_LL_SCAN_AUX_SEGMENT_CNT), + sizeof(struct ble_ll_scan_aux_data), + aux_data_mem, "ble_ll_scan_aux_data_pool"); + BLE_LL_ASSERT(err == 0); +} + +#endif /* BLE_LL_CFG_FEAT_LL_EXT_ADV */ diff --git a/nimble/controller/src/ble_ll_sched.c b/nimble/controller/src/ble_ll_sched.c index d01f10edab..7f1ac96054 100644 --- a/nimble/controller/src/ble_ll_sched.c +++ b/nimble/controller/src/ble_ll_sched.c @@ -20,34 +20,57 @@ #include #include #include -#include "os/os.h" -#include "os/os_cputime.h" #include "ble/xcvr.h" #include "controller/ble_phy.h" #include "controller/ble_ll.h" +#include "controller/ble_ll_pdu.h" #include "controller/ble_ll_sched.h" #include "controller/ble_ll_adv.h" #include "controller/ble_ll_scan.h" +#include "controller/ble_ll_scan_aux.h" #include "controller/ble_ll_rfmgmt.h" #include "controller/ble_ll_trace.h" +#include "controller/ble_ll_tmr.h" #include "controller/ble_ll_sync.h" +#include "controller/ble_ll_iso_big.h" +#if MYNEWT_VAL(BLE_LL_EXT) +#include "controller/ble_ll_ext.h" +#endif #include "ble_ll_priv.h" #include "ble_ll_conn_priv.h" -/* XXX: this is temporary. Not sure what I want to do here */ -struct hal_timer g_ble_ll_sched_timer; +#define BLE_LL_SCHED_MAX_DELAY_ANY (0x7fffffff) -uint8_t g_ble_ll_sched_offset_ticks; +static struct ble_ll_tmr g_ble_ll_sched_timer; -#define BLE_LL_SCHED_ADV_WORST_CASE_USECS \ - (BLE_LL_SCHED_MAX_ADV_PDU_USECS + BLE_LL_IFS + BLE_LL_SCHED_ADV_MAX_USECS \ - + XCVR_TX_SCHED_DELAY_USECS) +uint8_t g_ble_ll_sched_offset_ticks; #if (BLE_LL_SCHED_DEBUG == 1) int32_t g_ble_ll_sched_max_late; int32_t g_ble_ll_sched_max_early; #endif +#if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) +struct ble_ll_sched_css { + uint8_t enabled; +#if !MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED_FIXED) + uint32_t slot_us; + uint32_t period_slots; +#endif + uint32_t period_anchor_ticks; + uint8_t period_anchor_rem_us; + uint8_t period_anchor_idx; + uint16_t period_anchor_slot_idx; +}; + +static struct ble_ll_sched_css g_ble_ll_sched_css = { +#if !MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED_FIXED) + .slot_us = MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED_SLOT_US), + .period_slots = MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED_PERIOD_SLOTS), +#endif +}; +#endif + /* XXX: TODO: * 1) Add some accounting to the schedule code to see how late we are * (min/max?) @@ -61,507 +84,373 @@ int32_t g_ble_ll_sched_max_early; */ /* Queue for timers */ -TAILQ_HEAD(ll_sched_qhead, ble_ll_sched_item) g_ble_ll_sched_q; +static TAILQ_HEAD(ll_sched_qhead, ble_ll_sched_item) g_ble_ll_sched_q; +static uint8_t g_ble_ll_sched_q_head_changed; -#if MYNEWT_VAL(BLE_LL_STRICT_CONN_SCHEDULING) -struct ble_ll_sched_obj g_ble_ll_sched_data; -#endif - -/** - * Checks if two events in the schedule will overlap in time. NOTE: consecutive - * schedule items can end and start at the same time. - * - * @param s1 - * @param s2 - * - * @return int 0: dont overlap 1:overlap - */ static int -ble_ll_sched_is_overlap(struct ble_ll_sched_item *s1, - struct ble_ll_sched_item *s2) +preempt_any(struct ble_ll_sched_item *sch, + struct ble_ll_sched_item *item) { - int rc; - - rc = 1; - if (CPUTIME_LT(s1->start_time, s2->start_time)) { - /* Make sure this event does not overlap current event */ - if (CPUTIME_LEQ(s1->end_time, s2->start_time)) { - rc = 0; - } - } else { - /* Check for overlap */ - if (CPUTIME_GEQ(s1->start_time, s2->end_time)) { - rc = 0; - } - } + return 1; +} - return rc; +static int +preempt_none(struct ble_ll_sched_item *sch, + struct ble_ll_sched_item *item) +{ + return 0; } -/* - * Determines if the schedule item overlaps the currently running schedule - * item. We only care about connection schedule items - */ static int -ble_ll_sched_overlaps_current(struct ble_ll_sched_item *sch) +preempt_any_except_conn(struct ble_ll_sched_item *sch, + struct ble_ll_sched_item *item) { - int rc; - uint32_t ce_end_time; + BLE_LL_ASSERT(sch->sched_type == BLE_LL_SCHED_TYPE_CONN); - rc = 0; - if (ble_ll_state_get() == BLE_LL_STATE_CONNECTION) { - ce_end_time = ble_ll_conn_get_ce_end_time(); - if (CPUTIME_GT(ce_end_time, sch->start_time)) { - rc = 1; - } + if (item->sched_type != BLE_LL_SCHED_TYPE_CONN) { + return 1; } - return rc; + + return ble_ll_conn_is_lru(sch->cb_arg, item->cb_arg); } static int -ble_ll_sched_conn_overlap(struct ble_ll_sched_item *entry) +preempt_any_except_big(struct ble_ll_sched_item *sch, struct ble_ll_sched_item *item) { - int rc; - struct ble_ll_conn_sm *connsm; - - /* Should only be advertising or a connection here */ - if (entry->sched_type == BLE_LL_SCHED_TYPE_CONN) { - connsm = (struct ble_ll_conn_sm *)entry->cb_arg; - entry->enqueued = 0; - TAILQ_REMOVE(&g_ble_ll_sched_q, entry, link); - ble_ll_event_send(&connsm->conn_ev_end); - rc = 0; - } else { - rc = -1; + if (item->sched_type == BLE_LL_SCHED_TYPE_BIG) { + return 0; } - return rc; + return 1; } -static struct ble_ll_sched_item * -ble_ll_sched_insert_if_empty(struct ble_ll_sched_item *sch) +static inline int +ble_ll_sched_check_overlap(struct ble_ll_sched_item *sch1, + struct ble_ll_sched_item *sch2) { - struct ble_ll_sched_item *entry; - - entry = TAILQ_FIRST(&g_ble_ll_sched_q); - if (!entry) { - TAILQ_INSERT_HEAD(&g_ble_ll_sched_q, sch, link); - sch->enqueued = 1; - } - return entry; + /* Note: item ranges are defined as [start, end) so items do not overlap + * if one item starts at the same time as another ends. + */ + return LL_TMR_GT(sch1->end_time, sch2->start_time) && + LL_TMR_GT(sch2->end_time, sch1->start_time); } -int -ble_ll_sched_conn_reschedule(struct ble_ll_conn_sm *connsm) +static void +ble_ll_sched_preempt(struct ble_ll_sched_item *sch, + struct ble_ll_sched_item *first) { - int rc; - os_sr_t sr; - uint32_t usecs; - struct ble_ll_sched_item *sch; - struct ble_ll_sched_item *start_overlap; - struct ble_ll_sched_item *end_overlap; struct ble_ll_sched_item *entry; - struct ble_ll_conn_sm *tmp; - - /* Get schedule element from connection */ - sch = &connsm->conn_sch; - - /* Set schedule start and end times */ - sch->start_time = connsm->anchor_point - g_ble_ll_sched_offset_ticks; - if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) { - usecs = connsm->slave_cur_window_widening; - sch->start_time -= (os_cputime_usecs_to_ticks(usecs) + 1); - sch->remainder = 0; - } else { - sch->remainder = connsm->anchor_point_usecs; - } - sch->end_time = connsm->ce_end_time; - - /* Better be past current time or we just leave */ - if (CPUTIME_LT(sch->start_time, os_cputime_get32())) { - return -1; - } - - /* We have to find a place for this schedule */ - OS_ENTER_CRITICAL(sr); - - if (ble_ll_sched_overlaps_current(sch)) { - OS_EXIT_CRITICAL(sr); - return -1; - } + struct ble_ll_sched_item *next; +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + struct ble_ll_conn_sm *connsm; +#endif - /* Stop timer since we will add an element */ - os_cputime_timer_stop(&g_ble_ll_sched_timer); + entry = first; - start_overlap = NULL; - end_overlap = NULL; - rc = 0; - TAILQ_FOREACH(entry, &g_ble_ll_sched_q, link) { - if (ble_ll_sched_is_overlap(sch, entry)) { - if (entry->sched_type == BLE_LL_SCHED_TYPE_CONN && - !ble_ll_conn_is_lru((struct ble_ll_conn_sm *)sch->cb_arg, - (struct ble_ll_conn_sm *)entry->cb_arg)) { - /* Only insert if this element is older than all that we - * overlap - */ - start_overlap = NULL; - rc = -1; - break; - } + do { + next = TAILQ_NEXT(entry, link); - if (start_overlap == NULL) { - start_overlap = entry; - end_overlap = entry; - } else { - end_overlap = entry; - } - } else { - if (CPUTIME_LEQ(sch->end_time, entry->start_time)) { - rc = 0; - TAILQ_INSERT_BEFORE(entry, sch, link); - break; - } - } - } - - if (!rc) { - if (!entry) { - TAILQ_INSERT_TAIL(&g_ble_ll_sched_q, sch, link); - } - sch->enqueued = 1; - } + TAILQ_REMOVE(&g_ble_ll_sched_q, entry, link); + entry->enqueued = 0; - /* Remove first to last scheduled elements */ - entry = start_overlap; - while (entry) { - start_overlap = TAILQ_NEXT(entry,link); switch (entry->sched_type) { - case BLE_LL_SCHED_TYPE_CONN: - tmp = (struct ble_ll_conn_sm *)entry->cb_arg; - ble_ll_event_send(&tmp->conn_ev_end); - break; +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) || MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) + case BLE_LL_SCHED_TYPE_CONN: + connsm = (struct ble_ll_conn_sm *)entry->cb_arg; + ble_ll_event_add(&connsm->conn_ev_end); + break; +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) case BLE_LL_SCHED_TYPE_ADV: - ble_ll_adv_event_rmvd_from_sched((struct ble_ll_adv_sm *)entry->cb_arg); - break; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - case BLE_LL_SCHED_TYPE_AUX_SCAN: - ble_ll_scan_end_adv_evt((struct ble_ll_aux_data *)entry->cb_arg); + ble_ll_adv_preempted(entry->cb_arg); break; +#endif +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) && MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) + case BLE_LL_SCHED_TYPE_SCAN_AUX: + ble_ll_scan_aux_break(entry->cb_arg); + break; +#endif #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) - case BLE_LL_SCHED_TYPE_PERIODIC: - ble_ll_adv_periodic_rmvd_from_sched((struct ble_ll_adv_sm *)entry->cb_arg); - break; - case BLE_LL_SCHED_TYPE_SYNC: - ble_ll_sync_rmvd_from_sched((struct ble_ll_sync_sm *)entry->cb_arg); - break; +#if MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) + case BLE_LL_SCHED_TYPE_PERIODIC: + ble_ll_adv_periodic_rmvd_from_sched(entry->cb_arg); + break; #endif +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) && MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) + case BLE_LL_SCHED_TYPE_SYNC: + ble_ll_sync_rmvd_from_sched(entry->cb_arg); + break; #endif - default: +#endif +#if MYNEWT_VAL(BLE_LL_ISO_BROADCASTER) + case BLE_LL_SCHED_TYPE_BIG: + /* FIXME sometimes it may be useful to preempt... */ BLE_LL_ASSERT(0); break; +#endif +#if MYNEWT_VAL(BLE_LL_EXT) + case BLE_LL_SCHED_TYPE_EXTERNAL: + ble_ll_ext_sched_removed(entry); + break; +#endif + default: + BLE_LL_ASSERT(0); + break; } - TAILQ_REMOVE(&g_ble_ll_sched_q, entry, link); - entry->enqueued = 0; + entry = next; + } while (entry != sch); +} - if (entry == end_overlap) { - break; - } - entry = start_overlap; +static inline void +ble_ll_sched_q_head_changed(void) +{ + if (g_ble_ll_sched_q_head_changed) { + return; } - entry = TAILQ_FIRST(&g_ble_ll_sched_q); - if (entry == sch) { - ble_ll_rfmgmt_sched_changed(sch); - } else { - sch = entry; + g_ble_ll_sched_q_head_changed = 1; + + ble_ll_tmr_stop(&g_ble_ll_sched_timer); +} + +void +ble_ll_sched_restart(void) +{ + struct ble_ll_sched_item *first; + + if (!g_ble_ll_sched_q_head_changed) { + return; } - OS_EXIT_CRITICAL(sr); + g_ble_ll_sched_q_head_changed = 0; - /* Restart timer */ - BLE_LL_ASSERT(sch != NULL); - os_cputime_timer_start(&g_ble_ll_sched_timer, sch->start_time); + first = TAILQ_FIRST(&g_ble_ll_sched_q); - return rc; + ble_ll_rfmgmt_sched_changed(first); + + if (first) { + ble_ll_tmr_start(&g_ble_ll_sched_timer, first->start_time); + } } -/** - * Called to schedule a connection when the current role is master. - * - * Context: Interrupt - * - * @param connsm - * @param ble_hdr - * @param pyld_len - * - * @return int - */ -#if MYNEWT_VAL(BLE_LL_STRICT_CONN_SCHEDULING) int -ble_ll_sched_master_new(struct ble_ll_conn_sm *connsm, - struct ble_mbuf_hdr *ble_hdr, uint8_t pyld_len) +ble_ll_sched_insert(struct ble_ll_sched_item *sch, uint32_t max_delay, + ble_ll_sched_preempt_cb_t preempt_cb) { - int rc; - os_sr_t sr; - uint32_t initial_start; - uint32_t earliest_start; - uint32_t earliest_end; - uint32_t dur; - uint32_t itvl_t; - uint32_t adv_rxend; - int i; - uint32_t tpp; - uint32_t tse; - uint32_t np; - uint32_t cp; - uint32_t tick_in_period; - + struct ble_ll_sched_item *preempt_first; + struct ble_ll_sched_item *first; struct ble_ll_sched_item *entry; - struct ble_ll_sched_item *sch; + uint32_t max_start_time; + uint32_t duration; - /* Better have a connsm */ - BLE_LL_ASSERT(connsm != NULL); + OS_ASSERT_CRITICAL(); - /* Get schedule element from connection */ - rc = -1; - sch = &connsm->conn_sch; + preempt_first = NULL; - /* XXX: - * The calculations for the 32kHz crystal bear alot of explanation. The - * earliest possible time that the master can start the connection with a - * slave is 1.25 msecs from the end of the connection request. The - * connection request is sent an IFS time from the end of the advertising - * packet that was received plus the time it takes to send the connection - * request. At 1 Mbps, this is 1752 usecs, or 57.41 ticks. Using 57 ticks - * makes us off ~13 usecs. Since we dont want to actually calculate the - * receive end time tick (this would take too long), we assume the end of - * the advertising PDU is 'now' (we call os_cputime_get32). We dont know - * how much time it will take to service the ISR but if we are more than the - * rx to tx time of the chip we will not be successful transmitting the - * connect request. All this means is that we presume that the slave will - * receive the connect request later than we expect but no earlier than - * 13 usecs before (this is important). - * - * The code then attempts to schedule the connection at the - * earliest time although this may not be possible. When the actual - * schedule start time is determined, the master has to determine if this - * time is more than a transmit window offset interval (1.25 msecs). The - * master has to tell the slave how many transmit window offsets there are - * from the earliest possible time to when the actual transmit start will - * occur. Later in this function you will see the calculation. The actual - * transmission start has to occur within the transmit window. The transmit - * window interval is in units of 1.25 msecs and has to be at least 1. To - * make things a bit easier (but less power efficient for the slave), we - * use a transmit window of 2. We do this because we dont quite know the - * exact start of the transmission and if we are too early or too late we - * could miss the transmit window. A final note: the actual transmission - * start (the anchor point) is sched offset ticks from the schedule start - * time. We dont add this to the calculation when calculating the window - * offset. The reason we dont do this is we want to insure we transmit - * after the window offset we tell the slave. For example, say we think - * we are transmitting 1253 usecs from the earliest start. This would cause - * us to send a transmit window offset of 1. Since we are actually - * transmitting earlier than the slave thinks we could end up transmitting - * before the window offset. Transmitting later is fine since we have the - * transmit window to do so. Transmitting before is bad, since the slave - * wont be listening. We could do better calculation if we wanted to use - * a transmit window of 1 as opposed to 2, but for now we dont care. - */ - dur = os_cputime_usecs_to_ticks(g_ble_ll_sched_data.sch_ticks_per_period); - adv_rxend = os_cputime_get32(); - if (ble_hdr->rxinfo.channel >= BLE_PHY_NUM_DATA_CHANS) { - /* - * We received packet on advertising channel which means this is a legacy - * PDU on 1 Mbps - we do as described above. - */ - earliest_start = adv_rxend + 57; - } else { - /* - * The calculations are similar as above. - * - * We received packet on data channel which means this is AUX_ADV_IND - * received on secondary adv channel. We can schedule first packet at - * the earliest after "T_IFS + AUX_CONNECT_REQ + transmitWindowDelay". - * AUX_CONNECT_REQ and transmitWindowDelay times vary depending on which - * PHY we received on. - * - */ - if (ble_hdr->rxinfo.phy == BLE_PHY_1M) { - // 150 + 352 + 2500 = 3002us = 98.37 ticks - earliest_start = adv_rxend + 98; - } else if (ble_hdr->rxinfo.phy == BLE_PHY_2M) { - // 150 + 180 + 2500 = 2830us = 92.73 ticks - earliest_start = adv_rxend + 93; - } else if (ble_hdr->rxinfo.phy == BLE_PHY_CODED) { - // 150 + 2896 + 3750 = 6796us = 222.69 ticks - earliest_start = adv_rxend + 223; - } else { - BLE_LL_ASSERT(0); - } + max_start_time = sch->start_time + max_delay; + duration = sch->end_time - sch->start_time; + + first = TAILQ_FIRST(&g_ble_ll_sched_q); + if (!first) { + TAILQ_INSERT_HEAD(&g_ble_ll_sched_q, sch, link); + sch->enqueued = 1; + goto done; } - earliest_start += MYNEWT_VAL(BLE_LL_CONN_INIT_MIN_WIN_OFFSET) * - BLE_LL_SCHED_32KHZ_TICKS_PER_SLOT; - itvl_t = connsm->conn_itvl_ticks; - /* We have to find a place for this schedule */ - OS_ENTER_CRITICAL(sr); + TAILQ_FOREACH(entry, &g_ble_ll_sched_q, link) { + if (LL_TMR_LEQ(sch->end_time, entry->start_time)) { + TAILQ_INSERT_BEFORE(entry, sch, link); + sch->enqueued = 1; + goto done; + } - /* - * Are there any allocated periods? If not, set epoch start to earliest - * time - */ - if (g_ble_ll_sched_data.sch_num_occ_periods == 0) { - g_ble_ll_sched_data.sch_epoch_start = earliest_start; - cp = 0; - } else { - /* - * Earliest start must occur on period boundary. - * (tse = ticks since epoch) + /* If current item overlaps our item check if we can preempt. If we + * cannot preempt, move our item past current item and see if it's + * still within allowed range. */ - tpp = g_ble_ll_sched_data.sch_ticks_per_period; - tse = earliest_start - g_ble_ll_sched_data.sch_epoch_start; - np = tse / tpp; - cp = np % BLE_LL_SCHED_PERIODS; - tick_in_period = tse - (np * tpp); - if (tick_in_period != 0) { - ++cp; - if (cp == BLE_LL_SCHED_PERIODS) { - cp = 0; - } - earliest_start += (tpp - tick_in_period); - } - /* Now find first un-occupied period starting from cp */ - for (i = 0; i < BLE_LL_SCHED_PERIODS; ++i) { - if (g_ble_ll_sched_data.sch_occ_period_mask & (1 << cp)) { - ++cp; - if (cp == BLE_LL_SCHED_PERIODS) { - cp = 0; + if (ble_ll_sched_check_overlap(sch, entry)) { + if (preempt_cb(sch, entry)) { + if (!preempt_first) { + preempt_first = entry; } - earliest_start += tpp; } else { - /* not occupied */ - break; + preempt_first = NULL; + /* + * For the 32768 Hz crystal in nrf chip, 1 tick is 30.517us. + * The connection state machine use anchor point to store the + * cpu ticks and anchor_point_usec to store the remainder. + * Therefore, to compensate the inaccuracy of the crystal, the + * ticks of anchor_point will be add with 1 once the value of + * anchor_point_usec exceed 31. If two connections have same + * connection interval, the time difference between the two + * start of schedule item will decreased 1, which lead to + * an overlap. To prevent this from happenning, we set the + * start_time of sch to 1 cpu tick after the end_time of entry. + */ + sch->start_time = entry->end_time + 1; + + if ((max_delay == 0) || LL_TMR_GEQ(sch->start_time, + max_start_time)) { + sch->enqueued = 0; + goto done; + } + + sch->end_time = sch->start_time + duration; } } - /* Should never happen but if it does... */ - if (i == BLE_LL_SCHED_PERIODS) { - OS_EXIT_CRITICAL(sr); - return rc; + } + + if (!entry) { + TAILQ_INSERT_TAIL(&g_ble_ll_sched_q, sch, link); + sch->enqueued = 1; + } + +done: + if (preempt_first) { + BLE_LL_ASSERT(sch->enqueued); + ble_ll_sched_preempt(sch, preempt_first); + } + + /* Pause scheduler if inserted as 1st item, we do not want to miss this + * one. Caller should restart outside critical section. + */ + if (TAILQ_FIRST(&g_ble_ll_sched_q) == sch) { + BLE_LL_ASSERT(sch->enqueued); + ble_ll_sched_q_head_changed(); + } + + return sch->enqueued ? 0 : -1; +} + +/* + * Determines if the schedule item overlaps the currently running schedule + * item. We only care about connection schedule items + */ +static int +ble_ll_sched_overlaps_current(struct ble_ll_sched_item *sch) +{ + int rc = 0; +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) || MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + uint32_t ce_end_time; + + if (ble_ll_state_get() == BLE_LL_STATE_CONNECTION) { + ce_end_time = ble_ll_conn_get_ce_end_time(); + if (LL_TMR_GT(ce_end_time, sch->start_time)) { + rc = 1; } } +#endif + return rc; +} + +int +ble_ll_sched_conn_reschedule(struct ble_ll_conn_sm *connsm) +{ +#if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) + struct ble_ll_sched_css *css = &g_ble_ll_sched_css; +#endif + struct ble_ll_sched_item *sch; +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) + uint32_t usecs; +#endif + os_sr_t sr; + int rc; + + /* Get schedule element from connection */ + sch = &connsm->conn_sch; + + /* Set schedule start and end times */ + sch->start_time = connsm->anchor_point - g_ble_ll_sched_offset_ticks; + switch (connsm->conn_role) { +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) + case BLE_LL_CONN_ROLE_CENTRAL: + sch->remainder = connsm->anchor_point_usecs; + break; +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) + case BLE_LL_CONN_ROLE_PERIPHERAL: + usecs = connsm->periph_cur_window_widening; + sch->start_time -= (ble_ll_tmr_u2t(usecs) + 1); + sch->remainder = 0; + break; +#endif + default: + BLE_LL_ASSERT(0); + break; + } - sch->start_time = earliest_start; - initial_start = earliest_start; - earliest_end = earliest_start + dur; - - if (!ble_ll_sched_insert_if_empty(sch)) { - /* Nothing in schedule. Schedule as soon as possible */ - rc = 0; - connsm->tx_win_off = MYNEWT_VAL(BLE_LL_CONN_INIT_MIN_WIN_OFFSET); - } else { - os_cputime_timer_stop(&g_ble_ll_sched_timer); - TAILQ_FOREACH(entry, &g_ble_ll_sched_q, link) { - /* Set these because overlap function needs them to be set */ - sch->start_time = earliest_start; - sch->end_time = earliest_end; - - /* We can insert if before entry in list */ - if (CPUTIME_LEQ(sch->end_time, entry->start_time)) { - if ((earliest_start - initial_start) <= itvl_t) { - rc = 0; - TAILQ_INSERT_BEFORE(entry, sch, link); - } - break; - } + sch->end_time = connsm->ce_end_time; - /* Check for overlapping events */ - if (ble_ll_sched_is_overlap(sch, entry)) { - /* Earliest start is end of this event since we overlap */ - earliest_start = entry->end_time; - earliest_end = earliest_start + dur; - } - } + /* Better be past current time or we just leave */ + if (LL_TMR_LT(sch->start_time, ble_ll_tmr_get())) { + return -1; + } - /* Must be able to schedule within one connection interval */ - if (!entry) { - if ((earliest_start - initial_start) <= itvl_t) { - rc = 0; - TAILQ_INSERT_TAIL(&g_ble_ll_sched_q, sch, link); - } - } + OS_ENTER_CRITICAL(sr); - if (!rc) { - /* calculate number of window offsets. Each offset is 1.25 ms */ - sch->enqueued = 1; - /* - * NOTE: we dont add sched offset ticks as we want to under-estimate - * the transmit window slightly since the window size is currently - * 2 when using a 32768 crystal. - */ - dur = os_cputime_ticks_to_usecs(earliest_start - initial_start); - connsm->tx_win_off = dur / BLE_LL_CONN_TX_OFF_USECS; - } + if (ble_ll_sched_overlaps_current(sch)) { + OS_EXIT_CRITICAL(sr); + return -1; } - if (!rc) { - sch->start_time = earliest_start; - sch->end_time = earliest_end; - /* - * Since we have the transmit window to transmit in, we dont need - * to set the anchor point usecs; just transmit to the nearest tick. - */ - connsm->anchor_point = earliest_start + g_ble_ll_sched_offset_ticks; - connsm->anchor_point_usecs = 0; - connsm->ce_end_time = earliest_end; - connsm->period_occ_mask = (1 << cp); - g_ble_ll_sched_data.sch_occ_period_mask |= connsm->period_occ_mask; - ++g_ble_ll_sched_data.sch_num_occ_periods; + rc = ble_ll_sched_insert(sch, 0, preempt_any_except_conn); +#if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) + /* Store new anchor point for strict scheduling if successfully scheduled + * reference connection. + */ + if ((rc == 0) && (connsm == g_ble_ll_conn_css_ref)) { + css->period_anchor_idx = connsm->css_period_idx; + css->period_anchor_slot_idx = connsm->css_slot_idx; + css->period_anchor_ticks = connsm->anchor_point; + css->period_anchor_rem_us = connsm->anchor_point_usecs; } - - - /* Get head of list to restart timer */ - sch = TAILQ_FIRST(&g_ble_ll_sched_q); - ble_ll_rfmgmt_sched_changed(sch); +#endif OS_EXIT_CRITICAL(sr); - os_cputime_timer_start(&g_ble_ll_sched_timer, sch->start_time); + ble_ll_sched_restart(); return rc; } -#else + +/** + * Called to schedule a connection when the current role is central. + * + * Context: Interrupt + * + * @param connsm + * @param ble_hdr + * @param pyld_len + * + * @return int + */ int -ble_ll_sched_master_new(struct ble_ll_conn_sm *connsm, - struct ble_mbuf_hdr *ble_hdr, uint8_t pyld_len) +ble_ll_sched_conn_central_new(struct ble_ll_conn_sm *connsm, + struct ble_mbuf_hdr *ble_hdr, uint8_t pyld_len) { - int rc; - os_sr_t sr; - uint8_t req_slots; - uint32_t initial_start; - uint32_t earliest_start; - uint32_t earliest_end; - uint32_t dur; - uint32_t itvl_t; - uint32_t adv_rxend; - struct ble_ll_sched_item *entry; +#if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) + struct ble_ll_sched_css *css = &g_ble_ll_sched_css; + uint8_t rem_us; +#endif struct ble_ll_sched_item *sch; - - /* - * XXX: TODO this code assumes the advertisement and connect request were - * sent at 1Mbps. - */ + uint32_t orig_start_time; + uint32_t earliest_start = 0; + uint32_t min_win_offset; + uint32_t max_delay = 0; + uint32_t adv_rxend; + bool calc_sch = true; + os_sr_t sr; + int rc; /* Get schedule element from connection */ - rc = -1; sch = &connsm->conn_sch; - req_slots = MYNEWT_VAL(BLE_LL_CONN_INIT_SLOTS); /* XXX: * The calculations for the 32kHz crystal bear alot of explanation. The - * earliest possible time that the master can start the connection with a - * slave is 1.25 msecs from the end of the connection request. The + * earliest possible time that the central can start the connection with a + * peripheral is 1.25 msecs from the end of the connection request. The * connection request is sent an IFS time from the end of the advertising * packet that was received plus the time it takes to send the connection * request. At 1 Mbps, this is 1752 usecs, or 57.41 ticks. Using 57 ticks @@ -570,43 +459,42 @@ ble_ll_sched_master_new(struct ble_ll_conn_sm *connsm, * the advertising PDU is 'now' (we call os_cputime_get32). We dont know * how much time it will take to service the ISR but if we are more than the * rx to tx time of the chip we will not be successful transmitting the - * connect request. All this means is that we presume that the slave will + * connect request. All this means is that we presume that the peripheral will * receive the connect request later than we expect but no earlier than * 13 usecs before (this is important). * * The code then attempts to schedule the connection at the * earliest time although this may not be possible. When the actual - * schedule start time is determined, the master has to determine if this + * schedule start time is determined, the central has to determine if this * time is more than a transmit window offset interval (1.25 msecs). The - * master has to tell the slave how many transmit window offsets there are + * central has to tell the peripheral how many transmit window offsets there are * from the earliest possible time to when the actual transmit start will * occur. Later in this function you will see the calculation. The actual * transmission start has to occur within the transmit window. The transmit * window interval is in units of 1.25 msecs and has to be at least 1. To - * make things a bit easier (but less power efficient for the slave), we + * make things a bit easier (but less power efficient for the peripheral), we * use a transmit window of 2. We do this because we dont quite know the * exact start of the transmission and if we are too early or too late we * could miss the transmit window. A final note: the actual transmission * start (the anchor point) is sched offset ticks from the schedule start * time. We dont add this to the calculation when calculating the window * offset. The reason we dont do this is we want to insure we transmit - * after the window offset we tell the slave. For example, say we think + * after the window offset we tell the peripheral. For example, say we think * we are transmitting 1253 usecs from the earliest start. This would cause * us to send a transmit window offset of 1. Since we are actually - * transmitting earlier than the slave thinks we could end up transmitting + * transmitting earlier than the peripheral thinks we could end up transmitting * before the window offset. Transmitting later is fine since we have the - * transmit window to do so. Transmitting before is bad, since the slave + * transmit window to do so. Transmitting before is bad, since the peripheral * wont be listening. We could do better calculation if we wanted to use * a transmit window of 1 as opposed to 2, but for now we dont care. */ - dur = req_slots * BLE_LL_SCHED_32KHZ_TICKS_PER_SLOT; - adv_rxend = os_cputime_get32(); + adv_rxend = ble_ll_tmr_get(); if (ble_hdr->rxinfo.channel >= BLE_PHY_NUM_DATA_CHANS) { /* * We received packet on advertising channel which means this is a legacy * PDU on 1 Mbps - we do as described above. */ - earliest_start = adv_rxend + 57; + earliest_start = adv_rxend + ble_ll_tmr_u2t(1752); } else { /* * The calculations are similar as above. @@ -619,105 +507,110 @@ ble_ll_sched_master_new(struct ble_ll_conn_sm *connsm, * */ if (ble_hdr->rxinfo.phy == BLE_PHY_1M) { - // 150 + 352 + 2500 = 3002us = 98.37 ticks - earliest_start = adv_rxend + 98; + /* 150 + 352 + 2500 = 3002us */ + earliest_start = adv_rxend + ble_ll_tmr_u2t(3002); } else if (ble_hdr->rxinfo.phy == BLE_PHY_2M) { - // 150 + 180 + 2500 = 2830us = 92.73 ticks - earliest_start = adv_rxend + 93; + /* 150 + 180 + 2500 = 2830us */ + earliest_start = adv_rxend + ble_ll_tmr_u2t(2830); } else if (ble_hdr->rxinfo.phy == BLE_PHY_CODED) { - // 150 + 2896 + 3750 = 6796us = 222.69 ticks - earliest_start = adv_rxend + 223; + /* 150 + 2896 + 3750 = 6796us */ + earliest_start = adv_rxend + ble_ll_tmr_u2t(6796); } else { BLE_LL_ASSERT(0); } } - earliest_start += MYNEWT_VAL(BLE_LL_CONN_INIT_MIN_WIN_OFFSET) * - BLE_LL_SCHED_32KHZ_TICKS_PER_SLOT; - earliest_end = earliest_start + dur; - itvl_t = connsm->conn_itvl_ticks; - /* We have to find a place for this schedule */ - OS_ENTER_CRITICAL(sr); + orig_start_time = earliest_start - g_ble_ll_sched_offset_ticks; - /* The schedule item must occur after current running item (if any) */ - sch->start_time = earliest_start; - initial_start = earliest_start; +#if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) + if (ble_ll_sched_css_is_enabled()) { + OS_ENTER_CRITICAL(sr); - if (!ble_ll_sched_insert_if_empty(sch)) { - /* Nothing in schedule. Schedule as soon as possible */ - rc = 0; - connsm->tx_win_off = MYNEWT_VAL(BLE_LL_CONN_INIT_MIN_WIN_OFFSET); - } else { - os_cputime_timer_stop(&g_ble_ll_sched_timer); - TAILQ_FOREACH(entry, &g_ble_ll_sched_q, link) { - /* Set these because overlap function needs them to be set */ - sch->start_time = earliest_start; - sch->end_time = earliest_end; - - /* We can insert if before entry in list */ - if (CPUTIME_LEQ(sch->end_time, entry->start_time)) { - if ((earliest_start - initial_start) <= itvl_t) { - rc = 0; - TAILQ_INSERT_BEFORE(entry, sch, link); - } - break; - } + if (!g_ble_ll_conn_css_ref) { + css->period_anchor_ticks = earliest_start; + css->period_anchor_rem_us = 0; + css->period_anchor_idx = 0; + css->period_anchor_slot_idx = connsm->css_slot_idx; - /* Check for overlapping events */ - if (ble_ll_sched_is_overlap(sch, entry)) { - /* Earliest start is end of this event since we overlap */ - earliest_start = entry->end_time; - earliest_end = earliest_start + dur; + connsm->css_period_idx = 0; + max_delay = connsm->conn_itvl_ticks; + } else { + /* Reference connection may be already at next period if it has + * slot index lower than our, so we first try schedule one period + * earlier since our slot index in that period may not yet have + * passed. This avoids scheduling 1st connection event too far in + * the future, i.e. more than conn interval. + */ + if (connsm->css_slot_idx > css->period_anchor_slot_idx) { + connsm->css_period_idx = css->period_anchor_idx - 1; + } else { + connsm->css_period_idx = css->period_anchor_idx; } } - /* Must be able to schedule within one connection interval */ - if (!entry) { - if ((earliest_start - initial_start) <= itvl_t) { - rc = 0; - TAILQ_INSERT_TAIL(&g_ble_ll_sched_q, sch, link); - } - } + /* Calculate anchor point and move to next period if scheduled too + * early. + */ + connsm->css_period_idx--; + do { + connsm->css_period_idx++; + ble_ll_sched_css_set_conn_anchor(connsm); + sch->start_time = + connsm->anchor_point - g_ble_ll_sched_offset_ticks; + } while (LL_TMR_LT(sch->start_time, orig_start_time)); + + sch->end_time = connsm->anchor_point; + sch->remainder = connsm->anchor_point_usecs; - if (!rc) { - /* calculate number of window offsets. Each offset is 1.25 ms */ - sch->enqueued = 1; - /* - * NOTE: we dont add sched offset ticks as we want to under-estimate - * the transmit window slightly since the window size is currently - * 2 when using a 32768 crystal. - */ - dur = os_cputime_ticks_to_usecs(earliest_start - initial_start); - connsm->tx_win_off = dur / BLE_LL_CONN_TX_OFF_USECS; + OS_EXIT_CRITICAL(sr); + + rem_us = sch->remainder; + ble_ll_tmr_add(&sch->end_time, &rem_us, ble_ll_sched_css_get_slot_us()); + if (rem_us == 0) { + sch->end_time--; } + + calc_sch = false; } +#endif - if (!rc) { - sch->start_time = earliest_start; - sch->end_time = earliest_end; - /* - * Since we have the transmit window to transmit in, we dont need - * to set the anchor point usecs; just transmit to the nearest tick. - */ - connsm->anchor_point = earliest_start + g_ble_ll_sched_offset_ticks; - connsm->anchor_point_usecs = 0; - connsm->ce_end_time = earliest_end; + if (calc_sch) { + sch->start_time = earliest_start - g_ble_ll_sched_offset_ticks; + sch->end_time = earliest_start + + ble_ll_tmr_u2t(MYNEWT_VAL(BLE_LL_CONN_INIT_SLOTS) * + BLE_LL_SCHED_USECS_PER_SLOT); + + min_win_offset = ble_ll_tmr_u2t( + MYNEWT_VAL(BLE_LL_CONN_INIT_MIN_WIN_OFFSET) * + BLE_LL_SCHED_USECS_PER_SLOT); + sch->start_time += min_win_offset; + sch->end_time += min_win_offset; + sch->remainder = 0; + + max_delay = connsm->conn_itvl_ticks - min_win_offset; } - /* Get head of list to restart timer */ - sch = TAILQ_FIRST(&g_ble_ll_sched_q); - ble_ll_rfmgmt_sched_changed(sch); + OS_ENTER_CRITICAL(sr); + + rc = ble_ll_sched_insert(sch, max_delay, preempt_none); + if (rc == 0) { + connsm->tx_win_off = ble_ll_tmr_t2u(sch->start_time - orig_start_time) / + BLE_LL_CONN_TX_OFF_USECS; + + connsm->anchor_point = sch->start_time + g_ble_ll_sched_offset_ticks; + connsm->anchor_point_usecs = sch->remainder; + connsm->ce_end_time = sch->end_time; + } OS_EXIT_CRITICAL(sr); - os_cputime_timer_start(&g_ble_ll_sched_timer, sch->start_time); + ble_ll_sched_restart(); return rc; } -#endif /** - * Schedules a slave connection for the first time. + * Schedules a peripheral connection for the first time. * * Context: Link Layer * @@ -726,98 +619,39 @@ ble_ll_sched_master_new(struct ble_ll_conn_sm *connsm, * @return int */ int -ble_ll_sched_slave_new(struct ble_ll_conn_sm *connsm) +ble_ll_sched_conn_periph_new(struct ble_ll_conn_sm *connsm) { - int rc; - os_sr_t sr; - struct ble_ll_sched_item *entry; - struct ble_ll_sched_item *next_sch; struct ble_ll_sched_item *sch; - int first = 0; + os_sr_t sr; + int rc; /* Get schedule element from connection */ - rc = -1; sch = &connsm->conn_sch; /* Set schedule start and end times */ /* - * XXX: for now, we dont care about anchor point usecs for the slave. It + * XXX: for now, we dont care about anchor point usecs for the peripheral. It * does not matter if we turn on the receiver up to one tick before w * need to. We also subtract one extra tick since the conversion from * usecs to ticks could be off by up to 1 tick. */ sch->start_time = connsm->anchor_point - g_ble_ll_sched_offset_ticks - - os_cputime_usecs_to_ticks(connsm->slave_cur_window_widening) - 1; + ble_ll_tmr_u2t(connsm->periph_cur_window_widening) - 1; sch->end_time = connsm->ce_end_time; sch->remainder = 0; - /* We have to find a place for this schedule */ OS_ENTER_CRITICAL(sr); - /* The schedule item must occur after current running item (if any) */ - if (ble_ll_sched_overlaps_current(sch)) { - OS_EXIT_CRITICAL(sr); - return rc; - } - - entry = ble_ll_sched_insert_if_empty(sch); - if (!entry) { - /* Nothing in schedule. Schedule as soon as possible */ - rc = 0; - first = 1; - } else { - os_cputime_timer_stop(&g_ble_ll_sched_timer); - while (1) { - next_sch = entry->link.tqe_next; - /* Insert if event ends before next starts */ - if (CPUTIME_LEQ(sch->end_time, entry->start_time)) { - rc = 0; - TAILQ_INSERT_BEFORE(entry, sch, link); - break; - } - - if (ble_ll_sched_is_overlap(sch, entry)) { - /* If we overlap with a connection, we re-schedule */ - if (ble_ll_sched_conn_overlap(entry)) { - break; - } - } - - /* Move to next entry */ - entry = next_sch; - - /* Insert at tail if none left to check */ - if (!entry) { - rc = 0; - TAILQ_INSERT_TAIL(&g_ble_ll_sched_q, sch, link); - break; - } - } - - if (!rc) { - sch->enqueued = 1; - } - - next_sch = TAILQ_FIRST(&g_ble_ll_sched_q); - if (next_sch == sch) { - first = 1; - } else { - sch = next_sch; - } - } - - if (first) { - ble_ll_rfmgmt_sched_changed(sch); - } + rc = ble_ll_sched_insert(sch, 0, preempt_any); OS_EXIT_CRITICAL(sr); - os_cputime_timer_start(&g_ble_ll_sched_timer, sch->start_time); + ble_ll_sched_restart(); return rc; } -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) && MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) /* * Determines if the schedule item overlaps the currently running schedule * item. This function cares about connection and sync. @@ -830,9 +664,11 @@ ble_ll_sched_sync_overlaps_current(struct ble_ll_sched_item *sch) state = ble_ll_state_get(); switch (state) { +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) || MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) case BLE_LL_STATE_CONNECTION: end_time = ble_ll_conn_get_ce_end_time(); break; +#endif case BLE_LL_STATE_SYNC: end_time = ble_ll_sync_get_event_end_time(); break; @@ -840,56 +676,18 @@ ble_ll_sched_sync_overlaps_current(struct ble_ll_sched_item *sch) return 0; } - return CPUTIME_GT(end_time, sch->start_time); + return LL_TMR_GT(end_time, sch->start_time); } int -ble_ll_sched_sync_reschedule(struct ble_ll_sched_item *sch, - uint32_t anchor_point, uint8_t anchor_point_usecs, - uint32_t window_widening, - int8_t phy_mode) +ble_ll_sched_sync_reschedule(struct ble_ll_sched_item *sch, uint32_t ww_us) { - struct ble_ll_sched_item *entry; - uint8_t start_time_rem_usecs; - uint8_t window_rem_usecs; - uint32_t window_ticks; - uint32_t start_time; - uint32_t end_time; - uint32_t dur; - int rc = 0; os_sr_t sr; + int rc = 0; - window_ticks = os_cputime_usecs_to_ticks(window_widening); - window_rem_usecs = window_widening - os_cputime_ticks_to_usecs(window_ticks); - - /* adjust for subtraction */ - anchor_point_usecs += 31; - anchor_point--; - - start_time = anchor_point - window_ticks; - start_time_rem_usecs = anchor_point_usecs - window_rem_usecs; - if (start_time_rem_usecs >= 31) { - start_time++; - start_time_rem_usecs -= 31; - } - - dur = ble_ll_pdu_tx_time_get(MYNEWT_VAL(BLE_LL_SCHED_SCAN_SYNC_PDU_LEN), - phy_mode); - end_time = start_time + os_cputime_usecs_to_ticks(dur); - - start_time -= g_ble_ll_sched_offset_ticks; - - /* Set schedule start and end times */ - sch->start_time = start_time; - sch->remainder = start_time_rem_usecs; - sch->end_time = end_time; - - /* Better be past current time or we just leave */ - if (CPUTIME_LEQ(sch->start_time, os_cputime_get32())) { - return -1; - } + /* Adjust start time to include window widening */ + ble_ll_tmr_sub(&sch->start_time, &sch->remainder, ww_us); - /* We have to find a place for this schedule */ OS_ENTER_CRITICAL(sr); if (ble_ll_sched_sync_overlaps_current(sch)) { @@ -897,129 +695,29 @@ ble_ll_sched_sync_reschedule(struct ble_ll_sched_item *sch, return -1; } - /* Try to find slot for sync scan. */ - os_cputime_timer_stop(&g_ble_ll_sched_timer); - - TAILQ_FOREACH(entry, &g_ble_ll_sched_q, link) { - /* We can insert if before entry in list */ - if (CPUTIME_LEQ(sch->end_time, entry->start_time)) { - TAILQ_INSERT_BEFORE(entry, sch, link); - sch->enqueued = 1; - break; - } - - /* Check for overlapping events. For now drop if it overlaps with - * anything. We can make it smarter later on - */ - if (ble_ll_sched_is_overlap(sch, entry)) { - rc = -1; - break; - } - } - - if (!entry) { - TAILQ_INSERT_TAIL(&g_ble_ll_sched_q, sch, link); - sch->enqueued = 1; - } - - entry = TAILQ_FIRST(&g_ble_ll_sched_q); - if (entry == sch) { - ble_ll_rfmgmt_sched_changed(sch); - } else { - sch = entry; - } + rc = ble_ll_sched_insert(sch, 0, preempt_none); OS_EXIT_CRITICAL(sr); - /* Restart timer */ - BLE_LL_ASSERT(sch != NULL); - os_cputime_timer_start(&g_ble_ll_sched_timer, sch->start_time); + ble_ll_sched_restart(); return rc; } int -ble_ll_sched_sync(struct ble_ll_sched_item *sch, - uint32_t beg_cputime, uint32_t rem_usecs, - uint32_t offset, int8_t phy_mode) +ble_ll_sched_sync(struct ble_ll_sched_item *sch) { - struct ble_ll_sched_item *entry; - uint32_t start_time_rem_usecs; - uint32_t off_rem_usecs; - uint32_t start_time; - uint32_t off_ticks; - uint32_t end_time; - uint32_t dur; os_sr_t sr; int rc = 0; - off_ticks = os_cputime_usecs_to_ticks(offset); - off_rem_usecs = offset - os_cputime_ticks_to_usecs(off_ticks); - - start_time = beg_cputime + off_ticks; - start_time_rem_usecs = rem_usecs + off_rem_usecs; - if (start_time_rem_usecs >= 31) { - start_time++; - start_time_rem_usecs -= 31; - } - - dur = ble_ll_pdu_tx_time_get(MYNEWT_VAL(BLE_LL_SCHED_SCAN_SYNC_PDU_LEN), - phy_mode); - end_time = start_time + os_cputime_usecs_to_ticks(dur); - - start_time -= g_ble_ll_sched_offset_ticks; - - sch->start_time = start_time; - sch->remainder = start_time_rem_usecs; - sch->end_time = end_time; - OS_ENTER_CRITICAL(sr); - if (!ble_ll_sched_insert_if_empty(sch)) { - /* Nothing in schedule. Schedule as soon as possible - * If we are here it means sch has been added to the scheduler */ - goto done; - } - - /* Try to find slot for scan. */ - os_cputime_timer_stop(&g_ble_ll_sched_timer); - TAILQ_FOREACH(entry, &g_ble_ll_sched_q, link) { - /* We can insert if before entry in list */ - if (CPUTIME_LEQ(sch->end_time, entry->start_time)) { - TAILQ_INSERT_BEFORE(entry, sch, link); - sch->enqueued = 1; - break; - } - - /* Check for overlapping events. For now drop if it overlaps with - * anything. We can make it smarter later on - */ - if (ble_ll_sched_is_overlap(sch, entry)) { - rc = -1; - break; - } - } - - if (!entry) { - TAILQ_INSERT_TAIL(&g_ble_ll_sched_q, sch, link); - sch->enqueued = 1; - } - -done: - entry = TAILQ_FIRST(&g_ble_ll_sched_q); - if (entry == sch) { - ble_ll_rfmgmt_sched_changed(sch); - } else { - sch = entry; - } + rc = ble_ll_sched_insert(sch, 0, preempt_none); OS_EXIT_CRITICAL(sr); - /* Restart timer */ - BLE_LL_ASSERT(sch != NULL); - os_cputime_timer_start(&g_ble_ll_sched_timer, sch->start_time); + ble_ll_sched_restart(); - STATS_INC(ble_ll_stats, sync_scheduled); return rc; } #endif @@ -1029,257 +727,87 @@ ble_ll_sched_adv_new(struct ble_ll_sched_item *sch, ble_ll_sched_adv_new_cb cb, void *arg) { os_sr_t sr; - uint32_t adv_start; - uint32_t duration; - struct ble_ll_sched_item *entry; - struct ble_ll_sched_item *orig; - - /* Get length of schedule item */ - duration = sch->end_time - sch->start_time; - orig = sch; + int rc; OS_ENTER_CRITICAL(sr); - entry = ble_ll_sched_insert_if_empty(sch); - if (!entry) { - adv_start = sch->start_time; - } else { - /* XXX: no need to stop timer if not first on list. Modify code? */ - os_cputime_timer_stop(&g_ble_ll_sched_timer); - TAILQ_FOREACH(entry, &g_ble_ll_sched_q, link) { - /* We can insert if before entry in list */ - if (CPUTIME_LEQ(sch->end_time, entry->start_time)) { - TAILQ_INSERT_BEFORE(entry, sch, link); - break; - } - - /* Check for overlapping events */ - if (ble_ll_sched_is_overlap(sch, entry)) { - /* Earliest start is end of this event since we overlap */ - sch->start_time = entry->end_time; - sch->end_time = sch->start_time + duration; - } - } - - if (!entry) { - TAILQ_INSERT_TAIL(&g_ble_ll_sched_q, sch, link); - } - adv_start = sch->start_time; - - sch->enqueued = 1; - - /* Restart with head of list */ - sch = TAILQ_FIRST(&g_ble_ll_sched_q); - } - if (cb) { - cb((struct ble_ll_adv_sm *)orig->cb_arg, adv_start, arg); - } + rc = ble_ll_sched_insert(sch, BLE_LL_SCHED_MAX_DELAY_ANY, + preempt_none); + BLE_LL_ASSERT(rc == 0); - if (orig == sch) { - ble_ll_rfmgmt_sched_changed(sch); - } + cb(sch->cb_arg, sch->start_time, arg); OS_EXIT_CRITICAL(sr); - /* Restart timer */ - BLE_LL_ASSERT(sch != NULL); - os_cputime_timer_start(&g_ble_ll_sched_timer, sch->start_time); + ble_ll_sched_restart(); - return 0; + return rc; } int -ble_ll_sched_periodic_adv(struct ble_ll_sched_item *sch, uint32_t *start, - bool after_overlap) +ble_ll_sched_periodic_adv(struct ble_ll_sched_item *sch, bool first_event) { - int rc = 0; os_sr_t sr; - uint32_t adv_start; - uint32_t duration; - struct ble_ll_sched_item *entry; - struct ble_ll_sched_item *orig = sch; - - /* Get length of schedule item */ - duration = sch->end_time - sch->start_time; + int rc; OS_ENTER_CRITICAL(sr); - entry = ble_ll_sched_insert_if_empty(sch); - if (!entry) { - adv_start = sch->start_time; - } else { - /* XXX: no need to stop timer if not first on list. Modify code? */ - os_cputime_timer_stop(&g_ble_ll_sched_timer); - TAILQ_FOREACH(entry, &g_ble_ll_sched_q, link) { - /* We can insert if before entry in list */ - if (CPUTIME_LEQ(sch->end_time, entry->start_time)) { - TAILQ_INSERT_BEFORE(entry, sch, link); - break; - } - - /* Check for overlapping events */ - if (ble_ll_sched_is_overlap(sch, entry)) { - if (after_overlap) { - /* Earliest start is end of this event since we overlap */ - sch->start_time = entry->end_time; - sch->end_time = sch->start_time + duration; - } else { - rc = -1; - break; - } - } - } - - if (!entry) { - TAILQ_INSERT_TAIL(&g_ble_ll_sched_q, sch, link); - } - adv_start = sch->start_time; - - if (!rc) { - sch->enqueued = 1; - } - - /* Restart with head of list */ - sch = TAILQ_FIRST(&g_ble_ll_sched_q); - } - - if (!rc) { - *start = adv_start; - } - if (orig == sch) { - ble_ll_rfmgmt_sched_changed(sch); + if (first_event) { + rc = ble_ll_sched_insert(sch, BLE_LL_SCHED_MAX_DELAY_ANY, + preempt_none); + } else { + rc = ble_ll_sched_insert(sch, 0, preempt_any_except_big); } OS_EXIT_CRITICAL(sr); - /* Restart timer */ - BLE_LL_ASSERT(sch != NULL); - os_cputime_timer_start(&g_ble_ll_sched_timer, sch->start_time); + ble_ll_sched_restart(); return rc; } int -ble_ll_sched_adv_reschedule(struct ble_ll_sched_item *sch, uint32_t *start, +ble_ll_sched_adv_reschedule(struct ble_ll_sched_item *sch, uint32_t max_delay_ticks) { - int rc; - os_sr_t sr; - uint32_t orig_start; - uint32_t duration; + struct ble_ll_sched_item *next; + uint32_t max_end_time; uint32_t rand_ticks; - struct ble_ll_sched_item *entry; - struct ble_ll_sched_item *next_sch; - struct ble_ll_sched_item *before; - struct ble_ll_sched_item *start_overlap; - struct ble_ll_sched_item *end_overlap; - - /* Get length of schedule item */ - duration = sch->end_time - sch->start_time; - - /* Add maximum randomization delay to end */ - rand_ticks = max_delay_ticks; - sch->end_time += max_delay_ticks; - - start_overlap = NULL; - end_overlap = NULL; - before = NULL; - rc = 0; - OS_ENTER_CRITICAL(sr); - - entry = ble_ll_sched_insert_if_empty(sch); - if (entry) { - os_cputime_timer_stop(&g_ble_ll_sched_timer); - while (1) { - next_sch = entry->link.tqe_next; - if (ble_ll_sched_is_overlap(sch, entry)) { - if (start_overlap == NULL) { - start_overlap = entry; - end_overlap = entry; - } else { - end_overlap = entry; - } - } else { - if (CPUTIME_LEQ(sch->end_time, entry->start_time)) { - before = entry; - break; - } - } - - entry = next_sch; - if (entry == NULL) { - break; - } - } + os_sr_t sr; + int rc; - /* - * If there is no overlap, we either insert before the 'before' entry - * or we insert at the end if there is no before entry. - */ - if (start_overlap == NULL) { - if (before) { - TAILQ_INSERT_BEFORE(before, sch, link); - } else { - TAILQ_INSERT_TAIL(&g_ble_ll_sched_q, sch, link); - } - } else { - /* - * This item will overlap with others. See if we can fit it in - * with original duration. - */ - before = NULL; - orig_start = sch->start_time; - entry = start_overlap; - sch->end_time = sch->start_time + duration; - while (1) { - next_sch = entry->link.tqe_next; - if (CPUTIME_LEQ(sch->end_time, entry->start_time)) { - rand_ticks = entry->start_time - sch->end_time; - before = entry; - TAILQ_INSERT_BEFORE(before, sch, link); - break; - } else { - sch->start_time = entry->end_time; - sch->end_time = sch->start_time + duration; - } + max_end_time = sch->end_time + max_delay_ticks; - if (entry == end_overlap) { - rand_ticks = (orig_start + max_delay_ticks) - sch->start_time; - if (rand_ticks > max_delay_ticks) { - /* No place for advertisement. */ - rc = -1; - } else { - if (next_sch == NULL) { - TAILQ_INSERT_TAIL(&g_ble_ll_sched_q, sch, link); - } else { - TAILQ_INSERT_BEFORE(next_sch, sch, link); - } - } - break; - } - entry = next_sch; - BLE_LL_ASSERT(entry != NULL); + OS_ENTER_CRITICAL(sr); + + /* Try to schedule as early as possible but no later than max allowed delay. + * If succeeded, randomize start time to be within max allowed delay from + * the original start time but make sure it ends before next scheduled item. + */ + + rc = ble_ll_sched_insert(sch, max_delay_ticks, preempt_none); + if (rc == 0) { + next = TAILQ_NEXT(sch, link); + if (next) { + if (LL_TMR_LT(next->start_time, max_end_time)) { + max_end_time = next->start_time; } + rand_ticks = max_end_time - sch->end_time; + } else { + rand_ticks = max_delay_ticks; } - } - if (!rc) { - sch->enqueued = 1; if (rand_ticks) { - sch->start_time += ble_ll_rand() % rand_ticks; + rand_ticks = ble_ll_rand() % rand_ticks; } - sch->end_time = sch->start_time + duration; - *start = sch->start_time; - if (sch == TAILQ_FIRST(&g_ble_ll_sched_q)) { - ble_ll_rfmgmt_sched_changed(sch); - } + sch->start_time += rand_ticks; + sch->end_time += rand_ticks; } OS_EXIT_CRITICAL(sr); - sch = TAILQ_FIRST(&g_ble_ll_sched_q); - os_cputime_timer_start(&g_ble_ll_sched_timer, sch->start_time); + ble_ll_sched_restart(); return rc; } @@ -1289,37 +817,63 @@ ble_ll_sched_adv_resched_pdu(struct ble_ll_sched_item *sch) { uint8_t lls; os_sr_t sr; - struct ble_ll_sched_item *entry; + int rc; OS_ENTER_CRITICAL(sr); lls = ble_ll_state_get(); - if ((lls == BLE_LL_STATE_ADV) || (lls == BLE_LL_STATE_CONNECTION) || - (lls == BLE_LL_STATE_SYNC)) { - goto adv_resched_pdu_fail; - } - - entry = ble_ll_sched_insert_if_empty(sch); - if (entry) { - /* If we overlap with the first item, simply re-schedule */ - if (ble_ll_sched_is_overlap(sch, entry)) { - goto adv_resched_pdu_fail; - } - os_cputime_timer_stop(&g_ble_ll_sched_timer); - TAILQ_INSERT_BEFORE(entry, sch, link); - sch->enqueued = 1; + switch(lls) { +#if MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) + case BLE_LL_STATE_ADV: + OS_EXIT_CRITICAL(sr); + return -1; +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) || MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) + case BLE_LL_STATE_CONNECTION: + OS_EXIT_CRITICAL(sr); + return -1; +#endif +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) && MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) + case BLE_LL_STATE_SYNC: + OS_EXIT_CRITICAL(sr); + return -1; +#endif + default: + break; } - ble_ll_rfmgmt_sched_changed(TAILQ_FIRST(&g_ble_ll_sched_q)); + rc = ble_ll_sched_insert(sch, 0, preempt_none); OS_EXIT_CRITICAL(sr); - os_cputime_timer_start(&g_ble_ll_sched_timer, sch->start_time); - return 0; -adv_resched_pdu_fail: + ble_ll_sched_restart(); + + return rc; +} + +#if MYNEWT_VAL(BLE_LL_ISO_BROADCASTER) +int +ble_ll_sched_iso_big(struct ble_ll_sched_item *sch, int first, int fixed) +{ + os_sr_t sr; + int rc; + + OS_ENTER_CRITICAL(sr); + + if (first && !fixed) { + rc = ble_ll_sched_insert(sch, BLE_LL_SCHED_MAX_DELAY_ANY, preempt_none); + } else { + /* XXX provide better strategy for preemption */ + rc = ble_ll_sched_insert(sch, 0, preempt_any); + } + OS_EXIT_CRITICAL(sr); - return -1; + + ble_ll_sched_restart(); + + return rc; } +#endif /* BLE_LL_ISO_BROADCASTER */ /** * Remove a schedule element @@ -1331,75 +885,71 @@ ble_ll_sched_adv_resched_pdu(struct ble_ll_sched_item *sch) int ble_ll_sched_rmv_elem(struct ble_ll_sched_item *sch) { + uint8_t first_removed; os_sr_t sr; - struct ble_ll_sched_item *first; - int rc = 1; + int rc; - if (!sch) { - return rc; - } + BLE_LL_ASSERT(sch); OS_ENTER_CRITICAL(sr); + + first_removed = 0; + if (sch->enqueued) { - first = TAILQ_FIRST(&g_ble_ll_sched_q); - if (first == sch) { - os_cputime_timer_stop(&g_ble_ll_sched_timer); + if (sch == TAILQ_FIRST(&g_ble_ll_sched_q)) { + first_removed = 1; } TAILQ_REMOVE(&g_ble_ll_sched_q, sch, link); sch->enqueued = 0; + rc = 0; + } else { + rc = 1; + } - if (first == sch) { - first = TAILQ_FIRST(&g_ble_ll_sched_q); - if (first) { - os_cputime_timer_start(&g_ble_ll_sched_timer, first->start_time); - } - ble_ll_rfmgmt_sched_changed(first); - } + if (first_removed) { + ble_ll_sched_q_head_changed(); } + OS_EXIT_CRITICAL(sr); + ble_ll_sched_restart(); + return rc; } void ble_ll_sched_rmv_elem_type(uint8_t type, sched_remove_cb_func remove_cb) { - os_sr_t sr; - struct ble_ll_sched_item *entry; struct ble_ll_sched_item *first; + struct ble_ll_sched_item *entry; + uint8_t first_removed; + os_sr_t sr; OS_ENTER_CRITICAL(sr); - first = TAILQ_FIRST(&g_ble_ll_sched_q); - if (!first) { - OS_EXIT_CRITICAL(sr); - return; + first = TAILQ_FIRST(&g_ble_ll_sched_q); + if (first->sched_type == type) { + first_removed = 1; } TAILQ_FOREACH(entry, &g_ble_ll_sched_q, link) { - if (entry->sched_type == type) { - if (first == entry) { - os_cputime_timer_stop(&g_ble_ll_sched_timer); - first = NULL; - } - - TAILQ_REMOVE(&g_ble_ll_sched_q, entry, link); - remove_cb(entry); - entry->enqueued = 0; + if (entry->sched_type != type) { + continue; } + TAILQ_REMOVE(&g_ble_ll_sched_q, entry, link); + remove_cb(entry); + entry->enqueued = 0; } - if (!first) { - first = TAILQ_FIRST(&g_ble_ll_sched_q); - if (first) { - os_cputime_timer_start(&g_ble_ll_sched_timer, first->start_time); - } - ble_ll_rfmgmt_sched_changed(first); + if (first_removed) { + ble_ll_sched_q_head_changed(); } OS_EXIT_CRITICAL(sr); + + ble_ll_sched_restart(); } /** @@ -1419,27 +969,13 @@ ble_ll_sched_execute_item(struct ble_ll_sched_item *sch) lls = ble_ll_state_get(); - ble_ll_trace_u32x3(BLE_LL_TRACE_ID_SCHED, lls, os_cputime_get32(), + ble_ll_trace_u32x3(BLE_LL_TRACE_ID_SCHED, lls, ble_ll_tmr_get(), sch->start_time); if (lls == BLE_LL_STATE_STANDBY) { goto sched; } - /* If aux scan scheduled and LL is in state when scanner is running - * in 3 states: - * BLE_LL_STATE_SCANNING - * BLE_LL_STATE_INITIATING - * BLE_LL_STATE_STANDBY - * - * Let scanner to decide to disable phy or not. - */ - if (sch->sched_type == BLE_LL_SCHED_TYPE_AUX_SCAN) { - if (lls == BLE_LL_STATE_INITIATING || lls == BLE_LL_STATE_SCANNING) { - goto sched; - } - } - /* * This is either an advertising event or connection event start. If * we are scanning or initiating just stop it. @@ -1448,32 +984,61 @@ ble_ll_sched_execute_item(struct ble_ll_sched_item *sch) /* We have to disable the PHY no matter what */ ble_phy_disable(); - if (lls == BLE_LL_STATE_SCANNING) { + switch (lls) { +#if MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) + case BLE_LL_STATE_SCANNING: ble_ll_state_set(BLE_LL_STATE_STANDBY); ble_ll_scan_halt(); - } else if (lls == BLE_LL_STATE_INITIATING) { - ble_ll_state_set(BLE_LL_STATE_STANDBY); - ble_ll_scan_halt(); - /* PHY is disabled - make sure we do not wait for AUX_CONNECT_RSP */ - ble_ll_conn_reset_pending_aux_conn_rsp(); - } else if (lls == BLE_LL_STATE_ADV) { - STATS_INC(ble_ll_stats, sched_state_adv_errs); - ble_ll_adv_halt(); + break; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) - } else if (lls == BLE_LL_STATE_SYNC) { + case BLE_LL_STATE_SYNC: STATS_INC(ble_ll_stats, sched_state_sync_errs); ble_ll_sync_halt(); + break; #endif - } else { +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) + case BLE_LL_STATE_SCAN_AUX: + ble_ll_state_set(BLE_LL_STATE_STANDBY); + ble_ll_scan_aux_halt(); + break; +#endif +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) + case BLE_LL_STATE_ADV: + STATS_INC(ble_ll_stats, sched_state_adv_errs); + ble_ll_adv_halt(); + break; +#endif +#if MYNEWT_VAL(BLE_LL_ROLE_CENTRAL) || MYNEWT_VAL(BLE_LL_ROLE_PERIPHERAL) + case BLE_LL_STATE_CONNECTION: STATS_INC(ble_ll_stats, sched_state_conn_errs); ble_ll_conn_event_halt(); + break; +#endif +#if MYNEWT_VAL(BLE_LL_ISO_BROADCASTER) + case BLE_LL_STATE_BIG: + ble_ll_iso_big_halt(); + break; +#endif +#if MYNEWT_VAL(BLE_LL_EXT) + case BLE_LL_STATE_EXTERNAL: + ble_ll_ext_halt(); + break; +#endif + default: + BLE_LL_ASSERT(0); + break; } sched: - BLE_LL_DEBUG_GPIO(SCHED_ITEM_CB, 1); BLE_LL_ASSERT(sch->sched_cb); + + BLE_LL_DEBUG_GPIO(SCHED_ITEM, 1); rc = sch->sched_cb(sch); - BLE_LL_DEBUG_GPIO(SCHED_ITEM_CB, 0); + if (rc != BLE_LL_SCHED_STATE_RUNNING) { + BLE_LL_DEBUG_GPIO(SCHED_ITEM, 0); + } + return rc; } @@ -1498,7 +1063,7 @@ ble_ll_sched_run(void *arg) int32_t dt; /* Make sure we have passed the start time of the first event */ - dt = (int32_t)(os_cputime_get32() - sch->start_time); + dt = (int32_t)(ble_ll_tmr_get() - sch->start_time); if (dt > g_ble_ll_sched_max_late) { g_ble_ll_sched_max_late = dt; } @@ -1510,14 +1075,11 @@ ble_ll_sched_run(void *arg) /* Remove schedule item and execute the callback */ TAILQ_REMOVE(&g_ble_ll_sched_q, sch, link); sch->enqueued = 0; + g_ble_ll_sched_q_head_changed = 1; + ble_ll_sched_execute_item(sch); - /* Restart if there is an item on the schedule */ - sch = TAILQ_FIRST(&g_ble_ll_sched_q); - if (sch) { - os_cputime_timer_start(&g_ble_ll_sched_timer, sch->start_time); - } - ble_ll_rfmgmt_sched_changed(sch); + ble_ll_sched_restart(); } BLE_LL_DEBUG_GPIO(SCHED_RUN, 0); @@ -1553,164 +1115,19 @@ ble_ll_sched_next_time(uint32_t *next_event_time) } #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -/** - * Called to check if there is place for a planned scan req. - * - * @param chan - * @param phy_mode - * - * @return int 0: Clear for scan req 1: there is an upcoming event - */ -int -ble_ll_sched_scan_req_over_aux_ptr(uint32_t chan, uint8_t phy_mode) -{ - struct ble_ll_sched_item *sch; - uint32_t usec_dur; - uint32_t now = os_cputime_get32(); - - /* Lets calculate roughly how much time we need for scan req and scan rsp */ - usec_dur = ble_ll_pdu_tx_time_get(BLE_SCAN_REQ_LEN, phy_mode); - if (chan >= BLE_PHY_NUM_DATA_CHANS) { - usec_dur += ble_ll_pdu_tx_time_get(BLE_SCAN_RSP_MAX_LEN, phy_mode); - } else { - usec_dur += ble_ll_pdu_tx_time_get(BLE_SCAN_RSP_MAX_EXT_LEN, phy_mode); - } - - sch = TAILQ_FIRST(&g_ble_ll_sched_q); - while (sch) { - /* Let's check if there is no scheduled item which want to start within - * given usecs.*/ - if (CPUTIME_GT(sch->start_time, now + os_cputime_usecs_to_ticks(usec_dur))) { - /* We are fine. Have time for scan req */ - return 0; - } - - /* There is something in the scheduler. If it is not aux ptr we assume - * it is more important that scan req - */ - if (sch->sched_type != BLE_LL_SCHED_TYPE_AUX_SCAN) { - return 1; - } - - ble_ll_scan_end_adv_evt((struct ble_ll_aux_data *)sch->cb_arg); - TAILQ_REMOVE(&g_ble_ll_sched_q, sch, link); - sch->enqueued = 0; - sch = TAILQ_FIRST(&g_ble_ll_sched_q); - } - return 0; -} - -/** - * Called to schedule a aux scan. - * - * Context: Interrupt - * - * @param ble_hdr - * @param scansm - * @param aux_scan - * - * @return 0 on success, 1 otherwise - */ int -ble_ll_sched_aux_scan(struct ble_mbuf_hdr *ble_hdr, - struct ble_ll_scan_sm *scansm, - struct ble_ll_aux_data *aux_scan) +ble_ll_sched_scan_aux(struct ble_ll_sched_item *sch) { - int rc = 1; os_sr_t sr; - uint32_t off_ticks; - uint32_t off_rem_usecs; - uint32_t start_time; - uint32_t start_time_rem_usecs; - uint32_t end_time; - uint32_t dur; - struct ble_ll_sched_item *entry; - struct ble_ll_sched_item *sch; - int phy_mode; - - sch = &aux_scan->sch; - BLE_LL_ASSERT(sch->cb_arg == NULL); - - off_ticks = os_cputime_usecs_to_ticks(aux_scan->offset); - off_rem_usecs = aux_scan->offset - os_cputime_ticks_to_usecs(off_ticks); - - start_time = ble_hdr->beg_cputime + off_ticks; - start_time_rem_usecs = ble_hdr->rem_usecs + off_rem_usecs; - if (start_time_rem_usecs >= 31) { - start_time++; - start_time_rem_usecs -= 31; - } - start_time -= g_ble_ll_sched_offset_ticks; - - /* Let's calculate time we reserve for aux packet. For now we assume to wait - * for fixed number of bytes and handle possible interrupting it in - * ble_ll_sched_execute_item(). This is because aux packet can be up to - * 256bytes and we don't want to block sched that long - */ - phy_mode = ble_ll_phy_to_phy_mode(aux_scan->aux_phy, - BLE_HCI_LE_PHY_CODED_ANY); - dur = ble_ll_pdu_tx_time_get(MYNEWT_VAL(BLE_LL_SCHED_SCAN_AUX_PDU_LEN), - phy_mode); - end_time = start_time + os_cputime_usecs_to_ticks(dur); - - sch->start_time = start_time; - sch->remainder = start_time_rem_usecs; - sch->end_time = end_time; + int rc; OS_ENTER_CRITICAL(sr); - if (!ble_ll_sched_insert_if_empty(sch)) { - /* Nothing in schedule. Schedule as soon as possible - * If we are here it means sch has been added to the scheduler */ - rc = 0; - goto done; - } - - /* Try to find slot for aux scan. */ - os_cputime_timer_stop(&g_ble_ll_sched_timer); - TAILQ_FOREACH(entry, &g_ble_ll_sched_q, link) { - /* We can insert if before entry in list */ - if (CPUTIME_LEQ(sch->end_time, entry->start_time)) { - rc = 0; - TAILQ_INSERT_BEFORE(entry, sch, link); - sch->enqueued = 1; - break; - } - - /* Check for overlapping events. For now drop if it overlaps with - * anything. We can make it smarter later on - */ - if (ble_ll_sched_is_overlap(sch, entry)) { - break; - } - } - - if (!entry) { - rc = 0; - TAILQ_INSERT_TAIL(&g_ble_ll_sched_q, sch, link); - sch->enqueued = 1; - } - -done: - - if (rc == 0) { - sch->cb_arg = ble_ll_scan_aux_data_ref(aux_scan); - STATS_INC(ble_ll_stats, aux_scheduled); - } - - /* Get head of list to restart timer */ - entry = TAILQ_FIRST(&g_ble_ll_sched_q); - if (entry == sch) { - ble_ll_rfmgmt_sched_changed(sch); - } else { - sch = entry; - } + rc = ble_ll_sched_insert(sch, 0, preempt_none); OS_EXIT_CRITICAL(sr); - /* Restart timer */ - BLE_LL_ASSERT(sch != NULL); - os_cputime_timer_start(&g_ble_ll_sched_timer, sch->start_time); + ble_ll_sched_restart(); return rc; } @@ -1719,57 +1136,18 @@ ble_ll_sched_aux_scan(struct ble_mbuf_hdr *ble_hdr, #if MYNEWT_VAL(BLE_LL_DTM) int ble_ll_sched_dtm(struct ble_ll_sched_item *sch) { - int rc; os_sr_t sr; - struct ble_ll_sched_item *entry; + int rc; OS_ENTER_CRITICAL(sr); - if (!ble_ll_sched_insert_if_empty(sch)) { - /* Nothing in schedule. Schedule as soon as possible - * If we are here it means sch has been added to the scheduler */ - rc = 0; - goto done; - } - - /* Try to find slot for test. */ - os_cputime_timer_stop(&g_ble_ll_sched_timer); - TAILQ_FOREACH(entry, &g_ble_ll_sched_q, link) { - /* We can insert if before entry in list */ - if (sch->end_time <= entry->start_time) { - rc = 0; - TAILQ_INSERT_BEFORE(entry, sch, link); - sch->enqueued = 1; - break; - } - - /* Check for overlapping events. For now drop if it overlaps with - * anything. We can make it smarter later on - */ - if (ble_ll_sched_is_overlap(sch, entry)) { - OS_EXIT_CRITICAL(sr); - return -1; - } - } - - if (!entry) { - rc = 0; - TAILQ_INSERT_TAIL(&g_ble_ll_sched_q, sch, link); - sch->enqueued = 1; - } - -done: - - /* Get head of list to restart timer */ - sch = TAILQ_FIRST(&g_ble_ll_sched_q); - - ble_ll_rfmgmt_sched_changed(sch); + rc = ble_ll_sched_insert(sch, 0, preempt_any); OS_EXIT_CRITICAL(sr); - /* Restart timer */ - BLE_LL_ASSERT(sch != NULL); - os_cputime_timer_start(&g_ble_ll_sched_timer, sch->start_time); + if (rc == 0) { + ble_ll_sched_restart(); + } return rc; } @@ -1782,7 +1160,7 @@ int ble_ll_sched_dtm(struct ble_ll_sched_item *sch) void ble_ll_sched_stop(void) { - os_cputime_timer_stop(&g_ble_ll_sched_timer); + ble_ll_tmr_stop(&g_ble_ll_sched_timer); } /** @@ -1794,7 +1172,7 @@ ble_ll_sched_stop(void) int ble_ll_sched_init(void) { - BLE_LL_DEBUG_GPIO_INIT(SCHED_ITEM_CB); + BLE_LL_DEBUG_GPIO_INIT(SCHED_ITEM); BLE_LL_DEBUG_GPIO_INIT(SCHED_RUN); /* @@ -1810,19 +1188,107 @@ ble_ll_sched_init(void) * This is the offset from the start of the scheduled item until the actual * tx/rx should occur, in ticks. We also "round up" to the nearest tick. */ - g_ble_ll_sched_offset_ticks = - (uint8_t) os_cputime_usecs_to_ticks(XCVR_TX_SCHED_DELAY_USECS + 30); + g_ble_ll_sched_offset_ticks = ble_ll_tmr_u2t_up(XCVR_TX_SCHED_DELAY_USECS); /* Initialize cputimer for the scheduler */ - os_cputime_timer_init(&g_ble_ll_sched_timer, ble_ll_sched_run, NULL); - -#if MYNEWT_VAL(BLE_LL_STRICT_CONN_SCHEDULING) - memset(&g_ble_ll_sched_data, 0, sizeof(struct ble_ll_sched_obj)); - g_ble_ll_sched_data.sch_ticks_per_period = - os_cputime_usecs_to_ticks(MYNEWT_VAL(BLE_LL_USECS_PER_PERIOD)); - g_ble_ll_sched_data.sch_ticks_per_epoch = BLE_LL_SCHED_PERIODS * - g_ble_ll_sched_data.sch_ticks_per_period; + ble_ll_tmr_init(&g_ble_ll_sched_timer, ble_ll_sched_run, NULL); + + g_ble_ll_sched_q_head_changed = 0; + +#if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) + memset(&g_ble_ll_sched_css, 0, sizeof (g_ble_ll_sched_css)); +#if !MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED_FIXED) + g_ble_ll_sched_css.slot_us = MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED_SLOT_US); + g_ble_ll_sched_css.period_slots = MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED_PERIOD_SLOTS); +#endif +#if !MYNEWT_VAL(BLE_LL_HCI_VS_CONN_STRICT_SCHED) + g_ble_ll_sched_css.enabled = 1; +#endif #endif return 0; } + +#if MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED) +#if !MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED_FIXED) +void +ble_ll_sched_css_set_params(uint32_t slot_us, uint32_t period_slots) +{ + g_ble_ll_sched_css.slot_us = slot_us; + g_ble_ll_sched_css.period_slots = period_slots; +} +#endif + +void +ble_ll_sched_css_set_enabled(uint8_t enabled) +{ + g_ble_ll_sched_css.enabled = enabled; +} + +void +ble_ll_sched_css_update_anchor(struct ble_ll_conn_sm *connsm) +{ + struct ble_ll_sched_css *css = &g_ble_ll_sched_css; + + if (!g_ble_ll_conn_css_ref) { + g_ble_ll_conn_css_ref = connsm; + css->period_anchor_ticks = connsm->anchor_point; + css->period_anchor_rem_us = connsm->anchor_point_usecs; + } +} + +void +ble_ll_sched_css_set_conn_anchor(struct ble_ll_conn_sm *connsm) +{ + struct ble_ll_sched_css *css = &g_ble_ll_sched_css; + int8_t period_diff; + int16_t slot_diff; + int32_t diff; + + period_diff = connsm->css_period_idx - css->period_anchor_idx; + slot_diff = connsm->css_slot_idx - css->period_anchor_slot_idx; + + diff = (period_diff * ble_ll_sched_css_get_period_slots() + slot_diff) * + ble_ll_sched_css_get_slot_us(); + + connsm->anchor_point = css->period_anchor_ticks; + connsm->anchor_point_usecs = css->period_anchor_rem_us; + + if (diff < 0) { + ble_ll_tmr_sub(&connsm->anchor_point, &connsm->anchor_point_usecs, + -diff); + } else if (diff > 0) { + ble_ll_tmr_add(&connsm->anchor_point, &connsm->anchor_point_usecs, + diff); + } +} + +#if !MYNEWT_VAL(BLE_LL_CONN_STRICT_SCHED_FIXED) +inline bool +ble_ll_sched_css_is_enabled(void) +{ + return g_ble_ll_sched_css.enabled; +} + +inline uint32_t +ble_ll_sched_css_get_slot_us(void) +{ + return g_ble_ll_sched_css.slot_us; +} + +inline uint32_t +ble_ll_sched_css_get_period_slots(void) +{ + return g_ble_ll_sched_css.period_slots; +} + +inline uint32_t +ble_ll_sched_css_get_conn_interval_us(void) +{ + return ble_ll_sched_css_get_period_slots() * + ble_ll_sched_css_get_slot_us() / + BLE_LL_CONN_ITVL_USECS; +} +#endif + +#endif diff --git a/nimble/controller/src/ble_ll_supp_cmd.c b/nimble/controller/src/ble_ll_supp_cmd.c deleted file mode 100644 index cae9eb7dd1..0000000000 --- a/nimble/controller/src/ble_ll_supp_cmd.c +++ /dev/null @@ -1,543 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#include -#include - -#include "nimble/ble.h" -#include "nimble/nimble_opt.h" -#include "nimble/hci_common.h" -#include "controller/ble_ll.h" -#include "controller/ble_ll_hci.h" - -/* Octet 0 */ -#define BLE_SUPP_CMD_DISCONNECT (1 << 5) -#define BLE_LL_SUPP_CMD_OCTET_0 (BLE_SUPP_CMD_DISCONNECT) - -/* Octet 5 */ -#define BLE_SUPP_CMD_SET_EVENT_MASK (1 << 6) -#define BLE_LL_SUPP_CMD_OCTET_5 (BLE_SUPP_CMD_SET_EVENT_MASK) - -/* Octet 10 */ -#define BLE_SUPP_CMD_RD_TX_PWR (0 << 2) -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_CTRL_TO_HOST_FLOW_CONTROL) -#define BLE_SUPP_CMD_SET_CTRL_TO_HOST_FLOW (1 << 5) -#define BLE_SUPP_CMD_HOST_BUFFER_SIZE (1 << 6) -#define BLE_SUPP_CMD_HOST_NUM_COMP_PACKETS (1 << 7) -#else -#define BLE_SUPP_CMD_SET_CTRL_TO_HOST_FLOW (0 << 5) -#define BLE_SUPP_CMD_HOST_BUFFER_SIZE (0 << 6) -#define BLE_SUPP_CMD_HOST_NUM_COMP_PACKETS (0 << 7) -#endif -#define BLE_LL_SUPP_CMD_OCTET_10 \ -( \ - BLE_SUPP_CMD_RD_TX_PWR | \ - BLE_SUPP_CMD_SET_CTRL_TO_HOST_FLOW | \ - BLE_SUPP_CMD_HOST_BUFFER_SIZE | \ - BLE_SUPP_CMD_HOST_NUM_COMP_PACKETS \ -) - -/* Octet 14 */ -#define BLE_SUPP_CMD_RD_LOC_VER (1 << 3) -#define BLE_SUPP_CMD_RD_LOC_SUPP_FEAT (1 << 5) -#define BLE_LL_SUPP_CMD_OCTET_14 \ -( \ - BLE_SUPP_CMD_RD_LOC_VER | \ - BLE_SUPP_CMD_RD_LOC_SUPP_FEAT \ -) - -/* Octet 15 */ -#define BLE_SUPP_CMD_RD_BD_ADDR (1 << 1) -#define BLE_SUPP_CMD_RD_RSSI (1 << 5) - -#define BLE_LL_SUPP_CMD_OCTET_15 \ -( \ - BLE_SUPP_CMD_RD_BD_ADDR | \ - BLE_SUPP_CMD_RD_RSSI \ -) - -/* Octet 25 */ -#define BLE_SUPP_CMD_LE_SET_EV_MASK (1 << 0) -#define BLE_SUPP_CMD_LE_RD_BUF_SIZE (1 << 1) -#define BLE_SUPP_CMD_LE_RD_LOC_FEAT (1 << 2) -#define BLE_SUPP_CMD_LE_SET_RAND_ADDR (1 << 4) -#define BLE_SUPP_CMD_LE_SET_ADV_PARAMS (1 << 5) -#define BLE_SUPP_CMD_LE_SET_ADV_TX_PWR (1 << 6) -#define BLE_SUPP_CMD_LE_SET_ADV_DATA (1 << 7) - -#define BLE_LL_SUPP_CMD_OCTET_25 \ -( \ - BLE_SUPP_CMD_LE_SET_EV_MASK | \ - BLE_SUPP_CMD_LE_RD_BUF_SIZE | \ - BLE_SUPP_CMD_LE_RD_LOC_FEAT | \ - BLE_SUPP_CMD_LE_SET_RAND_ADDR | \ - BLE_SUPP_CMD_LE_SET_ADV_PARAMS | \ - BLE_SUPP_CMD_LE_SET_ADV_TX_PWR | \ - BLE_SUPP_CMD_LE_SET_ADV_DATA \ -) - -/* Octet 26 */ -#define BLE_SUPP_CMD_LE_SET_SCAN_RSP_DATA (1 << 0) -#define BLE_SUPP_CMD_LE_SET_ADV_ENABLE (1 << 1) -#define BLE_SUPP_CMD_LE_SET_SCAN_PARAMS (1 << 2) -#define BLE_SUPP_CMD_LE_SET_SCAN_ENABLE (1 << 3) -#define BLE_SUPP_CMD_LE_CREATE_CONN (1 << 4) -#define BLE_SUPP_CMD_LE_CREATE_CONN_CANCEL (1 << 5) -#define BLE_SUPP_CMD_LE_RD_WHITELIST_SIZE (1 << 6) -#define BLE_SUPP_CMD_LE_CLR_WHITELIST (1 << 7) - -#define BLE_LL_SUPP_CMD_OCTET_26 \ -( \ - BLE_SUPP_CMD_LE_SET_SCAN_RSP_DATA | \ - BLE_SUPP_CMD_LE_SET_ADV_ENABLE | \ - BLE_SUPP_CMD_LE_SET_SCAN_PARAMS | \ - BLE_SUPP_CMD_LE_SET_SCAN_ENABLE | \ - BLE_SUPP_CMD_LE_CREATE_CONN | \ - BLE_SUPP_CMD_LE_CREATE_CONN_CANCEL | \ - BLE_SUPP_CMD_LE_RD_WHITELIST_SIZE | \ - BLE_SUPP_CMD_LE_CLR_WHITELIST \ -) - -/* Octet 27 */ -#define BLE_SUPP_CMD_LE_ADD_DEV_WHITELIST (1 << 0) -#define BLE_SUPP_CMD_LE_RMV_DEV_WHITELIST (1 << 1) -#define BLE_SUPP_CMD_LE_CONN_UPDATE (1 << 2) -#define BLE_SUPP_CMD_LE_SET_HOST_CHAN_CLASS (1 << 3) -#define BLE_SUPP_CMD_LE_RD_CHAN_MAP (1 << 4) -#define BLE_SUPP_CMD_LE_RD_REM_USED_FEAT (1 << 5) -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) -#define BLE_SUPP_CMD_LE_ENCRYPT (1 << 6) -#else -#define BLE_SUPP_CMD_LE_ENCRYPT (0 << 6) -#endif -#define BLE_SUPP_CMD_LE_RAND (1 << 7) - -#define BLE_LL_SUPP_CMD_OCTET_27 \ -( \ - BLE_SUPP_CMD_LE_ENCRYPT | \ - BLE_SUPP_CMD_LE_RAND | \ - BLE_SUPP_CMD_LE_ADD_DEV_WHITELIST | \ - BLE_SUPP_CMD_LE_RMV_DEV_WHITELIST | \ - BLE_SUPP_CMD_LE_CONN_UPDATE | \ - BLE_SUPP_CMD_LE_SET_HOST_CHAN_CLASS | \ - BLE_SUPP_CMD_LE_RD_CHAN_MAP | \ - BLE_SUPP_CMD_LE_RD_REM_USED_FEAT \ -) - -/* Octet 28 */ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) -#define BLE_SUPP_CMD_LE_START_ENCRYPT (1 << 0) -#define BLE_SUPP_CMD_LE_LTK_REQ_REPLY (1 << 1) -#define BLE_SUPP_CMD_LE_LTK_REQ_NEG_REPLY (1 << 2) -#else -#define BLE_SUPP_CMD_LE_START_ENCRYPT (0 << 0) -#define BLE_SUPP_CMD_LE_LTK_REQ_REPLY (0 << 1) -#define BLE_SUPP_CMD_LE_LTK_REQ_NEG_REPLY (0 << 2) -#endif -#define BLE_SUPP_CMD_LE_READ_SUPP_STATES (1 << 3) - -#if MYNEWT_VAL(BLE_LL_DTM) -#define BLE_SUPP_CMD_LE_RX_TEST (1 << 4) -#define BLE_SUPP_CMD_LE_TX_TEST (1 << 5) -#define BLE_SUPP_CMD_LE_TEST_END (1 << 6) - -#else -#define BLE_SUPP_CMD_LE_RX_TEST (0 << 4) -#define BLE_SUPP_CMD_LE_TX_TEST (0 << 5) -#define BLE_SUPP_CMD_LE_TEST_END (0 << 6) -#endif - -#define BLE_LL_SUPP_CMD_OCTET_28 \ -( \ - BLE_SUPP_CMD_LE_START_ENCRYPT | \ - BLE_SUPP_CMD_LE_LTK_REQ_REPLY | \ - BLE_SUPP_CMD_LE_LTK_REQ_NEG_REPLY | \ - BLE_SUPP_CMD_LE_READ_SUPP_STATES | \ - BLE_SUPP_CMD_LE_RX_TEST | \ - BLE_SUPP_CMD_LE_TX_TEST | \ - BLE_SUPP_CMD_LE_TEST_END \ -) - -/* Octet 33 */ -#define BLE_SUPP_CMD_LE_REM_CONN_PRR (1 << 4) -#define BLE_SUPP_CMD_LE_REM_CONN_PRNR (1 << 5) -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_DATA_LEN_EXT) -#define BLE_SUPP_CMD_LE_SET_DATALEN (1 << 6) -#define BLE_SUPP_CMD_LE_RD_SUGG_DATALEN (1 << 7) -#else -#define BLE_SUPP_CMD_LE_SET_DATALEN (0 << 6) -#define BLE_SUPP_CMD_LE_RD_SUGG_DATALEN (0 << 7) -#endif - -#define BLE_LL_SUPP_CMD_OCTET_33 \ -( \ - BLE_SUPP_CMD_LE_REM_CONN_PRR | \ - BLE_SUPP_CMD_LE_REM_CONN_PRNR | \ - BLE_SUPP_CMD_LE_SET_DATALEN | \ - BLE_SUPP_CMD_LE_RD_SUGG_DATALEN \ -) - -/* Octet 34 */ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_DATA_LEN_EXT) -#define BLE_SUPP_CMD_LE_WR_SUGG_DATALEN (1 << 0) -#else -#define BLE_SUPP_CMD_LE_WR_SUGG_DATALEN (0 << 0) -#endif -#define BLE_SUPP_CMD_LE_READ_LOCAL_P256_PK (0 << 1) -#define BLE_SUPP_CMD_LE_GENERATE_DH_KEY (0 << 2) -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) -#define BLE_SUPP_CMD_LE_ADD_RESOLV_LIST (1 << 3) -#define BLE_SUPP_CMD_LE_REMOVE_RESOLV_LIST (1 << 4) -#define BLE_SUPP_CMD_LE_CLEAR_RESOLV_LIST (1 << 5) -#define BLE_SUPP_CMD_LE_RD_RESOLV_SIZE (1 << 6) -#define BLE_SUPP_CMD_LE_RD_PEER_RESV_ADDR (1 << 7) -#else -#define BLE_SUPP_CMD_LE_ADD_RESOLV_LIST (0 << 3) -#define BLE_SUPP_CMD_LE_REMOVE_RESOLV_LIST (0 << 4) -#define BLE_SUPP_CMD_LE_CLEAR_RESOLV_LIST (0 << 5) -#define BLE_SUPP_CMD_LE_RD_RESOLV_SIZE (0 << 6) -#define BLE_SUPP_CMD_LE_RD_PEER_RESV_ADDR (0 << 7) -#endif - -#define BLE_LL_SUPP_CMD_OCTET_34 \ -( \ - BLE_SUPP_CMD_LE_WR_SUGG_DATALEN | \ - BLE_SUPP_CMD_LE_READ_LOCAL_P256_PK | \ - BLE_SUPP_CMD_LE_GENERATE_DH_KEY | \ - BLE_SUPP_CMD_LE_ADD_RESOLV_LIST | \ - BLE_SUPP_CMD_LE_REMOVE_RESOLV_LIST | \ - BLE_SUPP_CMD_LE_CLEAR_RESOLV_LIST | \ - BLE_SUPP_CMD_LE_RD_RESOLV_SIZE | \ - BLE_SUPP_CMD_LE_RD_PEER_RESV_ADDR \ -) - -/* Octet 35 */ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) -#define BLE_SUPP_CMD_LE_RD_LOCAL_RESV_ADDR (1 << 0) -#define BLE_SUPP_CMD_LE_SET_ADDR_RES_EN (1 << 1) -#define BLE_SUPP_CMD_LE_SET_RESV_ADDR_TMO (1 << 2) -#else -#define BLE_SUPP_CMD_LE_RD_LOCAL_RESV_ADDR (0 << 0) -#define BLE_SUPP_CMD_LE_SET_ADDR_RES_EN (0 << 1) -#define BLE_SUPP_CMD_LE_SET_RESV_ADDR_TMO (0 << 2) -#endif -#define BLE_SUPP_CMD_LE_RD_MAX_DATALEN (1 << 3) -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) -#define BLE_SUPP_CMD_LE_READ_PHY (1 << 4) -#define BLE_SUPP_CMD_LE_SET_DEFAULT_PHY (1 << 5) -#define BLE_SUPP_CMD_LE_SET_PHY (1 << 6) -#else -#define BLE_SUPP_CMD_LE_READ_PHY (0 << 4) -#define BLE_SUPP_CMD_LE_SET_DEFAULT_PHY (0 << 5) -#define BLE_SUPP_CMD_LE_SET_PHY (0 << 6) -#endif - -#if MYNEWT_VAL(BLE_LL_DTM) -#define BLE_SUPP_CMD_LE_ENHANCED_RX_TEST (1 << 7) -#else -#define BLE_SUPP_CMD_LE_ENHANCED_RX_TEST (0 << 7) -#endif - -#define BLE_LL_SUPP_CMD_OCTET_35 \ -( \ - BLE_SUPP_CMD_LE_RD_LOCAL_RESV_ADDR | \ - BLE_SUPP_CMD_LE_SET_ADDR_RES_EN | \ - BLE_SUPP_CMD_LE_SET_RESV_ADDR_TMO | \ - BLE_SUPP_CMD_LE_RD_MAX_DATALEN | \ - BLE_SUPP_CMD_LE_READ_PHY | \ - BLE_SUPP_CMD_LE_SET_DEFAULT_PHY | \ - BLE_SUPP_CMD_LE_SET_PHY | \ - BLE_SUPP_CMD_LE_ENHANCED_RX_TEST \ -) - -/* Octet 36 */ -#if MYNEWT_VAL(BLE_LL_DTM) -#define BLE_SUPP_CMD_LE_ENHANCED_TX_TEST (1 << 0) -#else -#define BLE_SUPP_CMD_LE_ENHANCED_TX_TEST (0 << 0) -#endif - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -#define BLE_SUPP_CMD_LE_SET_ADVS_RAND_ADDR (1 << 1) -#define BLE_SUPP_CMD_LE_SET_EXT_ADV_PARAM (1 << 2) -#define BLE_SUPP_CMD_LE_SET_EXT_ADV_DATA (1 << 3) -#define BLE_SUPP_CMD_LE_SET_EXT_SCAN_RSP (1 << 4) -#define BLE_SUPP_CMD_LE_SET_EXT_ADV_ENABLE (1 << 5) -#define BLE_SUPP_CMD_LE_RD_MAX_ADV_DATA_LEN (1 << 6) -#define BLE_SUPP_CMD_LE_RD_NUM_SUPP_ADVS (1 << 7) -#else -#define BLE_SUPP_CMD_LE_SET_ADVS_RAND_ADDR (0 << 1) -#define BLE_SUPP_CMD_LE_SET_EXT_ADV_PARAM (0 << 2) -#define BLE_SUPP_CMD_LE_SET_EXT_ADV_DATA (0 << 3) -#define BLE_SUPP_CMD_LE_SET_EXT_SCAN_RSP (0 << 4) -#define BLE_SUPP_CMD_LE_SET_EXT_ADV_ENABLE (0 << 5) -#define BLE_SUPP_CMD_LE_RD_MAX_ADV_DATA_LEN (0 << 6) -#define BLE_SUPP_CMD_LE_RD_NUM_SUPP_ADVS (0 << 7) -#endif - -#define BLE_LL_SUPP_CMD_OCTET_36 \ -( \ - BLE_SUPP_CMD_LE_ENHANCED_TX_TEST | \ - BLE_SUPP_CMD_LE_SET_ADVS_RAND_ADDR | \ - BLE_SUPP_CMD_LE_SET_EXT_ADV_PARAM | \ - BLE_SUPP_CMD_LE_SET_EXT_ADV_DATA | \ - BLE_SUPP_CMD_LE_SET_EXT_SCAN_RSP | \ - BLE_SUPP_CMD_LE_SET_EXT_ADV_ENABLE | \ - BLE_SUPP_CMD_LE_RD_MAX_ADV_DATA_LEN | \ - BLE_SUPP_CMD_LE_RD_NUM_SUPP_ADVS \ -) - -/* Octet 37 */ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -#define BLE_SUPP_CMD_LE_REMOVE_ADVS (1 << 0) -#define BLE_SUPP_CMD_LE_CLEAR_ADVS (1 << 1) -#else -#define BLE_SUPP_CMD_LE_REMOVE_ADVS (0 << 0) -#define BLE_SUPP_CMD_LE_CLEAR_ADVS (0 << 1) -#endif -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) -#define BLE_SUPP_CMD_LE_SET_PADV_PARAM (1 << 2) -#define BLE_SUPP_CMD_LE_SET_PADV_DATA (1 << 3) -#define BLE_SUPP_CMD_LE_SET_PADV_ENABLE (1 << 4) -#else -#define BLE_SUPP_CMD_LE_SET_PADV_PARAM (0 << 2) -#define BLE_SUPP_CMD_LE_SET_PADV_DATA (0 << 3) -#define BLE_SUPP_CMD_LE_SET_PADV_ENABLE (0 << 4) -#endif -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) -#define BLE_SUPP_CMD_LE_SET_EXT_SCAN_PARAM (1 << 5) -#define BLE_SUPP_CMD_LE_SET_EXT_SCAN_ENABLE (1 << 6) -#define BLE_SUPP_CMD_LE_EXT_CREATE_CONN (1 << 7) -#else -#define BLE_SUPP_CMD_LE_SET_EXT_SCAN_PARAM (0 << 5) -#define BLE_SUPP_CMD_LE_SET_EXT_SCAN_ENABLE (0 << 6) -#define BLE_SUPP_CMD_LE_EXT_CREATE_CONN (0 << 7) -#endif - -#define BLE_LL_SUPP_CMD_OCTET_37 \ -( \ - BLE_SUPP_CMD_LE_REMOVE_ADVS | \ - BLE_SUPP_CMD_LE_CLEAR_ADVS | \ - BLE_SUPP_CMD_LE_SET_PADV_PARAM | \ - BLE_SUPP_CMD_LE_SET_PADV_DATA | \ - BLE_SUPP_CMD_LE_SET_PADV_ENABLE | \ - BLE_SUPP_CMD_LE_SET_EXT_SCAN_PARAM | \ - BLE_SUPP_CMD_LE_SET_EXT_SCAN_ENABLE | \ - BLE_SUPP_CMD_LE_EXT_CREATE_CONN \ -) - -/* Octet 38 */ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) -#define BLE_SUPP_CMD_LE_PADV_CREATE_SYNC (1 << 0) -#define BLE_SUPP_CMD_LE_PADV_CREATE_SYNC_C (1 << 1) -#define BLE_SUPP_CMD_LE_PADV_TERMINATE_SYNC (1 << 2) -#define BLE_SUPP_CMD_LE_ADD_PADV_LIST (1 << 3) -#define BLE_SUPP_CMD_LE_REMOVE_PADV_LIST (1 << 4) -#define BLE_SUPP_CMD_LE_CLEAR_PADV_LIST (1 << 5) -#define BLE_SUPP_CMD_LE_RD_PADV_LIST_SIZE (1 << 6) -#else -#define BLE_SUPP_CMD_LE_PADV_CREATE_SYNC (0 << 0) -#define BLE_SUPP_CMD_LE_PADV_CREATE_SYNC_C (0 << 1) -#define BLE_SUPP_CMD_LE_PADV_TERMINATE_SYNC (0 << 2) -#define BLE_SUPP_CMD_LE_ADD_PADV_LIST (0 << 3) -#define BLE_SUPP_CMD_LE_REMOVE_PADV_LIST (0 << 4) -#define BLE_SUPP_CMD_LE_CLEAR_PADV_LIST (0 << 5) -#define BLE_SUPP_CMD_LE_RD_PADV_LIST_SIZE (0 << 6) -#endif -#define BLE_SUPP_CMD_LE_RD_TX_POWER (1 << 7) - -#define BLE_LL_SUPP_CMD_OCTET_38 \ -( \ - BLE_SUPP_CMD_LE_PADV_CREATE_SYNC | \ - BLE_SUPP_CMD_LE_PADV_CREATE_SYNC_C | \ - BLE_SUPP_CMD_LE_PADV_TERMINATE_SYNC | \ - BLE_SUPP_CMD_LE_ADD_PADV_LIST | \ - BLE_SUPP_CMD_LE_REMOVE_PADV_LIST | \ - BLE_SUPP_CMD_LE_CLEAR_PADV_LIST | \ - BLE_SUPP_CMD_LE_RD_PADV_LIST_SIZE | \ - BLE_SUPP_CMD_LE_RD_TX_POWER \ -) - -/* Octet 39 */ -#define BLE_SUPP_CMD_LE_RD_RF_PATH_COMP (1 << 0) -#define BLE_SUPP_CMD_LE_WR_RF_PATH_COMP (1 << 1) -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) -#define BLE_SUPP_CMD_LE_SET_PRIVACY_MODE (1 << 2) -#else -#define BLE_SUPP_CMD_LE_SET_PRIVACY_MODE (0 << 2) -#endif - -#define BLE_LL_SUPP_CMD_OCTET_39 \ -( \ - BLE_SUPP_CMD_LE_RD_RF_PATH_COMP | \ - BLE_SUPP_CMD_LE_WR_RF_PATH_COMP | \ - BLE_SUPP_CMD_LE_SET_PRIVACY_MODE \ -) - -/* Octet 40 */ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) && MYNEWT_VAL(BLE_VERSION) >= 51 -#define BLE_SUPP_CMD_LE_PADV_RECV_ENABLE (1 << 5) -#else -#define BLE_SUPP_CMD_LE_PADV_RECV_ENABLE (0 << 5) -#endif -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER) -#define BLE_SUPP_CMD_LE_PADV_SYNC_TRANSFER (1 << 6) -#define BLE_SUPP_CMD_LE_PADV_SET_INFO_TRANSFER (1 << 7) -#else -#define BLE_SUPP_CMD_LE_PADV_SYNC_TRANSFER (0 << 6) -#define BLE_SUPP_CMD_LE_PADV_SET_INFO_TRANSFER (0 << 7) -#endif - -#define BLE_LL_SUPP_CMD_OCTET_40 \ -( \ - BLE_SUPP_CMD_LE_PADV_RECV_ENABLE | \ - BLE_SUPP_CMD_LE_PADV_SYNC_TRANSFER | \ - BLE_SUPP_CMD_LE_PADV_SET_INFO_TRANSFER \ -) - -/* Octet 41 */ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER) -#define BLE_SUPP_CMD_LE_PADV_SYNC_TRANSFER_PARAMS (1 << 0) -#define BLE_SUPP_CMD_LE_PADV_DEFAULT_SYNC_TRANSFER_PARAMS (1 << 1) -#else -#define BLE_SUPP_CMD_LE_PADV_SYNC_TRANSFER_PARAMS (0 << 0) -#define BLE_SUPP_CMD_LE_PADV_DEFAULT_SYNC_TRANSFER_PARAMS (0 << 1) -#endif -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ISO) -#define BLE_SUPP_CMD_LE_READ_BUF_SIZE_V2 (1 << 5) -#define BLE_SUPP_CMD_LE_READ_ISO_TX_SYNC (1 << 6) -#define BLE_SUPP_CMD_LE_SET_CIG_PARAM (1 << 7) -#else -#define BLE_SUPP_CMD_LE_READ_BUF_SIZE_V2 (0 << 5) -#define BLE_SUPP_CMD_LE_READ_ISO_TX_SYNC (0 << 6) -#define BLE_SUPP_CMD_LE_SET_CIG_PARAM (0 << 7) -#endif - -#define BLE_LL_SUPP_CMD_OCTET_41 \ -( \ - BLE_SUPP_CMD_LE_PADV_SYNC_TRANSFER_PARAMS | \ - BLE_SUPP_CMD_LE_PADV_DEFAULT_SYNC_TRANSFER_PARAMS | \ - BLE_SUPP_CMD_LE_READ_BUF_SIZE_V2 | \ - BLE_SUPP_CMD_LE_READ_ISO_TX_SYNC | \ - BLE_SUPP_CMD_LE_SET_CIG_PARAM \ -) - -/* Octet 42 */ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ISO) -#define BLE_SUPP_CMD_LE_SET_CIG_PARAM_TEST (1 << 0) -#define BLE_SUPP_CMD_LE_CREATE_CIS (1 << 1) -#define BLE_SUPP_CMD_LE_REMOVE_CIG (1 << 2) -#define BLE_SUPP_CMD_LE_ACCEPT_CIS_REQ (1 << 3) -#define BLE_SUPP_CMD_LE_REJECT_CIS_REQ (1 << 4) -#define BLE_SUPP_CMD_LE_CREATE_BIG (1 << 5) -#define BLE_SUPP_CMD_LE_CREATE_BIG_TEST (1 << 6) -#define BLE_SUPP_CMD_LE_TERMINATE_BIG (1 << 7) -#else -#define BLE_SUPP_CMD_LE_SET_CIG_PARAM_TEST (0 << 0) -#define BLE_SUPP_CMD_LE_CREATE_CIS (0 << 1) -#define BLE_SUPP_CMD_LE_REMOVE_CIG (0 << 2) -#define BLE_SUPP_CMD_LE_ACCEPT_CIS_REQ (0 << 3) -#define BLE_SUPP_CMD_LE_REJECT_CIS_REQ (0 << 4) -#define BLE_SUPP_CMD_LE_CREATE_BIG (0 << 5) -#define BLE_SUPP_CMD_LE_CREATE_BIG_TEST (0 << 6) -#define BLE_SUPP_CMD_LE_TERMINATE_BIG (0 << 7) -#endif -#define BLE_LL_SUPP_CMD_OCTET_42 \ -( \ - BLE_SUPP_CMD_LE_SET_CIG_PARAM_TEST | \ - BLE_SUPP_CMD_LE_CREATE_CIS | \ - BLE_SUPP_CMD_LE_REMOVE_CIG | \ - BLE_SUPP_CMD_LE_ACCEPT_CIS_REQ | \ - BLE_SUPP_CMD_LE_REJECT_CIS_REQ | \ - BLE_SUPP_CMD_LE_CREATE_BIG | \ - BLE_SUPP_CMD_LE_CREATE_BIG_TEST | \ - BLE_SUPP_CMD_LE_TERMINATE_BIG \ -) - -/* Octet 43 */ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_SCA_UPDATE) -#define BLE_SUPP_CMD_LE_REQUEST_PEER_SCA (1 << 2) -#else -#define BLE_SUPP_CMD_LE_REQUEST_PEER_SCA (0 << 0) -#endif -#define BLE_LL_SUPP_CMD_OCTET_43 \ -( \ - BLE_SUPP_CMD_LE_REQUEST_PEER_SCA \ -) - -/* Octet 44 */ -#if MYNEWT_VAL(BLE_VERSION) >= 52 -#define BLE_SUPP_CMD_LE_SET_HOST_FEATURE (1 << 0) -#else -#define BLE_SUPP_CMD_LE_SET_HOST_FEATURE (0 << 0) -#endif -#define BLE_LL_SUPP_CMD_OCTET_44 \ -( \ - BLE_SUPP_CMD_LE_SET_HOST_FEATURE \ -) - -/* Defines the array of supported commands */ -const uint8_t g_ble_ll_supp_cmds[BLE_LL_SUPP_CMD_LEN] = -{ - BLE_LL_SUPP_CMD_OCTET_0, /* Octet 0 */ - 0, - 0, - 0, - 0, - BLE_LL_SUPP_CMD_OCTET_5, - 0, - 0, - 0, /* Octet 8 */ - 0, - BLE_LL_SUPP_CMD_OCTET_10, - 0, - 0, - 0, - BLE_LL_SUPP_CMD_OCTET_14, - BLE_LL_SUPP_CMD_OCTET_15, - 0, /* Octet 16 */ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, /* Octet 24 */ - BLE_LL_SUPP_CMD_OCTET_25, - BLE_LL_SUPP_CMD_OCTET_26, - BLE_LL_SUPP_CMD_OCTET_27, - BLE_LL_SUPP_CMD_OCTET_28, - 0, - 0, - 0, - 0, /* Octet 32 */ - BLE_LL_SUPP_CMD_OCTET_33, - BLE_LL_SUPP_CMD_OCTET_34, - BLE_LL_SUPP_CMD_OCTET_35, - BLE_LL_SUPP_CMD_OCTET_36, - BLE_LL_SUPP_CMD_OCTET_37, - BLE_LL_SUPP_CMD_OCTET_38, - BLE_LL_SUPP_CMD_OCTET_39, - BLE_LL_SUPP_CMD_OCTET_40, /* Octet 40 */ - BLE_LL_SUPP_CMD_OCTET_41, - BLE_LL_SUPP_CMD_OCTET_42, - BLE_LL_SUPP_CMD_OCTET_43, - BLE_LL_SUPP_CMD_OCTET_44, -}; diff --git a/nimble/controller/src/ble_ll_sync.c b/nimble/controller/src/ble_ll_sync.c index 7c46d10a29..f1a709fb9e 100644 --- a/nimble/controller/src/ble_ll_sync.c +++ b/nimble/controller/src/ble_ll_sync.c @@ -20,10 +20,12 @@ #include #include #include +#include #include "syscfg/syscfg.h" #include "controller/ble_ll.h" +#include "controller/ble_ll_pdu.h" #include "controller/ble_ll_hci.h" #include "controller/ble_ll_sync.h" #include "controller/ble_ll_utils.h" @@ -32,16 +34,16 @@ #include "controller/ble_ll_scan.h" #include "controller/ble_ll_resolv.h" #include "controller/ble_ll_rfmgmt.h" +#include "controller/ble_ll_tmr.h" #include "nimble/ble.h" #include "nimble/hci_common.h" -#include "nimble/ble_hci_trans.h" #include "ble_ll_conn_priv.h" #include "stats/stats.h" -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV) && MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) /* defines number of events that can be lost during sync establishment * before failed to be established error is reported @@ -61,10 +63,14 @@ #define BLE_LL_SYNC_SM_FLAG_ADDR_RESOLVED 0x0080 #define BLE_LL_SYNC_SM_FLAG_HCI_TRUNCATED 0x0100 #define BLE_LL_SYNC_SM_FLAG_NEW_CHANMAP 0x0200 +#define BLE_LL_SYNC_SM_FLAG_CHAIN 0x0400 +#define BLE_LL_SYNC_SM_FLAG_DUPLICATES 0x0800 -#define BLE_LL_SYNC_CHMAP_LEN 5 #define BLE_LL_SYNC_ITVL_USECS 1250 +#define BLE_LL_SYNC_BIGINFO_LEN 33 +#define BLE_LL_SYNC_BIGINFO_LEN_ENC 57 + struct ble_ll_sync_sm { uint16_t flags; @@ -73,11 +79,11 @@ struct ble_ll_sync_sm { uint8_t adv_addr_type; uint8_t sca; - uint8_t chanmap[BLE_LL_SYNC_CHMAP_LEN]; - uint8_t num_used_chans; + uint8_t chan_map[BLE_LL_CHAN_MAP_LEN]; + uint8_t chan_map_used; - uint8_t chanmap_new[BLE_LL_SYNC_CHMAP_LEN]; - uint16_t chanmap_new_instant; + uint8_t chan_map_new[BLE_LL_CHAN_MAP_LEN]; + uint16_t chan_map_new_instant; uint8_t chan_index; uint8_t chan_chain; @@ -116,6 +122,10 @@ struct ble_ll_sync_sm { uint16_t event_cntr_last_received; uint8_t adv_addr_rpa[6]; #endif + +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_ADI_SUPPORT) + uint16_t prev_adi; +#endif }; static struct ble_ll_sync_sm g_ble_ll_sync_sm[BLE_LL_SYNC_CNT]; @@ -137,10 +147,12 @@ static uint8_t *g_ble_ll_sync_create_comp_ev; static struct ble_ll_sync_sm *g_ble_ll_sync_sm_current; +static int ble_ll_sync_event_start_cb(struct ble_ll_sched_item *sch); + static int ble_ll_sync_on_list(const uint8_t *addr, uint8_t addr_type, uint8_t sid) { - int i; + unsigned int i; for (i = 0; i < ARRAY_SIZE(g_ble_ll_sync_adv_list); i++) { if ((g_ble_ll_sync_adv_list[i].adv_sid == sid) && @@ -156,7 +168,7 @@ ble_ll_sync_on_list(const uint8_t *addr, uint8_t addr_type, uint8_t sid) static int ble_ll_sync_list_get_free(void) { - int i; + unsigned int i; for (i = 0; i < ARRAY_SIZE(g_ble_ll_sync_adv_list); i++) { if (g_ble_ll_sync_adv_list[i].adv_sid == 0xff) { @@ -169,7 +181,7 @@ ble_ll_sync_list_get_free(void) static bool ble_ll_sync_list_empty(void) { - int i; + unsigned int i; for (i = 0; i < ARRAY_SIZE(g_ble_ll_sync_adv_list); i++) { if (g_ble_ll_sync_adv_list[i].adv_sid != 0xff) { @@ -193,11 +205,11 @@ ble_ll_sync_sm_clear(struct ble_ll_sync_sm *sm) if (sm->flags & (BLE_LL_SYNC_SM_FLAG_ESTABLISHING | BLE_LL_SYNC_SM_FLAG_ESTABLISHED)) { ble_ll_sched_rmv_elem(&sm->sch); - ble_npl_eventq_remove(&g_ble_ll_data.ll_evq, &sm->sync_ev_end); + ble_ll_event_remove(&sm->sync_ev_end); } if (sm->next_report) { - ble_hci_trans_buf_free(sm->next_report); + ble_transport_free(sm->next_report); } if (g_ble_ll_sync_sm_current == sm) { @@ -208,16 +220,20 @@ ble_ll_sync_sm_clear(struct ble_ll_sync_sm *sm) } ble_ll_rfmgmt_release(); - - BLE_LL_ASSERT(sm->sync_ev_end.ev.ev_queued == 0); + BLE_LL_ASSERT(ble_npl_event_is_queued(&sm->sync_ev_end) == 0); BLE_LL_ASSERT(sm->sch.enqueued == 0); + memset(sm, 0, sizeof(*sm)); + + sm->sch.sched_cb = ble_ll_sync_event_start_cb; + sm->sch.cb_arg = sm; + sm->sch.sched_type = BLE_LL_SCHED_TYPE_SYNC; } static uint8_t ble_ll_sync_phy_mode_to_hci(int8_t phy_mode) { -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) +#if MYNEWT_VAL(BLE_LL_PHY) switch (phy_mode) { case BLE_PHY_MODE_1M: return BLE_HCI_LE_PHY_1M; @@ -324,7 +340,7 @@ ble_ll_sync_transfer_received(struct ble_ll_sync_sm *sm, uint8_t status) ble_ll_hci_event_send(hci_ev); } else { - ble_hci_trans_buf_free(sm->transfer_received_ev); + ble_transport_free(sm->transfer_received_ev); } sm->transfer_received_ev = NULL; @@ -362,7 +378,7 @@ ble_ll_sync_est_event_success(struct ble_ll_sync_sm *sm) ble_ll_hci_event_send(hci_ev); } else { - ble_hci_trans_buf_free(g_ble_ll_sync_create_comp_ev); + ble_transport_free(g_ble_ll_sync_create_comp_ev); } g_ble_ll_sync_create_comp_ev = NULL; @@ -390,7 +406,7 @@ ble_ll_sync_est_event_failed(uint8_t status) ble_ll_hci_event_send(hci_ev); } else { - ble_hci_trans_buf_free(g_ble_ll_sync_create_comp_ev); + ble_transport_free(g_ble_ll_sync_create_comp_ev); } g_ble_ll_sync_create_comp_ev = NULL; @@ -403,7 +419,7 @@ ble_ll_sync_lost_event(struct ble_ll_sync_sm *sm) struct ble_hci_ev *hci_ev; if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_PERIODIC_ADV_SYNC_LOST)) { - hci_ev = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); + hci_ev = ble_transport_alloc_evt(0); if (hci_ev) { hci_ev->opcode = BLE_HCI_EVCODE_LE_META; hci_ev->length = sizeof(*ev); @@ -436,6 +452,7 @@ ble_ll_sync_event_start_cb(struct ble_ll_sched_item *sch) struct ble_ll_sync_sm *sm; uint32_t wfr_usecs; uint32_t start; + uint8_t chan; int rc; /* Set current connection state machine */ @@ -451,7 +468,9 @@ ble_ll_sync_event_start_cb(struct ble_ll_sched_item *sch) ble_ll_state_set(BLE_LL_STATE_SYNC); /* Set channel */ - ble_phy_setchan(sm->chan_index, sm->access_addr, sm->crcinit); + chan = sm->flags & BLE_LL_SYNC_SM_FLAG_CHAIN ? sm->chan_chain : + sm->chan_index; + ble_phy_setchan(chan, sm->access_addr, sm->crcinit); #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) ble_phy_resolv_list_disable(); @@ -461,7 +480,7 @@ ble_ll_sync_event_start_cb(struct ble_ll_sched_item *sch) ble_phy_encrypt_disable(); #endif -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) +#if MYNEWT_VAL(BLE_LL_PHY) ble_phy_mode_set(sm->phy_mode, sm->phy_mode); #endif @@ -469,31 +488,35 @@ ble_ll_sync_event_start_cb(struct ble_ll_sched_item *sch) rc = ble_phy_rx_set_start_time(start, sch->remainder); if (rc && rc != BLE_PHY_ERR_RX_LATE) { STATS_INC(ble_ll_stats, sync_event_failed); - rc = BLE_LL_SCHED_STATE_DONE; - ble_ll_event_send(&sm->sync_ev_end); + ble_ll_event_add(&sm->sync_ev_end); ble_ll_sync_current_sm_over(); + rc = BLE_LL_SCHED_STATE_DONE; } else { - /* - * Set flag that tells to set last anchor point if a packet - * has been received. - */ - sm->flags |= BLE_LL_SYNC_SM_FLAG_SET_ANCHOR; - - /* Set WFR timer. - * If establishing we always adjust with offset unit. - * If this is first packet of sync (one that was pointed by from - * SyncInfo we don't adjust WFT with window widening. - */ - if (sm->flags & BLE_LL_SYNC_SM_FLAG_ESTABLISHING) { + if (sm->flags & BLE_LL_SYNC_SM_FLAG_CHAIN) { wfr_usecs = (sm->flags & BLE_LL_SYNC_SM_FLAG_OFFSET_300) ? 300 : 30; - if (!(sm->flags & BLE_LL_SYNC_SM_FLAG_SYNC_INFO)) { - wfr_usecs += 2 * sm->window_widening; - } } else { - wfr_usecs = 2 * sm->window_widening; + /* Set flag that tells to set last anchor point if a packet + * has been received. + */ + sm->flags |= BLE_LL_SYNC_SM_FLAG_SET_ANCHOR; + + /* Set WFR timer. + * If establishing we always adjust with offset unit. + * If this is first packet of sync (one that was pointed by from + * SyncInfo we don't adjust WFR with window widening. + */ + if (sm->flags & BLE_LL_SYNC_SM_FLAG_ESTABLISHING) { + wfr_usecs = (sm->flags & BLE_LL_SYNC_SM_FLAG_OFFSET_300) ? 300 + : 30; + if (!(sm->flags & BLE_LL_SYNC_SM_FLAG_SYNC_INFO)) { + wfr_usecs += 2 * sm->window_widening; + } + } else { + wfr_usecs = 2 * sm->window_widening; + } } - ble_phy_wfr_enable(BLE_PHY_WFR_ENABLE_RX, 0, wfr_usecs); + ble_phy_wfr_enable(BLE_PHY_WFR_ENABLE_RX, 0, wfr_usecs); rc = BLE_LL_SCHED_STATE_RUNNING; } @@ -518,7 +541,7 @@ ble_ll_sync_rx_isr_start(uint8_t pdu_type, struct ble_mbuf_hdr *rxhdr) /* this also handles chains as those have same PDU type */ if (pdu_type != BLE_ADV_PDU_TYPE_AUX_SYNC_IND) { - ble_ll_event_send(&g_ble_ll_sync_sm_current->sync_ev_end); + ble_ll_event_add(&g_ble_ll_sync_sm_current->sync_ev_end); ble_ll_sync_current_sm_over(); STATS_INC(ble_ll_stats, sched_invalid_pdu); return -1; @@ -530,7 +553,7 @@ ble_ll_sync_rx_isr_start(uint8_t pdu_type, struct ble_mbuf_hdr *rxhdr) static int ble_ll_sync_parse_ext_hdr(struct os_mbuf *om, uint8_t **aux, int8_t *tx_power, - uint8_t **acad, uint8_t *acad_len) + uint8_t **acad, uint8_t *acad_len, uint16_t **adi) { uint8_t *rxbuf = om->om_data; uint8_t ext_hdr_flags; @@ -566,11 +589,13 @@ ble_ll_sync_parse_ext_hdr(struct os_mbuf *om, uint8_t **aux, int8_t *tx_power, /* Ignore CTE for now */ if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_CTE_INFO_BIT)) { - i += 1; + i += BLE_LL_EXT_ADV_CTE_INFO_SIZE; } - /* there should be no ADI in Sync or chain, skip it */ if (ext_hdr_flags & (1 << BLE_LL_EXT_ADV_DATA_INFO_BIT)) { + if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_ADI_SUPPORT) { + *adi = (uint16_t *) ext_hdr + i; + } i += BLE_LL_EXT_ADV_DATA_INFO_SIZE; } @@ -626,7 +651,7 @@ ble_ll_sync_send_truncated_per_adv_rpt(struct ble_ll_sync_sm *sm, uint8_t *evbuf if (!ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_PERIODIC_ADV_RPT) || (sm->flags & BLE_LL_SYNC_SM_FLAG_DISABLED)) { - ble_hci_trans_buf_free(evbuf); + ble_transport_free(evbuf); return; } @@ -647,6 +672,70 @@ ble_ll_sync_send_truncated_per_adv_rpt(struct ble_ll_sync_sm *sm, uint8_t *evbuf ble_ll_hci_event_send(hci_ev); } +#if MYNEWT_VAL(BLE_LL_PERIODIC_ADV_SYNC_BIGINFO_REPORTS) +static void +ble_ll_sync_parse_biginfo_to_ev(struct ble_hci_ev_le_subev_biginfo_adv_report *ev, + const uint8_t *biginfo, uint8_t biginfo_len) +{ + uint32_t fields_buf; + + fields_buf = get_le32(&biginfo[0]); + ev->iso_interval = (fields_buf >> 15) & 0x0FFF; + ev->bis_cnt = (fields_buf >> 27) & 0x1F; + + fields_buf = get_le32(&biginfo[4]); + ev->nse = fields_buf & 0x1F; + ev->bn = (fields_buf >> 5) & 0x07; + ev->pto = (fields_buf >> 28) & 0x0F; + + fields_buf = get_le32(&biginfo[8]); + ev->irc = (fields_buf >> 20) & 0x0F; + ev->max_pdu = (fields_buf >> 24) & 0xFF; + + fields_buf = get_le32(&biginfo[17]); + ev->sdu_interval[0] = fields_buf & 0xFF; + ev->sdu_interval[1] = (fields_buf >> 8) & 0xFF; + ev->sdu_interval[2] = (fields_buf >> 16) & 0x0F; + ev->max_sdu = (fields_buf >> 20) & 0x0FFF; + + ev->phy = (biginfo[27] >> 5) & 0x07; + + ev->framing = (biginfo[32] >> 7) & 0x01; + + if (biginfo_len == BLE_LL_SYNC_BIGINFO_LEN_ENC) { + ev->encryption = 1; + } else { + ev->encryption = 0; + } +} + +static void +ble_ll_sync_send_biginfo_adv_rpt(struct ble_ll_sync_sm *sm, const uint8_t *biginfo, uint8_t biginfo_len) +{ + struct ble_hci_ev_le_subev_biginfo_adv_report *ev; + struct ble_hci_ev *hci_ev; + + if (!ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_BIGINFO_ADV_REPORT)) { + return; + } + + hci_ev = ble_transport_alloc_evt(1); + if (!hci_ev) { + return; + } + + hci_ev->opcode = BLE_HCI_EVCODE_LE_META; + hci_ev->length = sizeof(*ev); + ev = (void *) hci_ev->data; + + ev->subev_code = BLE_HCI_LE_SUBEV_BIGINFO_ADV_REPORT; + ev->sync_handle = htole16(ble_ll_sync_get_handle(sm)); + ble_ll_sync_parse_biginfo_to_ev(ev, biginfo, biginfo_len); + + ble_ll_hci_event_send(hci_ev); +} +#endif + static void ble_ll_sync_send_per_adv_rpt(struct ble_ll_sync_sm *sm, struct os_mbuf *rxpdu, int8_t rssi, int8_t tx_power, int datalen, @@ -663,7 +752,7 @@ ble_ll_sync_send_per_adv_rpt(struct ble_ll_sync_sm *sm, struct os_mbuf *rxpdu, hci_ev = (void *) sm->next_report; sm->next_report = NULL; } else { - hci_ev = (void * )ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_LO); + hci_ev = ble_transport_alloc_evt(1); if (!hci_ev) { goto done; } @@ -689,7 +778,7 @@ ble_ll_sync_send_per_adv_rpt(struct ble_ll_sync_sm *sm, struct os_mbuf *rxpdu, ev->rssi = rssi; ev->cte_type = 0xff; - ev->data_len = min(max_data_len, datalen - offset); + ev->data_len = MIN(max_data_len, datalen - offset); /* adjust event length */ hci_ev->length += ev->data_len; @@ -698,7 +787,7 @@ ble_ll_sync_send_per_adv_rpt(struct ble_ll_sync_sm *sm, struct os_mbuf *rxpdu, /* Need another event for next fragment of this PDU */ if (offset < datalen) { - hci_ev_next = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_LO); + hci_ev_next = ble_transport_alloc_evt(1); if (hci_ev_next) { ev->data_status = BLE_HCI_PERIODIC_DATA_STATUS_INCOMPLETE; } else { @@ -709,7 +798,7 @@ ble_ll_sync_send_per_adv_rpt(struct ble_ll_sync_sm *sm, struct os_mbuf *rxpdu, if (aux) { if (aux_scheduled) { /* if we scheduled aux, we need buffer for next report */ - hci_ev_next = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_LO); + hci_ev_next = ble_transport_alloc_evt(1); if (hci_ev_next) { ev->data_status = BLE_HCI_PERIODIC_DATA_STATUS_INCOMPLETE; } else { @@ -770,7 +859,7 @@ ble_ll_sync_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr) ble_ll_rx_pdu_in(rxpdu); } else { STATS_INC(ble_ll_stats, sync_rx_buf_err); - ble_ll_event_send(&g_ble_ll_sync_sm_current->sync_ev_end); + ble_ll_event_add(&g_ble_ll_sync_sm_current->sync_ev_end); } /* PHY is disabled here */ @@ -793,7 +882,7 @@ ble_ll_sync_wfr_timer_exp(void) STATS_INC(ble_ll_stats, sync_missed_err); ble_ll_sync_current_sm_over(); - ble_ll_event_send(&sm->sync_ev_end); + ble_ll_event_add(&sm->sync_ev_end); } /** @@ -810,7 +899,7 @@ ble_ll_sync_halt(void) ble_ll_sync_current_sm_over(); if (sm) { - ble_ll_event_send(&sm->sync_ev_end); + ble_ll_event_add(&sm->sync_ev_end); } } @@ -822,7 +911,7 @@ ble_ll_sync_get_event_end_time(void) if (g_ble_ll_sync_sm_current) { end_time = g_ble_ll_sync_sm_current->sch.end_time; } else { - end_time = os_cputime_get32(); + end_time = ble_ll_tmr_get(); } return end_time; } @@ -848,7 +937,7 @@ static void ble_ll_sync_parse_aux_ptr(const uint8_t *buf, uint8_t *chan, uint32_t *offset, uint8_t *offset_units, uint8_t *phy) { - uint32_t aux_ptr_field = get_le32(buf) & 0x00FFFFFF; + uint32_t aux_ptr_field = get_le24(buf); *chan = aux_ptr_field & 0x3F; @@ -865,61 +954,24 @@ ble_ll_sync_parse_aux_ptr(const uint8_t *buf, uint8_t *chan, uint32_t *offset, *phy = (aux_ptr_field >> 21) & 0x07; } -static int -ble_ll_sync_chain_start_cb(struct ble_ll_sched_item *sch) +static void +ble_ll_sync_sched_set(struct ble_ll_sched_item *sch, uint32_t start_ticks, + uint8_t start_rem_us, uint32_t offset, uint8_t phy_mode) { - struct ble_ll_sync_sm *sm; - uint32_t wfr_usecs; - uint32_t start; - int rc; - - /* Set current connection state machine */ - sm = sch->cb_arg; - g_ble_ll_sync_sm_current = sm; - BLE_LL_ASSERT(sm); - - /* Disable whitelisting */ - ble_ll_whitelist_disable(); - - /* Set LL state */ - ble_ll_state_set(BLE_LL_STATE_SYNC); - - /* Set channel */ - ble_phy_setchan(sm->chan_chain, sm->access_addr, sm->crcinit); + uint32_t duration_us; + uint32_t duration; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - ble_phy_resolv_list_disable(); -#endif - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - ble_phy_encrypt_disable(); -#endif - -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) - ble_phy_mode_set(sm->phy_mode, sm->phy_mode); -#endif - - start = sch->start_time + g_ble_ll_sched_offset_ticks; - rc = ble_phy_rx_set_start_time(start, sch->remainder); - if (rc && rc != BLE_PHY_ERR_RX_LATE) { - STATS_INC(ble_ll_stats, sync_chain_failed); - rc = BLE_LL_SCHED_STATE_DONE; - ble_ll_event_send(&sm->sync_ev_end); - ble_ll_sync_current_sm_over(); - } else { - /* - * Clear flag that tells to set last anchor point if a packet - * has been received, this is chain and we don't need it. - */ - sm->flags &= ~BLE_LL_SYNC_SM_FLAG_SET_ANCHOR; - - wfr_usecs = (sm->flags & BLE_LL_SYNC_SM_FLAG_OFFSET_300) ? 300 : 30; - - ble_phy_wfr_enable(BLE_PHY_WFR_ENABLE_RX, 0, wfr_usecs); - rc = BLE_LL_SCHED_STATE_RUNNING; + if (offset > 0) { + ble_ll_tmr_add(&start_ticks, &start_rem_us, offset); } - return rc; + duration_us = ble_ll_pdu_us(MYNEWT_VAL(BLE_LL_SCHED_SCAN_SYNC_PDU_LEN), + phy_mode); + duration = ble_ll_tmr_u2t(duration_us); + + sch->start_time = start_ticks - g_ble_ll_sched_offset_ticks; + sch->remainder = start_rem_us; + sch->end_time = start_ticks + duration; } static int @@ -941,7 +993,7 @@ ble_ll_sync_schedule_chain(struct ble_ll_sync_sm *sm, struct ble_mbuf_hdr *hdr, return -1; } - /* chain should use same PHY as master PDU */ + /* chain should use same PHY as central PDU */ if (phy != ble_ll_sync_phy_mode_to_aux_phy(sm->phy_mode)) { return -1; } @@ -954,12 +1006,12 @@ ble_ll_sync_schedule_chain(struct ble_ll_sync_sm *sm, struct ble_mbuf_hdr *hdr, sm->chan_chain = chan; - sm->sch.sched_cb = ble_ll_sync_chain_start_cb; - sm->sch.cb_arg = sm; - sm->sch.sched_type = BLE_LL_SCHED_TYPE_SYNC; + sm->flags |= BLE_LL_SYNC_SM_FLAG_CHAIN; + + ble_ll_sync_sched_set(&sm->sch, hdr->beg_cputime, hdr->rem_usecs, offset, + sm->phy_mode); - return ble_ll_sched_sync(&sm->sch, hdr->beg_cputime, hdr->rem_usecs, - offset, sm->phy_mode); + return ble_ll_sched_sync(&sm->sch); } static void @@ -1008,7 +1060,8 @@ ble_ll_sync_check_failed(struct ble_ll_sync_sm *sm) static bool ble_ll_sync_check_acad(struct ble_ll_sync_sm *sm, - const uint8_t *acad, uint8_t acad_len) + const uint8_t *acad, uint8_t acad_len, + const uint8_t **biginfo, uint8_t *biginfo_len) { const struct ble_ll_acad_channel_map_update_ind *chmu; unsigned int ad_len; @@ -1040,20 +1093,32 @@ ble_ll_sync_check_acad(struct ble_ll_sync_sm *sm, /* Channels Mask (37 bits) * TODO should we check this? */ - sm->chanmap_new[0] = chmu->map[0]; - sm->chanmap_new[1] = chmu->map[1]; - sm->chanmap_new[2] = chmu->map[2]; - sm->chanmap_new[3] = chmu->map[3]; - sm->chanmap_new[4] = chmu->map[4] & 0x1f; + sm->chan_map_new[0] = chmu->map[0]; + sm->chan_map_new[1] = chmu->map[1]; + sm->chan_map_new[2] = chmu->map[2]; + sm->chan_map_new[3] = chmu->map[3]; + sm->chan_map_new[4] = chmu->map[4] & 0x1f; /* drop if channel map is invalid */ - if (ble_ll_utils_calc_num_used_chans(sm->chanmap_new) == 0) { + if (ble_ll_utils_chan_map_used_get(sm->chan_map_new) == 0) { return false; } - sm->chanmap_new_instant = le16toh(chmu->instant); + sm->chan_map_new_instant = le16toh(chmu->instant); sm->flags |= BLE_LL_SYNC_SM_FLAG_NEW_CHANMAP; break; + +#if MYNEWT_VAL(BLE_LL_PERIODIC_ADV_SYNC_BIGINFO_REPORTS) + case BLE_LL_ACAD_BIGINFO: + if ((ad_len - 1 == BLE_LL_SYNC_BIGINFO_LEN) || (ad_len - 1 == BLE_LL_SYNC_BIGINFO_LEN_ENC)) { + *biginfo = &acad[2]; + *biginfo_len = ad_len - 1; + } else { + return false; + } + break; +#endif + default: break; } @@ -1078,9 +1143,13 @@ ble_ll_sync_rx_pkt_in(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *hdr) int8_t tx_power = 127; /* defaults to not available */ uint8_t *aux = NULL; uint8_t *acad = NULL; - uint8_t acad_len; + uint8_t acad_len = 0; + uint16_t *adi = NULL; + const uint8_t *biginfo = NULL; + uint8_t biginfo_len = 0; int datalen; bool reports_enabled; + bool is_duplicate = false; BLE_LL_ASSERT(sm); @@ -1126,14 +1195,22 @@ ble_ll_sync_rx_pkt_in(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *hdr) } /* get ext header data */ - datalen = ble_ll_sync_parse_ext_hdr(rxpdu, &aux, &tx_power, &acad, &acad_len); + datalen = ble_ll_sync_parse_ext_hdr(rxpdu, &aux, &tx_power, &acad, &acad_len, &adi); if (datalen < 0) { /* we got bad packet, end event */ goto end_event; } +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_ADI_SUPPORT) + if (adi != NULL) { + is_duplicate = (sm->flags & BLE_LL_SYNC_SM_FLAG_DUPLICATES) && (*adi == sm->prev_adi); + sm->prev_adi = *adi; + } +#endif + reports_enabled = ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_PERIODIC_ADV_RPT) && - !(sm->flags & BLE_LL_SYNC_SM_FLAG_DISABLED); + !(sm->flags & BLE_LL_SYNC_SM_FLAG_DISABLED) && + !is_duplicate; /* no need to schedule for chain if reporting is disabled */ if (reports_enabled) { @@ -1144,7 +1221,7 @@ ble_ll_sync_rx_pkt_in(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *hdr) } /* check ACAD, needs to be done before rxpdu is adjusted for ADV data */ - if (acad && !ble_ll_sync_check_acad(sm, acad, acad_len)) { + if (acad && !ble_ll_sync_check_acad(sm, acad, acad_len, &biginfo, &biginfo_len)) { /* we got bad packet (bad ACAD data), end event */ goto end_event; } @@ -1162,6 +1239,12 @@ ble_ll_sync_rx_pkt_in(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *hdr) /* send reports from this PDU */ ble_ll_sync_send_per_adv_rpt(sm, rxpdu, hdr->rxinfo.rssi, tx_power, datalen, aux, aux_scheduled); + +#if MYNEWT_VAL(BLE_LL_PERIODIC_ADV_SYNC_BIGINFO_REPORTS) + if (biginfo) { + ble_ll_sync_send_biginfo_adv_rpt(sm, biginfo, biginfo_len); + } +#endif } /* if chain was scheduled we don't end event yet */ @@ -1173,7 +1256,7 @@ ble_ll_sync_rx_pkt_in(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *hdr) } end_event: - ble_ll_event_send(&sm->sync_ev_end); + ble_ll_event_add(&sm->sync_ev_end); ble_ll_rfmgmt_release(); } @@ -1182,14 +1265,12 @@ ble_ll_sync_next_event(struct ble_ll_sync_sm *sm, uint32_t cur_ww_adjust) { uint32_t cur_ww; uint32_t max_ww; - uint32_t ticks; uint32_t itvl; - uint8_t usecs; uint16_t skip = sm->skip; /* don't skip if are establishing sync or we missed last event */ if (skip && ((sm->flags & BLE_LL_SYNC_SM_FLAG_ESTABLISHING) || - CPUTIME_LT(sm->last_anchor_point, sm->anchor_point))) { + LL_TMR_LT(sm->last_anchor_point, sm->anchor_point))) { skip = 0; } @@ -1197,19 +1278,12 @@ ble_ll_sync_next_event(struct ble_ll_sync_sm *sm, uint32_t cur_ww_adjust) * interval if not skipping */ if (skip == 0) { - ticks = sm->itvl_ticks; - usecs = sm->itvl_usecs; + sm->anchor_point += sm->itvl_ticks; + ble_ll_tmr_add_u(&sm->anchor_point, &sm->anchor_point_usecs, + sm->itvl_usecs); } else { itvl = sm->itvl * BLE_LL_SYNC_ITVL_USECS * (1 + skip); - ticks = os_cputime_usecs_to_ticks(itvl); - usecs = itvl - os_cputime_ticks_to_usecs(ticks); - } - - sm->anchor_point += ticks; - sm->anchor_point_usecs += usecs; - if (sm->anchor_point_usecs >= 31) { - sm->anchor_point++; - sm->anchor_point_usecs -= 31; + ble_ll_tmr_add(&sm->anchor_point, &sm->anchor_point_usecs, itvl); } /* Set event counter to the next event */ @@ -1217,21 +1291,21 @@ ble_ll_sync_next_event(struct ble_ll_sync_sm *sm, uint32_t cur_ww_adjust) /* update channel map if needed */ if (sm->flags & BLE_LL_SYNC_SM_FLAG_NEW_CHANMAP) { - if (((int16_t)(sm->event_cntr - sm->chanmap_new_instant)) >= 0) { + if (((int16_t)(sm->event_cntr - sm->chan_map_new_instant)) >= 0) { /* map was verified on reception */ - sm->chanmap[0] = sm->chanmap_new[0]; - sm->chanmap[1] = sm->chanmap_new[1]; - sm->chanmap[2] = sm->chanmap_new[2]; - sm->chanmap[3] = sm->chanmap_new[3]; - sm->chanmap[4] = sm->chanmap_new[4]; - sm->num_used_chans = ble_ll_utils_calc_num_used_chans(sm->chanmap); + sm->chan_map[0] = sm->chan_map_new[0]; + sm->chan_map[1] = sm->chan_map_new[1]; + sm->chan_map[2] = sm->chan_map_new[2]; + sm->chan_map[3] = sm->chan_map_new[3]; + sm->chan_map[4] = sm->chan_map_new[4]; + sm->chan_map_used = ble_ll_utils_chan_map_used_get(sm->chan_map); sm->flags &= ~BLE_LL_SYNC_SM_FLAG_NEW_CHANMAP; } } /* Calculate channel index of next event */ - sm->chan_index = ble_ll_utils_calc_dci_csa2(sm->event_cntr, sm->channel_id, - sm->num_used_chans, sm->chanmap); + sm->chan_index = ble_ll_utils_dci_csa2(sm->event_cntr, sm->channel_id, + sm->chan_map_used, sm->chan_map); cur_ww = ble_ll_utils_calc_window_widening(sm->anchor_point, sm->last_anchor_point, @@ -1256,7 +1330,7 @@ ble_ll_sync_next_event(struct ble_ll_sync_sm *sm, uint32_t cur_ww_adjust) * BLE_LL_SYNC_ESTABLISH_CNT events before failing regardless of timeout */ if (!(sm->flags & BLE_LL_SYNC_SM_FLAG_ESTABLISHING)) { - if (CPUTIME_GT(sm->anchor_point - os_cputime_usecs_to_ticks(cur_ww), + if (LL_TMR_GT(sm->anchor_point - ble_ll_tmr_u2t(cur_ww), sm->last_anchor_point + sm->timeout )) { return -1; } @@ -1286,7 +1360,7 @@ ble_ll_sync_event_end(struct ble_npl_event *ev) ble_ll_scan_chk_resume(); /* Remove any end events that might be enqueued */ - ble_npl_eventq_remove(&g_ble_ll_data.ll_evq, &sm->sync_ev_end); + ble_ll_event_remove(&sm->sync_ev_end); /* don't schedule next event if sync is not established nor establishing * at this point SM is no longer valid @@ -1308,10 +1382,7 @@ ble_ll_sync_event_end(struct ble_npl_event *ev) /* Event ended so we are no longer chaining */ sm->flags &= ~BLE_LL_SYNC_SM_FLAG_HCI_TRUNCATED; - - sm->sch.sched_cb = ble_ll_sync_event_start_cb; - sm->sch.cb_arg = sm; - sm->sch.sched_type = BLE_LL_SCHED_TYPE_SYNC; + sm->flags &= ~BLE_LL_SYNC_SM_FLAG_CHAIN; do { if (ble_ll_sync_next_event(sm, 0) < 0) { @@ -1327,20 +1398,18 @@ ble_ll_sync_event_end(struct ble_npl_event *ev) ble_ll_sync_sm_clear(sm); return; } - } while (ble_ll_sched_sync_reschedule(&sm->sch, sm->anchor_point, - sm->anchor_point_usecs, - sm->window_widening, sm->phy_mode)); + + ble_ll_sync_sched_set(&sm->sch, sm->anchor_point, + sm->anchor_point_usecs, 0, sm->phy_mode); + } while (ble_ll_sched_sync_reschedule(&sm->sch, sm->window_widening)); } void -ble_ll_sync_info_event(const uint8_t *addr, uint8_t addr_type, int rpa_index, +ble_ll_sync_info_event(struct ble_ll_scan_addr_data *addrd, uint8_t sid, struct ble_mbuf_hdr *rxhdr, const uint8_t *syncinfo) { struct ble_ll_sync_sm *sm = NULL; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER) - const uint8_t *rpa = NULL; -#endif uint16_t max_skip; uint32_t offset; uint32_t usecs; @@ -1365,28 +1434,21 @@ ble_ll_sync_info_event(const uint8_t *addr, uint8_t addr_type, int rpa_index, return; } - /* check if resolved */ - if (rpa_index >= 0) { -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER) - rpa = addr; -#endif - addr = g_ble_ll_resolv_list[rpa_index].rl_identity_addr; - addr_type = g_ble_ll_resolv_list[rpa_index].rl_addr_type; - } - /* check peer */ if (g_ble_ll_sync_create_params.options & BLE_HCI_LE_PERIODIC_ADV_CREATE_SYNC_OPT_FILTER) { - if (ble_ll_sync_on_list(addr, addr_type, sid) < 0) { + if (ble_ll_sync_on_list(addrd->adv_addr, + addrd->adv_addr_type, sid) < 0) { return; } /* set addr and sid in sm */ sm->adv_sid = sid; - sm->adv_addr_type = addr_type; - memcpy(sm->adv_addr, addr, BLE_DEV_ADDR_LEN); + sm->adv_addr_type = addrd->adv_addr_type; + memcpy(sm->adv_addr, addrd->adv_addr, BLE_DEV_ADDR_LEN); } else { - if ((sm->adv_sid != sid) || (sm->adv_addr_type != addr_type) || - memcmp(sm->adv_addr, addr, BLE_DEV_ADDR_LEN)) { + if ((sm->adv_sid != sid) || + (sm->adv_addr_type != addrd->adv_addr_type) || + memcmp(sm->adv_addr, addrd->adv_addr, BLE_DEV_ADDR_LEN)) { return; } } @@ -1406,12 +1468,14 @@ ble_ll_sync_info_event(const uint8_t *addr, uint8_t addr_type, int rpa_index, return; } - if (rpa_index >= 0) { +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + if (addrd->adva_resolved) { sm->flags |= BLE_LL_SYNC_SM_FLAG_ADDR_RESOLVED; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER) - memcpy(sm->adv_addr_rpa, rpa, BLE_DEV_ADDR_LEN); + memcpy(sm->adv_addr_rpa, addrd->adva, BLE_DEV_ADDR_LEN); #endif } +#endif /* set params from HCI LE Create Periodic Sync */ sm->timeout = g_ble_ll_sync_create_params.timeout; @@ -1433,21 +1497,15 @@ ble_ll_sync_info_event(const uint8_t *addr, uint8_t addr_type, int rpa_index, /* precalculate interval ticks and usecs */ usecs = sm->itvl * BLE_LL_SYNC_ITVL_USECS; - sm->itvl_ticks = os_cputime_usecs_to_ticks(usecs); - sm->itvl_usecs = (uint8_t)(usecs - - os_cputime_ticks_to_usecs(sm->itvl_ticks)); - if (sm->itvl_usecs == 31) { - sm->itvl_usecs = 0; - sm->itvl_ticks++; - } + sm->itvl_ticks = ble_ll_tmr_u2t_r(usecs, &sm->itvl_usecs); /* Channels Mask (37 bits) */ - sm->chanmap[0] = syncinfo[4]; - sm->chanmap[1] = syncinfo[5]; - sm->chanmap[2] = syncinfo[6]; - sm->chanmap[3] = syncinfo[7]; - sm->chanmap[4] = syncinfo[8] & 0x1f; - sm->num_used_chans = ble_ll_utils_calc_num_used_chans(sm->chanmap); + sm->chan_map[0] = syncinfo[4]; + sm->chan_map[1] = syncinfo[5]; + sm->chan_map[2] = syncinfo[6]; + sm->chan_map[3] = syncinfo[7]; + sm->chan_map[4] = syncinfo[8] & 0x1f; + sm->chan_map_used = ble_ll_utils_chan_map_used_get(sm->chan_map); /* SCA (3 bits) */ sm->sca = syncinfo[8] >> 5; @@ -1472,21 +1530,19 @@ ble_ll_sync_info_event(const uint8_t *addr, uint8_t addr_type, int rpa_index, } /* from now on we only need timeout in ticks */ - sm->timeout = os_cputime_usecs_to_ticks(sm->timeout); + sm->timeout = ble_ll_tmr_u2t(sm->timeout); sm->phy_mode = rxhdr->rxinfo.phy_mode; sm->window_widening = BLE_LL_JITTER_USECS; /* Calculate channel index of first event */ - sm->chan_index = ble_ll_utils_calc_dci_csa2(sm->event_cntr, sm->channel_id, - sm->num_used_chans, sm->chanmap); + sm->chan_index = ble_ll_utils_dci_csa2(sm->event_cntr, sm->channel_id, + sm->chan_map_used, sm->chan_map); - sm->sch.sched_cb = ble_ll_sync_event_start_cb; - sm->sch.cb_arg = sm; - sm->sch.sched_type = BLE_LL_SCHED_TYPE_SYNC; + ble_ll_sync_sched_set(&sm->sch, rxhdr->beg_cputime, rxhdr->rem_usecs, + offset, sm->phy_mode); - if (ble_ll_sched_sync(&sm->sch, rxhdr->beg_cputime, rxhdr->rem_usecs, - offset, sm->phy_mode)) { + if (ble_ll_sched_sync(&sm->sch)) { return; } @@ -1500,6 +1556,12 @@ ble_ll_sync_info_event(const uint8_t *addr, uint8_t addr_type, int rpa_index, } #endif +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_ADI_SUPPORT) + if (g_ble_ll_sync_create_params.options & BLE_HCI_LE_PERIODIC_ADV_CREATE_SYNC_OPT_DUPLICATES) { + sm->flags |= BLE_LL_SYNC_SM_FLAG_DUPLICATES; + } +#endif + sm->flags &= ~BLE_LL_SYNC_SM_FLAG_RESERVED; sm->flags |= BLE_LL_SYNC_SM_FLAG_ESTABLISHING; sm->flags |= BLE_LL_SYNC_SM_FLAG_SYNC_INFO; @@ -1539,11 +1601,23 @@ ble_ll_sync_create(const uint8_t *cmdbuf, uint8_t len) return BLE_ERR_INV_HCI_CMD_PARMS; } -#if MYNEWT_VAL(BLE_VERSION) >= 51 - if (cmd->options > BLE_HCI_LE_PERIODIC_ADV_CREATE_SYNC_OPT_DISABLED) { -#else - if (cmd->options > BLE_HCI_LE_PERIODIC_ADV_CREATE_SYNC_OPT_FILTER) { -#endif + if (MYNEWT_VAL(BLE_VERSION) >= 53) { + if (cmd->options & 0xf8) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + if (!(cmd->options & BLE_HCI_LE_PERIODIC_ADV_CREATE_SYNC_OPT_DISABLED) && + (cmd->options & BLE_HCI_LE_PERIODIC_ADV_CREATE_SYNC_OPT_DUPLICATES) && + !MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_ADI_SUPPORT)) { + /* We do not support ADI in periodic advertising thus cannot enable + * duplicate filtering. + */ + return BLE_ERR_UNSUPPORTED; + } + } else if (MYNEWT_VAL(BLE_VERSION) >= 51) { + if (cmd->options & 0xfc) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + } else if (cmd->options & 0xfe) { return BLE_ERR_INV_HCI_CMD_PARMS; } @@ -1590,7 +1664,7 @@ ble_ll_sync_create(const uint8_t *cmdbuf, uint8_t len) } /* reserve buffer for sync complete event */ - g_ble_ll_sync_create_comp_ev = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); + g_ble_ll_sync_create_comp_ev = ble_transport_alloc_evt(0); if (!g_ble_ll_sync_create_comp_ev) { return BLE_ERR_MEM_CAPACITY; } @@ -1600,7 +1674,7 @@ ble_ll_sync_create(const uint8_t *cmdbuf, uint8_t len) /* reserve 1 SM for created sync */ sm = ble_ll_sync_reserve(); if (!sm) { - ble_hci_trans_buf_free(g_ble_ll_sync_create_comp_ev); + ble_transport_free(g_ble_ll_sync_create_comp_ev); g_ble_ll_sync_create_comp_ev = NULL; OS_EXIT_CRITICAL(sr); return BLE_ERR_MEM_CAPACITY; @@ -1622,13 +1696,13 @@ ble_ll_sync_create(const uint8_t *cmdbuf, uint8_t len) } static void -ble_ll_sync_cancel_complete_event(void) +ble_ll_sync_cancel_complete_event(void *user_data) { ble_ll_sync_est_event_failed(BLE_ERR_OPERATION_CANCELLED); } int -ble_ll_sync_cancel(ble_ll_hci_post_cmd_complete_cb *post_cmd_cb) +ble_ll_sync_cancel(void) { struct ble_ll_sync_sm *sm; os_sr_t sr; @@ -1659,7 +1733,7 @@ ble_ll_sync_cancel(ble_ll_hci_post_cmd_complete_cb *post_cmd_cb) OS_EXIT_CRITICAL(sr); /* g_ble_ll_sync_create_comp_ev will be cleared by this callback */ - *post_cmd_cb = ble_ll_sync_cancel_complete_event; + ble_ll_hci_post_cmd_cb_set(ble_ll_sync_cancel_complete_event, NULL); return BLE_ERR_SUCCESS; } @@ -1779,7 +1853,7 @@ ble_ll_sync_list_remove(const uint8_t *cmdbuf, uint8_t len) int ble_ll_sync_list_clear(void) { - int i; + unsigned int i; if (g_ble_ll_sync_create_comp_ev) { return BLE_ERR_CMD_DISALLOWED; @@ -1817,7 +1891,17 @@ ble_ll_sync_receive_enable(const uint8_t *cmdbuf, uint8_t len) return BLE_ERR_INV_HCI_CMD_PARMS; } - if (cmd->enable > 0x01) { + if (MYNEWT_VAL(BLE_VERSION) >= 53) { + if (cmd->enable > 0x03) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } else if ((cmd->enable == 0x03) && + !MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_ADI_SUPPORT)) { + /* We do not support ADI in periodic advertising thus cannot enable + * duplicate filtering. + */ + return BLE_ERR_UNSUPPORTED; + } + } else if (cmd->enable > 0x01) { return BLE_ERR_INV_HCI_CMD_PARMS; } @@ -1839,8 +1923,14 @@ ble_ll_sync_receive_enable(const uint8_t *cmdbuf, uint8_t len) return BLE_ERR_UNK_ADV_INDENT; } - if (cmd->enable) { + if (cmd->enable & 0x1) { sm->flags &= ~BLE_LL_SYNC_SM_FLAG_DISABLED; + + if (cmd->enable & 0x2) { + sm->flags |= BLE_LL_SYNC_SM_FLAG_DUPLICATES; + } else { + sm->flags &= ~BLE_LL_SYNC_SM_FLAG_DUPLICATES; + } } else { sm->flags |= BLE_LL_SYNC_SM_FLAG_DISABLED; } @@ -1862,7 +1952,7 @@ ble_ll_sync_transfer_get(const uint8_t *addr, uint8_t addr_type, uint8_t sid) if (!sm->flags) { /* allocate event for transfer received event */ - sm->transfer_received_ev = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); + sm->transfer_received_ev = ble_transport_alloc_evt(0); if (!sm->transfer_received_ev) { break; } @@ -1881,7 +1971,7 @@ ble_ll_sync_transfer_get(const uint8_t *addr, uint8_t addr_type, uint8_t sid) void ble_ll_sync_periodic_ind(struct ble_ll_conn_sm *connsm, - const uint8_t *sync_ind, bool reports_disabled, + const uint8_t *sync_ind, uint8_t mode, uint16_t max_skip, uint32_t sync_timeout) { const uint8_t *syncinfo = sync_ind + 2; @@ -1907,6 +1997,10 @@ ble_ll_sync_periodic_ind(struct ble_ll_conn_sm *connsm, uint8_t sca; os_sr_t sr; + if (!mode) { + return; + } + phy_mode = ble_ll_ctrl_phy_from_phy_mask(sync_ind[25]); itvl = get_le16(syncinfo + 2); /* ignore if sync params are not valid */ @@ -1930,6 +2024,7 @@ ble_ll_sync_periodic_ind(struct ble_ll_conn_sm *connsm, rpa_index = -1; +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) /* check if need to resolve */ if (ble_ll_is_rpa(addr, addr_type)) { rpa_index = ble_ll_resolv_peer_rpa_any(addr); @@ -1939,6 +2034,7 @@ ble_ll_sync_periodic_ind(struct ble_ll_conn_sm *connsm, addr_type = g_ble_ll_resolv_list[rpa_index].rl_addr_type; } } +#endif OS_ENTER_CRITICAL(sr); /* check if already synchronized with this peer */ @@ -1963,7 +2059,7 @@ ble_ll_sync_periodic_ind(struct ble_ll_conn_sm *connsm, } /* set params from transfer */ - sm->timeout = os_cputime_usecs_to_ticks(sync_timeout); + sm->timeout = ble_ll_tmr_u2t(sync_timeout); sm->skip = max_skip; sm->sync_pending_cnt = BLE_LL_SYNC_ESTABLISH_CNT; sm->transfer_id = get_le16(sync_ind); /* first two bytes */ @@ -1993,21 +2089,15 @@ ble_ll_sync_periodic_ind(struct ble_ll_conn_sm *connsm, sm->itvl = itvl; /* precalculate interval ticks and usecs */ - sm->itvl_ticks = os_cputime_usecs_to_ticks(itvl_usecs); - sm->itvl_usecs = (uint8_t)(itvl_usecs - - os_cputime_ticks_to_usecs(sm->itvl_ticks)); - if (sm->itvl_usecs == 31) { - sm->itvl_usecs = 0; - sm->itvl_ticks++; - } + sm->itvl_ticks = ble_ll_tmr_u2t_r(itvl_usecs, &sm->itvl_usecs); /* Channels Mask (37 bits) */ - sm->chanmap[0] = syncinfo[4]; - sm->chanmap[1] = syncinfo[5]; - sm->chanmap[2] = syncinfo[6]; - sm->chanmap[3] = syncinfo[7]; - sm->chanmap[4] = syncinfo[8] & 0x1f; - sm->num_used_chans = ble_ll_utils_calc_num_used_chans(sm->chanmap); + sm->chan_map[0] = syncinfo[4]; + sm->chan_map[1] = syncinfo[5]; + sm->chan_map[2] = syncinfo[6]; + sm->chan_map[3] = syncinfo[7]; + sm->chan_map[4] = syncinfo[8] & 0x1f; + sm->chan_map_used = ble_ll_utils_chan_map_used_get(sm->chan_map); /* SCA (3 bits) */ sm->sca = syncinfo[8] >> 5; @@ -2034,17 +2124,13 @@ ble_ll_sync_periodic_ind(struct ble_ll_conn_sm *connsm, sm->phy_mode = phy_mode; /* Calculate channel index of first event */ - sm->chan_index = ble_ll_utils_calc_dci_csa2(sm->event_cntr, sm->channel_id, - sm->num_used_chans, sm->chanmap); - - sm->sch.sched_cb = ble_ll_sync_event_start_cb; - sm->sch.cb_arg = sm; - sm->sch.sched_type = BLE_LL_SCHED_TYPE_SYNC; + sm->chan_index = ble_ll_utils_dci_csa2(sm->event_cntr, sm->channel_id, + sm->chan_map_used, sm->chan_map); /* get anchor for specified conn event */ conn_event_count = get_le16(sync_ind + 20); - ble_ll_conn_get_anchor(connsm, conn_event_count, &sm->anchor_point, - &sm->anchor_point_usecs); + ble_ll_conn_anchor_event_cntr_get(connsm, conn_event_count, &sm->anchor_point, + &sm->anchor_point_usecs); /* Set last anchor point */ sm->last_anchor_point = sm->anchor_point - (last_pa_diff * sm->itvl_ticks); @@ -2052,14 +2138,14 @@ ble_ll_sync_periodic_ind(struct ble_ll_conn_sm *connsm, /* calculate extra window widening */ sync_conn_event_count = get_le16(sync_ind + 32); sca = sync_ind[24] >> 5; - ble_ll_conn_get_anchor(connsm, sync_conn_event_count, &sync_anchor, - &sync_anchor_usecs); + ble_ll_conn_anchor_event_cntr_get(connsm, sync_conn_event_count, &sync_anchor, + &sync_anchor_usecs); ww_adjust = ble_ll_utils_calc_window_widening(connsm->anchor_point, sync_anchor, sca); /* spin until we get anchor in future */ - future = os_cputime_get32() + g_ble_ll_sched_offset_ticks; - while (CPUTIME_LT(sm->anchor_point, future)) { + future = ble_ll_tmr_get() + g_ble_ll_sched_offset_ticks; + while (LL_TMR_LT(sm->anchor_point, future)) { if (ble_ll_sync_next_event(sm, ww_adjust) < 0) { /* release SM if this failed */ ble_ll_sync_transfer_received(sm, BLE_ERR_CONN_ESTABLISHMENT); @@ -2068,8 +2154,10 @@ ble_ll_sync_periodic_ind(struct ble_ll_conn_sm *connsm, } } - if (ble_ll_sched_sync(&sm->sch, sm->anchor_point, sm->anchor_point_usecs, - offset, sm->phy_mode)) { + ble_ll_sync_sched_set(&sm->sch, sm->anchor_point, sm->anchor_point_usecs, + offset, sm->phy_mode); + + if (ble_ll_sched_sync(&sm->sch)) { /* release SM if this failed */ ble_ll_sync_transfer_received(sm, BLE_ERR_CONN_ESTABLISHMENT); memset(sm, 0, sizeof(*sm)); @@ -2080,8 +2168,15 @@ ble_ll_sync_periodic_ind(struct ble_ll_conn_sm *connsm, sm->anchor_point = sm->sch.start_time + g_ble_ll_sched_offset_ticks; sm->anchor_point_usecs = sm->sch.remainder; - if (reports_disabled) { + switch (mode) { + case 0x1: sm->flags |= BLE_LL_SYNC_SM_FLAG_DISABLED; + break; + case 0x3: + sm->flags |= BLE_LL_SYNC_SM_FLAG_DUPLICATES; + break; + default: + break; } } @@ -2101,11 +2196,11 @@ ble_ll_sync_put_syncinfo(struct ble_ll_sync_sm *syncsm, conn_cnt = connsm->event_cntr; /* get anchor for conn event that is before periodic_adv_event_start_time */ - while (CPUTIME_GT(anchor, syncsm->anchor_point)) { - ble_ll_conn_get_anchor(connsm, --conn_cnt, &anchor, &anchor_usecs); + while (LL_TMR_GT(anchor, syncsm->anchor_point)) { + ble_ll_conn_anchor_event_cntr_get(connsm, --conn_cnt, &anchor, &anchor_usecs); } - offset = os_cputime_ticks_to_usecs(syncsm->anchor_point - anchor); + offset = ble_ll_tmr_t2u(syncsm->anchor_point - anchor); offset -= anchor_usecs; offset += syncsm->anchor_point_usecs; @@ -2136,11 +2231,11 @@ ble_ll_sync_put_syncinfo(struct ble_ll_sync_sm *syncsm, put_le16(&dptr[2], syncsm->itvl); /* Channels Mask (37 bits) */ - dptr[4] = syncsm->chanmap[0]; - dptr[5] = syncsm->chanmap[1]; - dptr[6] = syncsm->chanmap[2]; - dptr[7] = syncsm->chanmap[3]; - dptr[8] = syncsm->chanmap[4] & 0x1f; + dptr[4] = syncsm->chan_map[0]; + dptr[5] = syncsm->chan_map[1]; + dptr[6] = syncsm->chan_map[2]; + dptr[7] = syncsm->chan_map[3]; + dptr[8] = syncsm->chan_map[4] & 0x1f; /* SCA (3 bits) */ dptr[8] |= syncsm->sca << 5; @@ -2247,36 +2342,30 @@ ble_ll_sync_transfer(const uint8_t *cmdbuf, uint8_t len, if (!(sm->flags & BLE_LL_SYNC_SM_FLAG_ESTABLISHED)) { rc = BLE_ERR_UNK_ADV_INDENT; - OS_EXIT_CRITICAL(sr); - goto done; + goto exit_crit; } handle = le16toh(cmd->conn_handle); if (handle > 0xeff) { rc = BLE_ERR_INV_HCI_CMD_PARMS; - OS_EXIT_CRITICAL(sr); - goto done; + goto exit_crit; } - connsm = ble_ll_conn_find_active_conn(handle); + connsm = ble_ll_conn_find_by_handle(handle); if (!connsm) { rc = BLE_ERR_UNK_CONN_ID; - OS_EXIT_CRITICAL(sr); - goto done; + goto exit_crit; } - /* TODO should not need to shift - * byte 3 (0 byte is conn_feature) , bit 1 - * - * Allow initiate LL procedure only if remote supports it. - */ - if (!(connsm->remote_features[2] & (BLE_LL_FEAT_SYNC_TRANS_RECV >> (8 * 3)))) { + /* Allow initiate LL procedure only if remote supports it. */ + if (!ble_ll_conn_rem_feature_check(connsm, BLE_LL_FEAT_SYNC_TRANS_RECV)) { rc = BLE_ERR_UNSUPP_REM_FEATURE; - goto done; + goto exit_crit; } rc = ble_ll_sync_send_sync_ind(sm, connsm, cmd->service_data); +exit_crit: OS_EXIT_CRITICAL(sr); done: rsp->conn_handle = cmd->conn_handle; @@ -2292,7 +2381,7 @@ ble_ll_sync_transfer(const uint8_t *cmdbuf, uint8_t len, void ble_ll_sync_rmvd_from_sched(struct ble_ll_sync_sm *sm) { - ble_ll_event_send(&sm->sync_ev_end); + ble_ll_event_add(&sm->sync_ev_end); } bool @@ -2309,7 +2398,7 @@ ble_ll_sync_enabled(void) void ble_ll_sync_reset(void) { - int i; + unsigned int i; for (i = 0; i < BLE_LL_SYNC_CNT; i++) { ble_ll_sync_sm_clear(&g_ble_ll_sync_sm[i]); @@ -2327,7 +2416,7 @@ ble_ll_sync_reset(void) g_ble_ll_sync_sm_current = NULL; if (g_ble_ll_sync_create_comp_ev) { - ble_hci_trans_buf_free(g_ble_ll_sync_create_comp_ev); + ble_transport_free(g_ble_ll_sync_create_comp_ev); g_ble_ll_sync_create_comp_ev = NULL; } } @@ -2335,7 +2424,7 @@ ble_ll_sync_reset(void) void ble_ll_sync_init(void) { - int i; + unsigned int i; for (i = 0; i < ARRAY_SIZE(g_ble_ll_sync_adv_list); i++) { g_ble_ll_sync_adv_list[i].adv_sid = 0xff; diff --git a/nimble/controller/src/ble_ll_trace.c b/nimble/controller/src/ble_ll_trace.c index 330b3d4c6a..625d73dd15 100644 --- a/nimble/controller/src/ble_ll_trace.c +++ b/nimble/controller/src/ble_ll_trace.c @@ -20,6 +20,7 @@ #include #include "syscfg/syscfg.h" #include "os/os_trace_api.h" +#include "controller/ble_ll_trace.h" #if MYNEWT_VAL(BLE_LL_SYSVIEW) diff --git a/nimble/controller/src/ble_ll_utils.c b/nimble/controller/src/ble_ll_utils.c index ccdf37759c..9fa32f8fc7 100644 --- a/nimble/controller/src/ble_ll_utils.c +++ b/nimble/controller/src/ble_ll_utils.c @@ -21,6 +21,7 @@ #include #include "nimble/ble.h" #include "controller/ble_ll.h" +#include "controller/ble_ll_tmr.h" #include "controller/ble_ll_utils.h" /* 37 bits require 5 bytes */ @@ -31,10 +32,9 @@ static const uint16_t g_ble_sca_ppm_tbl[8] = { 500, 250, 150, 100, 75, 50, 30, 20 }; -uint32_t -ble_ll_utils_calc_access_addr(void) +int +ble_ll_utils_verify_aa(uint32_t aa) { - uint32_t aa; uint16_t aa_low; uint16_t aa_high; uint32_t temp; @@ -46,105 +46,175 @@ ble_ll_utils_calc_access_addr(void) uint8_t ones; int tmp; - /* Calculate a random access address */ - aa = 0; - while (1) { - /* Get two, 16-bit random numbers */ - aa_low = ble_ll_rand() & 0xFFFF; - aa_high = ble_ll_rand() & 0xFFFF; + aa_low = aa & 0xffff; + aa_high = aa >> 16; - /* All four bytes cannot be equal */ - if (aa_low == aa_high) { - continue; - } + /* All four bytes cannot be equal */ + if (aa_low == aa_high) { + return 0; + } - /* Upper 6 bits must have 2 transitions */ - tmp = (int16_t)aa_high >> 10; - if (__builtin_popcount(tmp ^ (tmp >> 1)) < 2) { - continue; - } + /* Upper 6 bits must have 2 transitions */ + tmp = (int16_t)aa_high >> 10; + if (__builtin_popcount(tmp ^ (tmp >> 1)) < 2) { + return 0; + } - /* Cannot be access address or be 1 bit different */ - aa = aa_high; - aa = (aa << 16) | aa_low; - bits_diff = 0; - temp = aa ^ BLE_ACCESS_ADDR_ADV; - for (mask = 0x00000001; mask != 0; mask <<= 1) { - if (mask & temp) { - ++bits_diff; - if (bits_diff > 1) { - break; - } + /* Cannot be access address or be 1 bit different */ + aa = aa_high; + aa = (aa << 16) | aa_low; + bits_diff = 0; + temp = aa ^ BLE_ACCESS_ADDR_ADV; + for (mask = 0x00000001; mask != 0; mask <<= 1) { + if (mask & temp) { + ++bits_diff; + if (bits_diff > 1) { + break; } } - if (bits_diff <= 1) { - continue; - } + } + if (bits_diff <= 1) { + return 0; + } - /* Cannot have more than 24 transitions */ - transitions = 0; - consecutive = 1; - ones = 0; - mask = 0x00000001; - while (mask < 0x80000000) { - prev_bit = aa & mask; - mask <<= 1; - if (mask & aa) { - if (prev_bit == 0) { - ++transitions; - consecutive = 1; - } else { - ++consecutive; - } + /* Cannot have more than 24 transitions */ + transitions = 0; + consecutive = 1; + ones = 0; + mask = 0x00000001; + while (mask < 0x80000000) { + prev_bit = aa & mask; + mask <<= 1; + if (mask & aa) { + if (prev_bit == 0) { + ++transitions; + consecutive = 1; } else { - if (prev_bit == 0) { - ++consecutive; - } else { - ++transitions; - consecutive = 1; - } + ++consecutive; } - - if (prev_bit) { - ones++; + } else { + if (prev_bit == 0) { + ++consecutive; + } else { + ++transitions; + consecutive = 1; } + } - /* 8 lsb should have at least three 1 */ - if (mask == 0x00000100 && ones < 3) { - break; - } + if (prev_bit) { + ones++; + } - /* 16 lsb should have no more than 11 transitions */ - if (mask == 0x00010000 && transitions > 11) { - break; - } + /* 8 lsb should have at least three 1 */ + if (mask == 0x00000100 && ones < 3) { + break; + } - /* This is invalid! */ - if (consecutive > 6) { - /* Make sure we always detect invalid sequence below */ - mask = 0; - break; - } + /* 16 lsb should have no more than 11 transitions */ + if (mask == 0x00010000 && transitions > 11) { + break; + } + + /* This is invalid! */ + if (consecutive > 6) { + /* Make sure we always detect invalid sequence below */ + mask = 0; + break; + } + } + + /* Invalid sequence found */ + if (mask != 0x80000000) { + return 0; + } + + /* Cannot be more than 24 transitions */ + if (transitions > 24) { + return 0; + } + + return 1; +} + +uint32_t +ble_ll_utils_calc_aa(void) +{ + uint32_t aa; + + do { + aa = ble_ll_rand(); + } while (!ble_ll_utils_verify_aa(aa)); + + return aa; +} + +uint32_t +ble_ll_utils_calc_seed_aa(void) +{ + uint32_t seed_aa; + + while (1) { + seed_aa = ble_ll_rand(); + + /* saa(19) == saa(15) */ + if (!!(seed_aa & (1 << 19)) != !!(seed_aa & (1 << 15))) { + continue; + } + + /* saa(22) = saa(16) */ + if (!!(seed_aa & (1 << 22)) != !!(seed_aa & (1 << 16))) { + continue; } - /* Invalid sequence found */ - if (mask != 0x80000000) { + /* saa(22) != saa(15) */ + if (!!(seed_aa & (1 << 22)) == !!(seed_aa & (1 << 15))) { continue; } - /* Cannot be more than 24 transitions */ - if (transitions > 24) { + /* saa(25) == 0 */ + if (seed_aa & (1 << 25)) { + continue; + } + + /* saa(23) == 1 */ + if (!(seed_aa & (1 << 23))) { continue; } - /* We have a valid access address */ break; } - return aa; + + return seed_aa; +} + +uint32_t +ble_ll_utils_calc_big_aa(uint32_t seed_aa, uint32_t n) +{ + uint32_t d; + uint32_t dw; + + /* Core 5.3, Vol 6, Part B, 2.1.2 */ + /* TODO simplify? */ + d = ((35 * n) + 42) % 128; + dw = (!!(d & (1 << 0)) << 31) | + (!!(d & (1 << 0)) << 30) | + (!!(d & (1 << 0)) << 29) | + (!!(d & (1 << 0)) << 28) | + (!!(d & (1 << 0)) << 27) | + (!!(d & (1 << 0)) << 26) | + (!!(d & (1 << 1)) << 25) | + (!!(d & (1 << 6)) << 24) | + (!!(d & (1 << 1)) << 23) | + (!!(d & (1 << 5)) << 21) | + (!!(d & (1 << 4)) << 20) | + (!!(d & (1 << 3)) << 18) | + (!!(d & (1 << 2)) << 17); + + return seed_aa ^ dw; } uint8_t -ble_ll_utils_remapped_channel(uint8_t remap_index, const uint8_t *chanmap) +ble_ll_utils_chan_map_remap(const uint8_t *chan_map, uint8_t remap_index) { uint8_t cntr; uint8_t mask; @@ -159,7 +229,7 @@ ble_ll_utils_remapped_channel(uint8_t remap_index, const uint8_t *chanmap) chan = 0; cntr = 0; for (i = 0; i < BLE_LL_CHMAP_LEN; i++) { - usable_chans = chanmap[i]; + usable_chans = chan_map[i]; if (usable_chans != 0) { mask = 0x01; for (j = 0; j < 8; j++) { @@ -181,39 +251,29 @@ ble_ll_utils_remapped_channel(uint8_t remap_index, const uint8_t *chanmap) } uint8_t -ble_ll_utils_calc_num_used_chans(const uint8_t *chmap) +ble_ll_utils_chan_map_used_get(const uint8_t *chan_map) { - int i; - int j; - uint8_t mask; - uint8_t chanbyte; - uint8_t used_channels; - - used_channels = 0; - for (i = 0; i < BLE_LL_CHMAP_LEN; ++i) { - chanbyte = chmap[i]; - if (chanbyte) { - if (chanbyte == 0xff) { - used_channels += 8; - } else { - mask = 0x01; - for (j = 0; j < 8; ++j) { - if (chanbyte & mask) { - ++used_channels; - } - mask <<= 1; - } - } - } - } - return used_channels; + return __builtin_popcountll(((uint64_t)(chan_map[4] & 0x1f) << 32) | + get_le32(chan_map)); } #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CSA2) -static uint16_t -ble_ll_utils_csa2_perm(uint16_t in) +#if __thumb2__ +static inline uint32_t +ble_ll_utils_csa2_perm(uint32_t val) +{ + __asm__ volatile (".syntax unified \n" + "rbit %[val], %[val] \n" + "rev %[val], %[val] \n" + : [val] "+r" (val)); + + return val; +} +#else +static uint32_t +ble_ll_utils_csa2_perm(uint32_t in) { - uint16_t out = 0; + uint32_t out = 0; int i; for (i = 0; i < 8; i++) { @@ -226,61 +286,180 @@ ble_ll_utils_csa2_perm(uint16_t in) return out; } +#endif + +static inline uint32_t +ble_ll_utils_csa2_mam(uint32_t a, uint32_t b) +{ + return (17 * a + b) % 65536; +} + +static uint16_t +ble_ll_utils_csa2_prn_s(uint16_t counter, uint16_t ch_id) +{ + uint32_t prn_s; + + prn_s = counter ^ ch_id; + + prn_s = ble_ll_utils_csa2_perm(prn_s); + prn_s = ble_ll_utils_csa2_mam(prn_s, ch_id); + + prn_s = ble_ll_utils_csa2_perm(prn_s); + prn_s = ble_ll_utils_csa2_mam(prn_s, ch_id); + + prn_s = ble_ll_utils_csa2_perm(prn_s); + prn_s = ble_ll_utils_csa2_mam(prn_s, ch_id); + + return prn_s; +} static uint16_t ble_ll_utils_csa2_prng(uint16_t counter, uint16_t ch_id) { + uint16_t prn_s; uint16_t prn_e; - prn_e = counter ^ ch_id; + prn_s = ble_ll_utils_csa2_prn_s(counter, ch_id); + prn_e = prn_s ^ ch_id; - prn_e = ble_ll_utils_csa2_perm(prn_e); - prn_e = (prn_e * 17) + ch_id; + return prn_e; +} - prn_e = ble_ll_utils_csa2_perm(prn_e); - prn_e = (prn_e * 17) + ch_id; +/* Find remap_idx for given chan_idx */ +static uint16_t +ble_ll_utils_csa2_chan2remap(uint16_t chan_idx, const uint8_t *chan_map) +{ + uint16_t remap_idx = 0; + uint32_t u32 = 0; + unsigned idx; - prn_e = ble_ll_utils_csa2_perm(prn_e); - prn_e = (prn_e * 17) + ch_id; + for (idx = 0; idx < 37; idx++) { + if ((idx % 8) == 0) { + u32 = chan_map[idx / 8]; + } + if (u32 & 1) { + if (idx == chan_idx) { + return remap_idx; + } + remap_idx++; + } + u32 >>= 1; + } - prn_e = prn_e ^ ch_id; + BLE_LL_ASSERT(0); - return prn_e; + return 0; +} + +/* Find chan_idx at given remap_idx */ +static uint16_t +ble_ll_utils_csa2_remap2chan(uint16_t remap_idx, const uint8_t *chan_map) +{ + uint32_t u32 = 0; + unsigned idx; + + for (idx = 0; idx < 37; idx++) { + if ((idx % 8) == 0) { + u32 = chan_map[idx / 8]; + } + if (u32 & 1) { + if (!remap_idx) { + return idx; + } + remap_idx--; + } + u32 >>= 1; + } + + BLE_LL_ASSERT(0); + + return 0; +} + +static uint16_t +ble_ll_utils_csa2_calc_chan_idx(uint16_t prn_e, uint8_t num_used_chans, + const uint8_t *chanm_map, uint16_t *remap_idx) +{ + uint16_t chan_idx; + + chan_idx = prn_e % 37; + if (chanm_map[chan_idx / 8] & (1 << (chan_idx % 8))) { + *remap_idx = ble_ll_utils_csa2_chan2remap(chan_idx, chanm_map); + return chan_idx; + } + + *remap_idx = (num_used_chans * prn_e) / 65536; + chan_idx = ble_ll_utils_csa2_remap2chan(*remap_idx, chanm_map); + + return chan_idx; } uint8_t -ble_ll_utils_calc_dci_csa2(uint16_t event_cntr, uint16_t channel_id, - uint8_t num_used_chans, const uint8_t *chanmap) +ble_ll_utils_dci_csa2(uint16_t counter, uint16_t chan_id, + uint8_t num_used_chans, const uint8_t *chan_map) { - uint16_t channel_unmapped; - uint8_t remap_index; + uint16_t prn_e; + uint16_t chan_idx; + uint16_t remap_idx; + + prn_e = ble_ll_utils_csa2_prng(counter, chan_id); + chan_idx = ble_ll_utils_csa2_calc_chan_idx(prn_e, num_used_chans, chan_map, + &remap_idx); + + return chan_idx; +} + +uint16_t +ble_ll_utils_dci_iso_event(uint16_t counter, uint16_t chan_id, + uint16_t *prn_sub_lu, uint8_t chan_map_used, + const uint8_t *chan_map, uint16_t *remap_idx) +{ + uint16_t prn_s; uint16_t prn_e; - uint8_t bitpos; + uint16_t chan_idx; - prn_e = ble_ll_utils_csa2_prng(event_cntr, channel_id); + prn_s = ble_ll_utils_csa2_prn_s(counter, chan_id); + prn_e = prn_s ^ chan_id; - channel_unmapped = prn_e % 37; + *prn_sub_lu = prn_s; - /* - * If unmapped channel is the channel index of a used channel it is used - * as channel index. - */ - bitpos = 1 << (channel_unmapped & 0x07); - if (chanmap[channel_unmapped >> 3] & bitpos) { - return channel_unmapped; - } + chan_idx = ble_ll_utils_csa2_calc_chan_idx(prn_e, chan_map_used, chan_map, + remap_idx); + + return chan_idx; +} + +uint16_t +ble_ll_utils_dci_iso_subevent(uint16_t chan_id, uint16_t *prn_sub_lu, + uint8_t chan_map_used, const uint8_t *chan_map, + uint16_t *remap_idx) +{ + uint16_t prn_sub_se; + uint16_t chan_idx; + uint16_t d; + + *prn_sub_lu = ble_ll_utils_csa2_perm(*prn_sub_lu); + *prn_sub_lu = ble_ll_utils_csa2_mam(*prn_sub_lu, chan_id); + prn_sub_se = *prn_sub_lu ^ chan_id; + + /* Core 5.3, Vol 6, Part B, 4.5.8.3.6 (enjoy!) */ + /* TODO optimize this somehow */ + d = MAX(1, MAX(MIN(3, chan_map_used - 5), + MIN(11, (chan_map_used - 10) / 2))); + *remap_idx = (*remap_idx + d + prn_sub_se * + (chan_map_used - 2 * d + 1) / 65536) % chan_map_used; - remap_index = (num_used_chans * prn_e) / 0x10000; + chan_idx = ble_ll_utils_csa2_remap2chan(*remap_idx, chan_map); - return ble_ll_utils_remapped_channel(remap_index, chanmap); + return chan_idx; } #endif uint32_t ble_ll_utils_calc_window_widening(uint32_t anchor_point, uint32_t last_anchor_point, - uint8_t master_sca) + uint8_t central_sca) { uint32_t total_sca_ppm; uint32_t window_widening; @@ -291,8 +470,8 @@ ble_ll_utils_calc_window_widening(uint32_t anchor_point, time_since_last_anchor = (int32_t)(anchor_point - last_anchor_point); if (time_since_last_anchor > 0) { - delta_msec = os_cputime_ticks_to_usecs(time_since_last_anchor) / 1000; - total_sca_ppm = g_ble_sca_ppm_tbl[master_sca] + MYNEWT_VAL(BLE_LL_SCA); + delta_msec = ble_ll_tmr_t2u(time_since_last_anchor) / 1000; + total_sca_ppm = g_ble_sca_ppm_tbl[central_sca] + MYNEWT_VAL(BLE_LL_SCA); window_widening = (total_sca_ppm * delta_msec) / 1000; } diff --git a/nimble/controller/src/ble_ll_whitelist.c b/nimble/controller/src/ble_ll_whitelist.c index 04ec6428b5..12d841a7f8 100644 --- a/nimble/controller/src/ble_ll_whitelist.c +++ b/nimble/controller/src/ble_ll_whitelist.c @@ -48,8 +48,6 @@ struct ble_ll_whitelist_entry g_ble_ll_whitelist[BLE_LL_WHITELIST_SIZE]; static int ble_ll_whitelist_chg_allowed(void) { - int rc; - /* * This command is not allowed if: * -> advertising uses the whitelist and we are currently advertising. @@ -57,11 +55,19 @@ ble_ll_whitelist_chg_allowed(void) * -> initiating uses whitelist and a LE create connection command is in * progress */ - rc = 1; - if (!ble_ll_adv_can_chg_whitelist() || !ble_ll_scan_can_chg_whitelist()) { - rc = 0; +#if MYNEWT_VAL(BLE_LL_ROLE_BROADCASTER) + if (ble_ll_adv_can_chg_whitelist()) { + return 1; } - return rc; +#endif + +#if MYNEWT_VAL(BLE_LL_ROLE_OBSERVER) + if (ble_ll_scan_can_chg_whitelist()) { + return 1; + } +#endif + + return 0; } /** diff --git a/nimble/controller/syscfg.defunct.yml b/nimble/controller/syscfg.defunct.yml new file mode 100644 index 0000000000..239861287f --- /dev/null +++ b/nimble/controller/syscfg.defunct.yml @@ -0,0 +1,106 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +syscfg.defs: +# deprecated settings (to be defunct/removed eventually) + BLE_LL_DIRECT_TEST_MODE: + description: use BLE_LL_DTM instead + value: 0 + deprecated: 1 + BLE_XTAL_SETTLE_TIME: + description: use BLE_LL_RFMGMT_ENABLE_TIME instead + value: 0 + deprecated: 1 + BLE_LL_OUR_SCA: + description: use BLE_LL_SCA instead + value: 60 + deprecated: 1 + BLE_LL_VND_EVENT_ON_ASSERT: + description: use BLE_LL_HCI_VS_EVENT_ON_ASSERT + value: 0 + deprecated: 1 + BLE_PUBLIC_DEV_ADDR: + description: use BLE_LL_PUBLIC_DEV_ADDR + value: "(uint8_t[6]){0x00, 0x00, 0x00, 0x00, 0x00, 0x00}" + deprecated: 1 + BLE_LL_EXT_ADV_AUX_PTR_CNT: + description: use BLE_LL_SCAN_AUX_SEGMENT_CNT + value: 0 + deprecated: 1 + BLE_LL_MFRG_ID: + description: use BLE_LL_MANUFACTURER_ID + value: 0x0B65 + deprecated: 1 + BLE_LL_PA: + description: use BLE_FEM_PA + value: 0 + deprecated: 1 + BLE_LL_PA_GPIO: + description: use BLE_FEM_PA_GPIO + value: -1 + deprecated: 1 + BLE_LL_PA_TURN_ON_US: + description: use BLE_FEM_PA_TURN_ON_US + value: 1 + deprecated: 1 + BLE_LL_LNA: + description: use BLE_FEM_LNA + value: 0 + deprecated: 1 + BLE_LL_LNA_GPIO: + description: use BLE_FEM_LNA_GPIO + value: -1 + deprecated: 1 + BLE_LL_LNA_TURN_ON_US: + description: use BLE_FEM_LNA_TURN_ON_US + value: 1 + deprecated: 1 + +# defunct settings (to be removed eventually) + BLE_DEVICE: + description: Superseded by BLE_CONTROLLER + value: 1 + defunct: 1 + BLE_LP_CLOCK: + description: Superseded by BLE_CONTROLLER + value: 1 + defunct: 1 + BLE_NUM_COMP_PKT_RATE: + description: Superseded by BLE_LL_NUM_COMP_PKT_ITVL_MS + value: '(2 * OS_TICKS_PER_SEC)' + defunct: 1 + BLE_LL_MASTER_SCA: + description: use BLE_LL_SCA instead + value: 4 + defunct: 1 + BLE_LL_CFG_FEAT_SLAVE_INIT_FEAT_XCHG: + description: Superseded by BLE_LL_CFG_FEAT_PERIPH_INIT_FEAT_XCHG + value: 0 + defaunt: 1 + BLE_LL_STRICT_CONN_SCHEDULING: + description: Superseded by BLE_LL_CONN_STRICT_SCHED + value: 0 + defunct: 1 + BLE_LL_ADD_STRICT_SCHED_PERIODS: + description: Superseded by BLE_LL_CONN_STRICT_SCHED + value: 0 + defunct: 1 + BLE_LL_USECS_PER_PERIOD: + description: Superseded by BLE_LL_CONN_STRICT_SCHED + value: 0 + defunct: 1 diff --git a/nimble/controller/syscfg.hbd.yml b/nimble/controller/syscfg.hbd.yml new file mode 100644 index 0000000000..ee5a86e942 --- /dev/null +++ b/nimble/controller/syscfg.hbd.yml @@ -0,0 +1,27 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +syscfg.defs: + BLE_LL_HBD_FAKE_DUAL_MODE: + description: > + This enables hacks to allow initialize controler as dual-mode + device. It can be initialized and used by Windows 10 to some + extent. + value: 0 + restrictions: + - '(BLE_TRANSPORT_EVT_SIZE == 257) if 1' diff --git a/nimble/controller/syscfg.yml b/nimble/controller/syscfg.yml index b900ba9106..517cfe0fdf 100644 --- a/nimble/controller/syscfg.yml +++ b/nimble/controller/syscfg.yml @@ -17,11 +17,31 @@ # syscfg.defs: - BLE_CONTROLLER: - description: > - Indicates that NimBLE controller is present. The default value for - this setting shall not be overriden. - value: 1 + BLE_CONTROLLER: 1 + + BLE_LL_ROLE_CENTRAL: + description: 'Enables controller support for the Central role.' + value: MYNEWT_VAL(BLE_ROLE_CENTRAL) + restrictions: + - 'BLE_LL_ROLE_OBSERVER if 1' + + BLE_LL_ROLE_PERIPHERAL: + description: 'Enables controller support for the Peripheral role.' + value: MYNEWT_VAL(BLE_ROLE_PERIPHERAL) + restrictions: + - 'BLE_LL_ROLE_BROADCASTER if 1' + + BLE_LL_ROLE_BROADCASTER: + description: 'Enables controller support for the Broadcaster role.' + value: MYNEWT_VAL(BLE_ROLE_BROADCASTER) + restrictions: + - 'BLE_LL_ROLE_OBSERVER if 0' + + BLE_LL_ROLE_OBSERVER: + description: 'Enables controller support for the Observer role.' + value: MYNEWT_VAL(BLE_ROLE_OBSERVER) + restrictions: + - 'BLE_LL_ROLE_BROADCASTER if 0' BLE_HW_WHITELIST_ENABLE: description: > @@ -44,19 +64,29 @@ syscfg.defs: range: 0..500 BLE_LL_TX_PWR_DBM: - description: 'Transmit power level.' + description: > + Default Transmit power level (in dBm). Actual transmit power + may be rounded up or down depending on used radio. value: '0' + BLE_LL_TX_PWR_MAX_DBM: + description: > + Maximum allowed transmit power level (in dBm). This limits maximum + power to specified value (including FEM and/or host compensation). + Useful for ensuring selected power class of device. Defaults to + maximum allowed by specification (Power Class 1). + value: '20' + BLE_LL_NUM_COMP_PKT_ITVL_MS: description: > Determines the interval at which the controller will send the number of completed packets event to the host. Rate is in milliseconds. value: 2000 - BLE_LL_MFRG_ID: + BLE_LL_MANUFACTURER_ID: description: > - Manufacturer ID. Should be set to unique ID per manufacturer. - value: '0xFFFF' + Manufacturer ID, as assigned by Bluetooth SIG + value: MYNEWT_VAL(BLE_LL_MFRG_ID) # Configuration items for the number of duplicate advertisers and the # number of advertisers from which we have heard a scan response. @@ -77,6 +107,24 @@ syscfg.defs: description: 'Size of the resolving list.' value: '4' + BLE_LL_CONN_PHY_DEFAULT_PREF_MASK: + description: > + Default PHY preference mask used if no HCI LE Set Preferred PHY + was received. + value: 0x07 + BLE_LL_CONN_PHY_PREFER_2M: + description: > + If enabled, LL will always attempt to switch to 2M PHY if present + in preferred mask even if active PHY is also allowed by that mask. + Otherwise LL will not attempt to switch PHY as long as active PHY + is present in preferred mask. + value: 0 + BLE_LL_CONN_PHY_INIT_UPDATE: + description: > + If enabled, LL will attempt to switch PHY (depending on preferences + mask set) after connection was established. + value: 0 + # Data length management definitions for connections. These define the # maximum size of the PDU's that will be sent and/or received in a # connection. @@ -92,11 +140,15 @@ syscfg.defs: BLE_LL_CONN_INIT_MAX_TX_BYTES: description: > Used to set the initial maximum transmit PDU size in a - connection. If this is set to a value greater than 27, - the controller will automatically attempt to do the - data length update procedure. The host can always tell - the controller to update this value. + connection. The host can always tell the controller to update this + value. value: '27' + BLE_LL_CONN_INIT_AUTO_DLE: + description: > + If BLE_LL_CONN_INIT_MAX_TX_BYTES is set to value greater than 27 + controller will automatically attempt to do the data length update + procedure. + value: 1 # The number of slots that will be allocated to each connection BLE_LL_CONN_INIT_SLOTS: @@ -120,26 +172,32 @@ syscfg.defs: ensure interoperability with such devices set this value to 2 (or more). value: '0' - # Strict scheduling - BLE_LL_STRICT_CONN_SCHEDULING: + BLE_LL_CONN_STRICT_SCHED: description: > - Forces the scheduler on a central to schedule connections in fixed - time intervals called periods. If set to 0, the scheduler is not forced - to do this. If set to 1, the scheduler will only schedule connections at - period boundaries. See comments in ble_ll_sched.h for more details. - value: '0' - - BLE_LL_ADD_STRICT_SCHED_PERIODS: + Enable connection strict scheduling (css). + In css mode, connections in central role are scheduled in fixed time + intervals called periods. Each period is divided into an arbitrary + number of slots and each connection anchor point is always scheduled + at slot boundary. This means (assuming only central connections are + active) it's possible to reliably schedule up to number-of-slots + connections each at period-duration interval, each connection will + be allocated at least one slot in each connection event. + value: 0 + BLE_LL_CONN_STRICT_SCHED_FIXED: description: > - The number of additional periods that will be allocated for strict - scheduling. The total # of periods allocated for strict scheduling - will be equal to the number of connections plus this number. - value: '0' - - BLE_LL_USECS_PER_PERIOD: + Enable fixed mode for connection strict scheduling, i.e. slot duration + and slots per period values are fixed to syscfg values and cannot + be changed in runtime. This allows for some compile-time optimizations. + value: 0 + BLE_LL_CONN_STRICT_SCHED_SLOT_US: + description: > + Slot duration in microseconds. Shall be multiply of 1250us. + value: 3750 + BLE_LL_CONN_STRICT_SCHED_PERIOD_SLOTS: description: > - The number of usecs per period. - value: '3250' + Number of slots per period. Duration of slot determines connection + interval used for each connection in central role. + value: 8 # The number of random bytes to store BLE_LL_RNG_BUFSIZE: @@ -163,6 +221,11 @@ syscfg.defs: PHY enabled all the time. value: MYNEWT_VAL(BLE_XTAL_SETTLE_TIME) + BLE_LL_HCI_LLCP_TRACE: + description: > + Enables LLCP tracing using HCI vendor-specific events. + value: '0' + # Configuration for LL supported features. # # There are a total 8 features that the LL can support. These can be found @@ -179,21 +242,21 @@ syscfg.defs: description: > This option enables/disables encryption support in the controller. This option saves both both code and RAM. - value: '1' + value: 'MYNEWT_VAL_BLE_LL_ROLE_CENTRAL || MYNEWT_VAL_BLE_LL_ROLE_PERIPHERAL || MYNEWT_VAL_BLE_LL_ISO' BLE_LL_CFG_FEAT_CONN_PARAM_REQ: description: > This option enables/disables the connection parameter request procedure. This is implemented in the controller but is disabled by default. - value: '1' + value: 'MYNEWT_VAL_BLE_LL_ROLE_CENTRAL || MYNEWT_VAL_BLE_LL_ROLE_PERIPHERAL' - BLE_LL_CFG_FEAT_SLAVE_INIT_FEAT_XCHG: + BLE_LL_CFG_FEAT_PERIPH_INIT_FEAT_XCHG: description: > This option allows a slave to initiate the feature exchange procedure. This feature is implemented but currently has no impact on code or ram size - value: '1' + value: 'MYNEWT_VAL_BLE_LL_ROLE_CENTRAL || MYNEWT_VAL_BLE_LL_ROLE_PERIPHERAL' BLE_LL_CFG_FEAT_LE_PING: description: > @@ -208,7 +271,7 @@ syscfg.defs: the controller. If enabled, the controller is allowed to change the size of tx/rx pdu's used in a connection. This option has only minor impact on code size and non on RAM. - value: '1' + value: 'MYNEWT_VAL_BLE_LL_ROLE_CENTRAL || MYNEWT_VAL_BLE_LL_ROLE_PERIPHERAL' BLE_LL_CFG_FEAT_LL_PRIVACY: description: > @@ -224,12 +287,12 @@ syscfg.defs: BLE_LL_CFG_FEAT_LE_2M_PHY: description: > This option is used to enable/disable support for the 2Mbps PHY. - value: '0' + value: MYNEWT_VAL(BLE_PHY_2M) BLE_LL_CFG_FEAT_LE_CODED_PHY: description: > This option is used to enable/disable support for the coded PHY. - value: '0' + value: MYNEWT_VAL(BLE_PHY_CODED) BLE_LL_CFG_FEAT_LL_EXT_ADV: description: > @@ -243,8 +306,6 @@ syscfg.defs: This option is used to enable/disable support for Periodic Advertising Feature. value: MYNEWT_VAL(BLE_PERIODIC_ADV) - restrictions: - - 'BLE_LL_CFG_FEAT_LL_EXT_ADV if 1' BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_CNT: description: > @@ -258,16 +319,27 @@ syscfg.defs: BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER: description: > - This option is use to enable/disable support for Periodic + This option is used to enable/disable support for Periodic Advertising Sync Transfer Feature. value: MYNEWT_VAL(BLE_PERIODIC_ADV_SYNC_TRANSFER) + BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_ADI_SUPPORT: + description: > + This option is used to enable/disable support for Periodic + Advertising ADI. + value: 0 + restrictions: + - '(BLE_VERSION >= 53) if 1' + - '(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV == 1)' + BLE_LL_CFG_FEAT_CTRL_TO_HOST_FLOW_CONTROL: description: > Enable controller-to-host flow control support. This allows host to limit number of ACL packets sent at once from controller to avoid congestion on HCI transport if feature is also supported by host. value: 0 + restrictions: + - '(BLE_ROLE_CENTRAL || BLE_ROLE_PERIPHERAL) if 1' BLE_LL_CFG_FEAT_LL_SCA_UPDATE: description: > @@ -276,35 +348,52 @@ syscfg.defs: restrictions: - '(BLE_VERSION >= 52) if 1' - BLE_LL_CFG_FEAT_LL_ISO: + BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE: description: > - This option is used to enable/disable support for LE Isochronous Channels - as per Bluetooth v5.2 channels - value: MYNEWT_VAL(BLE_ISO) + Enables support LE Enhanced Connection Update. + This allows to use Conenction Subrate Update and Connection Subrate + Request procedures to modify subrate paramters for a connection. + value: MYNEWT_VAL(BLE_CONN_SUBRATING) restrictions: - - '(BLE_VERSION >= 52) if 1' + - '(BLE_VERSION >= 53) if 1' - BLE_LL_CFG_FEAT_LL_ISO_TEST: + BLE_LL_ADV_CODING_SELECTION: description: > - This option is used to enable/disbale test commands for ISO support - value: MYNEWT_VAL(BLE_ISO_TEST) + Enables support Advertising Coding Selection. + value: 0 restrictions: - - 'BLE_LL_CFG_FEAT_LL_ISO if 1' + - '(BLE_VERSION >= 54) if 1' + + BLE_LL_PERIODIC_ADV_SYNC_BIGINFO_REPORTS: + description: > + This option is used to enable/disable support for + handling BIGInfo data + value: MYNEWT_VAL(BLE_PERIODIC_ADV_SYNC_BIGINFO_REPORTS) + experimental: 1 - BLE_LL_EXT_ADV_AUX_PTR_CNT: + BLE_LL_SCAN_AUX_SEGMENT_CNT: description: > - This option configure a max number of scheduled outstanding auxiliary - packets for receive on secondary advertising channel. - value: 0 + Number of auxiliary advertising segments that can be scanned + concurrently (Core 5.2, Vol 6, Part B, 4.4.2.2.2). + value: MYNEWT_VAL(BLE_LL_EXT_ADV_AUX_PTR_CNT) - BLE_PUBLIC_DEV_ADDR: + BLE_LL_SCAN_ACTIVE_SCAN_NRPA: description: > - Allows the target or app to override the public device address - used by the controller. If all zero, the controller will - attempt to retrieve the public device address from its - chip specific location. If non-zero, this address will - be used. - value: "(uint8_t[6]){0x00, 0x00, 0x00, 0x00, 0x00, 0x00}" + The controller will automatically generate NRPA for scan requests + if host requested to use privacy (i.e. 0x02 or 0x03 own address + type) but the peer is not on the resolving list. + If disabled, public or random address will be used. + value: MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + restrictions: + - BLE_LL_CFG_FEAT_LL_PRIVACY if 1 + + BLE_LL_PUBLIC_DEV_ADDR: + description: > + Set public device address. Address is specified as 48-bit number. + If non-zero, this setting has priority over BLE_PUBLIC_DEV_ADDR. + Note: this setting should only be used for testing purposes, it is + not intended for production builds. + value: 0x000000000000 BLE_LL_DTM: description: > @@ -329,13 +418,158 @@ syscfg.defs: depending on specified HCI command length. value: 0 - BLE_LL_VND_EVENT_ON_ASSERT: + BLE_LL_HCI_VS: + description: > + Enables support for vendor-specific HCI commands. + value: MYNEWT_VAL(BLE_HCI_VS) + BLE_LL_HCI_VS_CONN_STRICT_SCHED: + description: > + Enable HCI commands to control connection strict scheduling. + value: 0 + restrictions: + - BLE_LL_HCI_VS if 1 + BLE_LL_HCI_VS_LOCAL_IRK: + description: > + Enables HCI command to set local IRK. + The local IRK is used by controller to generate RPA address in case + own address type 0x02 or 0x03 was requested by host but there is no + corresponding entry on resolving list. This allows to handle privacy + scenarios almost entirely in controller. If no local IRK is set, the + controller behaves as if feature is not enabled. + value: 0 + restrictions: + - BLE_LL_HCI_VS if 1 + BLE_LL_HCI_VS_SET_SCAN_CFG: + description: > + Enables HCI command to set global PDU filter for scanner. + It allows: + - ignoring extended or legacy PDUs while scanning, + - setting minimal RSSI filter on primary channel + value: 0 + restrictions: + - BLE_LL_HCI_VS if 1 + - BLE_LL_CFG_FEAT_LL_EXT_ADV if 1 + - BLE_LL_ROLE_OBSERVER if 1 + + + BLE_LL_HCI_VS_EVENT_ON_ASSERT: description: > This options enables controller to send a vendor-specific event on an assertion in controller code. The event contains file name and line number where assertion occured. + value: MYNEWT_VAL(BLE_LL_VND_EVENT_ON_ASSERT) + + BLE_FEM_PA: + description: Enable FEM PA support + value: MYNEWT_VAL(BLE_LL_PA) + BLE_FEM_PA_GAIN: + description: PA fixed TX gain (in dBm). + value: 0 + BLE_FEM_PA_GAIN_TUNABLE: + description: > + PA TX gain is tunable and not constant. If enabled + ble_fem_pa_tx_power_set() and ble_fem_pa_tx_power_round() + shall be implemented (see ble_fem.h for details). + value: 0 + BLE_FEM_PA_GPIO: + description: > + GPIO pin number to control PA. Pin is set to high state when PA + should be enabled. + value: MYNEWT_VAL(BLE_LL_PA_GPIO) + BLE_FEM_PA_TURN_ON_US: + description: > + Time required for PA to turn on, in microseconds. + value: MYNEWT_VAL(BLE_LL_PA_TURN_ON_US) + BLE_FEM_LNA: + description: Enable LNA support + value: MYNEWT_VAL(BLE_LL_LNA) + BLE_FEM_LNA_GAIN: + description: LNA fixed RX gain (in dBm). + value: 0 + BLE_FEM_LNA_GAIN_TUNABLE: + description: > + LNA RX gain is tunable and not constant. If enabled + ble_fem_lna_rx_gain() shall be implemented (see ble_fem.h for + details). + value: 0 + BLE_FEM_LNA_GPIO: + description: > + GPIO pin number to control LNA. Pin is set to high state when LNA + should be enabled. + value: MYNEWT_VAL(BLE_LL_LNA_GPIO) + BLE_FEM_LNA_TURN_ON_US: + description: > + Time required for LNA to turn on, in microseconds. + value: MYNEWT_VAL(BLE_LL_LNA_TURN_ON_US) + BLE_FEM_ANTENNA: + description: > + Enable support for runtime antenna selection in FEM. value: 0 + BLE_LL_ISO: + description: > + Enable support for isochronous data. + This enables common code (e.g. ISOAL) for all types of isochronous + data, particular ISO features have to be enabled separately. + restrictions: + - (BLE_VERSION >= 52) if 1 + value: MYNEWT_VAL(BLE_ISO) + state: experimental + BLE_LL_ISO_BROADCASTER: + description: > + Enable support for Isochronous Broadcasting state. + restrictions: + - BLE_LL_ISO if 1 + value: 0 + state: experimental + + BLE_LL_ISO_HCI_FEEDBACK_INTERVAL_MS: + description: > + Enables ISO synchronization feedback using vendor-specific HCI event. + The event is sent at configured interval after completed ISO event + and contains BIG handle, number of expected SDUs per ISO interval + and difference between expected vs actual number of SDUs queued in + controller. + The expected number of SDUs queued after each event is number of + SDUs required for each ISO event (i.e. including pre-transmissions) + minus number of SDUs expected per each ISO interval. + The host can use feedback to e.g. adjust for jitter between audio + clock and LL clock. + Set to 0 to disable. + value: 0 + experimental: 1 + restrictions: + - BLE_LL_HCI_VS || BLE_LL_ISO_HCI_FEEDBACK_INTERVAL_MS == 0 + BLE_LL_ISO_HCI_DISCARD_THRESHOLD: + description: > + Enables automatic discarding of excessive ISO SDUs to avoid exhaustion + of HCI ISO buffers in case host sends too many SDUs. + Threshold is defined as number of ISO events. If number of queued + SDUs exceeds number of SDUs required for single event (i.e. including + pre-transmissions) and number of subsequent ISO events defined by + threshold value, the controller will drop any excessive SDUs and + notify to host as if they were already sent. + Set to 0 to disable. + value: 0 + experimental: 1 + + BLE_LL_ISOAL_MUX_PREFILL: + description: > + Waits until number of SDUs enqueued in mux is enough to fill complete + ISO event before providing data to ISO. + This is useful for pre-transmissions as it ensures that all subevents + in 1st ISO event are non-empty. + value: 0 + experimental: 1 + + BLE_LL_CHANNEL_SOUNDING: + description: > + Enable support for Channel Sounding feature. + restrictions: + - (BLE_VERSION >= 54) if 1 + value: MYNEWT_VAL(BLE_CHANNEL_SOUNDING) + state: experimental + BLE_LL_SYSINIT_STAGE: description: > Sysinit stage for the NimBLE controller. @@ -356,12 +590,23 @@ syscfg.defs: GPIO pin number to debug scheduler running (on timer). Pin is set to high state while scheduler is running. value: -1 - BLE_LL_DEBUG_GPIO_SCHED_ITEM_CB: + BLE_LL_DEBUG_GPIO_SCHED_ITEM: description: > GPIO pin number to debug scheduler item execution times. Pin is set - to high state while item is executed. + to high state while item is active. + value: -1 + BLE_LL_DEBUG_GPIO_RFMGMT: + description: > + GPIO pin number to debug rfmgmt activity. Pin is set to high state + while rfmgmt is active. value: -1 + BLE_LL_EXT: + description: > + Enables API to support external (i.e. non-native to LL) state for + NimBLE LL and scheduler. See ble_ll_ext.h. + experimental: 1 + value: 0 # Below settings allow to change scheduler timings. These should be left at # default values unless you know what you are doing! BLE_LL_SCHED_AUX_MAFS_DELAY: @@ -401,48 +646,53 @@ syscfg.defs: range: 1..257 value: 32 -# deprecated settings (to be defunct/removed eventually) - BLE_LL_DIRECT_TEST_MODE: - description: use BLE_LL_DTM instead - value: 0 - deprecated: 1 - BLE_XTAL_SETTLE_TIME: - description: use BLE_LL_RFMGMT_ENABLE_TIME instead + BLE_LL_CONN_EVENT_END_MARGIN: + description: > + Extra time needed for scheduling next connection event. Setting this + value results in ending connection event sooner (in microseconds) + which gives more time to schedule next event. This value should be + tuned only after measuring performance as depends on various factors + like build optimisation, cache, clock speed etc. value: 0 - deprecated: 1 - BLE_LL_OUR_SCA: - description: use BLE_LL_SCA instead - value: 60 - deprecated: 1 - -# defunct settings (to be removed eventually) - BLE_DEVICE: - description: Superseded by BLE_CONTROLLER - value: 1 - defunct: 1 - BLE_LP_CLOCK: - description: Superseded by BLE_CONTROLLER + + BLE_LL_EXT_ADV_ADVA_IN_AUX: + description: > + Put AdvA in AUX_ADV_IND instead of ADV_EXT_IND. value: 1 - defunct: 1 - BLE_NUM_COMP_PKT_RATE: - description: Superseded by BLE_LL_NUM_COMP_PKT_ITVL_MS - value: '(2 * OS_TICKS_PER_SEC)' - defunct: 1 - BLE_LL_MASTER_SCA: - description: use BLE_LL_SCA instead - value: 4 - defunct: 1 + BLE_LL_STACK_SIZE: + description: > + This is the stack size for LL task. + value: 120 + +syscfg.defs.'BLE_LL_CFG_FEAT_LE_2M_PHY || BLE_LL_CFG_FEAT_LE_CODED_PHY': + BLE_LL_PHY: 1 syscfg.vals.BLE_LL_CFG_FEAT_LL_EXT_ADV: BLE_LL_CFG_FEAT_LE_CSA2: 1 BLE_HW_WHITELIST_ENABLE: 0 - BLE_LL_EXT_ADV_AUX_PTR_CNT: 5 + BLE_LL_SCAN_AUX_SEGMENT_CNT: 8 + +syscfg.vals.'BLE_ISO_BROADCAST_SOURCE || BLE_ISO_BROADCAST_SINK': + BLE_LL_ISO_BROADCASTER: 1 + +syscfg.vals.BLE_LL_ISO_BROADCASTER: + BLE_LL_CFG_FEAT_LE_ENCRYPTION: 1 + BLE_LL_STACK_SIZE: 200 # Enable vendor event on assert in standalone build to make failed assertions in # controller code visible when connected to external host -syscfg.vals.!BLE_HOST: - BLE_LL_VND_EVENT_ON_ASSERT: 1 +syscfg.vals.'!BLE_HOST && !BABBLESIM': + BLE_LL_HCI_VS_EVENT_ON_ASSERT: 1 syscfg.restrictions: - - OS_CPUTIME_FREQ == 32768 + - BLE_TRANSPORT_LL == "native" + - BLE_LL_PUBLIC_DEV_ADDR <= 0xffffffffffff + - BLE_FEM_PA == 0 || BLE_FEM_PA_GPIO >= 0 + - BLE_FEM_LNA == 0 || BLE_FEM_LNA_GPIO >= 0 + +$import: + # defunct and deprecated settings + - "@apache-mynewt-nimble/nimble/controller/syscfg.defunct.yml" + # "Here be dragons" settings + - "@apache-mynewt-nimble/nimble/controller/syscfg.hbd.yml" diff --git a/nimble/controller/test/pkg.yml b/nimble/controller/test/pkg.yml index ea72881149..1b06a5b576 100644 --- a/nimble/controller/test/pkg.yml +++ b/nimble/controller/test/pkg.yml @@ -31,4 +31,4 @@ pkg.deps.SELFTEST: - "@apache-mynewt-core/sys/log/full" - "@apache-mynewt-core/sys/stats/stub" - nimble/drivers/native - - nimble/transport/ram + - nimble/transport diff --git a/nimble/controller/test/src/ble_ll_aa_test.c b/nimble/controller/test/src/ble_ll_aa_test.c new file mode 100644 index 0000000000..4d64d87a00 --- /dev/null +++ b/nimble/controller/test/src/ble_ll_aa_test.c @@ -0,0 +1,103 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include + +TEST_CASE_SELF(ble_ll_aa_test_1) +{ + uint32_t seed_aa; + uint32_t aa; + + seed_aa = 0x78e52493; + + /* BIG Control */ + aa = ble_ll_utils_calc_big_aa(seed_aa, 0); + TEST_ASSERT(aa == 0x7a412493); + + /* BISes */ + aa = ble_ll_utils_calc_big_aa(seed_aa, 1); + TEST_ASSERT(aa == 0x85e32493); + aa = ble_ll_utils_calc_big_aa(seed_aa, 2); + TEST_ASSERT(aa == 0x79d52493); + aa = ble_ll_utils_calc_big_aa(seed_aa, 3); + TEST_ASSERT(aa == 0x86752493); + aa = ble_ll_utils_calc_big_aa(seed_aa, 4); + TEST_ASSERT(aa == 0x7a572493); + aa = ble_ll_utils_calc_big_aa(seed_aa, 5); + TEST_ASSERT(aa == 0x85f12493); + aa = ble_ll_utils_calc_big_aa(seed_aa, 6); + TEST_ASSERT(aa == 0x79d32493); + aa = ble_ll_utils_calc_big_aa(seed_aa, 7); + TEST_ASSERT(aa == 0x86732493); + aa = ble_ll_utils_calc_big_aa(seed_aa, 8); + TEST_ASSERT(aa == 0x7b652493); + aa = ble_ll_utils_calc_big_aa(seed_aa, 9); + TEST_ASSERT(aa == 0x85c72493); + aa = ble_ll_utils_calc_big_aa(seed_aa, 10); + TEST_ASSERT(aa == 0x78e12493); + aa = ble_ll_utils_calc_big_aa(seed_aa, 11); + TEST_ASSERT(aa == 0x86412493); + aa = ble_ll_utils_calc_big_aa(seed_aa, 12); + TEST_ASSERT(aa == 0x7b632493); + aa = ble_ll_utils_calc_big_aa(seed_aa, 13); + TEST_ASSERT(aa == 0x85d52493); + aa = ble_ll_utils_calc_big_aa(seed_aa, 14); + TEST_ASSERT(aa == 0x78f72493); + aa = ble_ll_utils_calc_big_aa(seed_aa, 15); + TEST_ASSERT(aa == 0x86572493); + aa = ble_ll_utils_calc_big_aa(seed_aa, 16); + TEST_ASSERT(aa == 0x7b712493); + aa = ble_ll_utils_calc_big_aa(seed_aa, 17); + TEST_ASSERT(aa == 0x85d32493); + aa = ble_ll_utils_calc_big_aa(seed_aa, 18); + TEST_ASSERT(aa == 0x78c52493); + aa = ble_ll_utils_calc_big_aa(seed_aa, 19); + TEST_ASSERT(aa == 0x87652493); + aa = ble_ll_utils_calc_big_aa(seed_aa, 20); + TEST_ASSERT(aa == 0x7b472493); + aa = ble_ll_utils_calc_big_aa(seed_aa, 21); + TEST_ASSERT(aa == 0x84e12493); + aa = ble_ll_utils_calc_big_aa(seed_aa, 22); + TEST_ASSERT(aa == 0x78c32493); + aa = ble_ll_utils_calc_big_aa(seed_aa, 23); + TEST_ASSERT(aa == 0x87632493); + aa = ble_ll_utils_calc_big_aa(seed_aa, 24); + TEST_ASSERT(aa == 0x7b552493); + aa = ble_ll_utils_calc_big_aa(seed_aa, 25); + TEST_ASSERT(aa == 0x84f72493); + aa = ble_ll_utils_calc_big_aa(seed_aa, 26); + TEST_ASSERT(aa == 0x78d12493); + aa = ble_ll_utils_calc_big_aa(seed_aa, 27); + TEST_ASSERT(aa == 0x87712493); + aa = ble_ll_utils_calc_big_aa(seed_aa, 28); + TEST_ASSERT(aa == 0x7b532493); + aa = ble_ll_utils_calc_big_aa(seed_aa, 29); + TEST_ASSERT(aa == 0x84c52493); + aa = ble_ll_utils_calc_big_aa(seed_aa, 30); + TEST_ASSERT(aa == 0x79e72493); + aa = ble_ll_utils_calc_big_aa(seed_aa, 31); + TEST_ASSERT(aa == 0x87472493); +} + +TEST_SUITE(ble_ll_aa_test_suite) +{ + ble_ll_aa_test_1(); +} diff --git a/nimble/controller/test/src/ble_ll_crypto_test.c b/nimble/controller/test/src/ble_ll_crypto_test.c new file mode 100644 index 0000000000..a2e727a070 --- /dev/null +++ b/nimble/controller/test/src/ble_ll_crypto_test.c @@ -0,0 +1,147 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include + +TEST_CASE_SELF(ble_ll_crypto_test_h6) { + const uint8_t w[] = { + 0xec, 0x02, 0x34, 0xa3, 0x57, 0xc8, 0xad, 0x05, + 0x34, 0x10, 0x10, 0xa6, 0x0a, 0x39, 0x7d, 0x9b + }; + const uint8_t key_id[] = { 0x6c, 0x65, 0x62, 0x72 }; + const uint8_t ok[] = { + 0x2d, 0x9a, 0xe1, 0x02, 0xe7, 0x6d, 0xc9, 0x1c, + 0xe8, 0xd3, 0xa9, 0xe2, 0x80, 0xb1, 0x63, 0x99 + }; + uint8_t out[16]; + int rc; + + rc = ble_ll_crypto_h6(w, key_id, out); + TEST_ASSERT(rc == 0); + + rc = memcmp(out, ok, 16); + TEST_ASSERT(rc == 0); +} + +TEST_CASE_SELF(ble_ll_crypto_test_h7) { + const uint8_t salt[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x74, 0x6D, 0x70, 0x31 + }; + const uint8_t w[] = { + 0xec, 0x02, 0x34, 0xa3, 0x57, 0xc8, 0xad, 0x05, + 0x34, 0x10, 0x10, 0xa6, 0x0a, 0x39, 0x7d, 0x9b + }; + const uint8_t ok[] = { + 0xfb, 0x17, 0x35, 0x97, 0xc6, 0xa3, 0xc0, 0xec, + 0xd2, 0x99, 0x8c, 0x2a, 0x75, 0xa5, 0x70, 0x11 + }; + uint8_t out[16]; + int rc; + + rc = ble_ll_crypto_h7(salt, w, out); + TEST_ASSERT(rc == 0); + + rc = memcmp(out, ok, 16); + TEST_ASSERT(rc == 0); +} + +TEST_CASE_SELF(ble_ll_crypto_test_h8) { + const uint8_t k[] = { + 0xec, 0x02, 0x34, 0xa3, 0x57, 0xc8, 0xad, 0x05, + 0x34, 0x10, 0x10, 0xa6, 0x0a, 0x39, 0x7d, 0x9b + }; + const uint8_t s[] = { + 0x15, 0x36, 0xd1, 0x8d, 0xe3, 0xd2, 0x0d, 0xf9, + 0x9b, 0x70, 0x44, 0xc1, 0x2f, 0x9e, 0xd5, 0xba + }; + const uint8_t key_id[] = { 0xcc, 0x03, 0x01, 0x48 }; + const uint8_t ok[] = { + 0xe5, 0xe5, 0xbe, 0xba, 0xae, 0x72, 0x28, 0xe7, + 0x22, 0xa3, 0x89, 0x04, 0xed, 0x35, 0x0f, 0x6d + }; + uint8_t out[16]; + int rc; + + rc = ble_ll_crypto_h8(k, s, key_id, out); + TEST_ASSERT(rc == 0); + + rc = memcmp(out, ok, 16); + TEST_ASSERT(rc == 0); +} + +TEST_CASE_SELF(ble_ll_crypto_test_gskd) { + const uint8_t broadcast_code[] = { + 0x00, 0x00, 0x00, 0x00, 0x65, 0x73, 0x75, 0x6f, + 0x48, 0x20, 0x65, 0x6e, 0x72, 0xb8, 0xc3, 0x42 + }; + const uint8_t gskd[] = { + 0x55, 0x18, 0x8b, 0x3d, 0x32, 0xf6, 0xbb, 0x9a, + 0x90, 0x0a, 0xfc, 0xfb, 0xee, 0xd4, 0xe7, 0x2a + }; + const uint8_t big1[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x42, 0x49, 0x47, 0x31 + }; + const uint8_t big2[] = { 0x42, 0x49, 0x47, 0x32 }; + const uint8_t big3[] = { 0x42, 0x49, 0x47, 0x33 }; + const uint8_t ok_igltk[] = { + 0x4c, 0x0d, 0xd7, 0x4c, 0x2b, 0x19, 0xaa, 0x95, + 0xd8, 0x98, 0x23, 0x85, 0x5f, 0x10, 0x01, 0xb8 + }; + const uint8_t ok_gltk[] = { + 0xc4, 0xcd, 0x4b, 0x83, 0x49, 0xb5, 0xa1, 0x8a, + 0x02, 0xde, 0x66, 0x20, 0x90, 0x17, 0xae, 0xd3 + }; + const uint8_t ok_gsk[] = { + 0xbe, 0x2a, 0x16, 0xfc, 0x7a, 0xc4, 0x64, 0xe7, + 0x52, 0x30, 0x1b, 0xcc, 0xc8, 0x18, 0x81, 0x2c + }; + uint8_t igltk[16]; + uint8_t gltk[16]; + uint8_t gsk[16]; + int rc; + + rc = ble_ll_crypto_h7(big1, broadcast_code, igltk); + TEST_ASSERT(rc == 0); + + rc = memcmp(igltk, ok_igltk, 16); + TEST_ASSERT(rc == 0); + + rc = ble_ll_crypto_h6(igltk, big2, gltk); + TEST_ASSERT(rc == 0); + + rc = memcmp(gltk, ok_gltk, 16); + TEST_ASSERT(rc == 0); + + rc = ble_ll_crypto_h8(gltk, gskd, big3, gsk); + TEST_ASSERT(rc == 0); + + rc = memcmp(gsk, ok_gsk, 16); + TEST_ASSERT(rc == 0); +} + +TEST_SUITE(ble_ll_crypto_test_suite) { + ble_ll_crypto_test_h6(); + ble_ll_crypto_test_h7(); + ble_ll_crypto_test_h8(); + ble_ll_crypto_test_gskd(); +} diff --git a/nimble/controller/test/src/ble_ll_csa2_test.c b/nimble/controller/test/src/ble_ll_csa2_test.c index 5261eb5beb..7939367e5e 100644 --- a/nimble/controller/test/src/ble_ll_csa2_test.c +++ b/nimble/controller/test/src/ble_ll_csa2_test.c @@ -17,12 +17,10 @@ * under the License. */ -#include -#include -#include "testutil/testutil.h" -#include "controller/ble_ll_test.h" -#include "controller/ble_ll_conn.h" -#include "ble_ll_csa2_test.h" +#include +#include +#include +#include TEST_CASE_SELF(ble_ll_csa2_test_1) { @@ -36,8 +34,7 @@ TEST_CASE_SELF(ble_ll_csa2_test_1) */ memset(&conn, 0, sizeof(conn)); - - CONN_F_CSA2_SUPP(&conn) = 1; + conn.flags.csa2 = 1; /* * based on sample data from CoreSpec 5.0 Vol 6 Part C 3.1 @@ -46,12 +43,12 @@ TEST_CASE_SELF(ble_ll_csa2_test_1) conn.channel_id = ((0x8e89bed6 & 0xffff0000) >> 16) ^ (0x8e89bed6 & 0x0000ffff); - conn.num_used_chans = 37; - conn.chanmap[0] = 0xff; - conn.chanmap[1] = 0xff; - conn.chanmap[2] = 0xff; - conn.chanmap[3] = 0xff; - conn.chanmap[4] = 0x1f; + conn.chan_map_used = 37; + conn.chan_map[0] = 0xff; + conn.chan_map[1] = 0xff; + conn.chan_map[2] = 0xff; + conn.chan_map[3] = 0xff; + conn.chan_map[4] = 0x1f; conn.event_cntr = 1; rc = ble_ll_conn_calc_dci(&conn, 0); @@ -78,8 +75,7 @@ TEST_CASE_SELF(ble_ll_csa2_test_2) */ memset(&conn, 0, sizeof(conn)); - - CONN_F_CSA2_SUPP(&conn) = 1; + conn.flags.csa2 = 1; /* * based on sample data from CoreSpec 5.0 Vol 6 Part C 3.2 @@ -88,12 +84,12 @@ TEST_CASE_SELF(ble_ll_csa2_test_2) conn.channel_id = ((0x8e89bed6 & 0xffff0000) >> 16) ^ (0x8e89bed6 & 0x0000ffff); - conn.num_used_chans = 9; - conn.chanmap[0] = 0x00; - conn.chanmap[1] = 0x06; - conn.chanmap[2] = 0xe0; - conn.chanmap[3] = 0x00; - conn.chanmap[4] = 0x1e; + conn.chan_map_used = 9; + conn.chan_map[0] = 0x00; + conn.chan_map[1] = 0x06; + conn.chan_map[2] = 0xe0; + conn.chan_map[3] = 0x00; + conn.chan_map[4] = 0x1e; conn.event_cntr = 6; rc = ble_ll_conn_calc_dci(&conn, 0); @@ -108,8 +104,179 @@ TEST_CASE_SELF(ble_ll_csa2_test_2) TEST_ASSERT(rc == 34); } +TEST_CASE_SELF(ble_ll_csa2_test_3) +{ + uint8_t chan_map[5]; + uint8_t chan_map_used; + uint16_t chan_id; + uint16_t prn_sub_lu; + uint16_t chan_idx; + uint16_t remap_idx; + + /* Sample data: Core 5.3, Vol 6, Part C, 3.1 */ + chan_map[0] = 0xff; + chan_map[1] = 0xff; + chan_map[2] = 0xff; + chan_map[3] = 0xff; + chan_map[4] = 0x1f; + chan_map_used = ble_ll_utils_chan_map_used_get(chan_map); + TEST_ASSERT(chan_map_used == 37); + chan_id = 0x305f; + + chan_idx = ble_ll_utils_dci_iso_event(0, chan_id, &prn_sub_lu, chan_map_used, chan_map, &remap_idx); + TEST_ASSERT((prn_sub_lu ^ chan_id) == 56857); + TEST_ASSERT(chan_idx == 25); + TEST_ASSERT(remap_idx == 25); + + chan_idx = ble_ll_utils_dci_iso_subevent(chan_id, &prn_sub_lu, chan_map_used, chan_map, &remap_idx); + TEST_ASSERT((prn_sub_lu ^ chan_id) == 11710); + TEST_ASSERT(chan_idx == 1); + TEST_ASSERT(remap_idx == 1); + + chan_idx = ble_ll_utils_dci_iso_subevent(chan_id, &prn_sub_lu, chan_map_used, chan_map, &remap_idx); + TEST_ASSERT((prn_sub_lu ^ chan_id) == 16649); + TEST_ASSERT(chan_idx == 16); + TEST_ASSERT(remap_idx == 16); + + chan_idx = ble_ll_utils_dci_iso_subevent(chan_id, &prn_sub_lu, chan_map_used, chan_map, &remap_idx); + TEST_ASSERT((prn_sub_lu ^ chan_id) == 38198); + TEST_ASSERT(chan_idx == 36); + TEST_ASSERT(remap_idx == 36); + + chan_idx = ble_ll_utils_dci_iso_event(1, chan_id, &prn_sub_lu, chan_map_used, chan_map, &remap_idx); + TEST_ASSERT((prn_sub_lu ^ chan_id) == 1685); + TEST_ASSERT(chan_idx == 20); + TEST_ASSERT(remap_idx == 20); + + chan_idx = ble_ll_utils_dci_iso_subevent(chan_id, &prn_sub_lu, chan_map_used, chan_map, &remap_idx); + TEST_ASSERT((prn_sub_lu ^ chan_id) == 20925); + TEST_ASSERT(chan_idx == 36); + TEST_ASSERT(remap_idx == 36); + + chan_idx = ble_ll_utils_dci_iso_subevent(chan_id, &prn_sub_lu, chan_map_used, chan_map, &remap_idx); + TEST_ASSERT((prn_sub_lu ^ chan_id) == 11081); + TEST_ASSERT(chan_idx == 12); + TEST_ASSERT(remap_idx == 12); + + chan_idx = ble_ll_utils_dci_iso_subevent(chan_id, &prn_sub_lu, chan_map_used, chan_map, &remap_idx); + TEST_ASSERT((prn_sub_lu ^ chan_id) == 48920); + TEST_ASSERT(chan_idx == 34); + TEST_ASSERT(remap_idx == 34); + + chan_idx = ble_ll_utils_dci_iso_event(2, chan_id, &prn_sub_lu, chan_map_used, chan_map, &remap_idx); + TEST_ASSERT((prn_sub_lu ^ chan_id) == 38301); + TEST_ASSERT(chan_idx == 6); + TEST_ASSERT(remap_idx == 6); + + chan_idx = ble_ll_utils_dci_iso_subevent(chan_id, &prn_sub_lu, chan_map_used, chan_map, &remap_idx); + TEST_ASSERT((prn_sub_lu ^ chan_id) == 6541); + TEST_ASSERT(chan_idx == 18); + TEST_ASSERT(remap_idx == 18); + + chan_idx = ble_ll_utils_dci_iso_subevent(chan_id, &prn_sub_lu, chan_map_used, chan_map, &remap_idx); + TEST_ASSERT((prn_sub_lu ^ chan_id) == 14597); + TEST_ASSERT(chan_idx == 32); + TEST_ASSERT(remap_idx == 32); + + chan_idx = ble_ll_utils_dci_iso_subevent(chan_id, &prn_sub_lu, chan_map_used, chan_map, &remap_idx); + TEST_ASSERT((prn_sub_lu ^ chan_id) == 62982); + TEST_ASSERT(chan_idx == 21); + TEST_ASSERT(remap_idx == 21); + + chan_idx = ble_ll_utils_dci_iso_event(3, chan_id, &prn_sub_lu, chan_map_used, chan_map, &remap_idx); + TEST_ASSERT((prn_sub_lu ^ chan_id) == 27475); + TEST_ASSERT(chan_idx == 21); + TEST_ASSERT(remap_idx == 21); + + chan_idx = ble_ll_utils_dci_iso_subevent(chan_id, &prn_sub_lu, chan_map_used, chan_map, &remap_idx); + TEST_ASSERT((prn_sub_lu ^ chan_id) == 40400); + TEST_ASSERT(chan_idx == 4); + TEST_ASSERT(remap_idx == 4); + + chan_idx = ble_ll_utils_dci_iso_subevent(chan_id, &prn_sub_lu, chan_map_used, chan_map, &remap_idx); + TEST_ASSERT((prn_sub_lu ^ chan_id) == 30015); + TEST_ASSERT(chan_idx == 22); + TEST_ASSERT(remap_idx == 22); + + chan_idx = ble_ll_utils_dci_iso_subevent(chan_id, &prn_sub_lu, chan_map_used, chan_map, &remap_idx); + TEST_ASSERT((prn_sub_lu ^ chan_id) == 49818); + TEST_ASSERT(chan_idx == 8); + TEST_ASSERT(remap_idx == 8); + + /* Sample data: Core 5.3, Vol 6, Part C, 3.2 */ + chan_map[0] = 0x00; + chan_map[1] = 0x06; + chan_map[2] = 0xe0; + chan_map[3] = 0x00; + chan_map[4] = 0x1e; + chan_map_used = ble_ll_utils_chan_map_used_get(chan_map); + TEST_ASSERT(chan_map_used == 9); + chan_id = 0x305f; + + chan_idx = ble_ll_utils_dci_iso_event(6, chan_id, &prn_sub_lu, chan_map_used, chan_map, &remap_idx); + TEST_ASSERT((prn_sub_lu ^ chan_id) == 10975); + TEST_ASSERT(chan_idx == 23); + TEST_ASSERT(remap_idx == 4); + + chan_idx = ble_ll_utils_dci_iso_subevent(chan_id, &prn_sub_lu, chan_map_used, chan_map, &remap_idx); + TEST_ASSERT((prn_sub_lu ^ chan_id) == 14383); + TEST_ASSERT(chan_idx == 35); + TEST_ASSERT(remap_idx == 7); + + chan_idx = ble_ll_utils_dci_iso_subevent(chan_id, &prn_sub_lu, chan_map_used, chan_map, &remap_idx); + TEST_ASSERT((prn_sub_lu ^ chan_id) == 28946); + TEST_ASSERT(chan_idx == 21); + TEST_ASSERT(remap_idx == 2); + + chan_idx = ble_ll_utils_dci_iso_subevent(chan_id, &prn_sub_lu, chan_map_used, chan_map, &remap_idx); + TEST_ASSERT((prn_sub_lu ^ chan_id) == 61038); + TEST_ASSERT(chan_idx == 36); + TEST_ASSERT(remap_idx == 8); + + chan_idx = ble_ll_utils_dci_iso_event(7, chan_id, &prn_sub_lu, chan_map_used, chan_map, &remap_idx); + TEST_ASSERT((prn_sub_lu ^ chan_id) == 5490); + TEST_ASSERT(chan_idx == 9); + TEST_ASSERT(remap_idx == 0); + + chan_idx = ble_ll_utils_dci_iso_subevent(chan_id, &prn_sub_lu, chan_map_used, chan_map, &remap_idx); + TEST_ASSERT((prn_sub_lu ^ chan_id) == 4108); + TEST_ASSERT(chan_idx == 22); + TEST_ASSERT(remap_idx == 3); + + chan_idx = ble_ll_utils_dci_iso_subevent(chan_id, &prn_sub_lu, chan_map_used, chan_map, &remap_idx); + TEST_ASSERT((prn_sub_lu ^ chan_id) == 45462); + TEST_ASSERT(chan_idx == 36); + TEST_ASSERT(remap_idx == 8); + + chan_idx = ble_ll_utils_dci_iso_subevent(chan_id, &prn_sub_lu, chan_map_used, chan_map, &remap_idx); + TEST_ASSERT((prn_sub_lu ^ chan_id) == 64381); + TEST_ASSERT(chan_idx == 33); + TEST_ASSERT(remap_idx == 5); + + chan_idx = ble_ll_utils_dci_iso_event(8, chan_id, &prn_sub_lu, chan_map_used, chan_map, &remap_idx); + TEST_ASSERT((prn_sub_lu ^ chan_id) == 46970); + TEST_ASSERT(chan_idx == 34); + TEST_ASSERT(remap_idx == 6); + + chan_idx = ble_ll_utils_dci_iso_subevent(chan_id, &prn_sub_lu, chan_map_used, chan_map, &remap_idx); + TEST_ASSERT((prn_sub_lu ^ chan_id) == 7196); + TEST_ASSERT(chan_idx == 9); + TEST_ASSERT(remap_idx == 0); + + chan_idx = ble_ll_utils_dci_iso_subevent(chan_id, &prn_sub_lu, chan_map_used, chan_map, &remap_idx); + TEST_ASSERT((prn_sub_lu ^ chan_id) == 33054); + TEST_ASSERT(chan_idx == 33); + TEST_ASSERT(remap_idx == 5); + + chan_idx = ble_ll_utils_dci_iso_subevent(chan_id, &prn_sub_lu, chan_map_used, chan_map, &remap_idx); + TEST_ASSERT((prn_sub_lu ^ chan_id) == 42590); + TEST_ASSERT(chan_idx == 10); + TEST_ASSERT(remap_idx == 1); +} + TEST_SUITE(ble_ll_csa2_test_suite) { ble_ll_csa2_test_1(); ble_ll_csa2_test_2(); + ble_ll_csa2_test_3(); } diff --git a/nimble/controller/test/src/ble_ll_iso.c b/nimble/controller/test/src/ble_ll_iso.c new file mode 100644 index 0000000000..2f88214c93 --- /dev/null +++ b/nimble/controller/test/src/ble_ll_iso.c @@ -0,0 +1,191 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#include +#include +#include + +#ifndef min +#define min(a, b) ((a) < (b) ? (a) : (b)) +#endif + +#ifndef max +#define max(a, b) ((a) > (b) ? (a) : (b)) +#endif + +#define TSPX_max_tx_nse 3 +#define TSPX_max_tx_payload 32 + +/* LL.TS.p24 4.11.2 Common Parameters */ +struct test_ll_common_params { + uint8_t TxNumBIS; + uint8_t RxNumBIS; + uint8_t NumDataPDUs; + uint8_t RTN; + uint8_t NSE; + uint8_t IRC; + uint8_t PTO; + uint8_t BN; + uint8_t Transport_Latency; + uint8_t SDU_Interval; + uint8_t ISO_Interval; + uint8_t BIG_Sync_Timeout; + uint8_t Data_Size; + uint8_t PHY; + uint8_t Packing; + uint8_t Framing; + uint8_t Encryption; + uint8_t PADV_Interval; + uint8_t Sync_Timeout; +}; + +const struct test_ll_common_params test_ll_common_params_bn_1 = { + .TxNumBIS = 1, + .RxNumBIS = 1, + .NumDataPDUs = 20, + .RTN = TSPX_max_tx_nse, + .NSE = TSPX_max_tx_nse, + .IRC = TSPX_max_tx_nse, + .PTO = 0, + .BN = 1, + .Transport_Latency = 20, + .SDU_Interval = 10, + .ISO_Interval = 10, + .BIG_Sync_Timeout = 100, + .Data_Size = 0, + .PHY = 0x01, + .Packing = 0x00, + .Framing = 0x00, + .Encryption = 0x00, + .PADV_Interval = 20, + .Sync_Timeout = 100, +}; + +TEST_CASE_SELF(test_ll_ist_brd_bv_01_c) { + const uint8_t payload_types[] = { + BLE_HCI_PAYLOAD_TYPE_ZERO_LENGTH, + BLE_HCI_PAYLOAD_TYPE_VARIABLE_LENGTH, + BLE_HCI_PAYLOAD_TYPE_MAXIMUM_LENGTH + }; + const struct test_ll_common_params *params = &test_ll_common_params_bn_1; + struct ble_hci_le_setup_iso_data_path_cp setup_iso_data_path_cp; + struct ble_hci_le_setup_iso_data_path_rp setup_iso_data_path_rp; + struct ble_hci_le_iso_transmit_test_cp iso_transmit_test_cp; + struct ble_hci_le_iso_transmit_test_rp iso_transmit_test_rp; + struct ble_hci_le_iso_test_end_cp iso_test_end_cp; + struct ble_hci_le_iso_test_end_rp iso_test_end_rp; + struct ble_ll_iso_conn_init_param conn_param = { + .iso_interval_us = params->SDU_Interval * 1000, + .sdu_interval_us = params->SDU_Interval * 1000, + .conn_handle = 0x0001, + .max_sdu = TSPX_max_tx_payload, + .max_pdu = TSPX_max_tx_payload, + .framing = params->Framing, + .bn = params->BN + }; + struct ble_ll_iso_conn conn; + uint8_t payload_type; + uint8_t pdu[100]; + uint8_t llid; + uint8_t rsplen = 0; + int rc; + + ble_ll_iso_conn_init(&conn, &conn_param); + + for (uint8_t i = 0; i < ARRAY_SIZE(payload_types); i++) { + payload_type = payload_types[i]; + + /* 2. The Upper Tester sends the HCI_LE_ISO_Transmit_Test command with Payload_Type as + * specified in Table 4.12-2 and receives a successful HCI_Command_Complete event from the IUT in response. + */ + rsplen = 0xFF; + iso_transmit_test_cp.conn_handle = htole16(conn.handle); + iso_transmit_test_cp.payload_type = payload_type; + rc = ble_ll_iso_transmit_test((uint8_t *)&iso_transmit_test_cp, sizeof(iso_transmit_test_cp), + (uint8_t *)&iso_transmit_test_rp, &rsplen); + TEST_ASSERT(rc == 0); + TEST_ASSERT(rsplen == sizeof(iso_transmit_test_rp)); + TEST_ASSERT(iso_transmit_test_rp.conn_handle == iso_transmit_test_cp.conn_handle); + + /* 3. The IUT sends isochronous data PDUs with Payload as specified in Table 4.12-2. The SDU + * Count value meets the requirements for unframed PDUs as specified in [14] Section 7.1. + * 4. Repeat step 3 for a total of 5 payloads. + */ + for (uint8_t j = 0; j < 5; j++) { + rc = ble_ll_iso_conn_event_start(&conn, 30000); + TEST_ASSERT(rc == 0); + + for (uint8_t k = 0; k < conn_param.bn; k++) { + llid = 0xFF; + rc = ble_ll_iso_pdu_get(&conn, k, k, &llid, pdu); + if (payload_type == BLE_HCI_PAYLOAD_TYPE_ZERO_LENGTH) { + TEST_ASSERT(rc == 0); + TEST_ASSERT(llid == 0b00); + } else if (payload_type == BLE_HCI_PAYLOAD_TYPE_VARIABLE_LENGTH) { + TEST_ASSERT(rc >= 4); + TEST_ASSERT(llid == 0b00); + } else if (payload_type == BLE_HCI_PAYLOAD_TYPE_MAXIMUM_LENGTH) { + TEST_ASSERT(rc == conn_param.max_pdu); + TEST_ASSERT(llid == 0b00); + } + } + + rc = ble_ll_iso_conn_event_done(&conn); + TEST_ASSERT(rc == 0); + } + + /* 5. The Upper Tester sends an HCI_LE_Setup_ISO_Data_Path command to the IUT. + * 6. The IUT sends an HCI_Command_Complete event to the Upper Tester with Status set to 0x0C. + */ + setup_iso_data_path_cp.conn_handle = htole16(conn.handle); + setup_iso_data_path_cp.data_path_dir = 0x00; + setup_iso_data_path_cp.data_path_id = 0x00; + rc = ble_ll_iso_setup_iso_data_path((uint8_t *)&setup_iso_data_path_cp, sizeof(setup_iso_data_path_cp), + (uint8_t *)&setup_iso_data_path_rp, &rsplen); + TEST_ASSERT(rc == 0x0C); + + /* 7. The Upper Tester sends the HCI_LE_ISO_Test_End command to the IUT and receives an + * HCI_Command_Status event from the IUT with the Status field set to Success. The returned + * Received_SDU_Count, Missed_SDU_Count, and Failed_SDU_Count are all zero. + */ + rsplen = 0xFF; + iso_test_end_cp.conn_handle = htole16(conn.handle); + rc = ble_ll_iso_end_test((uint8_t *)&iso_test_end_cp, sizeof(iso_test_end_cp), + (uint8_t *)&iso_test_end_rp, &rsplen); + TEST_ASSERT(rc == 0); + TEST_ASSERT(rsplen == sizeof(iso_test_end_rp)); + TEST_ASSERT(iso_test_end_rp.conn_handle == iso_test_end_cp.conn_handle); + TEST_ASSERT(iso_test_end_rp.received_sdu_count == 0); + TEST_ASSERT(iso_test_end_rp.missed_sdu_count == 0); + TEST_ASSERT(iso_test_end_rp.failed_sdu_count == 0); + } + + ble_ll_iso_conn_free(&conn); +} + +TEST_SUITE(ble_ll_iso_test_suite) { + ble_ll_iso_init(); + + test_ll_ist_brd_bv_01_c(); + + ble_ll_iso_reset(); +} diff --git a/nimble/controller/test/src/ble_ll_isoal.c b/nimble/controller/test/src/ble_ll_isoal.c new file mode 100644 index 0000000000..b7c0aa2c35 --- /dev/null +++ b/nimble/controller/test/src/ble_ll_isoal.c @@ -0,0 +1,1332 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#include +#include +#include + +#define TSPX_max_sdu_length (503) +#define HCI_iso_sdu_max (MYNEWT_VAL(BLE_TRANSPORT_ISO_SIZE) - 4) + +#define MBUF_TEST_POOL_BUF_SIZE (TSPX_max_sdu_length + BLE_MBUF_MEMBLOCK_OVERHEAD) +#define MBUF_TEST_POOL_BUF_COUNT (10) + +os_membuf_t os_mbuf_membuf[OS_MEMPOOL_SIZE(MBUF_TEST_POOL_BUF_SIZE, MBUF_TEST_POOL_BUF_COUNT)]; + +static struct os_mbuf_pool os_mbuf_pool; +static struct os_mempool os_mbuf_mempool; +static uint8_t os_mbuf_test_data[TSPX_max_sdu_length]; + +void +os_mbuf_test_setup(void) +{ + int rc; + int i; + + rc = os_mempool_init(&os_mbuf_mempool, MBUF_TEST_POOL_BUF_COUNT, + MBUF_TEST_POOL_BUF_SIZE, &os_mbuf_membuf[0], "mbuf_pool"); + TEST_ASSERT_FATAL(rc == 0, "Error creating memory pool %d", rc); + + rc = os_mbuf_pool_init(&os_mbuf_pool, &os_mbuf_mempool, + MBUF_TEST_POOL_BUF_SIZE, MBUF_TEST_POOL_BUF_COUNT); + TEST_ASSERT_FATAL(rc == 0, "Error creating mbuf pool %d", rc); + + for (i = 0; i < sizeof os_mbuf_test_data; i++) { + os_mbuf_test_data[i] = i; + } + + TEST_ASSERT_FATAL(os_mbuf_mempool.mp_block_size == MBUF_TEST_POOL_BUF_SIZE, + "mp_block_size is %d", os_mbuf_mempool.mp_block_size); + TEST_ASSERT_FATAL(os_mbuf_mempool.mp_num_free == MBUF_TEST_POOL_BUF_COUNT, + "mp_num_free is %d", os_mbuf_mempool.mp_num_free); +} + +TEST_CASE_SELF(test_ble_ll_isoal_mux_init) { + struct ble_ll_isoal_mux mux; + const uint32_t iso_interval_us = 10000; + const uint32_t sdu_interval_us = 10000; + const bool Framed = 0; + const bool Framing_Mode = 0; + const uint8_t bn = 1; + const uint8_t max_pdu = 250; + + ble_ll_isoal_mux_init(&mux, max_pdu, iso_interval_us, sdu_interval_us, bn, + 0, Framed, Framing_Mode); + + TEST_ASSERT(mux.pdu_per_sdu == (bn * sdu_interval_us) / iso_interval_us); + + ble_ll_isoal_mux_free(&mux); +} + +TEST_CASE_SELF(ble_ll_isoal_mux_pdu_get_unframed_1_sdu_2_pdu) { + struct ble_ll_isoal_mux mux; + struct os_mbuf *sdu_1, *sdu_2; + const uint32_t iso_interval_us = 20000; + const uint32_t sdu_interval_us = 10000; + const bool Framed = 0; + const bool Framing_Mode = 0; + const uint8_t bn = 6; + const uint8_t max_pdu = 40; + const uint8_t sdu_len = 3 * max_pdu; + static uint8_t data[40]; + int num_completed_pkt; + int pdu_len; + uint8_t llid = 0x00; + int rc; + + ble_ll_isoal_mux_init(&mux, max_pdu, iso_interval_us, sdu_interval_us, bn, + 0, Framed, Framing_Mode); + + /* SDU #1 */ + sdu_1 = os_mbuf_get_pkthdr(&os_mbuf_pool, sizeof(struct ble_mbuf_hdr)); + TEST_ASSERT_FATAL(sdu_1 != NULL); + rc = os_mbuf_append(sdu_1, os_mbuf_test_data, sdu_len); + TEST_ASSERT_FATAL(rc == 0); + ble_ll_isoal_mux_sdu_enqueue(&mux, sdu_1); + + /* SDU #2 */ + sdu_2 = os_mbuf_get_pkthdr(&os_mbuf_pool, sizeof(struct ble_mbuf_hdr)); + TEST_ASSERT_FATAL(sdu_2 != NULL); + rc = os_mbuf_append(sdu_2, os_mbuf_test_data, sdu_len); + TEST_ASSERT_FATAL(rc == 0); + ble_ll_isoal_mux_sdu_enqueue(&mux, sdu_2); + + ble_ll_isoal_mux_event_start(&mux, 90990); + + /* PDU #1 */ + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 0, &llid, data); + TEST_ASSERT(pdu_len == max_pdu, "PDU length is incorrect %d", pdu_len); + /* Unframed CIS Data PDU; start or continuation fragment of an SDU. */ + TEST_ASSERT(llid == 0b01, "LLID is incorrect %d", llid); + + /* PDU #2 */ + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 1, &llid, data); + TEST_ASSERT(pdu_len == max_pdu, "PDU length is incorrect %d", pdu_len); + /* Unframed CIS Data PDU; start or continuation fragment of an SDU. */ + TEST_ASSERT(llid == 0b01, "LLID is incorrect %d", llid); + + /* PDU #3 */ + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 2, &llid, data); + TEST_ASSERT(pdu_len == max_pdu, "PDU length is incorrect %d", pdu_len); + /* Unframed CIS Data PDU; end fragment of an SDU or a complete SDU. */ + TEST_ASSERT(llid == 0b00, "LLID is incorrect %d", llid); + + /* PDU #4 */ + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 0, &llid, data); + TEST_ASSERT(pdu_len == max_pdu, "PDU length is incorrect %d", pdu_len); + /* Unframed CIS Data PDU; start or continuation fragment of an SDU. */ + TEST_ASSERT(llid == 0b01, "LLID is incorrect %d", llid); + + /* PDU #5 */ + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 1, &llid, data); + TEST_ASSERT(pdu_len == max_pdu, "PDU length is incorrect %d", pdu_len); + /* Unframed CIS Data PDU; start or continuation fragment of an SDU. */ + TEST_ASSERT(llid == 0b01, "LLID is incorrect %d", llid); + + /* PDU #6 */ + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 2, &llid, data); + TEST_ASSERT(pdu_len == max_pdu, "PDU length is incorrect %d", pdu_len); + /* Unframed CIS Data PDU; end fragment of an SDU or a complete SDU. */ + TEST_ASSERT(llid == 0b00, "LLID is incorrect %d", llid); + + num_completed_pkt = ble_ll_isoal_mux_event_done(&mux); + TEST_ASSERT(num_completed_pkt > 0, "num_completed_pkt is incorrect %d", num_completed_pkt); + + ble_ll_isoal_mux_free(&mux); +} + +TEST_CASE_SELF(test_ble_ll_isoal_mux_get_unframed_pdu) { + struct ble_ll_isoal_mux mux; + struct os_mbuf *sdu_1, *sdu_2; + const uint32_t iso_interval_us = 20000; + const uint32_t sdu_interval_us = 10000; + const bool Framed = 0; + const bool Framing_Mode = 0; + const uint8_t bn = 6; + const uint8_t max_pdu = 40; + const uint8_t sdu_len = 3 * max_pdu; + static uint8_t data[40]; + int num_completed_pkt; + int pdu_len; + uint8_t llid = 0x00; + int rc; + + ble_ll_isoal_mux_init(&mux, max_pdu, iso_interval_us, sdu_interval_us, bn, + 0, Framed, Framing_Mode); + + /* SDU #1 */ + sdu_1 = os_mbuf_get_pkthdr(&os_mbuf_pool, sizeof(struct ble_mbuf_hdr)); + TEST_ASSERT_FATAL(sdu_1 != NULL); + rc = os_mbuf_append(sdu_1, os_mbuf_test_data, sdu_len); + TEST_ASSERT_FATAL(rc == 0); + ble_ll_isoal_mux_sdu_enqueue(&mux, sdu_1); + + /* SDU #2 */ + sdu_2 = os_mbuf_get_pkthdr(&os_mbuf_pool, sizeof(struct ble_mbuf_hdr)); + TEST_ASSERT_FATAL(sdu_2 != NULL); + rc = os_mbuf_append(sdu_2, os_mbuf_test_data, sdu_len); + TEST_ASSERT_FATAL(rc == 0); + ble_ll_isoal_mux_sdu_enqueue(&mux, sdu_2); + + ble_ll_isoal_mux_event_start(&mux, 90990); + + /* PDU #1 */ + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 0, &llid, data); + TEST_ASSERT(pdu_len == max_pdu, "PDU length is incorrect %d", pdu_len); + /* Unframed CIS Data PDU; start or continuation fragment of an SDU. */ + TEST_ASSERT(llid == 0b01, "LLID is incorrect %d", llid); + + /* PDU #2 */ + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 1, &llid, data); + TEST_ASSERT(pdu_len == max_pdu, "PDU length is incorrect %d", pdu_len); + /* Unframed CIS Data PDU; start or continuation fragment of an SDU. */ + TEST_ASSERT(llid == 0b01, "LLID is incorrect %d", llid); + + /* PDU #3 */ + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 2, &llid, data); + TEST_ASSERT(pdu_len == max_pdu, "PDU length is incorrect %d", pdu_len); + /* Unframed CIS Data PDU; end fragment of an SDU or a complete SDU. */ + TEST_ASSERT(llid == 0b00, "LLID is incorrect %d", llid); + + /* PDU #4 */ + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 0, &llid, data); + TEST_ASSERT(pdu_len == max_pdu, "PDU length is incorrect %d", pdu_len); + /* Unframed CIS Data PDU; start or continuation fragment of an SDU. */ + TEST_ASSERT(llid == 0b01, "LLID is incorrect %d", llid); + + /* PDU #5 */ + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 1, &llid, data); + TEST_ASSERT(pdu_len == max_pdu, "PDU length is incorrect %d", pdu_len); + /* Unframed CIS Data PDU; start or continuation fragment of an SDU. */ + TEST_ASSERT(llid == 0b01, "LLID is incorrect %d", llid); + + /* PDU #6 */ + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 2, &llid, data); + TEST_ASSERT(pdu_len == max_pdu, "PDU length is incorrect %d", pdu_len); + /* Unframed CIS Data PDU; end fragment of an SDU or a complete SDU. */ + TEST_ASSERT(llid == 0b00, "LLID is incorrect %d", llid); + + num_completed_pkt = ble_ll_isoal_mux_event_done(&mux); + TEST_ASSERT(num_completed_pkt > 0, "num_completed_pkt is incorrect %d", + num_completed_pkt); + + ble_ll_isoal_mux_free(&mux); +} + +TEST_CASE_SELF(test_ble_ll_isoal_mux_sdu_not_in_event) { + struct ble_ll_isoal_mux mux; + struct os_mbuf *sdu_1; + const uint32_t iso_interval_us = 10000; + const uint32_t sdu_interval_us = 10000; + const bool Framed = 1; + const bool Framing_Mode = 0; + const uint8_t bn = 2; + const uint8_t max_pdu = 40; + const uint8_t sdu_len = 40; + static uint8_t data[40]; + int num_completed_pkt; + int pdu_len; + uint8_t llid = 0x00; + int rc; + + ble_ll_isoal_mux_init(&mux, max_pdu, iso_interval_us, sdu_interval_us, bn, + 0, Framed, Framing_Mode); + + ble_ll_isoal_mux_event_start(&mux, 90990); + TEST_ASSERT_FATAL(mux.sdu_in_event == 0, + "sdu_in_event %d != 0", mux.sdu_in_event); + + /* SDU #1 */ + sdu_1 = os_mbuf_get_pkthdr(&os_mbuf_pool, sizeof(struct ble_mbuf_hdr)); + TEST_ASSERT_FATAL(sdu_1 != NULL); + rc = os_mbuf_append(sdu_1, os_mbuf_test_data, sdu_len); + TEST_ASSERT_FATAL(rc == 0); + ble_ll_isoal_mux_sdu_enqueue(&mux, sdu_1); + + TEST_ASSERT_FATAL(mux.sdu_in_event == 0, + "sdu_in_event %d != 0", mux.sdu_in_event); + + /* PDU #1 */ + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 0, &llid, data); + TEST_ASSERT(pdu_len == 0, "PDU length is incorrect %d", pdu_len); + TEST_ASSERT(llid == 0b10, "LLID is incorrect %d", llid); + + /* PDU #2 */ + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 1, &llid, data); + TEST_ASSERT(pdu_len == 0, "PDU length is incorrect %d", pdu_len); + TEST_ASSERT(llid == 0b10, "LLID is incorrect %d", llid); + + num_completed_pkt = ble_ll_isoal_mux_event_done(&mux); + TEST_ASSERT(num_completed_pkt == 0, "num_completed_pkt is incorrect %d", + num_completed_pkt); + + ble_ll_isoal_mux_free(&mux); +} + +static int +test_sdu_enqueue(struct ble_ll_isoal_mux *mux, uint16_t sdu_len, + uint16_t packet_seq_num, uint32_t timestamp) +{ + struct ble_mbuf_hdr *blehdr; + struct os_mbuf *sdu, *frag; + uint16_t sdu_frag_len; + uint16_t offset = 0; + uint8_t num_pkt = 0; + int rc; + + TEST_ASSERT_FATAL(sdu_len <= TSPX_max_sdu_length, "incorrect sdu length"); + + sdu = os_mbuf_get_pkthdr(&os_mbuf_pool, sizeof(struct ble_mbuf_hdr)); + TEST_ASSERT_FATAL(sdu != NULL); + blehdr = BLE_MBUF_HDR_PTR(sdu); + blehdr->txiso.packet_seq_num = packet_seq_num; + blehdr->txiso.cpu_timestamp = timestamp; + + /* First SDU Fragment */ + sdu_frag_len = min(sdu_len, HCI_iso_sdu_max); + rc = os_mbuf_append(sdu, os_mbuf_test_data, sdu_frag_len); + TEST_ASSERT_FATAL(rc == 0); + + offset += sdu_frag_len; + num_pkt++; + + while (offset < sdu_len) { + frag = os_mbuf_get_pkthdr(&os_mbuf_pool, sizeof(struct ble_mbuf_hdr)); + TEST_ASSERT_FATAL(frag != NULL); + + /* Subsequent SDU Fragments */ + sdu_frag_len = min(sdu_len - offset, HCI_iso_sdu_max); + rc = os_mbuf_append(sdu, &os_mbuf_test_data[offset], sdu_frag_len); + TEST_ASSERT_FATAL(rc == 0); + + offset += sdu_frag_len; + num_pkt++; + + os_mbuf_concat(sdu, frag); + } + + ble_ll_isoal_mux_sdu_enqueue(mux, sdu); + + return num_pkt; +} + +static void +test_pdu_verify(uint8_t *pdu, int pdu_len, uint16_t sdu_offset) +{ + for (int i = 0; i < pdu_len; i++) { + TEST_ASSERT(pdu[i] == os_mbuf_test_data[sdu_offset + i], + "PDU verification failed pdu[%d] %d != %d", + i, pdu[i], os_mbuf_test_data[sdu_offset + i]); + } +} + +struct test_ial_broadcast_single_sdu_bis_cfg { + uint8_t NSE; + uint8_t Framed; + uint8_t Framing_Mode; + uint8_t Max_PDU; + uint8_t LLID; + uint8_t BN; + uint32_t SDU_Interval; + uint32_t ISO_Interval; +}; + +static void +test_ial_teardown(struct ble_ll_isoal_mux *mux) +{ + ble_ll_isoal_mux_free(mux); + TEST_ASSERT_FATAL(os_mbuf_mempool.mp_block_size == MBUF_TEST_POOL_BUF_SIZE, + "mp_block_size is %d", os_mbuf_mempool.mp_block_size); + TEST_ASSERT_FATAL(os_mbuf_mempool.mp_num_free == MBUF_TEST_POOL_BUF_COUNT, + "mp_num_free is %d", os_mbuf_mempool.mp_num_free); +} + +static void +test_ial_setup(struct ble_ll_isoal_mux *mux, uint8_t max_pdu, + uint32_t iso_interval_us, uint32_t sdu_interval_us, + uint8_t bn, uint8_t pte, bool framed, uint8_t framing_mode) +{ + ble_ll_isoal_mux_init(mux, max_pdu, iso_interval_us, sdu_interval_us, + bn, pte, framed, framing_mode); +} + +static void +test_ial_broadcast_single_sdu_bis(const struct test_ial_broadcast_single_sdu_bis_cfg *cfg) +{ + struct ble_ll_isoal_mux mux; + int num_completed_pkt; + int pdu_len; + uint32_t timeoffset; + uint16_t seg_hdr; + const uint8_t Max_SDU = 32; + uint8_t pdu[cfg->Max_PDU]; + uint8_t llid = 0xff; + + test_ial_setup(&mux, cfg->Max_PDU, cfg->ISO_Interval, + cfg->SDU_Interval, cfg->BN, 0, cfg->Framed, + cfg->Framing_Mode); + + /* Send Single SDU */ + test_sdu_enqueue(&mux, Max_SDU, 0, 20000); + + ble_ll_isoal_mux_event_start(&mux, 30500); + + /* PDU #1 */ + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 0, &llid, pdu); + TEST_ASSERT(llid == cfg->LLID, "LLID is incorrect %d", llid); + + if (cfg->Framed) { + TEST_ASSERT(pdu_len == 2 /* Header */ + 3 /* TimeOffset */ + Max_SDU, + "PDU length is incorrect %d", pdu_len); + seg_hdr = get_le16(&pdu[0]); + TEST_ASSERT(BLE_LL_ISOAL_SEGHDR_SC(seg_hdr) == 0, "SC is incorrect %d", + BLE_LL_ISOAL_SEGHDR_SC(seg_hdr)); + TEST_ASSERT(BLE_LL_ISOAL_SEGHDR_CMPLT(seg_hdr) == 1, "CMPLT is incorrect %d", + BLE_LL_ISOAL_SEGHDR_CMPLT(seg_hdr)); + TEST_ASSERT(BLE_LL_ISOAL_SEGHDR_LEN(seg_hdr) == 3 /* TimeOffset */ + Max_SDU, + "Length is incorrect %d", BLE_LL_ISOAL_SEGHDR_LEN(seg_hdr)); + timeoffset = get_le24(&pdu[2]); + TEST_ASSERT(timeoffset == 10500, "Time offset is incorrect %d", timeoffset); + + test_pdu_verify(&pdu[5], Max_SDU, 0); + } else { + TEST_ASSERT(pdu_len == Max_SDU, "PDU length is incorrect %d", pdu_len); + + test_pdu_verify(&pdu[0], Max_SDU, 0); + } + + num_completed_pkt = ble_ll_isoal_mux_event_done(&mux); + TEST_ASSERT(num_completed_pkt > 0, "num_completed_pkt is incorrect %d", num_completed_pkt); + + test_ial_teardown(&mux); +} + +TEST_CASE_SELF(test_ial_bis_unf_brd_bv_01_c) { + const struct test_ial_broadcast_single_sdu_bis_cfg cfg = { + .NSE = 2, + .Framed = 0, + .Framing_Mode = 0, + .Max_PDU = 40, + .LLID = 0b00, + .BN = 1, + .SDU_Interval = 10000, + .ISO_Interval = 10000, + }; + + test_ial_broadcast_single_sdu_bis(&cfg); +} + +TEST_CASE_SELF(test_ial_bis_unf_brd_bv_02_c) { + const struct test_ial_broadcast_single_sdu_bis_cfg cfg = { + .NSE = 4, + .Framed = 0, + .Framing_Mode = 0, + .Max_PDU = 40, + .LLID = 0b00, + .BN = 2, + .SDU_Interval = 5000, + .ISO_Interval = 10000, + }; + + test_ial_broadcast_single_sdu_bis(&cfg); +} + +TEST_CASE_SELF(test_ial_bis_fra_brd_bv_06_c) { + const struct test_ial_broadcast_single_sdu_bis_cfg cfg = { + .NSE = 4, + .Framed = 1, + .Framing_Mode = 0, + .Max_PDU = 40, + .LLID = 0b10, + .BN = 2, + .SDU_Interval = 5000, + .ISO_Interval = 10000, + }; + + test_ial_broadcast_single_sdu_bis(&cfg); +} + +TEST_CASE_SELF(test_ial_bis_fra_brd_bv_08_c) { + const struct test_ial_broadcast_single_sdu_bis_cfg cfg = { + .NSE = 2, + .Framed = 1, + .Framing_Mode = 0, + .Max_PDU = 40, + .LLID = 0b10, + .BN = 1, + .SDU_Interval = 10000, + .ISO_Interval = 10000, + }; + + test_ial_broadcast_single_sdu_bis(&cfg); +} + +TEST_CASE_SELF(test_ial_bis_fra_brd_bv_29_c) { + const struct test_ial_broadcast_single_sdu_bis_cfg cfg = { + .NSE = 6, + .Framed = 1, + .Framing_Mode = 1, + .Max_PDU = 32 + 5, + .LLID = 0b10, + .BN = 3, + .SDU_Interval = 5000, + .ISO_Interval = 10000, + }; + + test_ial_broadcast_single_sdu_bis(&cfg); +} + +struct test_ial_broadcast_large_sdu_bis_cfg { + uint8_t NSE; + uint8_t Framed; + uint8_t Framing_Mode; + uint8_t BN; + uint32_t SDU_Interval; + uint32_t ISO_Interval; +}; +struct test_ial_broadcast_large_sdu_bis_round { + uint16_t sdu_len; + uint8_t sc_packets_num; +}; + +static void +test_ial_broadcast_large_sdu_bis(const struct test_ial_broadcast_large_sdu_bis_cfg *cfg) +{ + const struct test_ial_broadcast_large_sdu_bis_round rounds[] = { + {.sdu_len = 495, .sc_packets_num = 1}, + {.sdu_len = 503, .sc_packets_num = 2}, + }; + struct ble_ll_isoal_mux mux; + /* const uint16_t Max_SDU = 503; */ + const uint8_t Max_PDU = 251; + int num_completed_pkt; + int num_expected_pkt; + int pdu_len; + uint8_t pdu[Max_PDU]; + uint32_t timestamp; + uint16_t seg_hdr; + uint16_t sdu_offset; + uint8_t llid = 0xff; + uint8_t sc_packets_num; + uint8_t seg_len; + uint8_t idx; + + test_ial_setup(&mux, Max_PDU, cfg->ISO_Interval, + cfg->SDU_Interval, cfg->BN, 0, cfg->Framed, + cfg->Framing_Mode); + + for (size_t round = 0; round < ARRAY_SIZE(rounds); round++) { + sc_packets_num = 0; + sdu_offset = 0; + + timestamp = (round + 1) * cfg->SDU_Interval; + + num_expected_pkt = test_sdu_enqueue(&mux, rounds[round].sdu_len, round, timestamp); + + ble_ll_isoal_mux_event_start(&mux, timestamp + 100); + + for (idx = 0; idx < cfg->BN; idx++) { + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, idx, &llid, pdu); + if (pdu_len == 0) { + TEST_ASSERT_FATAL(sdu_offset == rounds[round].sdu_len, + "Round #%d: idx %d sdu_offset %d", + round, idx, sdu_offset); + continue; + } + + /* The IUT sends the specified number of Start/Continuation + * packets specified in Table 4.29 of ISO Data PDUs to the + * Lower Tester with the LLID=0b01 for unframed payloads and + * LLID=0b10 for framed payloads, and Payload Data every 251 + * bytes offset in step 1. + */ + if (sc_packets_num < rounds[round].sc_packets_num) { + TEST_ASSERT_FATAL(pdu_len == 251, "Round #%d: idx #%d: Length is incorrect %d", + round, idx, pdu_len); + + if (cfg->Framed) { + TEST_ASSERT_FATAL(llid == 0b10, "Round #%d: LLID is incorrect %d", round, llid); + + seg_hdr = get_le16(&pdu[0]); + seg_len = BLE_LL_ISOAL_SEGHDR_LEN(seg_hdr); + if (idx == 0) { + TEST_ASSERT_FATAL(BLE_LL_ISOAL_SEGHDR_SC(seg_hdr) == 0, + "Round #%d: SC is incorrect %d", + round, BLE_LL_ISOAL_SEGHDR_SC(seg_hdr)); + + test_pdu_verify(&pdu[5], seg_len - 3, 0); + sdu_offset += seg_len - 3; + } else { + TEST_ASSERT_FATAL(BLE_LL_ISOAL_SEGHDR_SC(seg_hdr) == 1, + "Round #%d: SC is incorrect %d", + round, BLE_LL_ISOAL_SEGHDR_SC(seg_hdr)); + + test_pdu_verify(&pdu[2], seg_len, sdu_offset); + sdu_offset += seg_len; + } + } else { + TEST_ASSERT_FATAL(llid == 0b01, "Round #%d: LLID is incorrect %d", round, llid); + + test_pdu_verify(&pdu[0], pdu_len, sdu_offset); + sdu_offset += pdu_len; + } + + sc_packets_num++; + } else { + /* The IUT sends the last ISO Data PDU to the Lower Tester + * with the LLID=0b00 for unframed payloads and LLID=0b10 + * for framed payloads, with the remaining Payload Data. + */ + if (cfg->Framed) { + TEST_ASSERT_FATAL(pdu_len == rounds[round].sdu_len - sdu_offset + 2, + "Round #%d: idx %d: PDU length is incorrect %d != %d", + round, idx, pdu_len, rounds[round].sdu_len - sdu_offset + 2); + TEST_ASSERT_FATAL(llid == 0b10, "Round #%d: LLID is incorrect %d", + round, llid); + + seg_hdr = get_le16(&pdu[0]); + TEST_ASSERT_FATAL(BLE_LL_ISOAL_SEGHDR_SC(seg_hdr), + "Round #%d: SC is incorrect %d", + round, BLE_LL_ISOAL_SEGHDR_SC(seg_hdr)); + TEST_ASSERT_FATAL(BLE_LL_ISOAL_SEGHDR_CMPLT(seg_hdr), + "Round #%d: CMPLT is incorrect %d", + round, BLE_LL_ISOAL_SEGHDR_CMPLT(seg_hdr)); + seg_len = BLE_LL_ISOAL_SEGHDR_LEN(seg_hdr); + + test_pdu_verify(&pdu[2], seg_len, sdu_offset); + sdu_offset += seg_len; + } else { + TEST_ASSERT_FATAL(pdu_len == rounds[round].sdu_len - sdu_offset, + "Round #%d: idx %d: PDU length is incorrect %d != %d", + round, idx, pdu_len, rounds[round].sdu_len - sdu_offset); + TEST_ASSERT_FATAL(llid == 0b00, "Round #%d: LLID is incorrect %d", round, llid); + + test_pdu_verify(&pdu[0], pdu_len, sdu_offset); + sdu_offset += pdu_len; + } + } + } + + num_completed_pkt = ble_ll_isoal_mux_event_done(&mux); + TEST_ASSERT(num_completed_pkt == num_expected_pkt, + "num_completed_pkt %d != %d", num_completed_pkt, num_expected_pkt); + } + + test_ial_teardown(&mux); +} + +TEST_CASE_SELF(test_ial_bis_unf_brd_bv_09_c) { + const struct test_ial_broadcast_large_sdu_bis_cfg cfg = { + .NSE = 12, + .Framed = 0, + .Framing_Mode = 0, + .BN = 6, + .SDU_Interval = 20000, + .ISO_Interval = 40000, + }; + + test_ial_broadcast_large_sdu_bis(&cfg); +} + +TEST_CASE_SELF(test_ial_bis_unf_brd_bv_10_c) { + const struct test_ial_broadcast_large_sdu_bis_cfg cfg = { + .NSE = 6, + .Framed = 0, + .Framing_Mode = 0, + .BN = 4, + .SDU_Interval = 20000, + .ISO_Interval = 20000, + }; + + test_ial_broadcast_large_sdu_bis(&cfg); +} + +TEST_CASE_SELF(test_ial_bis_unf_brd_bv_11_c) { + const struct test_ial_broadcast_large_sdu_bis_cfg cfg = { + .NSE = 8, + .Framed = 0, + .Framing_Mode = 0, + .BN = 4, + .SDU_Interval = 25000, + .ISO_Interval = 25000, + }; + + test_ial_broadcast_large_sdu_bis(&cfg); +} + +TEST_CASE_SELF(test_ial_bis_fra_brd_bv_13_c) { + const struct test_ial_broadcast_large_sdu_bis_cfg cfg = { + .NSE = 10, + .Framed = 1, + .Framing_Mode = 0, + .BN = 5, + .SDU_Interval = 15000, + .ISO_Interval = 30000, + }; + + test_ial_broadcast_large_sdu_bis(&cfg); +} + +TEST_CASE_SELF(test_ial_bis_fra_brd_bv_15_c) { + const struct test_ial_broadcast_large_sdu_bis_cfg cfg = { + .NSE = 6, + .Framed = 1, + .Framing_Mode = 0, + .BN = 3, + .SDU_Interval = 20000, + .ISO_Interval = 20000, + }; + + test_ial_broadcast_large_sdu_bis(&cfg); +} + +struct test_ial_broadcast_multiple_small_sdus_bis_cfg { + uint8_t NSE; + uint8_t BN; + uint8_t Max_PDU; + uint32_t SDU_Interval; + uint32_t ISO_Interval; +}; + +static void +test_ial_broadcast_multiple_small_sdus_bis(const struct test_ial_broadcast_multiple_small_sdus_bis_cfg *cfg) +{ + struct ble_ll_isoal_mux mux; + /* const uint16_t Max_SDU = 25; */ + const uint8_t LLID = 0b10; + const uint8_t Framed = 0x01; + const uint8_t Framing_Mode = 0; + int pdu_len; + uint8_t pdu[cfg->Max_PDU]; + uint32_t sdu_1_ts, sdu_2_ts, event_ts; + uint32_t timeoffset; + uint16_t seg_hdr; + uint8_t llid = 0xff; + uint8_t seg_len; + uint8_t *seg; + + test_ial_setup(&mux, cfg->Max_PDU, cfg->ISO_Interval, + cfg->SDU_Interval, cfg->BN, 0, Framed, + Framing_Mode); + + /* The Upper Tester sends to the IUT a small SDU1 with data length of 20 bytes. */ + sdu_1_ts = 100; + test_sdu_enqueue(&mux, 20, 0, sdu_1_ts); + + /* The Upper Tester sends to the IUT a small SDU2 with data length of 25 bytes. */ + sdu_2_ts = sdu_1_ts + cfg->SDU_Interval; + test_sdu_enqueue(&mux, 25, 0, sdu_2_ts); + + event_ts = sdu_2_ts + 200; + ble_ll_isoal_mux_event_start(&mux, event_ts); + + /* The IUT sends a single Broadcast ISO Data PDU with SDU1 followed by SDU2 over the BIS. + * Each SDU header has SC = 0 and CMPT = 1. + */ + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 0, &llid, pdu); + TEST_ASSERT(llid == LLID, "LLID is incorrect %d", llid); + + /* SDU 1 */ + seg = &pdu[0]; + TEST_ASSERT(pdu_len > 24, "PDU length is incorrect %d", pdu_len); + seg_hdr = get_le16(&seg[0]); + TEST_ASSERT(BLE_LL_ISOAL_SEGHDR_SC(seg_hdr) == 0, + "SC is incorrect %d", BLE_LL_ISOAL_SEGHDR_SC(seg_hdr)); + TEST_ASSERT(BLE_LL_ISOAL_SEGHDR_CMPLT(seg_hdr) == 1, + "SC is incorrect %d", BLE_LL_ISOAL_SEGHDR_CMPLT(seg_hdr)); + seg_len = BLE_LL_ISOAL_SEGHDR_LEN(seg_hdr); + TEST_ASSERT(seg_len == 20 + 3, "Segment length is incorrect %d", pdu_len); + timeoffset = get_le24(&seg[2]); + TEST_ASSERT(timeoffset == event_ts - sdu_1_ts, + "Time offset is incorrect %d", timeoffset); + + /* SDU 1 */ + seg = &pdu[25]; + TEST_ASSERT(pdu_len == 55, "PDU length is incorrect %d", pdu_len); + seg_hdr = get_le16(&seg[0]); + TEST_ASSERT(BLE_LL_ISOAL_SEGHDR_SC(seg_hdr) == 0, + "SC is incorrect %d", BLE_LL_ISOAL_SEGHDR_SC(seg_hdr)); + TEST_ASSERT(BLE_LL_ISOAL_SEGHDR_CMPLT(seg_hdr) == 1, + "SC is incorrect %d", BLE_LL_ISOAL_SEGHDR_CMPLT(seg_hdr)); + seg_len = BLE_LL_ISOAL_SEGHDR_LEN(seg_hdr); + TEST_ASSERT(seg_len == 25 + 3, "Segment length is incorrect %d", pdu_len); + timeoffset = get_le24(&seg[2]); + TEST_ASSERT(timeoffset == event_ts - sdu_2_ts, + "Time offset is incorrect %d", timeoffset); + + (void)ble_ll_isoal_mux_event_done(&mux); + + test_ial_teardown(&mux); +} + +TEST_CASE_SELF(test_ial_bis_fra_brd_bv_17_c) { + const struct test_ial_broadcast_multiple_small_sdus_bis_cfg cfg = { + .NSE = 2, + .BN = 1, + .Max_PDU = 68, + .SDU_Interval = 500, + .ISO_Interval = 1000, + }; + + test_ial_broadcast_multiple_small_sdus_bis(&cfg); +} + +TEST_CASE_SELF(test_ial_bis_fra_brd_bv_18_c) { + const struct test_ial_broadcast_multiple_small_sdus_bis_cfg cfg = { + .NSE = 2, + .BN = 1, + .Max_PDU = 68, + .SDU_Interval = 1000, + .ISO_Interval = 2000, + }; + + test_ial_broadcast_multiple_small_sdus_bis(&cfg); +} + +TEST_CASE_SELF(test_ial_bis_fra_brd_bv_20_c) { + const struct test_ial_broadcast_multiple_small_sdus_bis_cfg cfg = { + .NSE = 4, + .BN = 2, + .Max_PDU = 65, + .SDU_Interval = 500, + .ISO_Interval = 2000, + }; + + test_ial_broadcast_multiple_small_sdus_bis(&cfg); +} + +struct test_ial_segmentation_header { + uint8_t SC; + uint8_t CMPLT; + uint8_t LENGTH; +}; +struct test_ial_broadcast_zero_length_sdu_bis_cfg { + uint8_t NSE; + uint8_t Framed; + uint8_t Framing_Mode; + uint8_t LLID; + uint8_t BN; + struct test_ial_segmentation_header Segmentation_Header; + bool Time_Offset; +}; + +static void +test_ial_broadcast_zero_length_sdu_bis(const struct test_ial_broadcast_zero_length_sdu_bis_cfg *cfg) +{ + struct ble_ll_isoal_mux mux; + const uint32_t ISO_Interval = 10000; + const uint32_t SDU_Interval = 10000; + /* const uint16_t Max_SDU = 32; */ + const uint16_t Max_PDU = 32; + int pdu_len; + uint8_t pdu[Max_PDU]; + uint32_t timeoffset; + uint16_t seg_hdr; + uint8_t llid = 0xff; + + test_ial_setup(&mux, Max_PDU, ISO_Interval, SDU_Interval, + cfg->BN, 0, cfg->Framed, cfg->Framing_Mode); + + /* The Upper Tester sends an HCI ISO Data packet to the IUT with zero data length. */ + test_sdu_enqueue(&mux, 0, 0, 100); + + ble_ll_isoal_mux_event_start(&mux, 500); + + /* The IUT sends a single Broadcast ISO Data PDU with the LLID, + * Framed, Framing_Mode, the segmentation header and time offset + * fields as specified in Table 4.35. Length is 0 if LLID is 0b00 + * and is 5 (Segmentation Header + TimeOffset) if LLID is 0b10. + * SDU field is empty.. + */ + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 0, &llid, pdu); + TEST_ASSERT(llid == cfg->LLID, "LLID is incorrect %d", llid); + + if (cfg->LLID == 0b00) { + TEST_ASSERT(pdu_len == 0, "PDU length is incorrect %d", pdu_len); + } else if (cfg->LLID == 0b01) { + TEST_ASSERT(pdu_len == 5, "PDU length is incorrect %d", pdu_len); + } + + if (cfg->Framed) { + seg_hdr = get_le16(&pdu[0]); + TEST_ASSERT(BLE_LL_ISOAL_SEGHDR_SC(seg_hdr) == cfg->Segmentation_Header.SC, + "SC is incorrect %d", BLE_LL_ISOAL_SEGHDR_SC(seg_hdr)); + TEST_ASSERT(BLE_LL_ISOAL_SEGHDR_CMPLT(seg_hdr) == cfg->Segmentation_Header.CMPLT, + "CMPLT is incorrect %d", BLE_LL_ISOAL_SEGHDR_CMPLT(seg_hdr)); + TEST_ASSERT(BLE_LL_ISOAL_SEGHDR_LEN(seg_hdr) == cfg->Segmentation_Header.LENGTH, + "LENGTH is incorrect %d", BLE_LL_ISOAL_SEGHDR_LEN(seg_hdr)); + timeoffset = get_le24(&pdu[2]); + TEST_ASSERT(timeoffset == 400, "Time offset is incorrect %d", timeoffset); + } + + for (uint8_t idx = 1; idx < cfg->BN; idx++) { + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, idx, &llid, pdu); + TEST_ASSERT(llid == cfg->LLID, "LLID is incorrect %d", llid); + TEST_ASSERT(pdu_len == 0, "PDU length is incorrect %d", pdu_len); + } + + (void)ble_ll_isoal_mux_event_done(&mux); + + test_ial_teardown(&mux); +} + +TEST_CASE_SELF(test_ial_bis_unf_brd_bv_21_c) { + const struct test_ial_broadcast_zero_length_sdu_bis_cfg cfg = { + .NSE = 4, + .Framed = 0, + .Framing_Mode = 0, + .LLID = 0b00, + .BN = 2, + }; + + test_ial_broadcast_zero_length_sdu_bis(&cfg); +} + +TEST_CASE_SELF(test_ial_bis_unf_brd_bv_22_c) { + const struct test_ial_broadcast_zero_length_sdu_bis_cfg cfg = { + .NSE = 6, + .Framed = 0, + .Framing_Mode = 0, + .LLID = 0b00, + .BN = 3, + }; + + test_ial_broadcast_zero_length_sdu_bis(&cfg); +} + +TEST_CASE_SELF(test_ial_bis_unf_brd_bv_23_c) { + const struct test_ial_broadcast_zero_length_sdu_bis_cfg cfg = { + .NSE = 1, + .Framed = 0, + .Framing_Mode = 0, + .LLID = 0b00, + .BN = 1, + }; + + test_ial_broadcast_zero_length_sdu_bis(&cfg); +} + +TEST_CASE_SELF(test_ial_bis_unf_brd_bv_24_c) { + const struct test_ial_broadcast_zero_length_sdu_bis_cfg cfg = { + .NSE = 2, + .Framed = 0, + .Framing_Mode = 0, + .LLID = 0b00, + .BN = 1, + }; + + test_ial_broadcast_zero_length_sdu_bis(&cfg); +} + +TEST_CASE_SELF(test_ial_bis_fra_brd_bv_25_c) { + const struct test_ial_broadcast_zero_length_sdu_bis_cfg cfg = { + .NSE = 6, + .Framed = 1, + .Framing_Mode = 0, + .LLID = 0b10, + .BN = 2, + .Segmentation_Header.SC = 0, + .Segmentation_Header.CMPLT = 1, + .Segmentation_Header.LENGTH = 3, + .Time_Offset = true, + }; + + test_ial_broadcast_zero_length_sdu_bis(&cfg); +} + +TEST_CASE_SELF(test_ial_bis_fra_brd_bv_26_c) { + const struct test_ial_broadcast_zero_length_sdu_bis_cfg cfg = { + .NSE = 2, + .Framed = 1, + .Framing_Mode = 0, + .LLID = 0b10, + .BN = 1, + .Segmentation_Header.SC = 0, + .Segmentation_Header.CMPLT = 1, + .Segmentation_Header.LENGTH = 3, + .Time_Offset = true, + }; + + test_ial_broadcast_zero_length_sdu_bis(&cfg); +} + +TEST_CASE_SELF(test_ial_bis_fra_brd_bv_27_c) { + const struct test_ial_broadcast_zero_length_sdu_bis_cfg cfg = { + .NSE = 4, + .Framed = 1, + .Framing_Mode = 0, + .LLID = 0b10, + .BN = 1, + .Segmentation_Header.SC = 0, + .Segmentation_Header.CMPLT = 1, + .Segmentation_Header.LENGTH = 3, + .Time_Offset = true, + }; + + test_ial_broadcast_zero_length_sdu_bis(&cfg); +} + +TEST_CASE_SELF(test_ial_bis_fra_brd_bv_28_c) { + const struct test_ial_broadcast_zero_length_sdu_bis_cfg cfg = { + .NSE = 6, + .Framed = 1, + .Framing_Mode = 0, + .LLID = 0b10, + .BN = 3, + .Segmentation_Header.SC = 0, + .Segmentation_Header.CMPLT = 1, + .Segmentation_Header.LENGTH = 3, + .Time_Offset = true, + }; + + test_ial_broadcast_zero_length_sdu_bis(&cfg); +} + +TEST_CASE_SELF(test_ial_bis_fra_brd_bv_30_c) { + const struct test_ial_broadcast_zero_length_sdu_bis_cfg cfg = { + .NSE = 6, + .Framed = 1, + .Framing_Mode = 1, + .LLID = 0b10, + .BN = 2, + .Segmentation_Header.SC = 0, + .Segmentation_Header.CMPLT = 1, + .Segmentation_Header.LENGTH = 3, + .Time_Offset = true, + }; + + test_ial_broadcast_zero_length_sdu_bis(&cfg); +} + +struct test_ial_unframed_empty_pdus_with_llid_0b01_cfg { + uint32_t sdu_int; + uint32_t iso_int; + uint8_t nse; + uint16_t mx_sdu; + uint8_t mx_pdu; + uint8_t bn; + uint8_t irc; + uint8_t pto; +}; + +static void +test_ial_unframed_empty_pdus_with_llid_0b01(const struct test_ial_unframed_empty_pdus_with_llid_0b01_cfg *cfg) +{ + struct ble_ll_isoal_mux mux; + int pdu_len; + uint8_t pdu[cfg->mx_pdu]; + uint32_t timestamp; + uint8_t llid = 0xff; + + ble_ll_isoal_mux_init(&mux, cfg->mx_pdu, cfg->iso_int, cfg->sdu_int, + cfg->bn, 0, false, 0); + + for (uint16_t sdu_len = 4; sdu_len < cfg->mx_sdu; sdu_len++) { + timestamp = sdu_len * cfg->sdu_int; + test_sdu_enqueue(&mux, sdu_len, sdu_len, timestamp); + + ble_ll_isoal_mux_event_start(&mux, timestamp + 50); + + /* As the mx_sdu == mx_pdu, the data will always fit the single PDU */ + TEST_ASSERT(cfg->mx_sdu == cfg->mx_pdu, + "#%d: SDU and PDU length should be same", sdu_len); + + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 0, &llid, pdu); + TEST_ASSERT(llid == 0b00, + "#%d: LLID is incorrect %d", sdu_len, llid); + TEST_ASSERT(pdu_len == sdu_len, + "#%d: PDU length is incorrect %d", sdu_len, pdu_len); + + /* Padding */ + for (uint8_t idx = 1; idx < cfg->bn; idx++) { + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, idx, &llid, pdu); + TEST_ASSERT(llid == 0b01, + "#%d #%d: LLID is incorrect %d", sdu_len, idx, llid); + TEST_ASSERT(pdu_len == 0, + "#%d #%d: PDU length is incorrect %d", + sdu_len, idx, pdu_len); + } + + (void)ble_ll_isoal_mux_event_done(&mux); + } + + ble_ll_isoal_mux_free(&mux); +} + +TEST_CASE_SELF(test_ial_bis_unf_brd_bv_29_c) { + const struct test_ial_unframed_empty_pdus_with_llid_0b01_cfg cfg = { + .sdu_int = 100, + .iso_int = 100, + .nse = 12, + .mx_sdu = 128, + .mx_pdu = 128, + .bn = 4, + .irc = 3, + .pto = 0, + }; + + test_ial_unframed_empty_pdus_with_llid_0b01(&cfg); +} + +TEST_CASE_SELF(test_ial_bis_unf_early_sdus) { + struct ble_ll_isoal_mux mux; + const uint32_t sdu_int = 7500; + const uint32_t iso_int = 7500; + /* const uint16_t mx_sdu = 40; */ + const uint8_t mx_pdu = 40; + const uint8_t bn = 4; + int num_completed_pkt; + int pdu_len; + uint8_t pdu[mx_pdu]; + uint32_t timestamp = 0; + uint8_t llid = 0xff; + + test_ial_setup(&mux, mx_pdu, iso_int, sdu_int, bn, 0, false, 0); + + test_sdu_enqueue(&mux, 21, 0, timestamp++); + test_sdu_enqueue(&mux, 32, 0, timestamp++); + test_sdu_enqueue(&mux, 40, 0, timestamp++); + + ble_ll_isoal_mux_event_start(&mux, timestamp + 50); + + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 0, &llid, pdu); + TEST_ASSERT(llid == 0b00, "LLID is incorrect %d", llid); + TEST_ASSERT(pdu_len == 21, "PDU length is incorrect %d", pdu_len); + test_pdu_verify(pdu, pdu_len, 0); + + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 1, &llid, pdu); + TEST_ASSERT(llid == 0b01, "LLID is incorrect %d", llid); + TEST_ASSERT(pdu_len == 0, "PDU length is incorrect %d", pdu_len); + + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 2, &llid, pdu); + TEST_ASSERT(llid == 0b01, "LLID is incorrect %d", llid); + TEST_ASSERT(pdu_len == 0, "PDU length is incorrect %d", pdu_len); + + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 3, &llid, pdu); + TEST_ASSERT(llid == 0b01, "LLID is incorrect %d", llid); + TEST_ASSERT(pdu_len == 0, "PDU length is incorrect %d", pdu_len); + + num_completed_pkt = ble_ll_isoal_mux_event_done(&mux); + TEST_ASSERT(num_completed_pkt == 1, + "num_completed_pkt is incorrect %d", num_completed_pkt); + + ble_ll_isoal_mux_event_start(&mux, timestamp + 50 + iso_int); + + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 0, &llid, pdu); + TEST_ASSERT(llid == 0b00, "LLID is incorrect %d", llid); + TEST_ASSERT(pdu_len == 32, "PDU length is incorrect %d", pdu_len); + test_pdu_verify(pdu, pdu_len, 0); + + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 1, &llid, pdu); + TEST_ASSERT(llid == 0b01, "LLID is incorrect %d", llid); + TEST_ASSERT(pdu_len == 0, "PDU length is incorrect %d", pdu_len); + + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 2, &llid, pdu); + TEST_ASSERT(llid == 0b01, "LLID is incorrect %d", llid); + TEST_ASSERT(pdu_len == 0, "PDU length is incorrect %d", pdu_len); + + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 3, &llid, pdu); + TEST_ASSERT(llid == 0b01, "LLID is incorrect %d", llid); + TEST_ASSERT(pdu_len == 0, "PDU length is incorrect %d", pdu_len); + + num_completed_pkt = ble_ll_isoal_mux_event_done(&mux); + TEST_ASSERT(num_completed_pkt == 1, + "num_completed_pkt is incorrect %d", num_completed_pkt); + + ble_ll_isoal_mux_event_start(&mux, timestamp + 50 + 2 * iso_int); + + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 0, &llid, pdu); + TEST_ASSERT(llid == 0b00, "LLID is incorrect %d", llid); + TEST_ASSERT(pdu_len == 40, "PDU length is incorrect %d", pdu_len); + test_pdu_verify(pdu, pdu_len, 0); + + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 1, &llid, pdu); + TEST_ASSERT(llid == 0b01, "LLID is incorrect %d", llid); + TEST_ASSERT(pdu_len == 0, "PDU length is incorrect %d", pdu_len); + + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 2, &llid, pdu); + TEST_ASSERT(llid == 0b01, "LLID is incorrect %d", llid); + TEST_ASSERT(pdu_len == 0, "PDU length is incorrect %d", pdu_len); + + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 3, &llid, pdu); + TEST_ASSERT(llid == 0b01, "LLID is incorrect %d", llid); + TEST_ASSERT(pdu_len == 0, "PDU length is incorrect %d", pdu_len); + + num_completed_pkt = ble_ll_isoal_mux_event_done(&mux); + TEST_ASSERT(num_completed_pkt == 1, + "num_completed_pkt is incorrect %d", num_completed_pkt); + + test_ial_teardown(&mux); +} + +TEST_CASE_SELF(test_ial_bis_fra_early_sdus) { + struct ble_ll_isoal_mux mux; + const uint32_t sdu_int = 87072; + const uint32_t iso_int = 87500; + const uint16_t mx_sdu = 32; + const uint8_t mx_pdu = 37; + const uint8_t bn = 2; + int num_completed_pkt; + int pdu_len; + uint8_t pdu[mx_pdu]; + uint32_t timestamp = 0; + uint8_t llid = 0xff; + + test_ial_setup(&mux, mx_pdu, iso_int, sdu_int, bn, 0, true, 0); + + for (int seq_num = 0; seq_num < 10; seq_num++) { + test_sdu_enqueue(&mux, mx_sdu, seq_num, timestamp++); + } + + ble_ll_isoal_mux_event_start(&mux, timestamp); + + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 0, &llid, pdu); + TEST_ASSERT(llid == 0b10, "LLID is incorrect %d", llid); + TEST_ASSERT(pdu_len == mx_pdu, "PDU length is incorrect %d", pdu_len); + test_pdu_verify(&pdu[5], mx_sdu, 0); + + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 1, &llid, pdu); + TEST_ASSERT(llid == 0b10, "LLID is incorrect %d", llid); + TEST_ASSERT(pdu_len == mx_pdu, "PDU length is incorrect %d", pdu_len); + test_pdu_verify(&pdu[5], mx_sdu, 0); + + num_completed_pkt = ble_ll_isoal_mux_event_done(&mux); + TEST_ASSERT(num_completed_pkt == 2, + "num_completed_pkt is incorrect %d", num_completed_pkt); + + ble_ll_isoal_mux_event_start(&mux, timestamp); + + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 0, &llid, pdu); + TEST_ASSERT(llid == 0b10, "LLID is incorrect %d", llid); + TEST_ASSERT(pdu_len == mx_pdu, "PDU length is incorrect %d", pdu_len); + test_pdu_verify(&pdu[5], mx_sdu, 0); + + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 1, &llid, pdu); + TEST_ASSERT(llid == 0b10, "LLID is incorrect %d", llid); + TEST_ASSERT(pdu_len == mx_pdu, "PDU length is incorrect %d", pdu_len); + test_pdu_verify(&pdu[5], mx_sdu, 0); + + num_completed_pkt = ble_ll_isoal_mux_event_done(&mux); + TEST_ASSERT(num_completed_pkt == 2, + "num_completed_pkt is incorrect %d", num_completed_pkt); + + ble_ll_isoal_mux_event_start(&mux, timestamp); + + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 0, &llid, pdu); + TEST_ASSERT(llid == 0b10, "LLID is incorrect %d", llid); + TEST_ASSERT(pdu_len == mx_pdu, "PDU length is incorrect %d", pdu_len); + test_pdu_verify(&pdu[5], mx_sdu, 0); + + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 1, &llid, pdu); + TEST_ASSERT(llid == 0b10, "LLID is incorrect %d", llid); + TEST_ASSERT(pdu_len == mx_pdu, "PDU length is incorrect %d", pdu_len); + test_pdu_verify(&pdu[5], mx_sdu, 0); + + num_completed_pkt = ble_ll_isoal_mux_event_done(&mux); + TEST_ASSERT(num_completed_pkt == 2, + "num_completed_pkt is incorrect %d", num_completed_pkt); + + ble_ll_isoal_mux_event_start(&mux, timestamp); + + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 0, &llid, pdu); + TEST_ASSERT(llid == 0b10, "LLID is incorrect %d", llid); + TEST_ASSERT(pdu_len == mx_pdu, "PDU length is incorrect %d", pdu_len); + test_pdu_verify(&pdu[5], mx_sdu, 0); + + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 1, &llid, pdu); + TEST_ASSERT(llid == 0b10, "LLID is incorrect %d", llid); + TEST_ASSERT(pdu_len == mx_pdu, "PDU length is incorrect %d", pdu_len); + test_pdu_verify(&pdu[5], mx_sdu, 0); + + num_completed_pkt = ble_ll_isoal_mux_event_done(&mux); + TEST_ASSERT(num_completed_pkt == 2, + "num_completed_pkt is incorrect %d", num_completed_pkt); + + ble_ll_isoal_mux_event_start(&mux, timestamp); + + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 0, &llid, pdu); + TEST_ASSERT(llid == 0b10, "LLID is incorrect %d", llid); + TEST_ASSERT(pdu_len == mx_pdu, "PDU length is incorrect %d", pdu_len); + test_pdu_verify(&pdu[5], mx_sdu, 0); + + pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 1, &llid, pdu); + TEST_ASSERT(llid == 0b10, "LLID is incorrect %d", llid); + TEST_ASSERT(pdu_len == mx_pdu, "PDU length is incorrect %d", pdu_len); + test_pdu_verify(&pdu[5], mx_sdu, 0); + + num_completed_pkt = ble_ll_isoal_mux_event_done(&mux); + TEST_ASSERT(num_completed_pkt == 2, + "num_completed_pkt is incorrect %d", num_completed_pkt); + + test_ial_teardown(&mux); +} + +TEST_SUITE(ble_ll_isoal_test_suite) { + os_mbuf_test_setup(); + + ble_ll_isoal_init(); + + test_ble_ll_isoal_mux_init(); + test_ble_ll_isoal_mux_get_unframed_pdu(); + test_ble_ll_isoal_mux_sdu_not_in_event(); + + /* Broadcast Single SDU, BIS */ + test_ial_bis_unf_brd_bv_01_c(); + test_ial_bis_unf_brd_bv_02_c(); + test_ial_bis_fra_brd_bv_06_c(); + test_ial_bis_fra_brd_bv_08_c(); + test_ial_bis_fra_brd_bv_29_c(); + + /* Broadcast Large SDU, BIS */ + test_ial_bis_unf_brd_bv_09_c(); + test_ial_bis_unf_brd_bv_10_c(); + test_ial_bis_unf_brd_bv_11_c(); + test_ial_bis_fra_brd_bv_13_c(); + test_ial_bis_fra_brd_bv_15_c(); + + /* Broadcast Multiple, Small SDUs, BIS */ + test_ial_bis_fra_brd_bv_17_c(); + test_ial_bis_fra_brd_bv_18_c(); + test_ial_bis_fra_brd_bv_20_c(); + + /* Broadcast a Zero-Length SDU, BIS */ + test_ial_bis_unf_brd_bv_21_c(); + test_ial_bis_unf_brd_bv_22_c(); + test_ial_bis_unf_brd_bv_23_c(); + test_ial_bis_unf_brd_bv_24_c(); + test_ial_bis_fra_brd_bv_25_c(); + test_ial_bis_fra_brd_bv_26_c(); + test_ial_bis_fra_brd_bv_27_c(); + test_ial_bis_fra_brd_bv_28_c(); + test_ial_bis_fra_brd_bv_30_c(); + + /* Broadcasting Unframed Empty PDUs with LLID=0b01, BIS */ + test_ial_bis_unf_brd_bv_29_c(); + /* test_ial_bis_unf_brd_bv_30_c(); + * Same as test_ial_bis_unf_brd_bv_29_c except encryption is required. + */ + + test_ial_bis_unf_early_sdus(); + test_ial_bis_fra_early_sdus(); + + ble_ll_isoal_reset(); +} diff --git a/nimble/controller/test/src/ble_ll_test.c b/nimble/controller/test/src/ble_ll_test.c index ee089afe7f..818430c577 100644 --- a/nimble/controller/test/src/ble_ll_test.c +++ b/nimble/controller/test/src/ble_ll_test.c @@ -17,19 +17,26 @@ * under the License. */ -#include "sysinit/sysinit.h" -#include "syscfg/syscfg.h" -#include "controller/ble_ll_test.h" -#include "os/os.h" -#include "testutil/testutil.h" -#include "ble_ll_csa2_test.h" +#include +#include #if MYNEWT_VAL(SELFTEST) +TEST_SUITE_DECL(ble_ll_aa_test_suite); +TEST_SUITE_DECL(ble_ll_crypto_test_suite); +TEST_SUITE_DECL(ble_ll_csa2_test_suite); +TEST_SUITE_DECL(ble_ll_isoal_test_suite); +TEST_SUITE_DECL(ble_ll_iso_test_suite); + int main(int argc, char **argv) { + ble_ll_aa_test_suite(); + ble_ll_crypto_test_suite(); ble_ll_csa2_test_suite(); + ble_ll_isoal_test_suite(); + ble_ll_iso_test_suite(); + return tu_any_failed; } diff --git a/nimble/controller/test/syscfg.yml b/nimble/controller/test/syscfg.yml index 6edad438bb..f7a3c4ef5e 100644 --- a/nimble/controller/test/syscfg.yml +++ b/nimble/controller/test/syscfg.yml @@ -18,8 +18,12 @@ syscfg.vals: BLE_LL_CFG_FEAT_LE_CSA2: 1 + BLE_LL_ISO: 1 + BLE_VERSION: 54 # Prevent priority conflict with controller task. MCU_TIMER_POLLER_PRIO: 1 MCU_UART_POLLER_PRIO: 2 NATIVE_SOCKETS_PRIO: 3 + + BLE_TRANSPORT_ISO_SIZE: 255 diff --git a/nimble/doc/hci_vendor.md b/nimble/doc/hci_vendor.md new file mode 100644 index 0000000000..ad9d465e7e --- /dev/null +++ b/nimble/doc/hci_vendor.md @@ -0,0 +1,336 @@ + + + +Nimble Vendor Supported Commands +================================ + +*OGF = 0x003F* + + +Read Static Address Command +--------------------------- + +Read the static random address assigned to the controller + +| Command | OCF | Params |Return params | +|-------------------|--------|------------|--------------| +| Read_Addr | 0x0001 | *none* | Static_Addr | + +
+Static_Addr + +| Value | Description | +|--------------------|-------------| +| 0xXXXXXXXXXXXX | Address | + +*Size: 6 octets* + + +Set Default Transmit Power +-------------------------- + +Set default transmit power level
+Selected TX power is returned
+Setting 0xFF restores controller setting to default
+ +| Command | OCF | Params | Return params | +|-------------------|--------|------------|---------------| +| Set_Tx_Pwr | 0x0002 | Tx_Pwr | Sel_Tx_Pwr | + +
+Tx_Pwr + +| Value | Description | +|----------------------------|------------------------| +| 0xXX | Desired TX Power Level | + +*Size: 1 octet* + +
+Sel_Tx_Pwr + +| Value | Description | +|------------------|------------------------------| +| 0xXX | Controller Selected TX power | + +*Size: 1 octet* + + +Configure Connection Strict Scheduling +-------------------------------------- + +Configure Connection Strict Scheduling + +| Command | OCF | Params | Return params | +|-------------------|--------|------------|---------------| +| CSS_Configure | 0x0003 | Slot_us | *none* | +| | | Num_Slots | | + +
+Slot_us + +| Value | Description | +|----------------------------|-----------------------| +| 0xXXXXXX | Slot duration in msec | + +*Size: 4 octets* + +
+Number_Of_Slots + +| Value | Description | +|----------------------------|------------------------| +| 0xXXXXXX | Number of period slots | + +*Size: 4 octets* + + +Connection strict scheduling enable +----------------------------------- + +Enable/Disable Connection Strict Scheduling + +| Command | OCF | Params | Return params | +|--------------|--------|--------------|---------------| +| CSS_Enable | 0x0004 |Enable/Disale | *none* | + + +
+Enable/Disable + +| Value | Description | +|----------------------------|--------------------| +| 0xXX | Enable/Disable CSS | + +*Size: 1 octet* + + +Connection Strict Scheduling - Select Next Slot +----------------------------------------------- + +Set next slot index for future connection + +| Command | OCF | Params | Return params | +|-------------------|--------|--------------|---------------| +| CSS_Set_Next_Slot | 0x0005 |Next_Slot_Idx | *none* | + + +
+Next_Slot_Idx + +| Value | Description | +|----------------------------|--------------| +| 0xXXXX | Next Slot ID | + +*Size: 2 octets* + + +Connection Strict Scheduling - Select Slot For Specific Connection +------------------------------------------------------------------ + +Set slot index for current connection + +| Command | OCF | Params | Return params | +|-------------------|--------|------------|---------------| +| CSS_Configure | 0x0006 | Conn_Hdl | *none* | +| | | Slot_Idx | | + +
+Conn_Hdl + +| Value | Description | +|----------------------------|-------------------| +| 0xXXXX | Connection Handle | + +*Size: 2 octets* + +
+Slot_Idx + +| Value | Description | +|----------------------------|-------------| +| 0xXXXX | Slot ID | + +*Size: 2 octets* + + +Connection Strict Scheduling - Read Connection Slot +--------------------------------------------------- + +Read current connection slot index + +| Command | OCF | Params | Return params | +|-------------------|--------|--------------|---------------| +| CSS_Set_Next_Slot | 0x0007 | Conn_Hdl | Conn_Hdl | +| | | | Slot_Idx | + +
+Conn_Hdl + +| Value | Description | +|----------------------------|-------------------| +| 0xXXXX | Connection Handle | + +*Size: 2 octets* + +
+Slot_Idx + +| Value | Description | +|--------------------|-------------| +| 0xXXXX | Slot_ID | +*Size: 2 octets* + + +Set Data Length +--------------- + +Change TX/RX values. +Waits for Data Length Changed event. + +| Command | OCF | Params | Return params | +|--------------|--------|-----------------|---------------| +| Set_Data_Len | 0x0008 | Conn_Hdl
| Conn_Hdl | +| | | Tx_Octets
| | +| | | Tx_Time
| | +| | | Rx_Octets
| | +| | | Rx_Time
| | + +
+Conn_Hdl + +| Value | Description | +|----------------------------|-------------------| +| 0xXXXX | Connection Handle | + +*Size: 2 octets* + +
+Tx_Octets + +| Value | Description | +|----------------------------|-----------------| +| 0xXXXX | Transmit octets | + +*Size: 2 octets* + +
+Tx_Time + +| Value | Description | +|----------------------------|-------------------| +| 0xXXXX | Transmission time | + +*Size: 2 octets* + +
+Rx_Octets + +| Value | Description | +|----------------------------|-----------------| +| 0xXXXX | Receiver octets | + +*Size: 2 octets* + +
+Rx_Time + +| Value | Description | +|----------------------------|---------------| +| 0xXXXX | Receiver time | + +*Size: 2 octets* + + +Set Antenna Location +-------------------- + +| Command | OCF | Params | Return params | +|---------------|--------|----------------|---------------| +| Set_Ant_Loc | 0x0009 | Ant_Loc | *none* | + + +
+Ant_Loc + +| Value | Description | +|----------------------------|------------------| +| 0xXX | Antenna location | + +*Size: 1 ocet* + + +Set Local Identity Resolving Key +-------------------------------- + +Set own address type & identity resolving key + +| Command | OCF | Params | Return params | +|-----------------|--------|---------------|---------------| +| Set_Local_IRK | 0x000A | Own_Addr_Type | *none* | +| | | IRK | | + +
+Rx_Time + +| Value | Description | +|----------------------------|---------------------| +| 0xXX | Device Address Type | + +*Size: 1 ocet* + +
+IRK + +| Value | Description | +|--------------------|------------------------| +| 0xXX(16) | Identity Resolving Key | + +*Size: 16 ocets* + + +Set Scan Configuration +---------------------- + +| Command | OCF | Params | Return params | +|-----------------|--------|---------------|---------------| +| Set_Scan_Cfg | 0x000B | Flags | *none* | +| | | Rssi_Tres | | + +
+Flags + +| Value | Description | +|----------------------------|-------------------------| +| 0x00000001
| No legacy advertising | +| 0x00000002 | No extended advertising | + +*Size: 4 octets* + +
+Rssi_Tres + +| Value | Description | +|----------------------------|---------------------| +| 0xXX | RSSI treshold value | + +*Size: 1 octet* diff --git a/nimble/doc/transport.md b/nimble/doc/transport.md new file mode 100644 index 0000000000..35065197c9 --- /dev/null +++ b/nimble/doc/transport.md @@ -0,0 +1,189 @@ + + +# NimBLE HCI transport + +## Overview + +Transport is split into host (HS) and controller (LL) sides. Those do not +necessarily represent actual host/controller, they can be just interfaces to +external host (e.g. UART or USB) or controller (e.g.IPC to LL running on +another core). + +``` ++----------+ +----------+ +| cmd pool | | evt pool | ++----------+ +----------+ +| acl pool | | acl pool | ++----------+ +----------+ + || || ++----+ +----+ +| | <--- ble_transport_to_hs_acl ---- | | +| | <--- ble_transport_to_hs_evt ---- | | +| HS | | LL | +| | ---- ble_transport_to_ll_cmd ---> | | +| | ---- ble_transport_to_ll_acl ---> | | ++----+ +----+ +``` + +HS side allocates buffers for HCI commands and ACL data from dedicated pools +using `ble_transport_alloc_cmd` and `ble_transport_alloc_acl_from_hs` calls +respectively, then sends them to LL side using `ble_transport_to_ll_cmd` and +`ble_transport_to_ll_acl`. + +Similarly, LL side allocates buffers for HCI events and ACL data from dedicated +pools using `ble_transport_alloc_evt` and `ble_transport_alloc_acl_from_ll` +calls respectively, then sends them to HS side using `ble_transport_to_hs_evt` +and `ble_transport_to_hs_acl`. + +Both HCI command and events buffers are freed using `ble_transport_free`, ACL +data are freed as regular `os_mbuf`. + +Selecting `native` transport for either HS or LL side will use actual NimBLE +host or controller respectively directly instead of transport implementation. +Both NimBLE host and controller do not use decidated pools for ACL data and +allocate data directly from msys pool - relevant ACL pools will be disabled +automatically. + +Actual transport implementation for each side can be set using `BLE_TRANSPORT_HS` +and `BLE_TRANSPORT_LL` syscfg for HS and LL sides respectively. Selecting +transport in either direction will automatically add dependencies to required +transport implementation packages, there's no need to do this manually. +Selecting `native` transport for HS and/or LL side will automatically add +dependencies to NimBLE host and/or controller packages. + +The order of initialization is defined as follows: +- `ble_transport_init` - generic transport initialization +- `ble_transport_hs_init` - HS side initialization +- `ble_transport_ll_init` - LL side initialization + +Initialization functions for HS and LL sides shall be implemented by transport +implementation. There's no need to define those functions as sysinit stages +since this is already done by generic transport implementation along with +proper dependencies. + + +## Application configuration + +To ensure that application can be easily run on different BSPs, it's strongly +recommended not to put hard dependencies to any transport in `pkg.yml` and +use automatic dependencies instead. That means an application that uses NimBLE +host should only include `nimble/host` in its dependencies (i.e. no direct +dependency to `nimble/controler` or any transport implementation). This will +pull `nimble/transport` automatically, force `BLE_TRANSPORT_HS: native` and +allow changing LL side using `BLE_TRANSPORT_LL` to any supported controller. + + +## Multicore SoCs + +On multicore SoCs with dedicated application and network cores (e.g. nRF5340, +DA1469x) NimBLE host and controller will run on different cores. In such setup +application core uses LL transport implementation instead of an actual NimBLE +controller and similarly network core uses HS transport implementation instead +of NimBLE host. Both sides of transport implementation are provided by the same +transport, e.g. `nrf5340` for nRF5340 or `dialog_cmac` for DA1469x, and exchange +data via IPC. This process is transparent from application point of view, +assuming it's properly configured (see above). + +``` + Application core | Network core ++----+ +----+ | +----+ +----+ +| | | LL | | | HS | | | +| | <- acl/evt -- | | | | | <- acl/evt -- | | +| HS | | tr | <- ipc -> | tr | | LL | +| | -- cmd/acl -> | an | | | an | -- cmd/acl -> | | +| | | sp | | | sp | | | ++----+ +----+ | +----+ +----+ +``` + + +## Build configurations + +### Combined build + +This setup runs both NimBLE host and controller on the same core. It's a typical +configuration when running application on SoCs like nRF51 or nRF52. + +Note: this is the default configuration, no need to set it explicitly. + +```yaml +BLE_TRANSPORT_HS: native +BLE_TRANSPORT_LL: native +``` + +### Controller-only build + +This setup makes NimBLE controller accessible to external host connected via +e.g. UART or USB, so it can be used as an external Bluetooth LE controller. +The controller runs on the same core as external interface. It's typically +used with `blehci` application running on SoCs like nRF51 or nRF52. + +```yaml +BLE_TRANSPORT_HS: uart +BLE_TRANSPORT_LL: native +``` + + +### Multicore build + +This is a variant of combined build but with NimBLE host and controller running +on different cores, like e.g. nRF5340 or DA1469x. Application core can run +any application while network core runs `blehci`. + +Note: BSPs for nRF5340 and DA1469x will automatically select proper transport + for LL side if NimBLE host or transport is included in build, so usually + there's no need to configure manually. + +#### Application core +```yaml +BLE_TRANSPORT_HS: native +BLE_TRANSPORT_LL: dialog_cmac +``` + +#### Network core +```yaml +BLE_TRANSPORT_HS: dialog_cmac +BLE_TRANSPORT_LL: native +``` + + +### Bridge build + +This is a variant of controller-only build but with NimBLE controller running +on different core than external interface used to access it, like e.g. nRF5340 +or DA1469x. In this setup both cores run `blehci` application. + +Note: BSPs for nRF5340 and DA1469x will automatically select proper transport + for LL side if NimBLE host or transport is included in build, so usually + there's only need to select required transport for external interface on + application core. + +#### Application core +```yaml +BLE_TRANSPORT_HS: uart +BLE_TRANSPORT_LL: nrf5340 +``` + +#### Network core +```yaml +BLE_TRANSPORT_HS: nrf5340 +BLE_TRANSPORT_LL: native +``` diff --git a/nimble/drivers/dialog_cmac/src/ble_hw.c b/nimble/drivers/dialog_cmac/src/ble_hw.c index 98c8144bb4..195dcd35dd 100644 --- a/nimble/drivers/dialog_cmac/src/ble_hw.c +++ b/nimble/drivers/dialog_cmac/src/ble_hw.c @@ -23,8 +23,7 @@ #include "nimble/ble.h" #include "controller/ble_hw.h" #include "CMAC.h" -#include "cmac_driver/cmac_shared.h" -#include "mcu/mcu.h" +#include #include "tinycrypt/aes.h" static struct tc_aes_key_sched_struct g_ctx; @@ -305,6 +304,12 @@ ble_hw_resolv_proc_disable(void) NVIC_DisableIRQ(CRYPTO_IRQn); } +void +ble_hw_resolv_proc_reset(const uint8_t *addr) +{ + g_ble_hw_resolv_proc.f_match = 0; +} + void ble_hw_resolv_proc_start(const uint8_t *addr) { diff --git a/nimble/drivers/dialog_cmac/src/ble_hw_priv.h b/nimble/drivers/dialog_cmac/src/ble_hw_priv.h index 627994ffcf..7595a20856 100644 --- a/nimble/drivers/dialog_cmac/src/ble_hw_priv.h +++ b/nimble/drivers/dialog_cmac/src/ble_hw_priv.h @@ -24,6 +24,7 @@ void ble_hw_resolv_proc_enable(void); void ble_hw_resolv_proc_disable(void); +void ble_hw_resolv_proc_reset(void); void ble_hw_resolv_proc_start(const uint8_t *addr); #endif /* _BLE_HW_PRIV_H_ */ diff --git a/nimble/drivers/dialog_cmac/src/ble_phy.c b/nimble/drivers/dialog_cmac/src/ble_phy.c index 74c67b68b5..de7024b463 100644 --- a/nimble/drivers/dialog_cmac/src/ble_phy.c +++ b/nimble/drivers/dialog_cmac/src/ble_phy.c @@ -24,11 +24,10 @@ #include #include -#include #include "nimble/ble.h" #include "mcu/mcu.h" #include "mcu/cmac_timer.h" -#include "cmac_driver/cmac_shared.h" +#include #include "controller/ble_phy.h" #include "controller/ble_ll.h" #include "stats/stats.h" @@ -40,6 +39,10 @@ #error LE Coded PHY cannot be enabled on DA1469x #endif +#ifndef min +#define min(a, b) ((a) < (b) ? (a) : (b)) +#endif + /* Statistics */ STATS_SECT_START(ble_phy_stats) STATS_SECT_ENTRY(phy_isrs) @@ -258,12 +261,11 @@ struct ble_phy_data { #endif uint32_t access_addr; /* Current access address */ uint32_t crc_init; - uint32_t llt_at_cputime; - uint32_t cputime_at_llt; - uint64_t start_llt; + uint64_t llt_rx_start; struct ble_mbuf_hdr rxhdr; ble_phy_tx_end_func txend_cb; void *txend_arg; + uint8_t phy_tx_set; }; static struct ble_phy_data g_ble_phy_data; @@ -312,6 +314,7 @@ static bool ble_phy_rx_start_isr(void); static void ble_phy_rx_setup_fields(void); static void ble_phy_rx_setup_xcvr(void); static void ble_phy_mode_apply(uint8_t phy_mode); +static int ble_phy_get_cur_phy(void); void FIELD_IRQHandler(void) @@ -454,24 +457,6 @@ SW_MAC_IRQHandler(void) MCU_DIAG_SER('s'); } -static inline uint32_t -ble_phy_convert_and_record_start_time(uint32_t cputime, uint8_t rem_usecs) -{ - uint64_t ll_val; - - ll_val = cmac_timer_convert_hal2llt(cputime); - - /* - * Since we just converted cputime to the LL timer, record both these - * values as they will be used to calculate packet reception start time. - */ - g_ble_phy_data.cputime_at_llt = cputime; - g_ble_phy_data.llt_at_cputime = ll_val; - g_ble_phy_data.start_llt = ll_val + rem_usecs; - - return ll_val; -} - static inline void ble_phy_sw_mac_handover(uint8_t exc) { @@ -525,12 +510,8 @@ ble_phy_rx_end_isr(void) static bool ble_phy_rx_start_isr(void) { - uint32_t llt32; - uint32_t llt_10_0; - uint32_t llt_10_0_mask; + uint64_t llt; uint32_t timestamp; - uint32_t ticks; - uint32_t usecs; struct ble_mbuf_hdr *ble_hdr; /* Initialize the ble mbuf header */ @@ -547,7 +528,7 @@ ble_phy_rx_start_isr(void) /* Read the latched RSSI value */ ble_hdr->rxinfo.rssi = ble_rf_get_rssi(); #if MYNEWT_VAL(CMAC_DEBUG_DATA_ENABLE) - g_cmac_shared_data.debug.last_rx_rssi = ble_hdr->rxinfo.rssi; + g_cmac_shm_debugdata.last_rx_rssi = ble_hdr->rxinfo.rssi; #endif /* Count rx starts */ @@ -565,44 +546,31 @@ ble_phy_rx_start_isr(void) timestamp = CMAC->CM_TS1_REG; assert((timestamp & CMAC_CM_TS1_REG_TS1_DIRTY_Msk) != 0); - /* Get the LL timer (only need 32 bits) */ - llt32 = cmac_timer_read32(); + llt = cmac_timer_read37(); - /* - * We assume that the timestamp was set within 11 bits, or 2047 usecs, of - * when we read the ll timer. We assume this because we need to calculate - * the LL timer value at the timestamp. If the low 11 bits of the LL timer - * are greater than the timestamp, it means that the upper bits of the - * timestamp are correct. If the timestamp value is greater, it means the - * timer wrapped the 11 bits and we need to adjust the LL timer value. + /* Captured timestamp has only 11lsb, we use current LL timer value to + * calculate 37-bit timestamp. To do this we will replace 11 lsb of current + * LL timer value with captured value, but we need to check if msb of + * captured timestamp (i.e. 11) is the same as in current LL timer value. + * If not, it means 10 lsb of LL timer value wrapped around since timestamp + * was captured and we need to adjust LL timer value. This assumes that + * LL timer value was read no later than 1024 usecs from timestamp capture, + * but that's fine since isr should be triggered immediately after capture. */ - llt_10_0_mask = (CMAC_CM_TS1_REG_TS1_TIMER1_9_0_Msk | - CMAC_CM_TS1_REG_TS1_TIMER1_10_Msk); - timestamp &= llt_10_0_mask; - llt_10_0 = llt32 & llt_10_0_mask; - llt32 &= ~llt_10_0_mask; - if (timestamp > llt_10_0) { - llt32 -= 2048; - } - llt32 |= timestamp; - - /* Actual RX start time needs to account for preamble and access address */ - llt32 -= g_ble_phy_mode_pkt_start_off[g_ble_phy_data.phy_mode_rx] + - g_ble_phy_data.path_delay_rx; - - if (llt32 < g_ble_phy_data.llt_at_cputime) { - g_ble_phy_data.llt_at_cputime -= 31; - g_ble_phy_data.cputime_at_llt--; + if (((uint32_t)llt ^ timestamp) & (1 << 10)) { + llt -= 1024; } + llt &= ~((uint64_t)0x3ff); + llt |= timestamp & 0x3ff; - /* - * We now have the LL timer when the packet was received. Get the cputime - * and the leftover usecs. + /* Timestamp is captured after access address so we need to adjust rx start + * time accordingly. */ - usecs = llt32 - g_ble_phy_data.llt_at_cputime; - ticks = os_cputime_usecs_to_ticks(usecs); - ble_hdr->beg_cputime = g_ble_phy_data.cputime_at_llt + ticks; - ble_hdr->rem_usecs = usecs - os_cputime_ticks_to_usecs(ticks); + llt -= g_ble_phy_mode_pkt_start_off[g_ble_phy_data.phy_mode_rx] + + g_ble_phy_data.path_delay_rx; + + ble_hdr->beg_cputime = llt >> 5; + ble_hdr->rem_usecs = llt & 0x1f; return true; } @@ -675,7 +643,7 @@ ble_phy_irq_frame_tx_exc_bs_stop(void) (void)CMAC->CM_TS1_REG; if (g_ble_phy_data.end_transition == BLE_PHY_TRANSITION_TX_RX) { -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) +#if MYNEWT_VAL(BLE_LL_PHY) ble_phy_mode_apply(g_ble_phy_data.phy_mode_rx); #endif ble_phy_rx_setup_fields(); @@ -684,6 +652,8 @@ ble_phy_irq_frame_tx_exc_bs_stop(void) CMAC_CM_EV_LINKUP_REG_LU_FRAME_START_2_NONE_Msk; } + g_ble_phy_data.phy_tx_set = 0; + if (g_ble_phy_data.txend_cb) { ble_phy_sw_mac_handover(SW_MAC_EXC_TXEND_CB); return; @@ -929,12 +899,21 @@ ble_phy_irq_frame_rx_exc_phy_to_idle_4this(void) CMAC->CM_EXC_STAT_REG = CMAC_CM_EXC_STAT_REG_EXC_PHY_TO_IDLE_4THIS_Msk; /* We are here only on transition, so switch to TX */ -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) +#if MYNEWT_VAL(BLE_LL_PHY) ble_phy_mode_apply(g_ble_phy_data.phy_mode_tx); #endif rf_chan = g_ble_phy_chan_to_rf[g_ble_phy_data.channel]; ble_rf_setup_tx(rf_chan, g_ble_phy_data.phy_mode_tx); + g_ble_phy_data.phy_state = BLE_PHY_STATE_TX; + + /* We do not want FIELD/FRAME interrupts until ble_phy_tx() has pushed all + * fields. + */ + if (!g_ble_phy_data.phy_tx_set) { + NVIC_DisableIRQ(FRAME_IRQn); + NVIC_DisableIRQ(FIELD_IRQn); + } } static void @@ -1038,10 +1017,10 @@ ble_phy_mode_set(uint8_t tx_phy_mode, uint8_t rx_phy_mode) g_ble_phy_data.frame_offset_rxtx = g_ble_phy_frame_offset_rxtx[rxtx]; } -int +static int ble_phy_get_cur_phy(void) { -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) +#if MYNEWT_VAL(BLE_LL_PHY) switch (g_ble_phy_data.phy_mode_cur) { case BLE_PHY_MODE_1M: return BLE_PHY_1M; @@ -1174,7 +1153,7 @@ ble_phy_wfr_enable(int txrx, uint8_t tx_phy_mode, uint32_t wfr_usecs) CMAC->CM_EV_LINKUP_REG = CMAC_CM_EV_LINKUP_REG_LU_CORR_TMR_LD_2_CORR_START_Msk; } else { wfr_usecs += aa_time; - llt = g_ble_phy_data.start_llt; + llt = g_ble_phy_data.llt_rx_start; /* * wfr is outside range of CORR_WINDOW so we need to use LLT to start @@ -1305,7 +1284,11 @@ ble_phy_disable(void) __enable_irq(); + NVIC_EnableIRQ(FRAME_IRQn); + NVIC_EnableIRQ(FIELD_IRQn); + g_ble_phy_data.phy_state = BLE_PHY_STATE_IDLE; + g_ble_phy_data.phy_tx_set = 0; } static void @@ -1338,6 +1321,10 @@ ble_phy_rx_setup_xcvr(void) { uint8_t rf_chan = g_ble_phy_chan_to_rf[g_ble_phy_data.channel]; +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) + ble_hw_resolv_proc_reset(); +#endif + CMAC->CM_EV_SET_REG = CMAC_CM_EV_SET_REG_EV1C_CALLBACK_VALID_SET_Msk; ble_rf_setup_rx(rf_chan, g_ble_phy_data.phy_mode_rx); @@ -1345,7 +1332,7 @@ ble_phy_rx_setup_xcvr(void) g_ble_phy_data.phy_rx_started = 0; } -int +static int ble_phy_rx(void) { MCU_DIAG_SER('R'); @@ -1367,35 +1354,35 @@ ble_phy_rx(void) int ble_phy_rx_set_start_time(uint32_t cputime, uint8_t rem_usecs) { - uint32_t ll_val32; + uint64_t llt_rx_start; + uint32_t llt32; int32_t time_till_start; int rc = 0; MCU_DIAG_SER('r'); -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) +#if MYNEWT_VAL(BLE_LL_PHY) ble_phy_mode_apply(g_ble_phy_data.phy_mode_rx); #endif - assert(ble_rf_is_enabled()); - ble_phy_rx(); - /* Get LL timer at cputime */ - ll_val32 = ble_phy_convert_and_record_start_time(cputime, rem_usecs); + /* Store LLT value at RX start, we'll need this to set wfr */ + llt_rx_start = (uint64_t)cputime * 32 + rem_usecs; + g_ble_phy_data.llt_rx_start = llt_rx_start; - /* Add remaining usecs to get exact receive start time */ - ll_val32 += rem_usecs; - - /* Adjust start time for rx delays */ - ll_val32 -= PHY_DELAY_POWER_UP_RX - g_ble_phy_data.path_delay_rx; + /* Adjust start time for rx delays. + * Note: we can use 32lsb for remaining calculations. + */ + llt32 = llt_rx_start; + llt32 -= PHY_DELAY_POWER_UP_RX - g_ble_phy_data.path_delay_rx; __disable_irq(); - CMAC->CM_LL_TIMER1_9_0_EQ_X_REG = ll_val32; + CMAC->CM_LL_TIMER1_9_0_EQ_X_REG = llt32; CMAC->CM_EV_LINKUP_REG = CMAC_CM_EV_LINKUP_REG_LU_FRAME_START_2_TMR1_9_0_EQ_X_Msk; - time_till_start = (int32_t)(ll_val32 - cmac_timer_read32()); + time_till_start = (int32_t)(llt32 - cmac_timer_read32()); if (time_till_start <= 0) { /* * Possible we missed the frame start! If we have, we need to start @@ -1482,6 +1469,8 @@ ble_phy_tx(ble_phy_tx_pducb_t pducb, void *pducb_arg, uint8_t end_trans) rc = BLE_ERR_SUCCESS; } + g_ble_phy_data.phy_tx_set = 1; + /* Now we can handle BS_CTRL */ NVIC_EnableIRQ(FRAME_IRQn); NVIC_EnableIRQ(FIELD_IRQn); @@ -1498,7 +1487,7 @@ ble_phy_tx_set_start_time(uint32_t cputime, uint8_t rem_usecs) MCU_DIAG_SER('t'); -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) +#if MYNEWT_VAL(BLE_LL_PHY) ble_phy_mode_apply(g_ble_phy_data.phy_mode_tx); #endif @@ -1507,8 +1496,7 @@ ble_phy_tx_set_start_time(uint32_t cputime, uint8_t rem_usecs) ble_rf_configure(); ble_rf_setup_tx(rf_chan, g_ble_phy_data.phy_mode_tx); - ll_val32 = ble_phy_convert_and_record_start_time(cputime, rem_usecs); - ll_val32 += rem_usecs; + ll_val32 = cputime * 32 + rem_usecs; ll_val32 -= PHY_DELAY_POWER_UP_TX + g_ble_phy_data.path_delay_tx; /* we can schedule TX only up to 1023us in advance */ assert((int32_t)(ll_val32 - cmac_timer_read32()) < 1024); @@ -1552,8 +1540,6 @@ ble_phy_tx_set_start_time(uint32_t cputime, uint8_t rem_usecs) tx_late: STATS_INC(ble_phy_stats, tx_late); ble_phy_disable(); - NVIC_EnableIRQ(FRAME_IRQn); - NVIC_EnableIRQ(FIELD_IRQn); rc = BLE_PHY_ERR_TX_LATE; done: @@ -1614,19 +1600,12 @@ ble_phy_rx_enc_start(uint8_t len) } void -ble_phy_encrypt_enable(uint64_t pkt_counter, uint8_t *iv, uint8_t *key, - uint8_t is_master) +ble_phy_encrypt_enable(const uint8_t *key) { struct ble_phy_encrypt_obj *enc; enc = &g_ble_phy_encrypt_data; memcpy(enc->key, key, 16); - memcpy(&enc->b0[6], iv, 8); - put_le32(&enc->b0[1], pkt_counter); - enc->b0[5] = is_master ? 0x80 : 0; - memcpy(&enc->ai[6], iv, 8); - put_le32(&enc->ai[1], pkt_counter); - enc->ai[5] = enc->b0[5]; g_ble_phy_data.phy_encrypted = 1; @@ -1647,14 +1626,25 @@ ble_phy_encrypt_enable(uint64_t pkt_counter, uint8_t *iv, uint8_t *key, } void -ble_phy_encrypt_set_pkt_cntr(uint64_t pkt_counter, int dir) +ble_phy_encrypt_iv_set(const uint8_t *iv) { struct ble_phy_encrypt_obj *enc; enc = &g_ble_phy_encrypt_data; - put_le32(&enc->b0[1], pkt_counter); - enc->b0[5] = dir ? 0x80 : 0; - put_le32(&enc->ai[1], pkt_counter); + memcpy(&enc->b0[6], iv, 8); + memcpy(&enc->ai[6], iv, 8); +} + + +void +ble_phy_encrypt_counter_set(uint64_t counter, uint8_t dir_bit) +{ + struct ble_phy_encrypt_obj *enc; + + enc = &g_ble_phy_encrypt_data; + put_le32(&enc->b0[1], counter); + enc->b0[5] = dir_bit ? 0x80 : 0; + put_le32(&enc->ai[1], counter); enc->ai[5] = enc->b0[5]; CMAC->CM_CRYPTO_CTRL_REG = CMAC_CM_CRYPTO_CTRL_REG_CM_CRYPTO_SW_REQ_PBUF_CLR_Msk; @@ -1667,31 +1657,46 @@ ble_phy_encrypt_disable(void) } #endif -int -ble_phy_txpwr_set(int dbm) +static int8_t +phy_txpower_round(int8_t dbm) { -#if MYNEWT_VAL(CMAC_DEBUG_DATA_ENABLE) - if (g_cmac_shared_data.debug.tx_power_override != INT8_MAX) { - ble_rf_set_tx_power(g_cmac_shared_data.debug.tx_power_override); - } else { - ble_rf_set_tx_power(dbm); + static const int8_t supported_pwr_levels[] = {-18, -12, -8, -6, -3, -2, + -1, 0, 1, 2, 3, 4, 5, 6 }; + int i; + + for (i = 0; i < ARRAY_SIZE(supported_pwr_levels); i++) { + if (dbm <= supported_pwr_levels[i]) { + dbm = supported_pwr_levels[i]; + break; + } } -#else - ble_rf_set_tx_power(dbm); -#endif - return 0; + if (i == ARRAY_SIZE(supported_pwr_levels)) { + dbm = supported_pwr_levels[ARRAY_SIZE(supported_pwr_levels) - 1]; + } + + return dbm; } int -ble_phy_txpower_round(int dbm) +ble_phy_tx_power_set(int dbm) { +#if MYNEWT_VAL(CMAC_DEBUG_DATA_ENABLE) + if (g_cmac_shm_debugdata.tx_power_ovr_enable) { + dbm = g_cmac_shm_debugdata.tx_power_ovr; + } +#endif + + dbm = phy_txpower_round(dbm); + ble_rf_set_tx_power(dbm); + return 0; } -void -ble_phy_set_rx_pwr_compensation(int8_t compensation) +int +ble_phy_tx_power_round(int dbm) { + return phy_txpower_round(dbm); } int @@ -1714,6 +1719,12 @@ ble_phy_setchan(uint8_t chan, uint32_t access_addr, uint32_t crc_init) return 0; } +uint8_t +ble_phy_chan_get(void) +{ + return g_ble_phy_data.channel; +} + void ble_phy_restart_rx(void) { @@ -1723,7 +1734,7 @@ ble_phy_restart_rx(void) ble_phy_disable(); /* Apply mode before starting RX */ -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) +#if MYNEWT_VAL(BLE_LL_PHY) ble_phy_mode_apply(g_ble_phy_data.phy_mode_rx); #endif @@ -1807,4 +1818,12 @@ ble_phy_disable_dtm(void) { g_ble_phy_data.phy_whitening = 1; } + +#if MYNEWT_VAL(BLE_LL_DTM_EXTENSIONS) +int +ble_phy_dtm_carrier(uint8_t rf_channel) +{ + return 1; +} +#endif #endif diff --git a/nimble/drivers/dialog_cmac/src/ble_rf.c b/nimble/drivers/dialog_cmac/src/ble_rf.c index 806f4ea82d..f9756ec645 100644 --- a/nimble/drivers/dialog_cmac/src/ble_rf.c +++ b/nimble/drivers/dialog_cmac/src/ble_rf.c @@ -23,7 +23,7 @@ #include "mcu/mcu.h" #include "mcu/cmac_timer.h" #include "controller/ble_phy.h" -#include "cmac_driver/cmac_shared.h" +#include #include "ble_rf_priv.h" #define RF_CALIBRATION_0 (0x01) @@ -206,8 +206,7 @@ ble_rf_rfcu_apply_recommended_settings(void) static void ble_rf_rfcu_apply_settings(void) { - ble_rf_apply_trim(g_cmac_shared_data.trim.rfcu, - g_cmac_shared_data.trim.rfcu_len); + ble_rf_apply_trim(g_cmac_shm_trim.rfcu, g_cmac_shm_trim.rfcu_len); ble_rf_rfcu_apply_recommended_settings(); } @@ -234,6 +233,9 @@ ble_rf_synth_is_enabled(void) static void ble_rf_synth_apply_recommended_settings(void) { + if (mcu_chip_variant_get() == MCU_CHIP_VARIANT_GF) { + set_reg32_mask(0x40022034, 0x00000018, 0x0215807B); + } set_reg32_mask(0x40022048, 0x0000000c, 0x000000d5); set_reg32_mask(0x40022050, 0x00000300, 0x00000300); set_reg16_mask(0x40022024, 0x0001, 0x0001); @@ -242,8 +244,7 @@ ble_rf_synth_apply_recommended_settings(void) static void ble_rf_synth_apply_settings(void) { - ble_rf_apply_trim(g_cmac_shared_data.trim.synth, - g_cmac_shared_data.trim.synth_len); + ble_rf_apply_trim(g_cmac_shm_trim.synth, g_cmac_shm_trim.synth_len); ble_rf_synth_apply_recommended_settings(); } @@ -337,7 +338,11 @@ ble_rf_calibration_1(void) set_reg32(0x40020000, 0x0f168820); set_reg32_bits(0x40022000, 0x00000001, 0); set_reg32_bits(0x4002101c, 0x00001e00, 0); - set_reg32_bits(0x4002001c, 0x0000003f, 47); + if (mcu_chip_variant_get() == MCU_CHIP_VARIANT_TSMC) { + set_reg32_bits(0x4002001c, 0x0000003f, 47); + } else { + set_reg32_bits(0x4002001c, 0x0000003f, 44); + } set_reg8(0x40020006, 1); set_reg32(0x40020020, 16); set_reg32_bits(0x4002003c, 0x00000800, 1); @@ -495,8 +500,8 @@ ble_rf_calibrate_int(uint8_t mask) __enable_irq(); #if MYNEWT_VAL(CMAC_DEBUG_DATA_ENABLE) - g_cmac_shared_data.debug.cal_res_1 = g_ble_phy_rf_data.cal_res_1; - g_cmac_shared_data.debug.cal_res_2 = g_ble_phy_rf_data.cal_res_2; + g_cmac_shm_debugdata.cal_res_1 = g_ble_phy_rf_data.cal_res_1; + g_cmac_shm_debugdata.cal_res_2 = g_ble_phy_rf_data.cal_res_2; #endif } @@ -539,25 +544,27 @@ ble_rf_init(void) static bool done = false; uint32_t val; + assert(mcu_chip_variant_get()); + ble_rf_disable(); if (done) { return; } - val = ble_rf_find_trim_reg(g_cmac_shared_data.trim.rfcu_mode1, - g_cmac_shared_data.trim.rfcu_mode1_len, + val = ble_rf_find_trim_reg(g_cmac_shm_trim.rfcu_mode1, + g_cmac_shm_trim.rfcu_mode1_len, 0x4002004c); g_ble_phy_rf_data.trim_val1_tx_1 = val; - val = ble_rf_find_trim_reg(g_cmac_shared_data.trim.rfcu_mode2, - g_cmac_shared_data.trim.rfcu_mode2_len, + val = ble_rf_find_trim_reg(g_cmac_shm_trim.rfcu_mode2, + g_cmac_shm_trim.rfcu_mode2_len, 0x4002004c); g_ble_phy_rf_data.trim_val1_tx_2 = val; if (!g_ble_phy_rf_data.trim_val1_tx_1 || !g_ble_phy_rf_data.trim_val1_tx_2) { - val = ble_rf_find_trim_reg(g_cmac_shared_data.trim.rfcu, - g_cmac_shared_data.trim.rfcu_len, + val = ble_rf_find_trim_reg(g_cmac_shm_trim.rfcu, + g_cmac_shm_trim.rfcu_len, 0x4002004c); if (!val) { val = 0x0300; @@ -566,8 +573,8 @@ ble_rf_init(void) g_ble_phy_rf_data.trim_val1_tx_2 = val; } - val = ble_rf_find_trim_reg(g_cmac_shared_data.trim.synth, - g_cmac_shared_data.trim.synth_len, + val = ble_rf_find_trim_reg(g_cmac_shm_trim.synth, + g_cmac_shm_trim.synth_len, 0x40022038); if (!val) { val = 0x0198ff03; @@ -577,10 +584,10 @@ ble_rf_init(void) set_reg32_bits((uint32_t)&g_ble_phy_rf_data.trim_val2_tx, 0x0001ff00, 0x87); #if MYNEWT_VAL(CMAC_DEBUG_DATA_ENABLE) - g_cmac_shared_data.debug.trim_val1_tx_1 = g_ble_phy_rf_data.trim_val1_tx_1; - g_cmac_shared_data.debug.trim_val1_tx_2 = g_ble_phy_rf_data.trim_val1_tx_2; - g_cmac_shared_data.debug.trim_val2_tx = g_ble_phy_rf_data.trim_val2_tx; - g_cmac_shared_data.debug.trim_val2_rx = g_ble_phy_rf_data.trim_val2_rx; + g_cmac_shm_debugdata.trim_val1_tx_1 = g_ble_phy_rf_data.trim_val1_tx_1; + g_cmac_shm_debugdata.trim_val1_tx_2 = g_ble_phy_rf_data.trim_val1_tx_2; + g_cmac_shm_debugdata.trim_val2_tx = g_ble_phy_rf_data.trim_val2_tx; + g_cmac_shm_debugdata.trim_val2_rx = g_ble_phy_rf_data.trim_val2_rx; #endif ble_rf_rfcu_enable(); diff --git a/nimble/transport/ram/include/transport/ram/ble_hci_ram.h b/nimble/drivers/fem/nrf21540/include/nrf21540/nrf21540.h similarity index 87% rename from nimble/transport/ram/include/transport/ram/ble_hci_ram.h rename to nimble/drivers/fem/nrf21540/include/nrf21540/nrf21540.h index 3c37e329c1..54efc854ad 100644 --- a/nimble/transport/ram/include/transport/ram/ble_hci_ram.h +++ b/nimble/drivers/fem/nrf21540/include/nrf21540/nrf21540.h @@ -17,19 +17,20 @@ * under the License. */ -#ifndef H_BLE_HCI_RAM_ -#define H_BLE_HCI_RAM_ -#include "nimble/ble_hci_trans.h" +#ifndef _NRF21540_H +#define _NRF21540_H + +#include #ifdef __cplusplus extern "C" { #endif -void ble_hci_ram_init(void); +int nrf21540_mode_set(uint8_t mode); #ifdef __cplusplus } #endif -#endif +#endif /* _NRF21540_H */ diff --git a/nimble/drivers/fem/nrf21540/pkg.yml b/nimble/drivers/fem/nrf21540/pkg.yml new file mode 100644 index 0000000000..c6dd5f55ea --- /dev/null +++ b/nimble/drivers/fem/nrf21540/pkg.yml @@ -0,0 +1,30 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +pkg.name: nimble/drivers/fem/nrf21540 +pkg.description: Driver for nRF21540 front-end module +pkg.author: "Apache Mynewt " +pkg.homepage: "https://mynewt.apache.org/" +pkg.apis: + - ble_fem_pa + - ble_fem_lna + - ble_fem_antenna + +pkg.init: + nrf21540_init: 999 diff --git a/nimble/drivers/fem/nrf21540/src/nrf21540.c b/nimble/drivers/fem/nrf21540/src/nrf21540.c new file mode 100644 index 0000000000..b70a66e769 --- /dev/null +++ b/nimble/drivers/fem/nrf21540/src/nrf21540.c @@ -0,0 +1,143 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#include +#include + +static void +nrf21540_pdn_set(int state) +{ + int pin; + + pin = MYNEWT_VAL(NRF21540_PIN_PDN); + hal_gpio_write(pin, state); +} + +int +nrf21540_mode_set(uint8_t mode) +{ +#ifdef MYNEWT_VAL_NRF21540_PIN_MODE + int pin; + + pin = MYNEWT_VAL(NRF21540_PIN_MODE); + hal_gpio_init_out(pin, mode); + + return 0; +#else + return -1; +#endif +} + +void +ble_fem_pa_init(void) +{ + nrf21540_pdn_set(0); +} + +void +ble_fem_pa_enable(void) +{ + nrf21540_pdn_set(1); +} + +void +ble_fem_pa_disable(void) +{ + nrf21540_pdn_set(0); +} + +void +ble_fem_lna_init(void) +{ +} + +void +ble_fem_lna_enable(void) +{ + nrf21540_pdn_set(1); +} + +void +ble_fem_lna_disable(void) +{ + nrf21540_pdn_set(0); +} + +int +ble_fem_antenna(uint8_t port) +{ +#ifdef MYNEWT_VAL_NRF21540_PIN_ANT_SEL + int pin; + + pin = MYNEWT_VAL(NRF21540_PIN_ANT_SEL); + switch (port) { + case 0: + case 1: + hal_gpio_write(pin, 0); + break; + case 2: + hal_gpio_write(pin, 1); + break; + default: + return -1; + } + + return 0; +#else + return -1; +#endif +} + +void +nrf21540_init(void) +{ + int pin; + + pin = MYNEWT_VAL(NRF21540_PIN_PDN); + assert(pin >= 0); + hal_gpio_init_out(pin, 0); + +#ifdef MYNEWT_VAL_NRF21540_PIN_ANT_SEL + pin = MYNEWT_VAL(NRF21540_PIN_ANT_SEL); + assert(pin >= 0); + switch (MYNEWT_VAL(NRF21540_ANTENNA_PORT)) { + case 1: + hal_gpio_init_out(pin, 0); + break; + case 2: + hal_gpio_init_out(pin, 1); + break; + default: + assert(0); + } +#endif + +#ifdef MYNEWT_VAL_NRF21540_PIN_MODE + pin = MYNEWT_VAL(NRF21540_PIN_MODE); + assert(pin >= 0); + if (MYNEWT_VAL_CHOICE(NRF21540_TX_GAIN_PRESET, POUTB)) { + hal_gpio_init_out(pin, 1); + } else { + hal_gpio_init_out(pin, 0); + } +#endif +} diff --git a/nimble/drivers/fem/nrf21540/syscfg.yml b/nimble/drivers/fem/nrf21540/syscfg.yml new file mode 100644 index 0000000000..13e5f17a9e --- /dev/null +++ b/nimble/drivers/fem/nrf21540/syscfg.yml @@ -0,0 +1,45 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +syscfg.defs: + NRF21540_PIN_PDN: + description: > + GPIO pin number to control PDN signal. + value: + restrictions: $notnull + NRF21540_PIN_ANT_SEL: + description: > + GPIO pin number to control ANT_SEL signal. + value: + NRF21540_PIN_MODE: + description: > + GPIO pin number to control MODE signal. + value: + NRF21540_ANTENNA_PORT: + description: > + Selects antenna port, valid only if ANT_SEL pin is configured. + range: 1, 2 + value: 1 + NRF21540_TX_GAIN_PRESET: + description: > + Selects TX gain preset, valid only if MODE pin is configured. + choices: + - none + - POUTA + - POUTB + value: none diff --git a/nimble/drivers/fem/sky66112/include/sky66112/sky66112.h b/nimble/drivers/fem/sky66112/include/sky66112/sky66112.h new file mode 100644 index 0000000000..4b995b616a --- /dev/null +++ b/nimble/drivers/fem/sky66112/include/sky66112/sky66112.h @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + +#ifndef _SKY66112_H +#define _SKY66112_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void sky66112_tx_hp_mode(uint8_t enabled); +void sky66112_rx_bypass(uint8_t enabled); +void sky66112_tx_bypass(uint8_t enabled); + +#if MYNEWT_VAL_CHOICE(SKY66112_ANTENNA_PORT, runtime) +uint8_t sky66112_default_antenna_get(void); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _SKY66112_H */ diff --git a/nimble/drivers/fem/sky66112/pkg.yml b/nimble/drivers/fem/sky66112/pkg.yml new file mode 100644 index 0000000000..822cfaa857 --- /dev/null +++ b/nimble/drivers/fem/sky66112/pkg.yml @@ -0,0 +1,32 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +pkg.name: nimble/drivers/fem/sky66112 +pkg.description: Driver for SKY66112 front-end module +pkg.author: "Apache Mynewt " +pkg.homepage: "https://mynewt.apache.org/" +pkg.apis: + - ble_fem_pa + - ble_fem_lna + - ble_fem_antenna +pkg.deps: + - nimble/controller + +pkg.init: + sky66112_init: 999 diff --git a/nimble/drivers/fem/sky66112/src/sky66112.c b/nimble/drivers/fem/sky66112/src/sky66112.c new file mode 100644 index 0000000000..615055c75b --- /dev/null +++ b/nimble/drivers/fem/sky66112/src/sky66112.c @@ -0,0 +1,201 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include "syscfg/syscfg.h" +#include "hal/hal_gpio.h" +#include "controller/ble_fem.h" + +static struct { + uint8_t rx_bypass : 1; + uint8_t tx_bypass : 1; +} sky66112_config = { + .rx_bypass = MYNEWT_VAL(SKY66112_RX_BYPASS), + .tx_bypass = MYNEWT_VAL(SKY66112_TX_BYPASS), +}; + +#if !MYNEWT_VAL_CHOICE(SKY66112_ANTENNA_PORT, runtime) +static uint8_t +sky66112_default_antenna_get(void) +{ + if (MYNEWT_VAL_CHOICE(SKY66112_ANTENNA_PORT, ANT2)) { + return 2; + } else { + return 1; + } +} +#endif + +static void +sky66112_bypass(uint8_t enabled) +{ + /* this is called only if bypass is enabled which means CPS PIN is + * correctly set and there is no need to check it here. + */ + hal_gpio_write(MYNEWT_VAL(SKY66112_PIN_CPS), enabled); +} + +void +ble_fem_pa_init(void) +{ + sky66112_tx_hp_mode(MYNEWT_VAL(SKY66112_TX_HP_MODE)); + sky66112_tx_bypass(0); +#if MYNEWT_VAL(BLE_FEM_ANTENNA) + ble_fem_antenna(0); +#endif +} + +void +ble_fem_pa_enable(void) +{ + if (sky66112_config.tx_bypass) { + sky66112_bypass(1); + } +} + +void +ble_fem_pa_disable(void) +{ + if (sky66112_config.tx_bypass) { + sky66112_bypass(0); + } +} + +void +ble_fem_lna_init(void) +{ + sky66112_rx_bypass(0); +#if MYNEWT_VAL(BLE_FEM_ANTENNA) + ble_fem_antenna(0); +#endif +} + +void +ble_fem_lna_enable(void) +{ + if (sky66112_config.rx_bypass) { + sky66112_bypass(1); + } +} + +void +ble_fem_lna_disable(void) +{ + if (sky66112_config.rx_bypass) { + sky66112_bypass(0); + } +} + +void +sky66112_tx_hp_mode(uint8_t enabled) +{ + int pin = MYNEWT_VAL(SKY66112_PIN_CHL); + + if (pin >= 0) { + hal_gpio_write(pin, enabled); + } +} + +int +ble_fem_antenna(uint8_t port) +{ + int pin = MYNEWT_VAL(SKY66112_PIN_SEL); + uint8_t ant; + + if (pin >= 0) { + switch (port) { + case 0: + ant = sky66112_default_antenna_get(); + assert(ant == 1 || ant == 2); + return ble_fem_antenna(ant); + case 1: + hal_gpio_write(pin, 0); + break; + case 2: + hal_gpio_write(pin, 1); + break; + default: + return -1; + } + } + + return 0; +} + +void +sky66112_rx_bypass(uint8_t enabled) +{ + int pin = MYNEWT_VAL(SKY66112_PIN_CPS); + + if (pin >= 0) { + sky66112_config.rx_bypass = enabled; + sky66112_bypass(enabled); + } +} + +void +sky66112_tx_bypass(uint8_t enabled) +{ + int pin = MYNEWT_VAL(SKY66112_PIN_CPS); + + if (pin >= 0) { + sky66112_config.tx_bypass = enabled; + sky66112_bypass(enabled); + } +} + +void +sky66112_init(void) +{ + int pin; + + /* Use CRX and CTX to enable sleep mode */ + pin = MYNEWT_VAL(SKY66112_PIN_CSD); + if (pin >= 0) { + hal_gpio_init_out(pin, 1); + } + + /* Set default tx power mode */ + pin = MYNEWT_VAL(SKY66112_PIN_CHL); + if (pin >= 0) { + hal_gpio_init_out(pin, MYNEWT_VAL(SKY66112_TX_HP_MODE)); + } + + /* Disable bypass, we'll enable it when needed */ + pin = MYNEWT_VAL(SKY66112_PIN_CPS); + if (pin >= 0) { + hal_gpio_init_out(pin, 0); + } + + /* configure default antenna */ + pin = MYNEWT_VAL(SKY66112_PIN_SEL); + if (pin >= 0) { + switch (sky66112_default_antenna_get()) { + case 1: + hal_gpio_init_out(pin, 0); + break; + case 2: + hal_gpio_init_out(pin, 1); + break; + default: + assert(0); + } + } +} diff --git a/nimble/drivers/fem/sky66112/syscfg.yml b/nimble/drivers/fem/sky66112/syscfg.yml new file mode 100644 index 0000000000..120fd4e519 --- /dev/null +++ b/nimble/drivers/fem/sky66112/syscfg.yml @@ -0,0 +1,76 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +syscfg.defs: + SKY66112_PIN_CSD: + description: > + GPIO pin number to control CSD signal. + When set to '-1', pin state will not be changed and it should be + driven externally. + value: -1 + SKY66112_PIN_CPS: + description: > + GPIO pin number to control CPS signal. + When set to '-1', pin state will not be changed and it should be + driven externally. + value: -1 + SKY66112_PIN_CHL: + description: > + GPIO pin number to control CHL signal. + When set to '-1', pin state will not be changed and it should be + driven externally. + value: -1 + SKY66112_PIN_SEL: + description: > + GPIO pin number to control SEL signal. + When set to '-1', pin state will not be changed and it should be + driven externally. + value: -1 + SKY66112_TX_HP_MODE: + description: > + Enables high-power mode for TX. + Only valid if CHL signal is controller by driver. + value: 0 + SKY66112_TX_BYPASS: + description: > + Enables bypass for TX which effectively disables operation as PA. + Only valid if CPS signal is controller by driver. + value: 0 + SKY66112_RX_BYPASS: + description: > + Enables bypass for RX which effectively disables operation as PA. + Only valid if CPS signal is controller by driver. + value: 0 + SKY66112_ANTENNA_PORT: + description: > + Selects which antenna port should be enabled. If 'runtime' is + selected sky66112_default_antenna_get() (see sky66112/sky66112.h) + shall be implemeneted by application. + choices: + - ANT1 + - ANT2 + - runtime + value: ANT1 + +syscfg.vals.!BLE_FEM_PA: + # Enable TX bypass by default if PA is disabled + SKY66112_TX_BYPASS: 1 + +syscfg.vals.!BLE_FEM_LNA: + # Enable RX bypass by default if LNA is disabled + SKY66112_RX_BYPASS: 1 diff --git a/nimble/drivers/fem/sky66403/include/sky66403/sky66403.h b/nimble/drivers/fem/sky66403/include/sky66403/sky66403.h new file mode 100644 index 0000000000..a9dc99babd --- /dev/null +++ b/nimble/drivers/fem/sky66403/include/sky66403/sky66403.h @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + +#ifndef _SKY66403_H +#define _SKY66403_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void sky66403_tx_linear_mode(uint8_t enabled); +void sky66403_rx_bypass(uint8_t enabled); +void sky66403_tx_bypass(uint8_t enabled); + +#if MYNEWT_VAL_CHOICE(SKY66403_ANTENNA_PORT, runtime) +uint8_t sky66403_default_antenna_get(void); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _SKY66403_H */ diff --git a/nimble/drivers/fem/sky66403/pkg.yml b/nimble/drivers/fem/sky66403/pkg.yml new file mode 100644 index 0000000000..d119cf12cd --- /dev/null +++ b/nimble/drivers/fem/sky66403/pkg.yml @@ -0,0 +1,32 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +pkg.name: nimble/drivers/fem/sky66403 +pkg.description: Driver for SKY66403 front-end module +pkg.author: "Apache Mynewt " +pkg.homepage: "https://mynewt.apache.org/" +pkg.apis: + - ble_fem_pa + - ble_fem_lna + - ble_fem_antenna +pkg.deps: + - nimble/controller + +pkg.init: + sky66403_init: 999 diff --git a/nimble/drivers/fem/sky66403/src/sky66403.c b/nimble/drivers/fem/sky66403/src/sky66403.c new file mode 100644 index 0000000000..1aa87d149d --- /dev/null +++ b/nimble/drivers/fem/sky66403/src/sky66403.c @@ -0,0 +1,201 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#include +#include + +static struct { + uint8_t rx_bypass : 1; + uint8_t tx_bypass : 1; +} sky66403_config = { + .rx_bypass = MYNEWT_VAL(SKY66403_RX_BYPASS), + .tx_bypass = MYNEWT_VAL(SKY66403_TX_BYPASS), +}; + +#if !MYNEWT_VAL_CHOICE(SKY66403_ANTENNA_PORT, runtime) +static uint8_t +sky66403_default_antenna_get(void) +{ + if (MYNEWT_VAL_CHOICE(SKY66403_ANTENNA_PORT, ANT2)) { + return 2; + } else { + return 1; + } +} +#endif + +static void +sky66403_bypass(uint8_t enabled) +{ + /* this is called only if bypass is enabled which means CPS PIN is + * correctly set and there is no need to check it here. + */ + hal_gpio_write(MYNEWT_VAL(SKY66403_PIN_CPS), enabled); +} + +void +ble_fem_pa_init(void) +{ + sky66403_tx_linear_mode(MYNEWT_VAL(SKY66403_TX_LINEAR_MODE)); + sky66403_tx_bypass(0); +#if MYNEWT_VAL(BLE_FEM_ANTENNA) + ble_fem_antenna(0); +#endif +} + +void +ble_fem_pa_enable(void) +{ + if (sky66403_config.tx_bypass) { + sky66403_bypass(1); + } +} + +void +ble_fem_pa_disable(void) +{ + if (sky66403_config.tx_bypass) { + sky66403_bypass(0); + } +} + +void +ble_fem_lna_init(void) +{ + sky66403_rx_bypass(0); +#if MYNEWT_VAL(BLE_FEM_ANTENNA) + ble_fem_antenna(0); +#endif +} + +void +ble_fem_lna_enable(void) +{ + if (sky66403_config.rx_bypass) { + sky66403_bypass(1); + } +} + +void +ble_fem_lna_disable(void) +{ + if (sky66403_config.rx_bypass) { + sky66403_bypass(0); + } +} + +void +sky66403_tx_linear_mode(uint8_t enabled) +{ + int pin = MYNEWT_VAL(SKY66403_PIN_CHL); + + if (pin >= 0) { + hal_gpio_write(pin, enabled); + } +} + +int +ble_fem_antenna(uint8_t port) +{ + int pin = MYNEWT_VAL(SKY66403_PIN_SEL); + uint8_t ant; + + if (pin >= 0) { + switch (port) { + case 0: + ant = sky66403_default_antenna_get(); + assert(ant == 1 || ant == 2); + return ble_fem_antenna(ant); + case 1: + hal_gpio_write(pin, 0); + break; + case 2: + hal_gpio_write(pin, 1); + break; + default: + return -1; + } + } + + return 0; +} + +void +sky66403_rx_bypass(uint8_t enabled) +{ + int pin = MYNEWT_VAL(SKY66403_PIN_CPS); + + if (pin >= 0) { + sky66403_config.rx_bypass = enabled; + sky66403_bypass(enabled); + } +} + +void +sky66403_tx_bypass(uint8_t enabled) +{ + int pin = MYNEWT_VAL(SKY66403_PIN_CPS); + + if (pin >= 0) { + sky66403_config.tx_bypass = enabled; + sky66403_bypass(enabled); + } +} + +void +sky66403_init(void) +{ + int pin; + + /* Use CRX and CTX to enable sleep mode */ + pin = MYNEWT_VAL(SKY66403_PIN_CSD); + if (pin >= 0) { + hal_gpio_init_out(pin, 1); + } + + /* Set default tx power mode */ + pin = MYNEWT_VAL(SKY66403_PIN_CHL); + if (pin >= 0) { + hal_gpio_init_out(pin, MYNEWT_VAL(SKY66403_TX_LINEAR_MODE)); + } + + /* Disable bypass, we'll enable it when needed */ + pin = MYNEWT_VAL(SKY66403_PIN_CPS); + if (pin >= 0) { + hal_gpio_init_out(pin, 0); + } + + /* configure default antenna */ + pin = MYNEWT_VAL(SKY66403_PIN_SEL); + if (pin >= 0) { + switch (sky66403_default_antenna_get()) { + case 1: + hal_gpio_init_out(pin, 0); + break; + case 2: + hal_gpio_init_out(pin, 1); + break; + default: + assert(0); + } + } +} diff --git a/nimble/drivers/fem/sky66403/syscfg.yml b/nimble/drivers/fem/sky66403/syscfg.yml new file mode 100644 index 0000000000..def2da51f3 --- /dev/null +++ b/nimble/drivers/fem/sky66403/syscfg.yml @@ -0,0 +1,76 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +syscfg.defs: + SKY66403_PIN_CSD: + description: > + GPIO pin number to control CSD signal. + When set to '-1', pin state will not be changed and it should be + driven externally. + value: -1 + SKY66403_PIN_CPS: + description: > + GPIO pin number to control CPS signal. + When set to '-1', pin state will not be changed and it should be + driven externally. + value: -1 + SKY66403_PIN_CHL: + description: > + GPIO pin number to control CHL signal. + When set to '-1', pin state will not be changed and it should be + driven externally. + value: -1 + SKY66403_PIN_SEL: + description: > + GPIO pin number to control SEL signal. + When set to '-1', pin state will not be changed and it should be + driven externally. + value: -1 + SKY66403_TX_LINEAR_MODE: + description: > + Enables linear mode for TX. + Only valid if CHL signal is controller by driver. + value: 0 + SKY66403_TX_BYPASS: + description: > + Enables bypass for TX which effectively disables operation as PA. + Only valid if CPS signal is controller by driver. + value: 0 + SKY66403_RX_BYPASS: + description: > + Enables bypass for RX which effectively disables operation as PA. + Only valid if CPS signal is controller by driver. + value: 0 + SKY66403_ANTENNA_PORT: + description: > + Selects which antenna port should be enabled. If 'runtime' is + selected SKY66403_default_antenna_get() (see SKY66403/SKY66403.h) + shall be implemeneted by application. + choices: + - ANT1 + - ANT2 + - runtime + value: ANT1 + +syscfg.vals.!BLE_FEM_PA: + # Enable TX bypass by default if PA is disabled + SKY66403_TX_BYPASS: 1 + +syscfg.vals.!BLE_FEM_LNA: + # Enable RX bypass by default if LNA is disabled + SKY66403_RX_BYPASS: 1 diff --git a/nimble/transport/dialog_cmac/cmac_driver/include/cmac_driver/cmac_diag.h b/nimble/drivers/fem/sky66405/include/sky66405/sky66405.h similarity index 83% rename from nimble/transport/dialog_cmac/cmac_driver/include/cmac_driver/cmac_diag.h rename to nimble/drivers/fem/sky66405/include/sky66405/sky66405.h index dc6ee903d1..8a8edb0ed3 100644 --- a/nimble/transport/dialog_cmac/cmac_driver/include/cmac_driver/cmac_diag.h +++ b/nimble/drivers/fem/sky66405/include/sky66405/sky66405.h @@ -17,18 +17,21 @@ * under the License. */ -#ifndef __MCU_CMAC_DIAG_H_ -#define __MCU_CMAC_DIAG_H_ + +#ifndef _SKY66405_H +#define _SKY66405_H + +#include #ifdef __cplusplus extern "C" { #endif -void cmac_diag_setup_host(void); -void cmac_diag_setup_cmac(void); +void sky66405_rx_bypass(uint8_t enabled); +void sky66405_tx_bypass(uint8_t enabled); #ifdef __cplusplus } #endif -#endif /* __MCU_CMAC_DIAG_H_ */ +#endif /* _SKY66405_H */ diff --git a/nimble/drivers/fem/sky66405/pkg.yml b/nimble/drivers/fem/sky66405/pkg.yml new file mode 100644 index 0000000000..459c232048 --- /dev/null +++ b/nimble/drivers/fem/sky66405/pkg.yml @@ -0,0 +1,31 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +pkg.name: nimble/drivers/fem/sky66405 +pkg.description: Driver for SKY66405 front-end module +pkg.author: "Apache Mynewt " +pkg.homepage: "https://mynewt.apache.org/" +pkg.apis: + - ble_fem_pa + - ble_fem_lna +pkg.deps: + - nimble/controller + +pkg.init: + sky66405_init: 999 diff --git a/nimble/drivers/fem/sky66405/src/sky66405.c b/nimble/drivers/fem/sky66405/src/sky66405.c new file mode 100644 index 0000000000..c4eb7c24a4 --- /dev/null +++ b/nimble/drivers/fem/sky66405/src/sky66405.c @@ -0,0 +1,118 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#include + +static struct { + uint8_t rx_bypass : 1; + uint8_t tx_bypass : 1; +} sky66405_config = { + .rx_bypass = MYNEWT_VAL(SKY66405_RX_BYPASS), + .tx_bypass = MYNEWT_VAL(SKY66405_TX_BYPASS), +}; + +static void +sky66405_bypass(uint8_t enabled) +{ + /* this is called only if bypass is enabled which means CPS PIN is + * correctly set and there is no need to check it here. + */ + hal_gpio_write(MYNEWT_VAL(SKY66405_PIN_CPS), enabled); +} + +void +ble_fem_pa_init(void) +{ + sky66405_tx_bypass(0); +} + +void +ble_fem_pa_enable(void) +{ + if (sky66405_config.tx_bypass) { + sky66405_bypass(1); + } +} + +void +ble_fem_pa_disable(void) +{ + if (sky66405_config.tx_bypass) { + sky66405_bypass(0); + } +} + +void +ble_fem_lna_init(void) +{ + sky66405_rx_bypass(0); +} + +void +ble_fem_lna_enable(void) +{ + if (sky66405_config.rx_bypass) { + sky66405_bypass(1); + } +} + +void +ble_fem_lna_disable(void) +{ + if (sky66405_config.rx_bypass) { + sky66405_bypass(0); + } +} + +void +sky66405_rx_bypass(uint8_t enabled) +{ + int pin = MYNEWT_VAL(SKY66405_PIN_CPS); + + if (pin >= 0) { + sky66405_config.rx_bypass = enabled; + sky66405_bypass(enabled); + } +} + +void +sky66405_tx_bypass(uint8_t enabled) +{ + int pin = MYNEWT_VAL(SKY66405_PIN_CPS); + + if (pin >= 0) { + sky66405_config.tx_bypass = enabled; + sky66405_bypass(enabled); + } +} + +void +sky66405_init(void) +{ + int pin; + + /* Disable bypass, we'll enable it when needed */ + pin = MYNEWT_VAL(SKY66405_PIN_CPS); + if (pin >= 0) { + hal_gpio_init_out(pin, 0); + } +} diff --git a/nimble/transport/ram/syscfg.yml b/nimble/drivers/fem/sky66405/syscfg.yml similarity index 51% rename from nimble/transport/ram/syscfg.yml rename to nimble/drivers/fem/sky66405/syscfg.yml index 3b822fcc60..b961bd44de 100644 --- a/nimble/transport/ram/syscfg.yml +++ b/nimble/drivers/fem/sky66405/syscfg.yml @@ -17,32 +17,27 @@ # syscfg.defs: - BLE_HCI_EVT_HI_BUF_COUNT: - description: 'Number of high-priority event buffers.' - value: 2 - - BLE_HCI_EVT_LO_BUF_COUNT: - description: 'Number of low-priority event buffers.' - value: 8 - - BLE_HCI_EVT_BUF_SIZE: - description: 'Size of each event buffer, in bytes.' - value: 70 - - BLE_ACL_BUF_COUNT: - description: 'The number of ACL data buffers' - value: 4 - - BLE_ACL_BUF_SIZE: + SKY66405_PIN_CPS: description: > - This is the maximum size of the data portion of HCI ACL data - packets. It does not include the HCI data header (of 4 bytes). - value: 255 - - BLE_TRANS_RAM_SYSINIT_STAGE: + GPIO pin number to control CPS signal. + When set to '-1', pin state will not be changed and it should be + driven externally. + value: -1 + SKY66405_TX_BYPASS: + description: > + Enables bypass for TX which effectively disables operation as PA. + Only valid if CPS signal is controller by driver. + value: 0 + SKY66405_RX_BYPASS: description: > - Sysinit stage for the RAM BLE transport. - value: 100 + Enables bypass for RX which effectively disables operation as PA. + Only valid if CPS signal is controller by driver. + value: 0 + +syscfg.vals.!BLE_FEM_PA: + # Enable TX bypass by default if PA is disabled + SKY66405_TX_BYPASS: 1 -syscfg.vals.BLE_EXT_ADV: - BLE_HCI_EVT_BUF_SIZE: 257 +syscfg.vals.!BLE_FEM_LNA: + # Enable RX bypass by default if LNA is disabled + SKY66405_RX_BYPASS: 1 diff --git a/nimble/drivers/native/src/ble_phy.c b/nimble/drivers/native/src/ble_phy.c index f9ab0fcb80..e1d2e4aa73 100644 --- a/nimble/drivers/native/src/ble_phy.c +++ b/nimble/drivers/native/src/ble_phy.c @@ -28,6 +28,10 @@ #include "controller/ble_phy.h" #include "controller/ble_ll.h" +#ifndef min +#define min(a, b) ((a) < (b) ? (a) : (b)) +#endif + /* BLE PHY data structure */ struct ble_phy_obj { @@ -165,7 +169,7 @@ ble_phy_rxpdu_copy(uint8_t *dptr, struct os_mbuf *rxpdu) struct os_mbuf_pkthdr *pkthdr; /* Better be aligned */ - assert(((uint32_t)dptr & 3) == 0); + assert(((uintptr_t)dptr & 3) == 0); pkthdr = OS_MBUF_PKTHDR(rxpdu); rem_bytes = pkthdr->omp_len; @@ -281,7 +285,7 @@ ble_phy_isr(void) ble_hdr->rxinfo.channel = g_ble_phy_data.phy_chan; ble_hdr->rxinfo.phy = BLE_PHY_1M; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - ble_hdr->rxinfo.aux_data = NULL; + ble_hdr->rxinfo.user_data = NULL; #endif /* Count PHY valid packets */ @@ -342,24 +346,23 @@ ble_phy_restart_rx(void) } #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) -/** - * Called to enable encryption at the PHY. Note that this state will persist - * in the PHY; in other words, if you call this function you have to call - * disable so that future PHY transmits/receives will not be encrypted. - * - * @param pkt_counter - * @param iv - * @param key - * @param is_master - */ void -ble_phy_encrypt_enable(uint64_t pkt_counter, uint8_t *iv, uint8_t *key, - uint8_t is_master) +ble_phy_encrypt_enable(const uint8_t *key) { } void -ble_phy_encrypt_set_pkt_cntr(uint64_t pkt_counter, int dir) +ble_phy_encrypt_header_mask_set(uint8_t mask) +{ +} + +void +ble_phy_encrypt_iv_set(const uint8_t *iv) +{ +} + +void +ble_phy_encrypt_counter_set(uint64_t counter, uint8_t dir_bit) { } @@ -464,7 +467,7 @@ ble_phy_tx(ble_phy_tx_pducb_t pducb, void *pducb_arg, uint8_t end_trans) * @return int 0: success; anything else is an error */ int -ble_phy_txpwr_set(int dbm) +ble_phy_tx_power_set(int dbm) { /* Check valid range */ assert(dbm <= BLE_PHY_MAX_PWR_DBM); @@ -492,7 +495,8 @@ ble_phy_txpwr_set(int dbm) * * @return int Rounded power in dBm */ -int ble_phy_txpower_round(int dbm) +int +ble_phy_tx_power_round(int dbm) { /* "Rail" power level if outside supported range */ if (dbm > BLE_XCVR_TX_PWR_MAX_DBM) { @@ -514,7 +518,7 @@ int ble_phy_txpower_round(int dbm) * @return int The current PHY transmit power, in dBm */ int -ble_phy_txpwr_get(void) +ble_phy_tx_power_get(void) { return g_ble_phy_data.phy_txpwr_dbm; } @@ -556,6 +560,12 @@ ble_phy_setchan(uint8_t chan, uint32_t access_addr, uint32_t crcinit) return 0; } +uint8_t +ble_phy_chan_get(void) +{ + return g_ble_phy_data.phy_chan; +} + /** * Disable the PHY. This will do the following: * -> Turn off all phy interrupts. @@ -650,3 +660,8 @@ void ble_phy_rfclk_disable(void) { } + +void +ble_phy_tifs_txtx_set(uint16_t usecs, uint8_t anchor) +{ +} diff --git a/nimble/drivers/nrf51/pkg.yml b/nimble/drivers/nrf51/pkg.yml index 816a563552..9311093b9c 100644 --- a/nimble/drivers/nrf51/pkg.yml +++ b/nimble/drivers/nrf51/pkg.yml @@ -29,3 +29,6 @@ pkg.apis: ble_driver pkg.deps: - nimble - nimble/controller + +# allows to override nimble/controller settings +pkg.subpriority: 1 diff --git a/nimble/drivers/nrf51/src/ble_hw.c b/nimble/drivers/nrf51/src/ble_hw.c index 3c7296b845..fc07506efe 100644 --- a/nimble/drivers/nrf51/src/ble_hw.c +++ b/nimble/drivers/nrf51/src/ble_hw.c @@ -88,11 +88,17 @@ ble_hw_get_public_addr(ble_addr_t *addr) int ble_hw_get_static_addr(ble_addr_t *addr) { + uint32_t addr_high; + uint32_t addr_low; int rc; if ((NRF_FICR->DEVICEADDRTYPE & 1) == 1) { - memcpy(addr->val, (void *)&NRF_FICR->DEVICEADDR[0], 4); - memcpy(&addr->val[4], (void *)&NRF_FICR->DEVICEADDR[1], 2); + addr_low = NRF_FICR->DEVICEADDR[0]; + addr_high = NRF_FICR->DEVICEADDR[1]; + + memcpy(addr->val, &addr_low, 4); + memcpy(&addr->val[4], &addr_high, 2); + addr->val[5] |= 0xc0; addr->type = BLE_ADDR_RANDOM; rc = 0; @@ -446,7 +452,7 @@ ble_hw_resolv_list_rmv(int index) if (index < g_nrf_num_irks) { --g_nrf_num_irks; - irk_entry = &g_nrf_irk_list[index]; + irk_entry = &g_nrf_irk_list[4 * index]; if (g_nrf_num_irks > index) { memmove(irk_entry, irk_entry + 4, 16 * (g_nrf_num_irks - index)); } @@ -474,13 +480,8 @@ ble_hw_resolv_list_size(void) int ble_hw_resolv_list_match(void) { - uint32_t index; - - if (NRF_AAR->EVENTS_END) { - if (NRF_AAR->EVENTS_RESOLVED) { - index = NRF_AAR->STATUS; - return (int)index; - } + if (NRF_AAR->ENABLE && NRF_AAR->EVENTS_END && NRF_AAR->EVENTS_RESOLVED) { + return (int)NRF_AAR->STATUS; } return -1; diff --git a/nimble/drivers/nrf51/src/ble_phy.c b/nimble/drivers/nrf51/src/ble_phy.c index b7e6329721..955db6351f 100644 --- a/nimble/drivers/nrf51/src/ble_phy.c +++ b/nimble/drivers/nrf51/src/ble_phy.c @@ -22,6 +22,8 @@ #include #include "syscfg/syscfg.h" #include "os/os.h" +/* Keep os_cputime explicitly to enable build on non-Mynewt platforms */ +#include "os/os_cputime.h" #include "ble/xcvr.h" #include "nimble/ble.h" #include "nimble/nimble_opt.h" @@ -45,6 +47,16 @@ #error LE Coded PHY cannot be enabled on nRF51 #endif +#ifndef min +#define min(a, b) ((a) < (b) ? (a) : (b)) +#endif + +static uint32_t +ble_phy_mode_pdu_start_off(int phy_mode) +{ + return 40; +} + /* XXX: 4) Make sure RF is higher priority interrupt than schedule */ /* @@ -94,7 +106,6 @@ struct ble_phy_obj uint8_t phy_privacy; uint8_t phy_tx_pyld_len; uint8_t *rxdptr; - int8_t rx_pwr_compensation; uint32_t phy_aar_scratch; uint32_t phy_access_address; struct ble_mbuf_hdr rxhdr; @@ -408,7 +419,7 @@ ble_phy_set_start_time(uint32_t cputime, uint8_t rem_usecs) /** * Function is used to set PPI so that we can time out waiting for a reception * to occur. This happens for two reasons: we have sent a packet and we are - * waiting for a respons (txrx should be set to ENABLE_TXRX) or we are + * waiting for a response (txrx should be set to ENABLE_TXRX) or we are * starting a connection event and we are a slave and we are waiting for the * master to send us a packet (txrx should be set to ENABLE_RX). * @@ -618,8 +629,7 @@ ble_phy_rx_end_isr(void) /* Set RSSI and CRC status flag in header */ ble_hdr = &g_ble_phy_data.rxhdr; assert(NRF_RADIO->EVENTS_RSSIEND != 0); - ble_hdr->rxinfo.rssi = (-1 * NRF_RADIO->RSSISAMPLE) + - g_ble_phy_data.rx_pwr_compensation; + ble_hdr->rxinfo.rssi = (-1 * NRF_RADIO->RSSISAMPLE); dptr = g_ble_phy_data.rxdptr; @@ -847,8 +857,6 @@ ble_phy_init(void) /* Set phy channel to an invalid channel so first set channel works */ g_ble_phy_data.phy_chan = BLE_PHY_NUM_CHANS; - g_ble_phy_data.rx_pwr_compensation = 0; - /* Toggle peripheral power to reset (just in case) */ NRF_RADIO->POWER = 0; NRF_RADIO->POWER = 1; @@ -979,24 +987,10 @@ ble_phy_rx(void) } #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) -/** - * Called to enable encryption at the PHY. Note that this state will persist - * in the PHY; in other words, if you call this function you have to call - * disable so that future PHY transmits/receives will not be encrypted. - * - * @param pkt_counter - * @param iv - * @param key - * @param is_master - */ void -ble_phy_encrypt_enable(uint64_t pkt_counter, uint8_t *iv, uint8_t *key, - uint8_t is_master) +ble_phy_encrypt_enable(const uint8_t *key) { memcpy(g_nrf_ccm_data.key, key, 16); - g_nrf_ccm_data.pkt_counter = pkt_counter; - memcpy(g_nrf_ccm_data.iv, iv, 8); - g_nrf_ccm_data.dir_bit = is_master; g_ble_phy_data.phy_encrypted = 1; /* Encryption uses LFLEN=5, S1LEN = 3. */ @@ -1010,10 +1004,16 @@ ble_phy_encrypt_enable(uint64_t pkt_counter, uint8_t *iv, uint8_t *key, } void -ble_phy_encrypt_set_pkt_cntr(uint64_t pkt_counter, int dir) +ble_phy_encrypt_iv_set(const uint8_t *iv) +{ + memcpy(g_nrf_ccm_data.iv, iv, 8); +} + +void +ble_phy_encrypt_counter_set(uint64_t counter, uint8_t dir_bit) { - g_nrf_ccm_data.pkt_counter = pkt_counter; - g_nrf_ccm_data.dir_bit = dir; + g_nrf_ccm_data.pkt_counter = counter; + g_nrf_ccm_data.dir_bit = dir_bit; } void @@ -1254,7 +1254,7 @@ ble_phy_tx(ble_phy_tx_pducb_t pducb, void *pducb_arg, uint8_t end_trans) * @return int 0: success; anything else is an error */ int -ble_phy_txpwr_set(int dbm) +ble_phy_tx_power_set(int dbm) { /* Check valid range */ assert(dbm <= BLE_PHY_MAX_PWR_DBM); @@ -1283,7 +1283,8 @@ ble_phy_txpwr_set(int dbm) * * @return int Rounded power in dBm */ -int ble_phy_txpower_round(int dbm) +int +ble_phy_tx_power_round(int dbm) { /* "Rail" power level if outside supported range */ if (dbm > NRF_TX_PWR_MAX_DBM) { @@ -1305,17 +1306,11 @@ int ble_phy_txpower_round(int dbm) * @return int The current PHY transmit power, in dBm */ int -ble_phy_txpwr_get(void) +ble_phy_tx_power_get(void) { return g_ble_phy_data.phy_txpwr_dbm; } -void -ble_phy_set_rx_pwr_compensation(int8_t compensation) -{ - g_ble_phy_data.rx_pwr_compensation = compensation; -} - /** * ble phy setchan * @@ -1357,7 +1352,7 @@ ble_phy_setchan(uint8_t chan, uint32_t access_addr, uint32_t crcinit) NRF_RADIO->RXADDRESSES = (1 << 1); NRF_RADIO->CRCINIT = crcinit; } else { - /* Logical adddress 0 preconfigured */ + /* Logical address 0 preconfigured */ NRF_RADIO->TXADDRESS = 0; NRF_RADIO->RXADDRESSES = (1 << 0); NRF_RADIO->CRCINIT = BLE_LL_CRCINIT_ADV; @@ -1374,6 +1369,12 @@ ble_phy_setchan(uint8_t chan, uint32_t access_addr, uint32_t crcinit) return 0; } +uint8_t +ble_phy_chan_get(void) +{ + return g_ble_phy_data.phy_chan; +} + /** * Stop the timer used to count microseconds when using RTC for cputime */ diff --git a/nimble/drivers/nrf51/syscfg.yml b/nimble/drivers/nrf51/syscfg.yml new file mode 100644 index 0000000000..451742a61a --- /dev/null +++ b/nimble/drivers/nrf51/syscfg.yml @@ -0,0 +1,21 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + + +syscfg.vals.!BLE_LL_CFG_FEAT_LL_EXT_ADV: + BLE_LL_STACK_SIZE: 96 diff --git a/nimble/drivers/nrf52/pkg.yml b/nimble/drivers/nrf52/pkg.yml index a1ff457e6f..c97452613a 100644 --- a/nimble/drivers/nrf52/pkg.yml +++ b/nimble/drivers/nrf52/pkg.yml @@ -18,14 +18,5 @@ # pkg.name: nimble/drivers/nrf52 -pkg.description: BLE driver for nRF52 systems. -pkg.author: "Apache Mynewt " -pkg.homepage: "http://mynewt.apache.org/" -pkg.keywords: - - ble - - bluetooth - -pkg.apis: ble_driver -pkg.deps: - - nimble - - nimble/controller +pkg.type: transient +pkg.link: "@apache-mynewt-nimble/nimble/drivers/nrf5x" diff --git a/nimble/drivers/nrf5340/pkg.yml b/nimble/drivers/nrf5340/pkg.yml index 3ff442120b..794697e9b0 100644 --- a/nimble/drivers/nrf5340/pkg.yml +++ b/nimble/drivers/nrf5340/pkg.yml @@ -18,14 +18,5 @@ # pkg.name: nimble/drivers/nrf5340 -pkg.description: BLE driver for nRF5340 systems. -pkg.author: "Apache Mynewt " -pkg.homepage: "http://mynewt.apache.org/" -pkg.keywords: - - ble - - bluetooth - -pkg.apis: ble_driver -pkg.deps: - - nimble - - nimble/controller +pkg.type: transient +pkg.link: "@apache-mynewt-nimble/nimble/drivers/nrf5x" diff --git a/nimble/drivers/nrf5340/src/ble_hw.c b/nimble/drivers/nrf5340/src/ble_hw.c deleted file mode 100644 index bbe6169779..0000000000 --- a/nimble/drivers/nrf5340/src/ble_hw.c +++ /dev/null @@ -1,475 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -/* Total number of resolving list elements */ -#define BLE_HW_RESOLV_LIST_SIZE (16) - -/* We use this to keep track of which entries are set to valid addresses */ -static uint8_t g_ble_hw_whitelist_mask; - -/* Random number generator isr callback */ -static ble_rng_isr_cb_t ble_rng_isr_cb; - -/* If LL privacy is enabled, allocate memory for AAR */ -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - -/* The NRF5340 supports up to 16 IRK entries */ -#if (MYNEWT_VAL(BLE_LL_RESOLV_LIST_SIZE) < 16) -#define NRF_IRK_LIST_ENTRIES (MYNEWT_VAL(BLE_LL_RESOLV_LIST_SIZE)) -#else -#define NRF_IRK_LIST_ENTRIES (16) -#endif - -/* NOTE: each entry is 16 bytes long. */ -uint32_t g_nrf_irk_list[NRF_IRK_LIST_ENTRIES * 4]; - -/* Current number of IRK entries */ -uint8_t g_nrf_num_irks; - -#endif - -/* Returns public device address or -1 if not present */ -int -ble_hw_get_public_addr(ble_addr_t *addr) -{ - uint32_t addr_high; - uint32_t addr_low; - - /* Does FICR have a public address */ - if ((NRF_FICR_NS->DEVICEADDRTYPE & 1) != 0) { - return -1; - } - - /* Copy into device address. We can do this because we know platform */ - addr_low = NRF_FICR_NS->DEVICEADDR[0]; - addr_high = NRF_FICR_NS->DEVICEADDR[1]; - memcpy(addr->val, &addr_low, 4); - memcpy(&addr->val[4], &addr_high, 2); - addr->type = BLE_ADDR_PUBLIC; - - return 0; -} - -/* Returns random static address or -1 if not present */ -int -ble_hw_get_static_addr(ble_addr_t *addr) -{ - int rc; - - if ((NRF_FICR_NS->DEVICEADDRTYPE & 1) == 1) { - memcpy(addr->val, (void *)&NRF_FICR_NS->DEVICEADDR[0], 4); - memcpy(&addr->val[4], (void *)&NRF_FICR_NS->DEVICEADDR[1], 2); - addr->val[5] |= 0xc0; - addr->type = BLE_ADDR_RANDOM; - rc = 0; - } else { - rc = -1; - } - - return rc; -} - -/** - * Clear the whitelist - * - * @return int - */ -void -ble_hw_whitelist_clear(void) -{ - NRF_RADIO_NS->DACNF = 0; - g_ble_hw_whitelist_mask = 0; -} - -/** - * Add a device to the hw whitelist - * - * @param addr - * @param addr_type - * - * @return int 0: success, BLE error code otherwise - */ -int -ble_hw_whitelist_add(const uint8_t *addr, uint8_t addr_type) -{ - int i; - uint32_t mask; - - /* Find first ununsed device address match element */ - mask = 0x01; - for (i = 0; i < BLE_HW_WHITE_LIST_SIZE; ++i) { - if ((mask & g_ble_hw_whitelist_mask) == 0) { - NRF_RADIO_NS->DAB[i] = get_le32(addr); - NRF_RADIO_NS->DAP[i] = get_le16(addr + 4); - if (addr_type == BLE_ADDR_RANDOM) { - NRF_RADIO_NS->DACNF |= (mask << 8); - } - g_ble_hw_whitelist_mask |= mask; - return BLE_ERR_SUCCESS; - } - mask <<= 1; - } - - return BLE_ERR_MEM_CAPACITY; -} - -/** - * Remove a device from the hw whitelist - * - * @param addr - * @param addr_type - * - */ -void -ble_hw_whitelist_rmv(const uint8_t *addr, uint8_t addr_type) -{ - int i; - uint16_t dap; - uint16_t txadd; - uint32_t dab; - uint32_t mask; - - /* Find first ununsed device address match element */ - dab = get_le32(addr); - dap = get_le16(addr + 4); - txadd = NRF_RADIO_NS->DACNF >> 8; - mask = 0x01; - for (i = 0; i < BLE_HW_WHITE_LIST_SIZE; ++i) { - if (mask & g_ble_hw_whitelist_mask) { - if ((dab == NRF_RADIO_NS->DAB[i]) && (dap == NRF_RADIO_NS->DAP[i])) { - if (addr_type == !!(txadd & mask)) { - break; - } - } - } - mask <<= 1; - } - - if (i < BLE_HW_WHITE_LIST_SIZE) { - g_ble_hw_whitelist_mask &= ~mask; - NRF_RADIO_NS->DACNF &= ~mask; - } -} - -/** - * Returns the size of the whitelist in HW - * - * @return int Number of devices allowed in whitelist - */ -uint8_t -ble_hw_whitelist_size(void) -{ - return BLE_HW_WHITE_LIST_SIZE; -} - -/** - * Enable the whitelisted devices - */ -void -ble_hw_whitelist_enable(void) -{ - /* Enable the configured device addresses */ - NRF_RADIO_NS->DACNF |= g_ble_hw_whitelist_mask; -} - -/** - * Disables the whitelisted devices - */ -void -ble_hw_whitelist_disable(void) -{ - /* Disable all whitelist devices */ - NRF_RADIO_NS->DACNF &= 0x0000ff00; -} - -/** - * Boolean function which returns true ('1') if there is a match on the - * whitelist. - * - * @return int - */ -int -ble_hw_whitelist_match(void) -{ - return NRF_RADIO_NS->EVENTS_DEVMATCH; -} - -/* Encrypt data */ -int -ble_hw_encrypt_block(struct ble_encryption_block *ecb) -{ - int rc; - uint32_t end; - uint32_t err; - - /* Stop ECB */ - NRF_ECB_NS->TASKS_STOPECB = 1; - /* XXX: does task stop clear these counters? Anyway to do this quicker? */ - NRF_ECB_NS->EVENTS_ENDECB = 0; - NRF_ECB_NS->EVENTS_ERRORECB = 0; - NRF_ECB_NS->ECBDATAPTR = (uint32_t)ecb; - - /* Start ECB */ - NRF_ECB_NS->TASKS_STARTECB = 1; - - /* Wait till error or done */ - rc = 0; - while (1) { - end = NRF_ECB_NS->EVENTS_ENDECB; - err = NRF_ECB_NS->EVENTS_ERRORECB; - if (end || err) { - if (err) { - rc = -1; - } - break; - } - } - - return rc; -} - -/** - * Random number generator ISR. - */ -static void -ble_rng_isr(void) -{ - uint8_t rnum; - - os_trace_isr_enter(); - - /* No callback? Clear and disable interrupts */ - if (ble_rng_isr_cb == NULL) { - NRF_RNG_NS->INTENCLR = 1; - NRF_RNG_NS->EVENTS_VALRDY = 0; - (void)NRF_RNG_NS->SHORTS; - os_trace_isr_exit(); - return; - } - - /* If there is a value ready grab it */ - if (NRF_RNG_NS->EVENTS_VALRDY) { - NRF_RNG_NS->EVENTS_VALRDY = 0; - rnum = (uint8_t)NRF_RNG_NS->VALUE; - (*ble_rng_isr_cb)(rnum); - } - - os_trace_isr_exit(); -} - -/** - * Initialize the random number generator - * - * @param cb - * @param bias - * - * @return int - */ -int -ble_hw_rng_init(ble_rng_isr_cb_t cb, int bias) -{ - /* Set bias */ - if (bias) { - NRF_RNG_NS->CONFIG = 1; - } else { - NRF_RNG_NS->CONFIG = 0; - } - - /* If we were passed a function pointer we need to enable the interrupt */ - if (cb != NULL) { -#ifndef RIOT_VERSION - NVIC_SetPriority(RNG_IRQn, (1 << __NVIC_PRIO_BITS) - 1); -#endif -#if MYNEWT - NVIC_SetVector(RNG_IRQn, (uint32_t)ble_rng_isr); -#else - ble_npl_hw_set_isr(RNG_IRQn, ble_rng_isr); -#endif - NVIC_EnableIRQ(RNG_IRQn); - ble_rng_isr_cb = cb; - } - - return 0; -} - -/** - * Start the random number generator - * - * @return int - */ -int -ble_hw_rng_start(void) -{ - os_sr_t sr; - - /* No need for interrupt if there is no callback */ - OS_ENTER_CRITICAL(sr); - NRF_RNG_NS->EVENTS_VALRDY = 0; - if (ble_rng_isr_cb) { - NRF_RNG_NS->INTENSET = 1; - } - NRF_RNG_NS->TASKS_START = 1; - OS_EXIT_CRITICAL(sr); - - return 0; -} - -/** - * Stop the random generator - * - * @return int - */ -int -ble_hw_rng_stop(void) -{ - os_sr_t sr; - - /* No need for interrupt if there is no callback */ - OS_ENTER_CRITICAL(sr); - NRF_RNG_NS->INTENCLR = 1; - NRF_RNG_NS->TASKS_STOP = 1; - NRF_RNG_NS->EVENTS_VALRDY = 0; - OS_EXIT_CRITICAL(sr); - - return 0; -} - -/** - * Read the random number generator. - * - * @return uint8_t - */ -uint8_t -ble_hw_rng_read(void) -{ - uint8_t rnum; - - /* Wait for a sample */ - while (NRF_RNG_NS->EVENTS_VALRDY == 0) { - } - - NRF_RNG_NS->EVENTS_VALRDY = 0; - rnum = (uint8_t)NRF_RNG_NS->VALUE; - - return rnum; -} - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) -/** - * Clear the resolving list - * - * @return int - */ -void -ble_hw_resolv_list_clear(void) -{ - g_nrf_num_irks = 0; -} - -/** - * Add a device to the hw resolving list - * - * @param irk Pointer to IRK to add - * - * @return int 0: success, BLE error code otherwise - */ -int -ble_hw_resolv_list_add(uint8_t *irk) -{ - uint32_t *nrf_entry; - - /* Find first ununsed device address match element */ - if (g_nrf_num_irks == NRF_IRK_LIST_ENTRIES) { - return BLE_ERR_MEM_CAPACITY; - } - - /* Copy into irk list */ - nrf_entry = &g_nrf_irk_list[4 * g_nrf_num_irks]; - memcpy(nrf_entry, irk, 16); - - /* Add to total */ - ++g_nrf_num_irks; - return BLE_ERR_SUCCESS; -} - -/** - * Remove a device from the hw resolving list - * - * @param index Index of IRK to remove - */ -void -ble_hw_resolv_list_rmv(int index) -{ - uint32_t *irk_entry; - - if (index < g_nrf_num_irks) { - --g_nrf_num_irks; - irk_entry = &g_nrf_irk_list[index]; - if (g_nrf_num_irks > index) { - memmove(irk_entry, irk_entry + 4, 16 * (g_nrf_num_irks - index)); - } - } -} - -/** - * Returns the size of the resolving list. NOTE: this returns the maximum - * allowable entries in the HW. Configuration options may limit this. - * - * @return int Number of devices allowed in resolving list - */ -uint8_t -ble_hw_resolv_list_size(void) -{ - return BLE_HW_RESOLV_LIST_SIZE; -} - -/** - * Called to determine if the address received was resolved. - * - * @return int Negative values indicate unresolved address; positive values - * indicate index in resolving list of resolved address. - */ -int -ble_hw_resolv_list_match(void) -{ - uint32_t index; - - if (NRF_AAR_NS->EVENTS_END) { - if (NRF_AAR_NS->EVENTS_RESOLVED) { - index = NRF_AAR_NS->STATUS; - return (int)index; - } - } - - return -1; -} -#endif diff --git a/nimble/drivers/nrf5340/src/ble_phy.c b/nimble/drivers/nrf5340/src/ble_phy.c deleted file mode 100644 index e07bbaa11f..0000000000 --- a/nimble/drivers/nrf5340/src/ble_phy.c +++ /dev/null @@ -1,1820 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -/* - * NOTE: This code uses 0-5 DPPI channels so care should be taken when using - * DPPI somewhere else. - * TODO maybe we could reduce number of used channels if we reuse same channel - * for mutually exclusive events but for now make it simpler to debug. - */ - -#define DPPI_CH_TIMER0_EVENTS_COMPARE_0 0 -#define DPPI_CH_TIMER0_EVENTS_COMPARE_3 1 -#define DPPI_CH_RADIO_EVENTS_END 2 -#define DPPI_CH_RADIO_EVENTS_BCMATCH 3 -#define DPPI_CH_RADIO_EVENTS_ADDRESS 4 -#define DPPI_CH_RTC0_EVENTS_COMPARE_0 5 - -#define DPPI_CH_ENABLE_ALL (DPPIC_CHEN_CH0_Msk | DPPIC_CHEN_CH1_Msk | DPPIC_CHEN_CH2_Msk | \ - DPPIC_CHEN_CH3_Msk | DPPIC_CHEN_CH4_Msk | DPPIC_CHEN_CH5_Msk) - -#define DPPI_PUBLISH_TIMER0_EVENTS_COMPARE_0 ((DPPI_CH_TIMER0_EVENTS_COMPARE_0 << TIMER_PUBLISH_COMPARE_CHIDX_Pos) | \ - (TIMER_PUBLISH_COMPARE_EN_Enabled << TIMER_PUBLISH_COMPARE_EN_Pos)) -#define DPPI_PUBLISH_TIMER0_EVENTS_COMPARE_3 ((DPPI_CH_TIMER0_EVENTS_COMPARE_3 << TIMER_PUBLISH_COMPARE_CHIDX_Pos) | \ - (TIMER_PUBLISH_COMPARE_EN_Enabled << TIMER_PUBLISH_COMPARE_EN_Pos)) -#define DPPI_PUBLISH_RADIO_EVENTS_END ((DPPI_CH_RADIO_EVENTS_END << RADIO_PUBLISH_END_CHIDX_Pos) | \ - (RADIO_PUBLISH_END_EN_Enabled << RADIO_PUBLISH_END_EN_Pos)) -#define DPPI_PUBLISH_RADIO_EVENTS_BCMATCH ((DPPI_CH_RADIO_EVENTS_BCMATCH << RADIO_PUBLISH_BCMATCH_CHIDX_Pos) | \ - (RADIO_PUBLISH_BCMATCH_EN_Enabled << RADIO_PUBLISH_BCMATCH_EN_Pos)) -#define DPPI_PUBLISH_RADIO_EVENTS_ADDRESS ((DPPI_CH_RADIO_EVENTS_ADDRESS << RADIO_PUBLISH_ADDRESS_CHIDX_Pos) | \ - (RADIO_PUBLISH_ADDRESS_EN_Enabled << RADIO_PUBLISH_ADDRESS_EN_Pos)) -#define DPPI_PUBLISH_RTC0_EVENTS_COMPARE_0 ((DPPI_CH_RTC0_EVENTS_COMPARE_0 << RTC_PUBLISH_COMPARE_CHIDX_Pos) | \ - (RTC_PUBLISH_COMPARE_EN_Enabled << RTC_PUBLISH_COMPARE_EN_Pos)) - -#define DPPI_SUBSCRIBE_TIMER0_TASKS_START(_enable) ((DPPI_CH_RTC0_EVENTS_COMPARE_0 << TIMER_SUBSCRIBE_START_CHIDX_Pos) | \ - ((_enable) << TIMER_SUBSCRIBE_START_EN_Pos)) -#define DPPI_SUBSCRIBE_TIMER0_TASKS_CAPTURE1(_enable) ((DPPI_CH_RADIO_EVENTS_ADDRESS << TIMER_SUBSCRIBE_CAPTURE_CHIDX_Pos) | \ - ((_enable) << TIMER_SUBSCRIBE_CAPTURE_EN_Pos)) -#define DPPI_SUBSCRIBE_TIMER0_TASKS_CAPTURE2(_enable) ((DPPI_CH_RADIO_EVENTS_END << TIMER_SUBSCRIBE_CAPTURE_CHIDX_Pos) | \ - ((_enable) << TIMER_SUBSCRIBE_CAPTURE_EN_Pos)) -#define DPPI_SUBSCRIBE_TIMER0_TASKS_CAPTURE3(_enable) ((DPPI_CH_RADIO_EVENTS_ADDRESS << TIMER_SUBSCRIBE_CAPTURE_CHIDX_Pos) | \ - ((_enable) << TIMER_SUBSCRIBE_CAPTURE_EN_Pos)) -#define DPPI_SUBSCRIBE_RADIO_TASKS_DISABLE(_enable) ((DPPI_CH_TIMER0_EVENTS_COMPARE_3 << RADIO_SUBSCRIBE_DISABLE_CHIDX_Pos) | \ - ((_enable) << RADIO_SUBSCRIBE_DISABLE_EN_Pos)) -#define DPPI_SUBSCRIBE_RADIO_TASKS_RXEN(_enable) ((DPPI_CH_TIMER0_EVENTS_COMPARE_0 << RADIO_SUBSCRIBE_RXEN_CHIDX_Pos) | \ - ((_enable) << RADIO_SUBSCRIBE_RXEN_EN_Pos)) -#define DPPI_SUBSCRIBE_RADIO_TASKS_TXEN(_enable) ((DPPI_CH_TIMER0_EVENTS_COMPARE_0 << RADIO_SUBSCRIBE_TXEN_CHIDX_Pos) | \ - ((_enable) << RADIO_SUBSCRIBE_TXEN_EN_Pos)) -#define DPPI_SUBSCRIBE_AAR_TASKS_START(_enable) ((DPPI_CH_RADIO_EVENTS_BCMATCH << AAR_SUBSCRIBE_START_CHIDX_Pos) | \ - ((_enable) << AAR_SUBSCRIBE_START_EN_Pos)) -#define DPPI_SUBSCRIBE_CCM_TASKS_CRYPT(_enable) ((DPPI_CH_RADIO_EVENTS_ADDRESS << CCM_SUBSCRIBE_CRYPT_CHIDX_Pos) | \ - ((_enable) << CCM_SUBSCRIBE_CRYPT_EN_Pos)) - -extern uint8_t g_nrf_num_irks; -extern uint32_t g_nrf_irk_list[]; - -/* To disable all radio interrupts */ -#define NRF_RADIO_IRQ_MASK_ALL (0x34FF) - -/* - * We configure the nrf with a 1 byte S0 field, 8 bit length field, and - * zero bit S1 field. The preamble is 8 bits long. - */ -#define NRF_LFLEN_BITS (8) -#define NRF_S0LEN (1) -#define NRF_S1LEN_BITS (0) -#define NRF_CILEN_BITS (2) -#define NRF_TERMLEN_BITS (3) - -/* Maximum length of frames */ -#define NRF_MAXLEN (255) -#define NRF_BALEN (3) /* For base address of 3 bytes */ - -/* NRF_RADIO_NS->PCNF0 configuration values */ -#define NRF_PCNF0 (NRF_LFLEN_BITS << RADIO_PCNF0_LFLEN_Pos) | \ - (RADIO_PCNF0_S1INCL_Msk) | \ - (NRF_S0LEN << RADIO_PCNF0_S0LEN_Pos) | \ - (NRF_S1LEN_BITS << RADIO_PCNF0_S1LEN_Pos) -#define NRF_PCNF0_1M (NRF_PCNF0) | \ - (RADIO_PCNF0_PLEN_8bit << RADIO_PCNF0_PLEN_Pos) -#define NRF_PCNF0_2M (NRF_PCNF0) | \ - (RADIO_PCNF0_PLEN_16bit << RADIO_PCNF0_PLEN_Pos) -#define NRF_PCNF0_CODED (NRF_PCNF0) | \ - (RADIO_PCNF0_PLEN_LongRange << RADIO_PCNF0_PLEN_Pos) | \ - (NRF_CILEN_BITS << RADIO_PCNF0_CILEN_Pos) | \ - (NRF_TERMLEN_BITS << RADIO_PCNF0_TERMLEN_Pos) - -/* BLE PHY data structure */ -struct ble_phy_obj { - uint8_t phy_stats_initialized; - int8_t phy_txpwr_dbm; - uint8_t phy_chan; - uint8_t phy_state; - uint8_t phy_transition; - uint8_t phy_transition_late; - uint8_t phy_rx_started; - uint8_t phy_encrypted; - uint8_t phy_privacy; - uint8_t phy_tx_pyld_len; - uint8_t phy_cur_phy_mode; - uint8_t phy_tx_phy_mode; - uint8_t phy_rx_phy_mode; - uint8_t phy_bcc_offset; - int8_t rx_pwr_compensation; - uint32_t phy_aar_scratch; - uint32_t phy_access_address; - struct ble_mbuf_hdr rxhdr; - void *txend_arg; - ble_phy_tx_end_func txend_cb; - uint32_t phy_start_cputime; -}; -struct ble_phy_obj g_ble_phy_data; - -/* XXX: if 27 byte packets desired we can make this smaller */ -/* Global transmit/receive buffer */ -static uint32_t g_ble_phy_tx_buf[(BLE_PHY_MAX_PDU_LEN + 3) / 4]; -static uint32_t g_ble_phy_rx_buf[(BLE_PHY_MAX_PDU_LEN + 3) / 4]; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) -/* Make sure word-aligned for faster copies */ -static uint32_t g_ble_phy_enc_buf[(BLE_PHY_MAX_PDU_LEN + 3) / 4]; -#endif - -/* RF center frequency for each channel index (offset from 2400 MHz) */ -static const uint8_t g_ble_phy_chan_freq[BLE_PHY_NUM_CHANS] = { - 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, /* 0-9 */ - 24, 28, 30, 32, 34, 36, 38, 40, 42, 44, /* 10-19 */ - 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, /* 20-29 */ - 66, 68, 70, 72, 74, 76, 78, 2, 26, 80, /* 30-39 */ -}; - -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) -/* packet start offsets (in usecs) */ -static const uint16_t g_ble_phy_mode_pkt_start_off[BLE_PHY_NUM_MODE] = { - [BLE_PHY_MODE_1M] = 40, - [BLE_PHY_MODE_2M] = 24, - [BLE_PHY_MODE_CODED_125KBPS] = 376, - [BLE_PHY_MODE_CODED_500KBPS] = 376 -}; -#endif - -/* Various radio timings */ -/* Radio ramp-up times in usecs (fast mode) */ -#define BLE_PHY_T_TXENFAST (XCVR_TX_RADIO_RAMPUP_USECS) -#define BLE_PHY_T_RXENFAST (XCVR_RX_RADIO_RAMPUP_USECS) - -/* delay between EVENTS_READY and start of tx */ -static const uint8_t g_ble_phy_t_txdelay[BLE_PHY_NUM_MODE] = { - [BLE_PHY_MODE_1M] = 4, - [BLE_PHY_MODE_2M] = 3, - [BLE_PHY_MODE_CODED_125KBPS] = 5, - [BLE_PHY_MODE_CODED_500KBPS] = 5 -}; -/* delay between EVENTS_END and end of txd packet */ -static const uint8_t g_ble_phy_t_txenddelay[BLE_PHY_NUM_MODE] = { - [BLE_PHY_MODE_1M] = 4, - [BLE_PHY_MODE_2M] = 3, - [BLE_PHY_MODE_CODED_125KBPS] = 9, - [BLE_PHY_MODE_CODED_500KBPS] = 3 -}; -/* delay between rxd access address (w/ TERM1 for coded) and EVENTS_ADDRESS */ -static const uint8_t g_ble_phy_t_rxaddrdelay[BLE_PHY_NUM_MODE] = { - [BLE_PHY_MODE_1M] = 6, - [BLE_PHY_MODE_2M] = 2, - [BLE_PHY_MODE_CODED_125KBPS] = 17, - [BLE_PHY_MODE_CODED_500KBPS] = 17 -}; -/* delay between end of rxd packet and EVENTS_END */ -static const uint8_t g_ble_phy_t_rxenddelay[BLE_PHY_NUM_MODE] = { - [BLE_PHY_MODE_1M] = 6, - [BLE_PHY_MODE_2M] = 2, - [BLE_PHY_MODE_CODED_125KBPS] = 27, - [BLE_PHY_MODE_CODED_500KBPS] = 22 -}; - -/* Statistics */ -STATS_SECT_START(ble_phy_stats) -STATS_SECT_ENTRY(phy_isrs) -STATS_SECT_ENTRY(tx_good) -STATS_SECT_ENTRY(tx_fail) -STATS_SECT_ENTRY(tx_late) -STATS_SECT_ENTRY(tx_bytes) -STATS_SECT_ENTRY(rx_starts) -STATS_SECT_ENTRY(rx_aborts) -STATS_SECT_ENTRY(rx_valid) -STATS_SECT_ENTRY(rx_crc_err) -STATS_SECT_ENTRY(rx_late) -STATS_SECT_ENTRY(radio_state_errs) -STATS_SECT_ENTRY(rx_hw_err) -STATS_SECT_ENTRY(tx_hw_err) -STATS_SECT_END -STATS_SECT_DECL(ble_phy_stats) ble_phy_stats; - -STATS_NAME_START(ble_phy_stats) -STATS_NAME(ble_phy_stats, phy_isrs) -STATS_NAME(ble_phy_stats, tx_good) -STATS_NAME(ble_phy_stats, tx_fail) -STATS_NAME(ble_phy_stats, tx_late) -STATS_NAME(ble_phy_stats, tx_bytes) -STATS_NAME(ble_phy_stats, rx_starts) -STATS_NAME(ble_phy_stats, rx_aborts) -STATS_NAME(ble_phy_stats, rx_valid) -STATS_NAME(ble_phy_stats, rx_crc_err) -STATS_NAME(ble_phy_stats, rx_late) -STATS_NAME(ble_phy_stats, radio_state_errs) -STATS_NAME(ble_phy_stats, rx_hw_err) -STATS_NAME(ble_phy_stats, tx_hw_err) -STATS_NAME_END(ble_phy_stats) - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) -/* - * Per nordic, the number of bytes needed for scratch is 16 + MAX_PKT_SIZE. - * However, when I used a smaller size it still overwrote the scratchpad. Until - * I figure this out I am just going to allocate 67 words so we have enough - * space for 267 bytes of scratch. I used 268 bytes since not sure if this - * needs to be aligned and burning a byte is no big deal. - * - *#define NRF_ENC_SCRATCH_WORDS (((MYNEWT_VAL(BLE_LL_MAX_PKT_SIZE) + 16) + 3) / 4) - */ -#define NRF_ENC_SCRATCH_WORDS (67) - -static uint32_t nrf_encrypt_scratchpad[NRF_ENC_SCRATCH_WORDS]; - -struct nrf_ccm_data { - uint8_t key[16]; - uint64_t pkt_counter; - uint8_t dir_bit; - uint8_t iv[8]; -} __attribute__((packed)); - -static struct nrf_ccm_data nrf_ccm_data; -#endif - -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) - -uint32_t -ble_phy_mode_pdu_start_off(int phy_mode) -{ - return g_ble_phy_mode_pkt_start_off[phy_mode]; -} - -static void -ble_phy_mode_apply(uint8_t phy_mode) -{ - if (phy_mode == g_ble_phy_data.phy_cur_phy_mode) { - return; - } - - switch (phy_mode) { - case BLE_PHY_MODE_1M: - NRF_RADIO_NS->MODE = RADIO_MODE_MODE_Ble_1Mbit; - NRF_RADIO_NS->PCNF0 = NRF_PCNF0_1M; - break; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY) - case BLE_PHY_MODE_2M: - NRF_RADIO_NS->MODE = RADIO_MODE_MODE_Ble_2Mbit; - NRF_RADIO_NS->PCNF0 = NRF_PCNF0_2M; - break; -#endif -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) - case BLE_PHY_MODE_CODED_125KBPS: - NRF_RADIO_NS->MODE = RADIO_MODE_MODE_Ble_LR125Kbit; - NRF_RADIO_NS->PCNF0 = NRF_PCNF0_CODED; - break; - case BLE_PHY_MODE_CODED_500KBPS: - NRF_RADIO_NS->MODE = RADIO_MODE_MODE_Ble_LR500Kbit; - NRF_RADIO_NS->PCNF0 = NRF_PCNF0_CODED; - break; -#endif - default: - assert(0); - } - - g_ble_phy_data.phy_cur_phy_mode = phy_mode; -} -#endif - -void -ble_phy_mode_set(uint8_t tx_phy_mode, uint8_t rx_phy_mode) -{ - g_ble_phy_data.phy_tx_phy_mode = tx_phy_mode; - g_ble_phy_data.phy_rx_phy_mode = rx_phy_mode; -} - -int -ble_phy_get_cur_phy(void) -{ -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) - switch (g_ble_phy_data.phy_cur_phy_mode) { - case BLE_PHY_MODE_1M: - return BLE_PHY_1M; - case BLE_PHY_MODE_2M: - return BLE_PHY_2M; - case BLE_PHY_MODE_CODED_125KBPS: - case BLE_PHY_MODE_CODED_500KBPS: - return BLE_PHY_CODED; - default: - assert(0); - return -1; - } -#else - return BLE_PHY_1M; -#endif -} - -void -ble_phy_rxpdu_copy(uint8_t *dptr, struct os_mbuf *rxpdu) -{ - uint32_t rem_len; - uint32_t copy_len; - uint32_t block_len; - uint32_t block_rem_len; - void *dst; - void *src; - struct os_mbuf * om; - - /* Better be aligned */ - assert(((uint32_t)dptr & 3) == 0); - - block_len = rxpdu->om_omp->omp_databuf_len; - rem_len = OS_MBUF_PKTHDR(rxpdu)->omp_len; - src = dptr; - - /* - * Setup for copying from first mbuf which is shorter due to packet header - * and extra leading space - */ - copy_len = block_len - rxpdu->om_pkthdr_len - 4; - om = rxpdu; - dst = om->om_data; - - while (true) { - /* - * Always copy blocks of length aligned to word size, only last mbuf - * will have remaining non-word size bytes appended. - */ - block_rem_len = copy_len; - copy_len = min(copy_len, rem_len); - copy_len &= ~3; - - dst = om->om_data; - om->om_len = copy_len; - rem_len -= copy_len; - block_rem_len -= copy_len; - - __asm__ volatile (".syntax unified \n" - " mov r4, %[len] \n" - " b 2f \n" - "1: ldr r3, [%[src], %[len]] \n" - " str r3, [%[dst], %[len]] \n" - "2: subs %[len], #4 \n" - " bpl 1b \n" - " adds %[src], %[src], r4 \n" - " adds %[dst], %[dst], r4 \n" - : [dst] "+r" (dst), [src] "+r" (src), - [len] "+r" (copy_len) - : - : "r3", "r4", "memory" - ); - - if ((rem_len < 4) && (block_rem_len >= rem_len)) { - break; - } - - /* Move to next mbuf */ - om = SLIST_NEXT(om, om_next); - copy_len = block_len; - } - - /* Copy remaining bytes, if any, to last mbuf */ - om->om_len += rem_len; - __asm__ volatile (".syntax unified \n" - " b 2f \n" - "1: ldrb r3, [%[src], %[len]] \n" - " strb r3, [%[dst], %[len]] \n" - "2: subs %[len], #1 \n" - " bpl 1b \n" - : [len] "+r" (rem_len) - : [dst] "r" (dst), [src] "r" (src) - : "r3", "memory" - ); - - /* Copy header */ - memcpy(BLE_MBUF_HDR_PTR(rxpdu), &g_ble_phy_data.rxhdr, - sizeof(struct ble_mbuf_hdr)); -} - -/** - * Called when we want to wait if the radio is in either the rx or tx - * disable states. We want to wait until that state is over before doing - * anything to the radio - */ -static void -nrf_wait_disabled(void) -{ - uint32_t state; - - state = NRF_RADIO_NS->STATE; - if (state != RADIO_STATE_STATE_Disabled) { - if ((state == RADIO_STATE_STATE_RxDisable) || - (state == RADIO_STATE_STATE_TxDisable)) { - /* This will end within a short time (6 usecs). Just poll */ - while (NRF_RADIO_NS->STATE == state) { - /* If this fails, something is really wrong. Should last - * no more than 6 usecs - */ - } - } - } -} - -static int -ble_phy_set_start_time(uint32_t cputime, uint8_t rem_usecs, bool tx) -{ - uint32_t next_cc; - uint32_t cur_cc; - uint32_t cntr; - uint32_t delta; - - /* - * We need to adjust start time to include radio ramp-up and TX pipeline - * delay (the latter only if applicable, so only for TX). - * - * Radio ramp-up time is 40 usecs and TX delay is 3 or 5 usecs depending on - * phy, thus we'll offset RTC by 2 full ticks (61 usecs) and then compensate - * using TIMER0 with 1 usec precision. - */ - - cputime -= 2; - rem_usecs += 61; - if (tx) { - rem_usecs -= BLE_PHY_T_TXENFAST; - rem_usecs -= g_ble_phy_t_txdelay[g_ble_phy_data.phy_cur_phy_mode]; - } else { - rem_usecs -= BLE_PHY_T_RXENFAST; - } - - /* - * rem_usecs will be no more than 2 ticks, but if it is more than single - * tick then we should better count one more low-power tick rather than - * 30 high-power usecs. Also make sure we don't set TIMER0 CC to 0 as the - * compare won't occur. - */ - - if (rem_usecs > 30) { - cputime++; - rem_usecs -= 30; - } - - /* - * Can we set the RTC compare to start TIMER0? We can do it if: - * a) Current compare value is not N+1 or N+2 ticks from current - * counter. - * b) The value we want to set is not at least N+2 from current - * counter. - * - * NOTE: since the counter can tick 1 while we do these calculations we - * need to account for it. - */ - next_cc = cputime & 0xffffff; - cur_cc = NRF_RTC0_NS->CC[0]; - cntr = NRF_RTC0_NS->COUNTER; - - delta = (cur_cc - cntr) & 0xffffff; - if ((delta <= 3) && (delta != 0)) { - return -1; - } - delta = (next_cc - cntr) & 0xffffff; - if ((delta & 0x800000) || (delta < 3)) { - return -1; - } - - /* Clear and set TIMER0 to fire off at proper time */ - NRF_TIMER0_NS->TASKS_CLEAR = 1; - NRF_TIMER0_NS->CC[0] = rem_usecs; - NRF_TIMER0_NS->EVENTS_COMPARE[0] = 0; - - /* Set RTC compare to start TIMER0 */ - NRF_RTC0_NS->EVENTS_COMPARE[0] = 0; - NRF_RTC0_NS->CC[0] = next_cc; - NRF_RTC0_NS->EVTENSET = RTC_EVTENSET_COMPARE0_Msk; - - /* Enable PPI */ - NRF_TIMER0_NS->SUBSCRIBE_START = DPPI_SUBSCRIBE_TIMER0_TASKS_START(1); - - /* Store the cputime at which we set the RTC */ - g_ble_phy_data.phy_start_cputime = cputime; - - return 0; -} - -static int -ble_phy_set_start_now(void) -{ - os_sr_t sr; - uint32_t now; - - OS_ENTER_CRITICAL(sr); - - /* - * Set TIMER0 to fire immediately. We can't set CC to 0 as compare will not - * occur in such case. - */ - NRF_TIMER0_NS->TASKS_CLEAR = 1; - NRF_TIMER0_NS->CC[0] = 1; - NRF_TIMER0_NS->EVENTS_COMPARE[0] = 0; - - /* - * Set RTC compare to start TIMER0. We need to set it to at least N+2 ticks - * from current value to guarantee triggering compare event, but let's set - * it to N+3 to account for possible extra tick on RTC0 during these - * operations. - */ - now = os_cputime_get32(); - NRF_RTC0_NS->EVENTS_COMPARE[0] = 0; - NRF_RTC0_NS->CC[0] = now + 3; - NRF_RTC0_NS->EVTENSET = RTC_EVTENSET_COMPARE0_Msk; - - /* Enable PPI */ - NRF_TIMER0_NS->SUBSCRIBE_START = DPPI_SUBSCRIBE_TIMER0_TASKS_START(1); - - /* - * Store the cputime at which we set the RTC - * - * XXX Compare event may be triggered on previous CC value (if it was set to - * less than N+2) so in rare cases actual start time may be 2 ticks earlier - * than what we expect. Since this is only used on RX, it may cause AUX scan - * to be scheduled 1 or 2 ticks too late so we'll miss it - it's acceptable - * for now. - */ - g_ble_phy_data.phy_start_cputime = now + 3; - - OS_EXIT_CRITICAL(sr); - - return 0; -} - -void -ble_phy_wfr_enable(int txrx, uint8_t tx_phy_mode, uint32_t wfr_usecs) -{ - uint32_t end_time; - uint8_t phy; - - phy = g_ble_phy_data.phy_cur_phy_mode; - - if (txrx == BLE_PHY_WFR_ENABLE_TXRX) { - /* RX shall start exactly T_IFS after TX end captured in CC[2] */ - end_time = NRF_TIMER0_NS->CC[2] + BLE_LL_IFS; - /* Adjust for delay between EVENT_END and actual TX end time */ - end_time += g_ble_phy_t_txenddelay[tx_phy_mode]; - /* Wait a bit longer due to allowed active clock accuracy */ - end_time += 2; - /* - * It's possible that we'll capture PDU start time at the end of timer - * cycle and since wfr expires at the beginning of calculated timer - * cycle it can be almost 1 usec too early. Let's compensate for this - * by waiting 1 usec more. - */ - end_time += 1; - } else { - /* - * RX shall start no later than wfr_usecs after RX enabled. - * CC[0] is the time of RXEN so adjust for radio ram-up. - * Do not add jitter since this is already covered by LL. - */ - end_time = NRF_TIMER0_NS->CC[0] + BLE_PHY_T_RXENFAST + wfr_usecs; - } - - /* - * Note: on LE Coded EVENT_ADDRESS is fired after TERM1 is received, so - * we are actually calculating relative to start of packet payload - * which is fine. - */ - - /* Adjust for receiving access address since this triggers EVENT_ADDRESS */ - end_time += ble_phy_mode_pdu_start_off(phy); - /* Adjust for delay between actual access address RX and EVENT_ADDRESS */ - end_time += g_ble_phy_t_rxaddrdelay[phy]; - - /* wfr_secs is the time from rxen until timeout */ - NRF_TIMER0_NS->CC[3] = end_time; - NRF_TIMER0_NS->EVENTS_COMPARE[3] = 0; - - /* Subscribe for wait for response events */ - NRF_TIMER0_NS->SUBSCRIBE_CAPTURE[3] = DPPI_SUBSCRIBE_TIMER0_TASKS_CAPTURE3(1); - NRF_RADIO_NS->SUBSCRIBE_DISABLE = DPPI_SUBSCRIBE_RADIO_TASKS_DISABLE(1); - - /* Enable the disabled interrupt so we time out on events compare */ - NRF_RADIO_NS->INTENSET = RADIO_INTENSET_DISABLED_Msk; - - /* - * It may happen that if CPU is halted for a brief moment (e.g. during flash - * erase or write), TIMER0 already counted past CC[3] and thus wfr will not - * fire as expected. In case this happened, let's just disable PPIs for wfr - * and trigger wfr manually (i.e. disable radio). - * - * Note that the same applies to RX start time set in CC[0] but since it - * should fire earlier than wfr, fixing wfr is enough. - * - * CC[1] is only used as a reference on RX start, we do not need it here so - * it can be used to read TIMER0 counter. - */ - NRF_TIMER0_NS->TASKS_CAPTURE[1] = 1; - if (NRF_TIMER0_NS->CC[1] > NRF_TIMER0_NS->CC[3]) { - /* Unsubscribe from wfr events */ - NRF_TIMER0_NS->SUBSCRIBE_CAPTURE[3] = DPPI_SUBSCRIBE_TIMER0_TASKS_CAPTURE3(0); - NRF_RADIO_NS->SUBSCRIBE_DISABLE = DPPI_SUBSCRIBE_RADIO_TASKS_DISABLE(0); - - NRF_RADIO_NS->TASKS_DISABLE = 1; - } -} - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) -static uint32_t -ble_phy_get_ccm_datarate(void) -{ -#if BLE_LL_BT5_PHY_SUPPORTED - switch (g_ble_phy_data.phy_cur_phy_mode) { - case BLE_PHY_MODE_1M: - return CCM_MODE_DATARATE_1Mbit << CCM_MODE_DATARATE_Pos; - case BLE_PHY_MODE_2M: - return CCM_MODE_DATARATE_2Mbit << CCM_MODE_DATARATE_Pos; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) - case BLE_PHY_MODE_CODED_125KBPS: - return CCM_MODE_DATARATE_125Kbps << CCM_MODE_DATARATE_Pos; - case BLE_PHY_MODE_CODED_500KBPS: - return CCM_MODE_DATARATE_500Kbps << CCM_MODE_DATARATE_Pos; -#endif - } - - assert(0); - return 0; -#else - return CCM_MODE_DATARATE_1Mbit << CCM_MODE_DATARATE_Pos; -#endif -} -#endif - -/** - * Setup transceiver for receive. - */ -static void -ble_phy_rx_xcvr_setup(void) -{ - uint8_t *dptr; - - dptr = (uint8_t *)&g_ble_phy_rx_buf[0]; - dptr += 3; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - if (g_ble_phy_data.phy_encrypted) { - NRF_RADIO_NS->PACKETPTR = (uint32_t)&g_ble_phy_enc_buf[0]; - NRF_CCM_NS->INPTR = (uint32_t)&g_ble_phy_enc_buf[0]; - NRF_CCM_NS->OUTPTR = (uint32_t)dptr; - NRF_CCM_NS->SCRATCHPTR = (uint32_t)&nrf_encrypt_scratchpad[0]; - NRF_CCM_NS->MODE = CCM_MODE_LENGTH_Msk | CCM_MODE_MODE_Decryption | - ble_phy_get_ccm_datarate(); - NRF_CCM_NS->CNFPTR = (uint32_t)&nrf_ccm_data; - NRF_CCM_NS->SHORTS = 0; - NRF_CCM_NS->EVENTS_ERROR = 0; - NRF_CCM_NS->EVENTS_ENDCRYPT = 0; - NRF_CCM_NS->TASKS_KSGEN = 1; - - /* Subscribe to radio address event */ - NRF_CCM_NS->SUBSCRIBE_CRYPT = DPPI_SUBSCRIBE_CCM_TASKS_CRYPT(1); - } else { - NRF_RADIO_NS->PACKETPTR = (uint32_t)dptr; - } -#else - NRF_RADIO_NS->PACKETPTR = (uint32_t)dptr; -#endif - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - if (g_ble_phy_data.phy_privacy) { - NRF_AAR_NS->ENABLE = AAR_ENABLE_ENABLE_Enabled; - NRF_AAR_NS->IRKPTR = (uint32_t)&g_nrf_irk_list[0]; - NRF_AAR_NS->SCRATCHPTR = (uint32_t)&g_ble_phy_data.phy_aar_scratch; - NRF_AAR_NS->EVENTS_END = 0; - NRF_AAR_NS->EVENTS_RESOLVED = 0; - NRF_AAR_NS->EVENTS_NOTRESOLVED = 0; - } else { - if (g_ble_phy_data.phy_encrypted == 0) { - NRF_AAR_NS->ENABLE = AAR_ENABLE_ENABLE_Disabled; - } - } -#endif - - /* Turn off trigger TXEN on output compare match and AAR on bcmatch */ - NRF_RADIO_NS->SUBSCRIBE_TXEN = DPPI_SUBSCRIBE_RADIO_TASKS_TXEN(0); - NRF_AAR_NS->SUBSCRIBE_START = DPPI_SUBSCRIBE_AAR_TASKS_START(0); - - /* Reset the rx started flag. Used for the wait for response */ - g_ble_phy_data.phy_rx_started = 0; - g_ble_phy_data.phy_state = BLE_PHY_STATE_RX; - -#if BLE_LL_BT5_PHY_SUPPORTED - /* - * On Coded PHY there are CI and TERM1 fields before PDU starts so we need - * to take this into account when setting up BCC. - */ - if (g_ble_phy_data.phy_cur_phy_mode == BLE_PHY_MODE_CODED_125KBPS || - g_ble_phy_data.phy_cur_phy_mode == BLE_PHY_MODE_CODED_500KBPS) { - g_ble_phy_data.phy_bcc_offset = 5; - } else { - g_ble_phy_data.phy_bcc_offset = 0; - } -#else - g_ble_phy_data.phy_bcc_offset = 0; -#endif - - /* I want to know when 1st byte received (after address) */ - NRF_RADIO_NS->BCC = 8 + g_ble_phy_data.phy_bcc_offset; /* in bits */ - NRF_RADIO_NS->EVENTS_ADDRESS = 0; - NRF_RADIO_NS->EVENTS_DEVMATCH = 0; - NRF_RADIO_NS->EVENTS_BCMATCH = 0; - NRF_RADIO_NS->EVENTS_RSSIEND = 0; - NRF_RADIO_NS->EVENTS_CRCOK = 0; - NRF_RADIO_NS->SHORTS = RADIO_SHORTS_END_DISABLE_Msk | - RADIO_SHORTS_READY_START_Msk | - RADIO_SHORTS_ADDRESS_BCSTART_Msk | - RADIO_SHORTS_ADDRESS_RSSISTART_Msk | - RADIO_SHORTS_DISABLED_RSSISTOP_Msk; - - NRF_RADIO_NS->INTENSET = RADIO_INTENSET_ADDRESS_Msk; -} - -/** - * Called from interrupt context when the transmit ends - * - */ -static void -ble_phy_tx_end_isr(void) -{ - uint8_t tx_phy_mode; - uint8_t was_encrypted; - uint8_t transition; - uint32_t rx_time; - uint32_t wfr_time; - - /* Store PHY on which we've just transmitted smth */ - tx_phy_mode = g_ble_phy_data.phy_cur_phy_mode; - - /* If this transmission was encrypted we need to remember it */ - was_encrypted = g_ble_phy_data.phy_encrypted; - (void)was_encrypted; - - /* Better be in TX state! */ - assert(g_ble_phy_data.phy_state == BLE_PHY_STATE_TX); - - /* Clear events and clear interrupt on disabled event */ - NRF_RADIO_NS->EVENTS_DISABLED = 0; - NRF_RADIO_NS->INTENCLR = RADIO_INTENCLR_DISABLED_Msk; - NRF_RADIO_NS->EVENTS_END = 0; - wfr_time = NRF_RADIO_NS->SHORTS; - (void)wfr_time; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - /* - * XXX: not sure what to do. We had a HW error during transmission. - * For now I just count a stat but continue on like all is good. - */ - if (was_encrypted) { - if (NRF_CCM_NS->EVENTS_ERROR) { - STATS_INC(ble_phy_stats, tx_hw_err); - NRF_CCM_NS->EVENTS_ERROR = 0; - } - } -#endif - - /* Call transmit end callback */ - if (g_ble_phy_data.txend_cb) { - g_ble_phy_data.txend_cb(g_ble_phy_data.txend_arg); - } - - transition = g_ble_phy_data.phy_transition; - if (transition == BLE_PHY_TRANSITION_TX_RX) { - -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) - ble_phy_mode_apply(g_ble_phy_data.phy_rx_phy_mode); -#endif - - /* Packet pointer needs to be reset. */ - ble_phy_rx_xcvr_setup(); - - ble_phy_wfr_enable(BLE_PHY_WFR_ENABLE_TXRX, tx_phy_mode, 0); - - /* Schedule RX exactly T_IFS after TX end captured in CC[2] */ - rx_time = NRF_TIMER0_NS->CC[2] + BLE_LL_IFS; - /* Adjust for delay between EVENT_END and actual TX end time */ - rx_time += g_ble_phy_t_txenddelay[tx_phy_mode]; - /* Adjust for radio ramp-up */ - rx_time -= BLE_PHY_T_RXENFAST; - /* Start listening a bit earlier due to allowed active clock accuracy */ - rx_time -= 2; - - NRF_TIMER0_NS->CC[0] = rx_time; - NRF_TIMER0_NS->EVENTS_COMPARE[0] = 0; - - /* Start radio on timer */ - NRF_RADIO_NS->SUBSCRIBE_RXEN = DPPI_SUBSCRIBE_RADIO_TASKS_RXEN(1); - - } else { - NRF_TIMER0_NS->TASKS_STOP = 1; - NRF_TIMER0_NS->TASKS_SHUTDOWN = 1; - - NRF_TIMER0_NS->SUBSCRIBE_CAPTURE[3] = DPPI_SUBSCRIBE_TIMER0_TASKS_CAPTURE3(0); - NRF_RADIO_NS->SUBSCRIBE_DISABLE = DPPI_SUBSCRIBE_RADIO_TASKS_DISABLE(0); - NRF_RADIO_NS->SUBSCRIBE_TXEN = DPPI_SUBSCRIBE_RADIO_TASKS_TXEN(0); - NRF_TIMER0_NS->SUBSCRIBE_START = DPPI_SUBSCRIBE_TIMER0_TASKS_START(0); - - assert(transition == BLE_PHY_TRANSITION_NONE); - } -} - -static inline uint8_t -ble_phy_get_cur_rx_phy_mode(void) -{ - uint8_t phy; - - phy = g_ble_phy_data.phy_cur_phy_mode; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) - /* - * For Coded PHY mode can be set to either codings since actual coding is - * set in packet header. However, here we need actual coding of received - * packet as this determines pipeline delays so need to figure this out - * using CI field. - */ - if ((phy == BLE_PHY_MODE_CODED_125KBPS) || - (phy == BLE_PHY_MODE_CODED_500KBPS)) { - phy = NRF_RADIO_NS->PDUSTAT & RADIO_PDUSTAT_CISTAT_Msk ? - BLE_PHY_MODE_CODED_500KBPS : BLE_PHY_MODE_CODED_125KBPS; - } -#endif - - return phy; -} - -static void -ble_phy_rx_end_isr(void) -{ - int rc; - uint8_t *dptr; - uint8_t crcok; - uint32_t tx_time; - struct ble_mbuf_hdr *ble_hdr; - - /* Clear events and clear interrupt */ - NRF_RADIO_NS->EVENTS_END = 0; - NRF_RADIO_NS->INTENCLR = RADIO_INTENCLR_END_Msk; - - /* Disable automatic RXEN */ - NRF_RADIO_NS->SUBSCRIBE_RXEN = DPPI_SUBSCRIBE_RADIO_TASKS_RXEN(0); - - /* Set RSSI and CRC status flag in header */ - ble_hdr = &g_ble_phy_data.rxhdr; - assert(NRF_RADIO_NS->EVENTS_RSSIEND != 0); - ble_hdr->rxinfo.rssi = (-1 * NRF_RADIO_NS->RSSISAMPLE) + - g_ble_phy_data.rx_pwr_compensation; - - dptr = (uint8_t *)&g_ble_phy_rx_buf[0]; - dptr += 3; - - /* Count PHY crc errors and valid packets */ - crcok = NRF_RADIO_NS->EVENTS_CRCOK; - if (!crcok) { - STATS_INC(ble_phy_stats, rx_crc_err); - } else { - STATS_INC(ble_phy_stats, rx_valid); - ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_CRC_OK; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - if (g_ble_phy_data.phy_encrypted) { - /* Only set MIC failure flag if frame is not zero length */ - if ((dptr[1] != 0) && (NRF_CCM_NS->MICSTATUS == 0)) { - ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_MIC_FAILURE; - } - - /* - * XXX: not sure how to deal with this. This should not - * be a MIC failure but we should not hand it up. I guess - * this is just some form of rx error and that is how we - * handle it? For now, just set CRC error flags - */ - if (NRF_CCM_NS->EVENTS_ERROR) { - STATS_INC(ble_phy_stats, rx_hw_err); - ble_hdr->rxinfo.flags &= ~BLE_MBUF_HDR_F_CRC_OK; - } - - /* - * XXX: This is a total hack work-around for now but I dont - * know what else to do. If ENDCRYPT is not set and we are - * encrypted we need to not trust this frame and drop it. - */ - if (NRF_CCM_NS->EVENTS_ENDCRYPT == 0) { - STATS_INC(ble_phy_stats, rx_hw_err); - ble_hdr->rxinfo.flags &= ~BLE_MBUF_HDR_F_CRC_OK; - } - } -#endif - } - -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) - ble_phy_mode_apply(g_ble_phy_data.phy_tx_phy_mode); -#endif - - /* - * Let's schedule TX now and we will just cancel it after processing RXed - * packet if we don't need TX. - * - * We need this to initiate connection in case AUX_CONNECT_REQ was sent on - * LE Coded S8. In this case the time we process RXed packet is roughly the - * same as the limit when we need to have TX scheduled (i.e. TIMER0 and PPI - * armed) so we may simply miss the slot and set the timer in the past. - * - * When TX is scheduled in advance, we may event process packet a bit longer - * during radio ramp-up - this gives us extra 40 usecs which is more than - * enough. - */ - - /* Schedule TX exactly T_IFS after RX end captured in CC[2] */ - tx_time = NRF_TIMER0_NS->CC[2] + BLE_LL_IFS; - /* Adjust for delay between actual RX end time and EVENT_END */ - tx_time -= g_ble_phy_t_rxenddelay[ble_hdr->rxinfo.phy_mode]; - /* Adjust for radio ramp-up */ - tx_time -= BLE_PHY_T_TXENFAST; - /* Adjust for delay between EVENT_READY and actual TX start time */ - tx_time -= g_ble_phy_t_txdelay[g_ble_phy_data.phy_cur_phy_mode]; - - NRF_TIMER0_NS->CC[0] = tx_time; - NRF_TIMER0_NS->EVENTS_COMPARE[0] = 0; - - /* Enable automatic TX */ - NRF_RADIO_NS->SUBSCRIBE_TXEN = DPPI_SUBSCRIBE_RADIO_TASKS_TXEN(1); - - /* - * XXX: Hack warning! - * - * It may happen (during flash erase) that CPU is stopped for a moment and - * TIMER0 already counted past CC[0]. In such case we will be stuck waiting - * for TX to start since EVENTS_COMPARE[0] will not happen any time soon. - * For now let's set a flag denoting that we are late in RX-TX transition so - * ble_phy_tx() will fail - this allows everything to cleanup nicely without - * the need for extra handling in many places. - * - * Note: CC[3] is used only for wfr which we do not need here. - */ - NRF_TIMER0_NS->TASKS_CAPTURE[3] = 1; - if (NRF_TIMER0_NS->CC[3] > NRF_TIMER0_NS->CC[0]) { - NRF_RADIO_NS->SUBSCRIBE_TXEN = DPPI_SUBSCRIBE_RADIO_TASKS_TXEN(0); - - g_ble_phy_data.phy_transition_late = 1; - } - - /* - * XXX: This is a horrible ugly hack to deal with the RAM S1 byte - * that is not sent over the air but is present here. Simply move the - * data pointer to deal with it. Fix this later. - */ - dptr[2] = dptr[1]; - dptr[1] = dptr[0]; - rc = ble_ll_rx_end(dptr + 1, ble_hdr); - if (rc < 0) { - ble_phy_disable(); - } -} - -static bool -ble_phy_rx_start_isr(void) -{ - int rc; - uint32_t state; - uint32_t usecs; - uint32_t pdu_usecs; - uint32_t ticks; - struct ble_mbuf_hdr *ble_hdr; - uint8_t *dptr; -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - int adva_offset; -#endif - - dptr = (uint8_t *)&g_ble_phy_rx_buf[0]; - - /* Clear events and clear interrupt */ - NRF_RADIO_NS->EVENTS_ADDRESS = 0; - - /* Clear wfr timer channels and DISABLED interrupt */ - NRF_RADIO_NS->INTENCLR = RADIO_INTENCLR_DISABLED_Msk | RADIO_INTENCLR_ADDRESS_Msk; - NRF_TIMER0_NS->SUBSCRIBE_CAPTURE[3] = DPPI_SUBSCRIBE_TIMER0_TASKS_CAPTURE3(0); - NRF_RADIO_NS->SUBSCRIBE_DISABLE = DPPI_SUBSCRIBE_RADIO_TASKS_DISABLE(0); - - /* Initialize the ble mbuf header */ - ble_hdr = &g_ble_phy_data.rxhdr; - ble_hdr->rxinfo.flags = ble_ll_state_get(); - ble_hdr->rxinfo.channel = g_ble_phy_data.phy_chan; - ble_hdr->rxinfo.handle = 0; - ble_hdr->rxinfo.phy = ble_phy_get_cur_phy(); - ble_hdr->rxinfo.phy_mode = ble_phy_get_cur_rx_phy_mode(); -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV) - ble_hdr->rxinfo.user_data = NULL; -#endif - - /* - * Calculate accurate packets start time (with remainder) - * - * We may start receiving packet somewhere during preamble in which case - * it is possible that actual transmission started before TIMER0 was - * running - need to take this into account. - */ - ble_hdr->beg_cputime = g_ble_phy_data.phy_start_cputime; - - usecs = NRF_TIMER0_NS->CC[1]; - pdu_usecs = ble_phy_mode_pdu_start_off(ble_hdr->rxinfo.phy_mode) + - g_ble_phy_t_rxaddrdelay[ble_hdr->rxinfo.phy_mode]; - if (usecs < pdu_usecs) { - g_ble_phy_data.phy_start_cputime--; - usecs += 30; - } - usecs -= pdu_usecs; - - ticks = os_cputime_usecs_to_ticks(usecs); - usecs -= os_cputime_ticks_to_usecs(ticks); - if (usecs == 31) { - usecs = 0; - ++ticks; - } - - ble_hdr->beg_cputime += ticks; - ble_hdr->rem_usecs = usecs; - - /* Wait to get 1st byte of frame */ - while (1) { - state = NRF_RADIO_NS->STATE; - if (NRF_RADIO_NS->EVENTS_BCMATCH != 0) { - break; - } - - /* - * If state is disabled, we should have the BCMATCH. If not, - * something is wrong! - */ - if (state == RADIO_STATE_STATE_Disabled) { - NRF_RADIO_NS->INTENCLR = NRF_RADIO_IRQ_MASK_ALL; - NRF_RADIO_NS->SHORTS = 0; - return false; - } - } - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - /* - * If privacy is enabled and received PDU has TxAdd bit set (i.e. random - * address) we try to resolve address using AAR. - */ - if (g_ble_phy_data.phy_privacy && (dptr[3] & 0x40)) { - /* - * AdvA is located at 4th octet in RX buffer (after S0, length an S1 - * fields). In case of extended advertising PDU we need to add 2 more - * octets for extended header. - */ - adva_offset = (dptr[3] & 0x0f) == 0x07 ? 2 : 0; - NRF_AAR_NS->ADDRPTR = (uint32_t)(dptr + 3 + adva_offset); - - /* Trigger AAR after last bit of AdvA is received */ - NRF_RADIO_NS->EVENTS_BCMATCH = 0; - NRF_AAR_NS->SUBSCRIBE_START = DPPI_SUBSCRIBE_AAR_TASKS_START(1); - NRF_RADIO_NS->BCC = (BLE_LL_PDU_HDR_LEN + adva_offset + BLE_DEV_ADDR_LEN) * 8 + - g_ble_phy_data.phy_bcc_offset; - } -#endif - - /* Call Link Layer receive start function */ - rc = ble_ll_rx_start(dptr + 3, - g_ble_phy_data.phy_chan, - &g_ble_phy_data.rxhdr); - if (rc >= 0) { - /* Set rx started flag and enable rx end ISR */ - g_ble_phy_data.phy_rx_started = 1; - NRF_RADIO_NS->INTENSET = RADIO_INTENSET_END_Msk; - } else { - /* Disable PHY */ - ble_phy_disable(); - STATS_INC(ble_phy_stats, rx_aborts); - } - - /* Count rx starts */ - STATS_INC(ble_phy_stats, rx_starts); - - return true; -} - -static void -ble_phy_isr(void) -{ - uint32_t irq_en; - - os_trace_isr_enter(); - - /* Read irq register to determine which interrupts are enabled */ - irq_en = NRF_RADIO_NS->INTENCLR; - - /* - * NOTE: order of checking is important! Possible, if things get delayed, - * we have both an ADDRESS and DISABLED interrupt in rx state. If we get - * an address, we disable the DISABLED interrupt. - */ - - /* We get this if we have started to receive a frame */ - if ((irq_en & RADIO_INTENCLR_ADDRESS_Msk) && NRF_RADIO_NS->EVENTS_ADDRESS) { - /* - * wfr timer is calculated to expire at the exact time we should start - * receiving a packet (with 1 usec precision) so it is possible it will - * fire at the same time as EVENT_ADDRESS. If this happens, radio will - * be disabled while we are waiting for EVENT_BCCMATCH after 1st byte - * of payload is received and ble_phy_rx_start_isr() will fail. In this - * case we should not clear DISABLED irq mask so it will be handled as - * regular radio disabled event below. In other case radio was disabled - * on purpose and there's nothing more to handle so we can clear mask. - */ - if (ble_phy_rx_start_isr()) { - irq_en &= ~RADIO_INTENCLR_DISABLED_Msk; - } - } - - /* Check for disabled event. This only happens for transmits now */ - if ((irq_en & RADIO_INTENCLR_DISABLED_Msk) && NRF_RADIO_NS->EVENTS_DISABLED) { - if (g_ble_phy_data.phy_state == BLE_PHY_STATE_RX) { - NRF_RADIO_NS->EVENTS_DISABLED = 0; - ble_ll_wfr_timer_exp(NULL); - } else if (g_ble_phy_data.phy_state == BLE_PHY_STATE_IDLE) { - assert(0); - } else { - ble_phy_tx_end_isr(); - } - } - - /* Receive packet end (we dont enable this for transmit) */ - if ((irq_en & RADIO_INTENCLR_END_Msk) && NRF_RADIO_NS->EVENTS_END) { - ble_phy_rx_end_isr(); - } - - g_ble_phy_data.phy_transition_late = 0; - - /* Ensures IRQ is cleared */ - irq_en = NRF_RADIO_NS->SHORTS; - - /* Count # of interrupts */ - STATS_INC(ble_phy_stats, phy_isrs); - - os_trace_isr_exit(); -} - -int -ble_phy_init(void) -{ - int rc; - - /* Default phy to use is 1M */ - g_ble_phy_data.phy_cur_phy_mode = BLE_PHY_MODE_1M; - g_ble_phy_data.phy_tx_phy_mode = BLE_PHY_MODE_1M; - g_ble_phy_data.phy_rx_phy_mode = BLE_PHY_MODE_1M; - - g_ble_phy_data.rx_pwr_compensation = 0; - - /* Set phy channel to an invalid channel so first set channel works */ - g_ble_phy_data.phy_chan = BLE_PHY_NUM_CHANS; - - /* Toggle peripheral power to reset (just in case) */ - NRF_RADIO_NS->POWER = 0; - NRF_RADIO_NS->POWER = 1; - - /* Errata 16 - RADIO: POWER register is not functional - * Workaround: Reset all RADIO registers in firmware. - */ - NRF_RADIO_NS->SUBSCRIBE_TXEN = 0; - NRF_RADIO_NS->SUBSCRIBE_RXEN = 0; - NRF_RADIO_NS->SUBSCRIBE_DISABLE = 0; - - /* Disable all interrupts */ - NRF_RADIO_NS->INTENCLR = NRF_RADIO_IRQ_MASK_ALL; - - /* Set configuration registers */ - NRF_RADIO_NS->MODE = RADIO_MODE_MODE_Ble_1Mbit; - NRF_RADIO_NS->PCNF0 = NRF_PCNF0; - - /* XXX: should maxlen be 251 for encryption? */ - NRF_RADIO_NS->PCNF1 = NRF_MAXLEN | - (RADIO_PCNF1_ENDIAN_Little << RADIO_PCNF1_ENDIAN_Pos) | - (NRF_BALEN << RADIO_PCNF1_BALEN_Pos) | - RADIO_PCNF1_WHITEEN_Msk; - - /* Enable radio fast ramp-up */ - NRF_RADIO_NS->MODECNF0 |= (RADIO_MODECNF0_RU_Fast << RADIO_MODECNF0_RU_Pos) & RADIO_MODECNF0_RU_Msk; - - /* Set logical address 1 for TX and RX */ - NRF_RADIO_NS->TXADDRESS = 0; - NRF_RADIO_NS->RXADDRESSES = (1 << 0); - - /* Configure the CRC registers */ - NRF_RADIO_NS->CRCCNF = (RADIO_CRCCNF_SKIPADDR_Skip << RADIO_CRCCNF_SKIPADDR_Pos) | RADIO_CRCCNF_LEN_Three; - - /* Configure BLE poly */ - NRF_RADIO_NS->CRCPOLY = 0x0000065B; - - /* Configure IFS */ - NRF_RADIO_NS->TIFS = BLE_LL_IFS; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - NRF_CCM_NS->INTENCLR = 0xffffffff; - NRF_CCM_NS->SHORTS = CCM_SHORTS_ENDKSGEN_CRYPT_Msk; - NRF_CCM_NS->EVENTS_ERROR = 0; - memset(nrf_encrypt_scratchpad, 0, sizeof(nrf_encrypt_scratchpad)); -#endif - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - g_ble_phy_data.phy_aar_scratch = 0; - NRF_AAR_NS->IRKPTR = (uint32_t)&g_nrf_irk_list[0]; - NRF_AAR_NS->INTENCLR = 0xffffffff; - NRF_AAR_NS->EVENTS_END = 0; - NRF_AAR_NS->EVENTS_RESOLVED = 0; - NRF_AAR_NS->EVENTS_NOTRESOLVED = 0; - NRF_AAR_NS->NIRK = 0; -#endif - - /* TIMER0 setup for PHY when using RTC */ - NRF_TIMER0_NS->TASKS_STOP = 1; - NRF_TIMER0_NS->TASKS_SHUTDOWN = 1; - NRF_TIMER0_NS->BITMODE = 3; /* 32-bit timer */ - NRF_TIMER0_NS->MODE = 0; /* Timer mode */ - NRF_TIMER0_NS->PRESCALER = 4; /* gives us 1 MHz */ - - /* Publish events */ - NRF_TIMER0_NS->PUBLISH_COMPARE[0] = DPPI_PUBLISH_TIMER0_EVENTS_COMPARE_0; - NRF_TIMER0_NS->PUBLISH_COMPARE[3] = DPPI_PUBLISH_TIMER0_EVENTS_COMPARE_3; - NRF_RADIO_NS->PUBLISH_END = DPPI_PUBLISH_RADIO_EVENTS_END; - NRF_RADIO_NS->PUBLISH_BCMATCH = DPPI_PUBLISH_RADIO_EVENTS_BCMATCH; - NRF_RADIO_NS->PUBLISH_ADDRESS = DPPI_PUBLISH_RADIO_EVENTS_ADDRESS; - NRF_RTC0_NS->PUBLISH_COMPARE[0] = DPPI_PUBLISH_RTC0_EVENTS_COMPARE_0; - - /* Enable channels we publish on */ - NRF_DPPIC_NS->CHENSET = DPPI_CH_ENABLE_ALL; - - /* Captures tx/rx start in timer0 cc 1 and tx/rx end in timer0 cc 2 */ - NRF_TIMER0_NS->SUBSCRIBE_CAPTURE[1] = DPPI_SUBSCRIBE_TIMER0_TASKS_CAPTURE1(1); - NRF_TIMER0_NS->SUBSCRIBE_CAPTURE[2] = DPPI_SUBSCRIBE_TIMER0_TASKS_CAPTURE2(1); - - /* Set isr in vector table and enable interrupt */ -#ifndef RIOT_VERSION - NVIC_SetPriority(RADIO_IRQn, 0); -#endif -#if MYNEWT - NVIC_SetVector(RADIO_IRQn, (uint32_t)ble_phy_isr); -#else - ble_npl_hw_set_isr(RADIO_IRQn, ble_phy_isr); -#endif - NVIC_EnableIRQ(RADIO_IRQn); - - /* Register phy statistics */ - if (!g_ble_phy_data.phy_stats_initialized) { - rc = stats_init_and_reg(STATS_HDR(ble_phy_stats), - STATS_SIZE_INIT_PARMS(ble_phy_stats, - STATS_SIZE_32), - STATS_NAME_INIT_PARMS(ble_phy_stats), - "ble_phy"); - assert(rc == 0); - - g_ble_phy_data.phy_stats_initialized = 1; - } - - return 0; -} - -int -ble_phy_rx(void) -{ - /* - * Check radio state. - * - * In case radio is now disabling we'll wait for it to finish, but if for - * any reason it's just in idle state we proceed with RX as usual since - * nRF52 radio can ramp-up from idle state as well. - * - * Note that TX and RX states values are the same except for 3rd bit so we - * can make a shortcut here when checking for idle state. - */ - nrf_wait_disabled(); - if ((NRF_RADIO_NS->STATE != RADIO_STATE_STATE_Disabled) && - ((NRF_RADIO_NS->STATE & 0x07) != RADIO_STATE_STATE_RxIdle)) { - ble_phy_disable(); - STATS_INC(ble_phy_stats, radio_state_errs); - return BLE_PHY_ERR_RADIO_STATE; - } - - /* Make sure all interrupts are disabled */ - NRF_RADIO_NS->INTENCLR = NRF_RADIO_IRQ_MASK_ALL; - - /* Clear events prior to enabling receive */ - NRF_RADIO_NS->EVENTS_END = 0; - NRF_RADIO_NS->EVENTS_DISABLED = 0; - - /* Setup for rx */ - ble_phy_rx_xcvr_setup(); - - /* task to start RX should be subscribed here */ - assert(NRF_RADIO_NS->SUBSCRIBE_RXEN & DPPI_SUBSCRIBE_RADIO_TASKS_RXEN(1)); - - return 0; -} - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) -void -ble_phy_encrypt_enable(uint64_t pkt_counter, uint8_t *iv, uint8_t *key, - uint8_t is_master) -{ - memcpy(nrf_ccm_data.key, key, 16); - nrf_ccm_data.pkt_counter = pkt_counter; - memcpy(nrf_ccm_data.iv, iv, 8); - nrf_ccm_data.dir_bit = is_master; - g_ble_phy_data.phy_encrypted = 1; - /* Enable the module (AAR cannot be on while CCM on) */ - NRF_AAR_NS->ENABLE = AAR_ENABLE_ENABLE_Disabled; - NRF_CCM_NS->ENABLE = CCM_ENABLE_ENABLE_Enabled; -} - -void -ble_phy_encrypt_set_pkt_cntr(uint64_t pkt_counter, int dir) -{ - nrf_ccm_data.pkt_counter = pkt_counter; - nrf_ccm_data.dir_bit = dir; -} - -void -ble_phy_encrypt_disable(void) -{ - NRF_CCM_NS->SUBSCRIBE_CRYPT = DPPI_SUBSCRIBE_CCM_TASKS_CRYPT(0); - NRF_CCM_NS->TASKS_STOP = 1; - NRF_CCM_NS->EVENTS_ERROR = 0; - NRF_CCM_NS->ENABLE = CCM_ENABLE_ENABLE_Disabled; - - g_ble_phy_data.phy_encrypted = 0; -} -#endif - -void -ble_phy_set_txend_cb(ble_phy_tx_end_func txend_cb, void *arg) -{ - /* Set transmit end callback and arg */ - g_ble_phy_data.txend_cb = txend_cb; - g_ble_phy_data.txend_arg = arg; -} - -int -ble_phy_tx_set_start_time(uint32_t cputime, uint8_t rem_usecs) -{ - int rc; - - ble_phy_trace_u32x2(BLE_PHY_TRACE_ID_START_TX, cputime, rem_usecs); - -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) - ble_phy_mode_apply(g_ble_phy_data.phy_tx_phy_mode); -#endif - - /* XXX: This should not be necessary, but paranoia is good! */ - /* Clear timer0 compare to RXEN since we are transmitting */ - NRF_RADIO_NS->SUBSCRIBE_RXEN = DPPI_SUBSCRIBE_RADIO_TASKS_RXEN(0); - - if (ble_phy_set_start_time(cputime, rem_usecs, true) != 0) { - STATS_INC(ble_phy_stats, tx_late); - ble_phy_disable(); - rc = BLE_PHY_ERR_TX_LATE; - } else { - /* Enable PPI to automatically start TXEN */ - NRF_RADIO_NS->SUBSCRIBE_TXEN = DPPI_SUBSCRIBE_RADIO_TASKS_TXEN(1); - rc = 0; - } - return rc; -} - -int -ble_phy_rx_set_start_time(uint32_t cputime, uint8_t rem_usecs) -{ - bool late = false; - int rc = 0; - - ble_phy_trace_u32x2(BLE_PHY_TRACE_ID_START_RX, cputime, rem_usecs); - -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) - ble_phy_mode_apply(g_ble_phy_data.phy_rx_phy_mode); -#endif - - /* XXX: This should not be necessary, but paranoia is good! */ - /* Clear timer0 compare to TXEN since we are transmitting */ - NRF_RADIO_NS->SUBSCRIBE_TXEN = DPPI_SUBSCRIBE_RADIO_TASKS_TXEN(0); - - if (ble_phy_set_start_time(cputime, rem_usecs, false) != 0) { - STATS_INC(ble_phy_stats, rx_late); - - /* We're late so let's just try to start RX as soon as possible */ - ble_phy_set_start_now(); - - late = true; - } - - /* Enable PPI to automatically start RXEN */ - NRF_RADIO_NS->SUBSCRIBE_RXEN = DPPI_SUBSCRIBE_RADIO_TASKS_RXEN(1); - - /* Start rx */ - rc = ble_phy_rx(); - - /* - * If we enabled receiver but were late, let's return proper error code so - * caller can handle this. - */ - if (!rc && late) { - rc = BLE_PHY_ERR_RX_LATE; - } - - return rc; -} - -int -ble_phy_tx(ble_phy_tx_pducb_t pducb, void *pducb_arg, uint8_t end_trans) -{ - int rc; - uint8_t *dptr; - uint8_t *pktptr; - uint8_t payload_len; - uint8_t hdr_byte; - uint32_t state; - uint32_t shortcuts; - - if (g_ble_phy_data.phy_transition_late) { - ble_phy_disable(); - STATS_INC(ble_phy_stats, tx_late); - return BLE_PHY_ERR_TX_LATE; - } - - /* - * This check is to make sure that the radio is not in a state where - * it is moving to disabled state. If so, let it get there. - */ - nrf_wait_disabled(); - - /* - * XXX: Although we may not have to do this here, I clear all the PPI - * that should not be used when transmitting. Some of them are only enabled - * if encryption and/or privacy is on, but I dont care. Better to be - * paranoid, and if you are going to clear one, might as well clear them - * all. - */ - NRF_TIMER0_NS->SUBSCRIBE_CAPTURE[3] = DPPI_SUBSCRIBE_TIMER0_TASKS_CAPTURE3(0); - NRF_RADIO_NS->SUBSCRIBE_DISABLE = DPPI_SUBSCRIBE_RADIO_TASKS_DISABLE(0); - NRF_AAR_NS->SUBSCRIBE_START = DPPI_SUBSCRIBE_AAR_TASKS_START(0); - NRF_CCM_NS->SUBSCRIBE_CRYPT = DPPI_SUBSCRIBE_CCM_TASKS_CRYPT(0); - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - if (g_ble_phy_data.phy_encrypted) { - dptr = (uint8_t *)&g_ble_phy_enc_buf[0]; - pktptr = (uint8_t *)&g_ble_phy_tx_buf[0]; - NRF_CCM_NS->SHORTS = CCM_SHORTS_ENDKSGEN_CRYPT_Msk; - NRF_CCM_NS->INPTR = (uint32_t)dptr; - NRF_CCM_NS->OUTPTR = (uint32_t)pktptr; - NRF_CCM_NS->SCRATCHPTR = (uint32_t)&nrf_encrypt_scratchpad[0]; - NRF_CCM_NS->EVENTS_ERROR = 0; - NRF_CCM_NS->MODE = CCM_MODE_LENGTH_Msk | ble_phy_get_ccm_datarate(); - NRF_CCM_NS->CNFPTR = (uint32_t)&nrf_ccm_data; - } else { -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) - NRF_AAR_NS->IRKPTR = (uint32_t)&g_nrf_irk_list[0]; -#endif - dptr = (uint8_t *)&g_ble_phy_tx_buf[0]; - pktptr = dptr; - } -#else - dptr = (uint8_t *)&g_ble_phy_tx_buf[0]; - pktptr = dptr; -#endif - - /* Set PDU payload */ - payload_len = pducb(&dptr[3], pducb_arg, &hdr_byte); - - /* RAM representation has S0, LENGTH and S1 fields. (3 bytes) */ - dptr[0] = hdr_byte; - dptr[1] = payload_len; - dptr[2] = 0; - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - /* Start key-stream generation and encryption (via short) */ - if (g_ble_phy_data.phy_encrypted) { - NRF_CCM_NS->TASKS_KSGEN = 1; - } -#endif - - NRF_RADIO_NS->PACKETPTR = (uint32_t)pktptr; - - /* Clear the ready, end and disabled events */ - NRF_RADIO_NS->EVENTS_READY = 0; - NRF_RADIO_NS->EVENTS_END = 0; - NRF_RADIO_NS->EVENTS_DISABLED = 0; - - /* Enable shortcuts for transmit start/end. */ - shortcuts = RADIO_SHORTS_END_DISABLE_Msk | RADIO_SHORTS_READY_START_Msk; - NRF_RADIO_NS->SHORTS = shortcuts; - NRF_RADIO_NS->INTENSET = RADIO_INTENSET_DISABLED_Msk; - - /* Set the PHY transition */ - g_ble_phy_data.phy_transition = end_trans; - - /* Set transmitted payload length */ - g_ble_phy_data.phy_tx_pyld_len = payload_len; - - /* If we already started transmitting, abort it! */ - state = NRF_RADIO_NS->STATE; - if (state != RADIO_STATE_STATE_Tx) { - /* Set phy state to transmitting and count packet statistics */ - g_ble_phy_data.phy_state = BLE_PHY_STATE_TX; - STATS_INC(ble_phy_stats, tx_good); - STATS_INCN(ble_phy_stats, tx_bytes, payload_len + BLE_LL_PDU_HDR_LEN); - rc = BLE_ERR_SUCCESS; - } else { - ble_phy_disable(); - STATS_INC(ble_phy_stats, tx_late); - rc = BLE_PHY_ERR_RADIO_STATE; - } - - return rc; -} - -int -ble_phy_txpwr_set(int dbm) -{ - /* "Rail" power level if outside supported range */ - dbm = ble_phy_txpower_round(dbm); - - NRF_RADIO_NS->TXPOWER = dbm; - g_ble_phy_data.phy_txpwr_dbm = dbm; - - return 0; -} - -int -ble_phy_txpower_round(int dbm) -{ - /* "Rail" power level if outside supported range */ - - if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_0dBm) { - return (int8_t)RADIO_TXPOWER_TXPOWER_0dBm; - } - - if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg1dBm) { - return (int8_t)RADIO_TXPOWER_TXPOWER_Neg1dBm; - } - - if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg2dBm) { - return (int8_t)RADIO_TXPOWER_TXPOWER_Neg2dBm; - } - - if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg3dBm) { - return (int8_t)RADIO_TXPOWER_TXPOWER_Neg4dBm; - } - - if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg4dBm) { - return (int8_t)RADIO_TXPOWER_TXPOWER_Neg4dBm; - } - - if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg5dBm) { - return (int8_t)RADIO_TXPOWER_TXPOWER_Neg5dBm; - } - - if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg6dBm) { - return (int8_t)RADIO_TXPOWER_TXPOWER_Neg6dBm; - } - - if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg7dBm) { - return (int8_t)RADIO_TXPOWER_TXPOWER_Neg7dBm; - } - - if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg8dBm) { - return (int8_t)RADIO_TXPOWER_TXPOWER_Neg8dBm; - } - - if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg12dBm) { - return (int8_t)RADIO_TXPOWER_TXPOWER_Neg12dBm; - } - - if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg16dBm) { - return (int8_t)RADIO_TXPOWER_TXPOWER_Neg16dBm; - } - - if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg20dBm) { - return (int8_t)RADIO_TXPOWER_TXPOWER_Neg20dBm; - } - - if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg40dBm) { - return (int8_t)RADIO_TXPOWER_TXPOWER_Neg40dBm; - } - - return (int8_t)RADIO_TXPOWER_TXPOWER_Neg40dBm; -} - -static int -ble_phy_set_access_addr(uint32_t access_addr) -{ - NRF_RADIO_NS->BASE0 = (access_addr << 8); - NRF_RADIO_NS->PREFIX0 = (NRF_RADIO_NS->PREFIX0 & 0xFFFFFF00) | (access_addr >> 24); - - g_ble_phy_data.phy_access_address = access_addr; - - return 0; -} - -int -ble_phy_txpwr_get(void) -{ - return g_ble_phy_data.phy_txpwr_dbm; -} - -void -ble_phy_set_rx_pwr_compensation(int8_t compensation) -{ - g_ble_phy_data.rx_pwr_compensation = compensation; -} - -int -ble_phy_setchan(uint8_t chan, uint32_t access_addr, uint32_t crcinit) -{ - assert(chan < BLE_PHY_NUM_CHANS); - - /* Check for valid channel range */ - if (chan >= BLE_PHY_NUM_CHANS) { - return BLE_PHY_ERR_INV_PARAM; - } - - /* Set current access address */ - ble_phy_set_access_addr(access_addr); - - /* Configure crcinit */ - NRF_RADIO_NS->CRCINIT = crcinit; - - /* Set the frequency and the data whitening initial value */ - g_ble_phy_data.phy_chan = chan; - NRF_RADIO_NS->FREQUENCY = g_ble_phy_chan_freq[chan]; - NRF_RADIO_NS->DATAWHITEIV = chan; - - return 0; -} - -/** - * Stop the timer used to count microseconds when using RTC for cputime - */ -static void -ble_phy_stop_usec_timer(void) -{ - NRF_TIMER0_NS->TASKS_STOP = 1; - NRF_TIMER0_NS->TASKS_SHUTDOWN = 1; - NRF_RTC0_NS->EVTENCLR = RTC_EVTENSET_COMPARE0_Msk; -} - -/** - * ble phy disable irq and ppi - * - * This routine is to be called when reception was stopped due to either a - * wait for response timeout or a packet being received and the phy is to be - * restarted in receive mode. Generally, the disable routine is called to stop - * the phy. - */ -static void -ble_phy_disable_irq_and_ppi(void) -{ - NRF_RADIO_NS->INTENCLR = NRF_RADIO_IRQ_MASK_ALL; - NRF_RADIO_NS->SHORTS = 0; - NRF_RADIO_NS->TASKS_DISABLE = 1; - - NRF_TIMER0_NS->SUBSCRIBE_START = DPPI_SUBSCRIBE_TIMER0_TASKS_START(0); - NRF_TIMER0_NS->SUBSCRIBE_CAPTURE[3] = DPPI_SUBSCRIBE_TIMER0_TASKS_CAPTURE3(0); - NRF_RADIO_NS->SUBSCRIBE_DISABLE = DPPI_SUBSCRIBE_RADIO_TASKS_DISABLE(0); - NRF_RADIO_NS->SUBSCRIBE_TXEN = DPPI_SUBSCRIBE_RADIO_TASKS_TXEN(0); - NRF_RADIO_NS->SUBSCRIBE_RXEN = DPPI_SUBSCRIBE_RADIO_TASKS_RXEN(0); - NRF_AAR_NS->SUBSCRIBE_START = DPPI_SUBSCRIBE_AAR_TASKS_START(0); - NRF_CCM_NS->SUBSCRIBE_CRYPT = DPPI_SUBSCRIBE_CCM_TASKS_CRYPT(0); - - NVIC_ClearPendingIRQ(RADIO_IRQn); - g_ble_phy_data.phy_state = BLE_PHY_STATE_IDLE; -} - -void -ble_phy_restart_rx(void) -{ - ble_phy_stop_usec_timer(); - ble_phy_disable_irq_and_ppi(); - - ble_phy_set_start_now(); - /* Enable PPI to automatically start RXEN */ - NRF_RADIO_NS->SUBSCRIBE_RXEN = DPPI_SUBSCRIBE_RADIO_TASKS_RXEN(1); - - ble_phy_rx(); -} - -void -ble_phy_disable(void) -{ - ble_phy_trace_void(BLE_PHY_TRACE_ID_DISABLE); - - ble_phy_stop_usec_timer(); - ble_phy_disable_irq_and_ppi(); -} - -uint32_t -ble_phy_access_addr_get(void) -{ - return g_ble_phy_data.phy_access_address; -} - -int -ble_phy_state_get(void) -{ - return g_ble_phy_data.phy_state; -} - -int -ble_phy_rx_started(void) -{ - return g_ble_phy_data.phy_rx_started; -} - -uint8_t -ble_phy_xcvr_state_get(void) -{ - uint32_t state; - state = NRF_RADIO_NS->STATE; - return (uint8_t)state; -} - -uint8_t -ble_phy_max_data_pdu_pyld(void) -{ - return BLE_LL_DATA_PDU_MAX_PYLD; -} - -#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) -void -ble_phy_resolv_list_enable(void) -{ - NRF_AAR_NS->NIRK = (uint32_t)g_nrf_num_irks; - g_ble_phy_data.phy_privacy = 1; -} - -void -ble_phy_resolv_list_disable(void) -{ - g_ble_phy_data.phy_privacy = 0; -} -#endif - -#if MYNEWT_VAL(BLE_LL_DTM) -void -ble_phy_enable_dtm(void) -{ - /* When DTM is enabled we need to disable whitening as per - * Bluetooth v5.0 Vol 6. Part F. 4.1.1 - */ - NRF_RADIO_NS->PCNF1 &= ~RADIO_PCNF1_WHITEEN_Msk; -} - -void -ble_phy_disable_dtm(void) -{ - /* Enable whitening */ - NRF_RADIO_NS->PCNF1 |= RADIO_PCNF1_WHITEEN_Msk; -} -#endif - -void -ble_phy_rfclk_enable(void) -{ -#if MYNEWT - nrf5340_net_clock_hfxo_request(); -#else - NRF_CLOCK_NS->TASKS_HFCLKSTART = 1; -#endif -} - -void -ble_phy_rfclk_disable(void) -{ -#if MYNEWT - nrf5340_net_clock_hfxo_release(); -#else - NRF_CLOCK_NS->TASKS_HFCLKSTOP = 1; -#endif -} diff --git a/nimble/drivers/nrf52/include/ble/xcvr.h b/nimble/drivers/nrf5x/include/ble/xcvr.h similarity index 76% rename from nimble/drivers/nrf52/include/ble/xcvr.h rename to nimble/drivers/nrf5x/include/ble/xcvr.h index 757bb80faa..bb2da56845 100644 --- a/nimble/drivers/nrf52/include/ble/xcvr.h +++ b/nimble/drivers/nrf5x/include/ble/xcvr.h @@ -24,14 +24,23 @@ extern "C" { #endif +#include + #define XCVR_RX_RADIO_RAMPUP_USECS (40) #define XCVR_TX_RADIO_RAMPUP_USECS (40) -/* - * NOTE: we have to account for the RTC output compare issue. We want it to be - * 5 ticks. +/* We need to account for the RTC compare issue, we want it to be 5 ticks. + * In case FEM turn on time is more than radio enable (i.e. 2 ticks) we want + * to add 1 more tick to compensate for additional delay. + * + * TODO this file should be refactored... */ +#if (MYNEWT_VAL(BLE_FEM_PA) && (MYNEWT_VAL(BLE_FEM_PA_TURN_ON_US) > 60)) || \ + (MYNEWT_VAL(BLE_FEM_LNA) && (MYNEWT_VAL(BLE_FEM_LNA_TURN_ON_US) > 60)) +#define XCVR_PROC_DELAY_USECS (183) +#else #define XCVR_PROC_DELAY_USECS (153) +#endif #define XCVR_RX_START_DELAY_USECS (XCVR_RX_RADIO_RAMPUP_USECS) #define XCVR_TX_START_DELAY_USECS (XCVR_TX_RADIO_RAMPUP_USECS) #define XCVR_TX_SCHED_DELAY_USECS \ diff --git a/nimble/drivers/nrf5x/pkg.yml b/nimble/drivers/nrf5x/pkg.yml new file mode 100644 index 0000000000..b99e669248 --- /dev/null +++ b/nimble/drivers/nrf5x/pkg.yml @@ -0,0 +1,36 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +pkg.name: nimble/drivers/nrf5x +pkg.description: PHY for nRF52 and nRF53 series +pkg.author: "Apache Mynewt " +pkg.homepage: "https://mynewt.apache.org/" +pkg.keywords: + - ble + - bluetooth + +pkg.apis: ble_driver +pkg.deps: + - nimble + - nimble/controller + +pkg.ign_dirs.'MCU_TARGET=="nRF5340_NET"': + - nrf52 +pkg.ign_dirs.'MCU_TARGET!="nRF5340_NET"': + - nrf53 diff --git a/nimble/drivers/nrf52/src/ble_hw.c b/nimble/drivers/nrf5x/src/ble_hw.c similarity index 84% rename from nimble/drivers/nrf52/src/ble_hw.c rename to nimble/drivers/nrf5x/src/ble_hw.c index 82e6d17ed7..f8cd59f098 100644 --- a/nimble/drivers/nrf52/src/ble_hw.c +++ b/nimble/drivers/nrf5x/src/ble_hw.c @@ -30,10 +30,14 @@ #if MYNEWT #include "mcu/cmsis_nvic.h" #else +#ifdef NRF52_SERIES #include "core_cm4.h" +#endif #include #endif #include "os/os_trace_api.h" +#include +#include "hal/nrf_ecb.h" /* Total number of resolving list elements */ #define BLE_HW_RESOLV_LIST_SIZE (16) @@ -44,6 +48,10 @@ static uint8_t g_ble_hw_whitelist_mask; /* Random number generator isr callback */ ble_rng_isr_cb_t g_ble_rng_isr_cb; +#if BABBLESIM +extern void tm_tick(void); +#endif + /* If LL privacy is enabled, allocate memory for AAR */ #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) @@ -69,6 +77,22 @@ ble_hw_get_public_addr(ble_addr_t *addr) uint32_t addr_high; uint32_t addr_low; +#if MYNEWT_VAL(BLE_PHY_UBLOX_BMD345_PUBLIC_ADDR) + /* + * The BMD-345 modules are preprogrammed from the factory with a unique public + * The Bluetooth device address stored in the CUSTOMER[0] and CUSTOMER[1] + * registers of the User Information Configuration Registers (UICR). + * The Bluetooth device address consists of the IEEE Organizationally Unique + * Identifier (OUI) combined with the hexadecimal digits that are printed on + * a 2D barcode and in human-readable text on the module label.The Bluetooth + * device address is stored in little endian format. The most significant + * bytes of the CUSTOMER[1] register are 0xFF to complete the 32-bit register. + */ + + /* Copy into device address. We can do this because we know platform */ + addr_low = NRF_UICR->CUSTOMER[0]; + addr_high = NRF_UICR->CUSTOMER[1]; +#else /* Does FICR have a public address */ if ((NRF_FICR->DEVICEADDRTYPE & 1) != 0) { return -1; @@ -77,6 +101,8 @@ ble_hw_get_public_addr(ble_addr_t *addr) /* Copy into device address. We can do this because we know platform */ addr_low = NRF_FICR->DEVICEADDR[0]; addr_high = NRF_FICR->DEVICEADDR[1]; +#endif + memcpy(addr->val, &addr_low, 4); memcpy(&addr->val[4], &addr_high, 2); addr->type = BLE_ADDR_PUBLIC; @@ -88,11 +114,17 @@ ble_hw_get_public_addr(ble_addr_t *addr) int ble_hw_get_static_addr(ble_addr_t *addr) { + uint32_t addr_high; + uint32_t addr_low; int rc; if ((NRF_FICR->DEVICEADDRTYPE & 1) == 1) { - memcpy(addr->val, (void *)&NRF_FICR->DEVICEADDR[0], 4); - memcpy(&addr->val[4], (void *)&NRF_FICR->DEVICEADDR[1], 2); + addr_low = NRF_FICR->DEVICEADDR[0]; + addr_high = NRF_FICR->DEVICEADDR[1]; + + memcpy(addr->val, &addr_low, 4); + memcpy(&addr->val[4], &addr_high, 2); + addr->val[5] |= 0xc0; addr->type = BLE_ADDR_RANDOM; rc = 0; @@ -245,14 +277,14 @@ ble_hw_encrypt_block(struct ble_encryption_block *ecb) uint32_t err; /* Stop ECB */ - NRF_ECB->TASKS_STOPECB = 1; + nrf_ecb_task_trigger(NRF_ECB, NRF_ECB_TASK_STOPECB); /* XXX: does task stop clear these counters? Anyway to do this quicker? */ NRF_ECB->EVENTS_ENDECB = 0; NRF_ECB->EVENTS_ERRORECB = 0; NRF_ECB->ECBDATAPTR = (uint32_t)ecb; /* Start ECB */ - NRF_ECB->TASKS_STARTECB = 1; + nrf_ecb_task_trigger(NRF_ECB, NRF_ECB_TASK_STARTECB); /* Wait till error or done */ rc = 0; @@ -265,6 +297,9 @@ ble_hw_encrypt_block(struct ble_encryption_block *ecb) } break; } +#if BABBLESIM + tm_tick(); +#endif } return rc; @@ -282,7 +317,7 @@ ble_rng_isr(void) /* No callback? Clear and disable interrupts */ if (g_ble_rng_isr_cb == NULL) { - NRF_RNG->INTENCLR = 1; + nrf_rng_int_disable(NRF_RNG, NRF_RNG_INT_VALRDY_MASK); NRF_RNG->EVENTS_VALRDY = 0; (void)NRF_RNG->SHORTS; os_trace_isr_exit(); @@ -347,10 +382,11 @@ ble_hw_rng_start(void) /* No need for interrupt if there is no callback */ OS_ENTER_CRITICAL(sr); NRF_RNG->EVENTS_VALRDY = 0; + if (g_ble_rng_isr_cb) { - NRF_RNG->INTENSET = 1; + nrf_rng_int_enable(NRF_RNG, NRF_RNG_INT_VALRDY_MASK); } - NRF_RNG->TASKS_START = 1; + nrf_rng_task_trigger(NRF_RNG, NRF_RNG_TASK_START); OS_EXIT_CRITICAL(sr); return 0; @@ -368,8 +404,8 @@ ble_hw_rng_stop(void) /* No need for interrupt if there is no callback */ OS_ENTER_CRITICAL(sr); - NRF_RNG->INTENCLR = 1; - NRF_RNG->TASKS_STOP = 1; + nrf_rng_int_disable(NRF_RNG, NRF_RNG_INT_VALRDY_MASK); + nrf_rng_task_trigger(NRF_RNG, NRF_RNG_TASK_STOP); NRF_RNG->EVENTS_VALRDY = 0; OS_EXIT_CRITICAL(sr); @@ -446,7 +482,7 @@ ble_hw_resolv_list_rmv(int index) if (index < g_nrf_num_irks) { --g_nrf_num_irks; - irk_entry = &g_nrf_irk_list[index]; + irk_entry = &g_nrf_irk_list[4 * index]; if (g_nrf_num_irks > index) { memmove(irk_entry, irk_entry + 4, 16 * (g_nrf_num_irks - index)); } @@ -474,13 +510,8 @@ ble_hw_resolv_list_size(void) int ble_hw_resolv_list_match(void) { - uint32_t index; - - if (NRF_AAR->EVENTS_END) { - if (NRF_AAR->EVENTS_RESOLVED) { - index = NRF_AAR->STATUS; - return (int)index; - } + if (NRF_AAR->ENABLE && NRF_AAR->EVENTS_END && NRF_AAR->EVENTS_RESOLVED) { + return (int)NRF_AAR->STATUS; } return -1; diff --git a/nimble/drivers/nrf52/src/ble_phy.c b/nimble/drivers/nrf5x/src/ble_phy.c similarity index 69% rename from nimble/drivers/nrf52/src/ble_phy.c rename to nimble/drivers/nrf5x/src/ble_phy.c index 2f6ce08e72..6f9e051423 100644 --- a/nimble/drivers/nrf52/src/ble_phy.c +++ b/nimble/drivers/nrf5x/src/ble_phy.c @@ -20,8 +20,16 @@ #include #include #include +#include +#include +#include +#include +#include +#include #include "syscfg/syscfg.h" #include "os/os.h" +/* Keep os_cputime explicitly to enable build on non-Mynewt platforms */ +#include "os/os_cputime.h" #include "ble/xcvr.h" #include "nimble/ble.h" #include "nimble/nimble_opt.h" @@ -31,27 +39,51 @@ #include "controller/ble_ll.h" #include "nrfx.h" #if MYNEWT -#include "mcu/nrf52_clock.h" +#ifdef NRF52_SERIES +#include +#endif +#ifdef NRF53_SERIES +#include +#endif #include "mcu/cmsis_nvic.h" #include "hal/hal_gpio.h" #else +#include +#ifdef NRF52_SERIES #include "core_cm4.h" #endif +#endif +#include +#include "phy_priv.h" + +#ifndef min +#define min(a, b) ((a) < (b) ? (a) : (b)) +#endif #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) -#if !MYNEWT_VAL_CHOICE(MCU_TARGET, nRF52840) && !MYNEWT_VAL_CHOICE(MCU_TARGET, nRF52811) -#error LE Coded PHY can only be enabled on nRF52811 or nRF52840 +#if !MYNEWT_VAL_CHOICE(MCU_TARGET, nRF52840) && \ + !MYNEWT_VAL_CHOICE(MCU_TARGET, nRF52811) && \ + !MYNEWT_VAL_CHOICE(MCU_TARGET, nRF5340_NET) +#error LE Coded PHY can only be enabled on nRF52811, nRF52840 or nRF5340 #endif #endif +#if BABBLESIM +extern void tm_tick(void); +#endif + +#include + /* * NOTE: This code uses a couple of PPI channels so care should be taken when * using PPI somewhere else. * * Pre-programmed channels: CH20, CH21, CH23, CH25, CH31 - * Regular channels: CH4, CH5 and optionally CH17, CH18, CH19 + * Regular channels: CH4, CH5 and optionally CH6, CH7, CH17, CH18, CH19 * - CH4 = cancel wfr timer on address match * - CH5 = disable radio on wfr timer expiry + * - CH6 = PA/LNA control (enable) + * - CH7 = PA/LNA control (disable) * - CH17 = (optional) gpio debug for radio ramp-up * - CH18 = (optional) gpio debug for wfr timer RX enabled * - CH19 = (optional) gpio debug for wfr timer radio disabled @@ -112,21 +144,30 @@ struct ble_phy_obj uint8_t phy_transition_late; uint8_t phy_rx_started; uint8_t phy_encrypted; +#if PHY_USE_HEADERMASK_WORKAROUND + uint8_t phy_headermask; + uint8_t phy_headerbyte; +#endif uint8_t phy_privacy; uint8_t phy_tx_pyld_len; uint8_t phy_cur_phy_mode; uint8_t phy_tx_phy_mode; uint8_t phy_rx_phy_mode; uint8_t phy_bcc_offset; - int8_t rx_pwr_compensation; uint32_t phy_aar_scratch; uint32_t phy_access_address; struct ble_mbuf_hdr rxhdr; void *txend_arg; ble_phy_tx_end_func txend_cb; uint32_t phy_start_cputime; +#if MYNEWT_VAL(BLE_PHY_VARIABLE_TIFS) + uint16_t tifs; +#endif + + uint16_t txtx_time_us; + uint8_t txtx_time_anchor; }; -struct ble_phy_obj g_ble_phy_data; +static struct ble_phy_obj g_ble_phy_data; /* XXX: if 27 byte packets desired we can make this smaller */ /* Global transmit/receive buffer */ @@ -146,7 +187,7 @@ static const uint8_t g_ble_phy_chan_freq[BLE_PHY_NUM_CHANS] = { 66, 68, 70, 72, 74, 76, 78, 2, 26, 80, /* 30-39 */ }; -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) +#if MYNEWT_VAL(BLE_LL_PHY) /* packet start offsets (in usecs) */ static const uint16_t g_ble_phy_mode_pkt_start_off[BLE_PHY_NUM_MODE] = { [BLE_PHY_MODE_1M] = 40, @@ -160,17 +201,47 @@ static const uint16_t g_ble_phy_mode_pkt_start_off[BLE_PHY_NUM_MODE] = { /* Radio ramp-up times in usecs (fast mode) */ #define BLE_PHY_T_TXENFAST (XCVR_TX_RADIO_RAMPUP_USECS) #define BLE_PHY_T_RXENFAST (XCVR_RX_RADIO_RAMPUP_USECS) + +#if BABBLESIM /* delay between EVENTS_READY and start of tx */ static const uint8_t g_ble_phy_t_txdelay[BLE_PHY_NUM_MODE] = { - [BLE_PHY_MODE_1M] = 4, - [BLE_PHY_MODE_2M] = 3, + [BLE_PHY_MODE_1M] = 1, + [BLE_PHY_MODE_2M] = 1, +}; +/* delay between EVENTS_END and end of txd packet */ +static const uint8_t g_ble_phy_t_txenddelay[BLE_PHY_NUM_MODE] = { + [BLE_PHY_MODE_1M] = 1, + [BLE_PHY_MODE_2M] = 1, +}; +/* delay between rxd access address (w/ TERM1 for coded) and EVENTS_ADDRESS */ +static const uint8_t g_ble_phy_t_rxaddrdelay[BLE_PHY_NUM_MODE] = { + [BLE_PHY_MODE_1M] = 9, + [BLE_PHY_MODE_2M] = 5, +}; +/* delay between end of rxd packet and EVENTS_END */ +static const uint8_t g_ble_phy_t_rxenddelay[BLE_PHY_NUM_MODE] = { + [BLE_PHY_MODE_1M] = 9, + [BLE_PHY_MODE_2M] = 5, +}; +#else +/* delay between EVENTS_READY and start of tx */ +static const uint8_t g_ble_phy_t_txdelay[BLE_PHY_NUM_MODE] = { + [BLE_PHY_MODE_1M] = 6, + [BLE_PHY_MODE_2M] = 5, [BLE_PHY_MODE_CODED_125KBPS] = 5, [BLE_PHY_MODE_CODED_500KBPS] = 5 }; +/* delay between EVENTS_ADDRESS and txd access address */ +static const uint8_t g_ble_phy_t_txaddrdelay[BLE_PHY_NUM_MODE] = { + [BLE_PHY_MODE_1M] = 7, + [BLE_PHY_MODE_2M] = 5, + [BLE_PHY_MODE_CODED_125KBPS] = 17, + [BLE_PHY_MODE_CODED_500KBPS] = 17 +}; /* delay between EVENTS_END and end of txd packet */ static const uint8_t g_ble_phy_t_txenddelay[BLE_PHY_NUM_MODE] = { - [BLE_PHY_MODE_1M] = 4, - [BLE_PHY_MODE_2M] = 3, + [BLE_PHY_MODE_1M] = 6, + [BLE_PHY_MODE_2M] = 4, [BLE_PHY_MODE_CODED_125KBPS] = 9, [BLE_PHY_MODE_CODED_500KBPS] = 3 }; @@ -183,11 +254,12 @@ static const uint8_t g_ble_phy_t_rxaddrdelay[BLE_PHY_NUM_MODE] = { }; /* delay between end of rxd packet and EVENTS_END */ static const uint8_t g_ble_phy_t_rxenddelay[BLE_PHY_NUM_MODE] = { - [BLE_PHY_MODE_1M] = 6, - [BLE_PHY_MODE_2M] = 2, + [BLE_PHY_MODE_1M] = 4, + [BLE_PHY_MODE_2M] = 1, [BLE_PHY_MODE_CODED_125KBPS] = 27, [BLE_PHY_MODE_CODED_500KBPS] = 22 }; +#endif /* Statistics */ STATS_SECT_START(ble_phy_stats) @@ -264,7 +336,7 @@ STATS_NAME_END(ble_phy_stats) //#define NRF_ENC_SCRATCH_WORDS (((MYNEWT_VAL(BLE_LL_MAX_PKT_SIZE) + 16) + 3) / 4) #define NRF_ENC_SCRATCH_WORDS (67) -uint32_t g_nrf_encrypt_scratchpad[NRF_ENC_SCRATCH_WORDS]; +static uint32_t g_nrf_encrypt_scratchpad[NRF_ENC_SCRATCH_WORDS]; struct nrf_ccm_data { @@ -278,28 +350,43 @@ struct nrf_ccm_data g_nrf_ccm_data; #endif static void -ble_phy_apply_errata_102_106_107(void) +timer0_reset(void) { - /* [102] RADIO: PAYLOAD/END events delayed or not triggered after ADDRESS - * [106] RADIO: Higher CRC error rates for some access addresses - * [107] RADIO: Immediate address match for access addresses containing MSBs 0x00 + /* Reset CC registers to avoid triggering spurious COMPARE events */ + NRF_TIMER0->CC[0] = 0; + NRF_TIMER0->CC[1] = 0; + NRF_TIMER0->CC[2] = 0; + NRF_TIMER0->CC[3] = 0; +} + +static bool +timer0_did_miss(int cc, int cc_scratch) +{ + uint32_t now, target; + + nrf_timer_task_trigger(NRF_TIMER0, nrf_timer_capture_task_get(cc_scratch)); + target = NRF_TIMER0->CC[cc]; + now = NRF_TIMER0->CC[cc_scratch]; + + /* COMPARE event is not triggered when CC is set to the current value of + * TIMER0 (at the time it was set), so the case of equal CC values without + * a COMPARE event should be also considered a miss here. */ - *(volatile uint32_t *)0x40001774 = ((*(volatile uint32_t *)0x40001774) & - 0xfffffffe) | 0x01000000; + return (now >= target) && !NRF_TIMER0->EVENTS_COMPARE[cc]; } -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) +#if MYNEWT_VAL(BLE_LL_PHY) /* Packet start offset (in usecs). This is the preamble plus access address. * For LE Coded PHY this also includes CI and TERM1. */ -uint32_t +static uint32_t ble_phy_mode_pdu_start_off(int phy_mode) { return g_ble_phy_mode_pkt_start_off[phy_mode]; } -#if NRF52840_XXAA -static inline bool +#if NRF52_ERRATA_191_ENABLE_WORKAROUND +static bool ble_phy_mode_is_coded(uint8_t phy_mode) { return (phy_mode == BLE_PHY_MODE_CODED_125KBPS) || @@ -307,48 +394,26 @@ ble_phy_mode_is_coded(uint8_t phy_mode) } static void -ble_phy_apply_nrf52840_errata(uint8_t new_phy_mode) +phy_nrf52_errata_191(uint8_t new_phy_mode) { - bool new_coded = ble_phy_mode_is_coded(new_phy_mode); - bool cur_coded = ble_phy_mode_is_coded(g_ble_phy_data.phy_cur_phy_mode); + bool from_coded = ble_phy_mode_is_coded(g_ble_phy_data.phy_cur_phy_mode); + bool to_coded = ble_phy_mode_is_coded(new_phy_mode); - /* - * Workarounds should be applied only when switching to/from LE Coded PHY - * so no need to apply them every time. - * - * nRF52840 Engineering A Errata v1.2 - * [164] RADIO: Low sensitivity in long range mode - * - * nRF52840 Rev 1 Errata - * [191] RADIO: High packet error rate in BLE Long Range mode + /* [191] RADIO: High packet error rate in BLE Long Range mode + * Should be applied only if switching to/from LE Coded, no need to apply + * on each mode change. */ - if (new_coded == cur_coded) { + if (from_coded == to_coded) { return; } - if (new_coded) { -#if MYNEWT_VAL(BLE_PHY_NRF52840_ERRATA_164) - /* [164] */ - *(volatile uint32_t *)0x4000173C |= 0x80000000; - *(volatile uint32_t *)0x4000173C = - ((*(volatile uint32_t *)0x4000173C & 0xFFFFFF00) | 0x5C); -#endif -#if MYNEWT_VAL(BLE_PHY_NRF52840_ERRATA_191) - /* [191] */ - *(volatile uint32_t *) 0x40001740 = - ((*((volatile uint32_t *) 0x40001740)) & 0x7FFF00FF) | - 0x80000000 | (((uint32_t)(196)) << 8); -#endif + if (to_coded) { + *(volatile uint32_t *)0x40001740 = + ((*((volatile uint32_t *)0x40001740)) & 0x7fff00ff) | + 0x80000000 | (((uint32_t)(196)) << 8); } else { -#if MYNEWT_VAL(BLE_PHY_NRF52840_ERRATA_164) - /* [164] */ - *(volatile uint32_t *)0x4000173C &= ~0x80000000; -#endif -#if MYNEWT_VAL(BLE_PHY_NRF52840_ERRATA_191) - /* [191] */ *(volatile uint32_t *) 0x40001740 = - ((*((volatile uint32_t *) 0x40001740)) & 0x7FFFFFFF); -#endif + ((*((volatile uint32_t *) 0x40001740)) & 0x7fffffff); } } #endif @@ -360,28 +425,42 @@ ble_phy_mode_apply(uint8_t phy_mode) return; } -#if NRF52840_XXAA - ble_phy_apply_nrf52840_errata(phy_mode); +#if NRF52_ERRATA_191_ENABLE_WORKAROUND + if (nrf52_errata_191()) { + phy_nrf52_errata_191(phy_mode); + } #endif switch (phy_mode) { case BLE_PHY_MODE_1M: NRF_RADIO->MODE = RADIO_MODE_MODE_Ble_1Mbit; +#ifdef NRF53_SERIES + *((volatile uint32_t *)0x41008588) = *((volatile uint32_t *)0x01FF0080); +#endif NRF_RADIO->PCNF0 = NRF_PCNF0_1M; break; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY) case BLE_PHY_MODE_2M: NRF_RADIO->MODE = RADIO_MODE_MODE_Ble_2Mbit; +#ifdef NRF53_SERIES + *((volatile uint32_t *)0x41008588) = *((volatile uint32_t *)0x01FF0084); +#endif NRF_RADIO->PCNF0 = NRF_PCNF0_2M; break; #endif #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY) case BLE_PHY_MODE_CODED_125KBPS: NRF_RADIO->MODE = RADIO_MODE_MODE_Ble_LR125Kbit; +#ifdef NRF53_SERIES + *((volatile uint32_t *)0x41008588) = *((volatile uint32_t *)0x01FF0080); +#endif NRF_RADIO->PCNF0 = NRF_PCNF0_CODED; break; case BLE_PHY_MODE_CODED_500KBPS: NRF_RADIO->MODE = RADIO_MODE_MODE_Ble_LR500Kbit; +#ifdef NRF53_SERIES + *((volatile uint32_t *)0x41008588) = *((volatile uint32_t *)0x01FF0080); +#endif NRF_RADIO->PCNF0 = NRF_PCNF0_CODED; break; #endif @@ -398,12 +477,18 @@ ble_phy_mode_set(uint8_t tx_phy_mode, uint8_t rx_phy_mode) g_ble_phy_data.phy_tx_phy_mode = tx_phy_mode; g_ble_phy_data.phy_rx_phy_mode = rx_phy_mode; } +#else +static uint32_t +ble_phy_mode_pdu_start_off(int phy_mode) +{ + return 40; +} #endif -int +static int ble_phy_get_cur_phy(void) { -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) +#if MYNEWT_VAL(BLE_LL_PHY) switch (g_ble_phy_data.phy_cur_phy_mode) { case BLE_PHY_MODE_1M: return BLE_PHY_1M; @@ -471,6 +556,11 @@ ble_phy_rxpdu_copy(uint8_t *dptr, struct os_mbuf *rxpdu) rem_len -= copy_len; block_rem_len -= copy_len; +#if BABBLESIM + memcpy(dst, src, copy_len); + dst += copy_len; + src += copy_len; +#else __asm__ volatile (".syntax unified \n" " mov r4, %[len] \n" " b 2f \n" @@ -485,6 +575,7 @@ ble_phy_rxpdu_copy(uint8_t *dptr, struct os_mbuf *rxpdu) : : "r3", "r4", "memory" ); +#endif if ((rem_len < 4) && (block_rem_len >= rem_len)) { break; @@ -497,6 +588,10 @@ ble_phy_rxpdu_copy(uint8_t *dptr, struct os_mbuf *rxpdu) /* Copy remaining bytes, if any, to last mbuf */ om->om_len += rem_len; + +#if BABBLESIM + memcpy(dst, src, rem_len); +#else __asm__ volatile (".syntax unified \n" " b 2f \n" "1: ldrb r3, [%[src], %[len]] \n" @@ -507,6 +602,7 @@ ble_phy_rxpdu_copy(uint8_t *dptr, struct os_mbuf *rxpdu) : [dst] "r" (dst), [src] "r" (src) : "r3", "memory" ); +#endif /* Copy header */ memcpy(BLE_MBUF_HDR_PTR(rxpdu), &g_ble_phy_data.rxhdr, @@ -531,51 +627,86 @@ nrf_wait_disabled(void) while (NRF_RADIO->STATE == state) { /* If this fails, something is really wrong. Should last * no more than 6 usecs */ +#if BABBLESIM + tm_tick(); +#endif } } } } +#if MYNEWT_VAL(BLE_PHY_VARIABLE_TIFS) +void +ble_phy_tifs_set(uint16_t tifs) +{ + g_ble_phy_data.tifs = tifs; +} +#endif + /** * * */ static int -ble_phy_set_start_time(uint32_t cputime, uint8_t rem_usecs, bool tx) +ble_phy_set_start_time(uint32_t cputime, uint8_t rem_us, bool tx) { uint32_t next_cc; uint32_t cur_cc; uint32_t cntr; uint32_t delta; + int radio_rem_us; +#if PHY_USE_FEM + int fem_rem_us = 0; +#endif + int rem_us_corr; + int min_rem_us; - /* - * We need to adjust start time to include radio ramp-up and TX pipeline - * delay (the latter only if applicable, so only for TX). - * - * Radio ramp-up time is 40 usecs and TX delay is 3 or 5 usecs depending on - * phy, thus we'll offset RTC by 2 full ticks (61 usecs) and then compensate - * using TIMER0 with 1 usec precision. + /* Calculate rem_us for radio and FEM enable. The result may be a negative + * value, but we'll adjust later. */ - - cputime -= 2; - rem_usecs += 61; if (tx) { - rem_usecs -= BLE_PHY_T_TXENFAST; - rem_usecs -= g_ble_phy_t_txdelay[g_ble_phy_data.phy_cur_phy_mode]; + radio_rem_us = rem_us - BLE_PHY_T_TXENFAST - + g_ble_phy_t_txdelay[g_ble_phy_data.phy_cur_phy_mode]; +#if PHY_USE_FEM_PA + fem_rem_us = rem_us - MYNEWT_VAL(BLE_FEM_PA_TURN_ON_US); +#endif } else { - rem_usecs -= BLE_PHY_T_RXENFAST; + radio_rem_us = rem_us - BLE_PHY_T_TXENFAST; +#if PHY_USE_FEM_LNA + fem_rem_us = rem_us - MYNEWT_VAL(BLE_FEM_LNA_TURN_ON_US); +#endif } - /* - * rem_usecs will be no more than 2 ticks, but if it is more than single - * tick then we should better count one more low-power tick rather than - * 30 high-power usecs. Also make sure we don't set TIMER0 CC to 0 as the - * compare won't occur. +#if PHY_USE_FEM + min_rem_us = min(radio_rem_us, fem_rem_us); +#else + min_rem_us = radio_rem_us; +#endif + + /* We need to adjust rem_us values, so they are >=1 for TIMER0 compare + * event to be triggered. + * + * If FEM is not enabled, calculated rem_us is -45<=rem_us<=-15 since we + * only had to adjust earlier for ramp-up and txdelay, i.e. 40+5=45us in + * worst case, so we adjust by 1 or 2 tick(s) only. + * + * If FEM is enabled, turn on time may be a bit longer, so we also allow to + * adjust by 3 ticks so up to 90us which should be enough. If needed, we + * can extend this by another tick but having FEM with turn on time >90us + * means transition may become tricky. */ - if (rem_usecs > 30) { - cputime++; - rem_usecs -= 30; + if ((PHY_USE_FEM) && (min_rem_us <= -61)) { + cputime -= 3; + rem_us_corr = 91; + } else if (min_rem_us <= -30) { + /* rem_us is -60..-30 */ + cputime -= 2; + rem_us_corr = 61; + } else { + /* rem_us is -29..0 */ + cputime -= 1; + rem_us_corr = 30; } /* @@ -601,18 +732,39 @@ ble_phy_set_start_time(uint32_t cputime, uint8_t rem_usecs, bool tx) return -1; } + timer0_reset(); + /* Clear and set TIMER0 to fire off at proper time */ - NRF_TIMER0->TASKS_CLEAR = 1; - NRF_TIMER0->CC[0] = rem_usecs; + nrf_timer_task_trigger(NRF_TIMER0, NRF_TIMER_TASK_CLEAR); + nrf_timer_cc_set(NRF_TIMER0, 0, radio_rem_us + rem_us_corr); NRF_TIMER0->EVENTS_COMPARE[0] = 0; +#if PHY_USE_FEM + if (fem_rem_us) { + nrf_timer_cc_set(NRF_TIMER0, 2, fem_rem_us + rem_us_corr); + NRF_TIMER0->EVENTS_COMPARE[2] = 0; + } +#endif /* Set RTC compare to start TIMER0 */ NRF_RTC0->EVENTS_COMPARE[0] = 0; - NRF_RTC0->CC[0] = next_cc; - NRF_RTC0->EVTENSET = RTC_EVTENSET_COMPARE0_Msk; + nrf_rtc_cc_set(NRF_RTC0, 0, next_cc); + nrf_rtc_event_enable(NRF_RTC0, RTC_EVTENSET_COMPARE0_Msk); /* Enable PPI */ - NRF_PPI->CHENSET = PPI_CHEN_CH31_Msk; +#if PHY_USE_FEM + if (fem_rem_us) { + if (tx) { +#if PHY_USE_FEM_PA + phy_fem_enable_pa(); +#endif + } else { +#if PHY_USE_FEM_LNA + phy_fem_enable_lna(); +#endif + } + } +#endif + phy_ppi_rtc0_compare0_to_timer0_start_enable(); /* Store the cputime at which we set the RTC */ g_ble_phy_data.phy_start_cputime = cputime; @@ -625,16 +777,41 @@ ble_phy_set_start_now(void) { os_sr_t sr; uint32_t now; + uint32_t radio_rem_us; +#if PHY_USE_FEM_LNA + uint32_t fem_rem_us; +#endif OS_ENTER_CRITICAL(sr); - /* - * Set TIMER0 to fire immediately. We can't set CC to 0 as compare will not - * occur in such case. + /* We need to set TIMER0 compare registers to at least 1 as otherwise + * compare event won't be triggered. Event (FEM/radio) that have to be + * triggered first is set to 1, other event is set to 1+diff. + * + * Note that this is only used for rx, so only need to handle LNA. */ - NRF_TIMER0->TASKS_CLEAR = 1; - NRF_TIMER0->CC[0] = 1; + +#if PHY_USE_FEM_LNA + if (MYNEWT_VAL(BLE_FEM_LNA_TURN_ON_US) > BLE_PHY_T_RXENFAST) { + radio_rem_us = 1 + MYNEWT_VAL(BLE_FEM_LNA_TURN_ON_US) - + BLE_PHY_T_RXENFAST; + fem_rem_us = 1; + } else { + radio_rem_us = 1; + fem_rem_us = 1 + BLE_PHY_T_RXENFAST - + MYNEWT_VAL(BLE_FEM_LNA_TURN_ON_US); + } +#else + radio_rem_us = 1; +#endif + + nrf_timer_task_trigger(NRF_TIMER0, NRF_TIMER_TASK_CLEAR); + nrf_timer_cc_set(NRF_TIMER0, 0, radio_rem_us); NRF_TIMER0->EVENTS_COMPARE[0] = 0; +#if PHY_USE_FEM_LNA + nrf_timer_cc_set(NRF_TIMER0, 2, fem_rem_us); + NRF_TIMER0->EVENTS_COMPARE[2] = 0; +#endif /* * Set RTC compare to start TIMER0. We need to set it to at least N+2 ticks @@ -644,11 +821,15 @@ ble_phy_set_start_now(void) */ now = os_cputime_get32(); NRF_RTC0->EVENTS_COMPARE[0] = 0; - NRF_RTC0->CC[0] = now + 3; - NRF_RTC0->EVTENSET = RTC_EVTENSET_COMPARE0_Msk; + nrf_rtc_cc_set(NRF_RTC0, 0, (now + 3) & 0xffffff); + nrf_rtc_event_enable(NRF_RTC0, RTC_EVTENSET_COMPARE0_Msk); + +#if PHY_USE_FEM_LNA + phy_fem_enable_lna(); +#endif /* Enable PPI */ - NRF_PPI->CHENSET = PPI_CHEN_CH31_Msk; + phy_ppi_rtc0_compare0_to_timer0_start_enable(); /* * Store the cputime at which we set the RTC @@ -669,7 +850,7 @@ ble_phy_set_start_now(void) /** * Function is used to set PPI so that we can time out waiting for a reception * to occur. This happens for two reasons: we have sent a packet and we are - * waiting for a respons (txrx should be set to ENABLE_TXRX) or we are + * waiting for a response (txrx should be set to ENABLE_TXRX) or we are * starting a connection event and we are a slave and we are waiting for the * master to send us a packet (txrx should be set to ENABLE_RX). * @@ -686,12 +867,19 @@ ble_phy_wfr_enable(int txrx, uint8_t tx_phy_mode, uint32_t wfr_usecs) { uint32_t end_time; uint8_t phy; + uint16_t tifs; phy = g_ble_phy_data.phy_cur_phy_mode; +#if MYNEWT_VAL(BLE_PHY_VARIABLE_TIFS) + tifs = g_ble_phy_data.tifs; +#else + tifs = BLE_LL_IFS; +#endif + if (txrx == BLE_PHY_WFR_ENABLE_TXRX) { /* RX shall start exactly T_IFS after TX end captured in CC[2] */ - end_time = NRF_TIMER0->CC[2] + BLE_LL_IFS; + end_time = NRF_TIMER0->CC[2] + tifs; /* Adjust for delay between EVENT_END and actual TX end time */ end_time += g_ble_phy_t_txenddelay[tx_phy_mode]; /* Wait a bit longer due to allowed active clock accuracy */ @@ -703,17 +891,8 @@ ble_phy_wfr_enable(int txrx, uint8_t tx_phy_mode, uint32_t wfr_usecs) * by waiting 1 usec more. */ end_time += 1; -#if MYNEWT_VAL(BLE_PHY_CODED_RX_IFS_EXTRA_MARGIN) > 0 - if ((phy == BLE_PHY_MODE_CODED_125KBPS) || - (phy == BLE_PHY_MODE_CODED_500KBPS)) { - /* - * Some controllers exceed T_IFS when transmitting on coded phy - * so let's wait a bit longer to be able to talk to them if this - * workaround is enabled. - */ - end_time += MYNEWT_VAL(BLE_PHY_CODED_RX_IFS_EXTRA_MARGIN); - } -#endif + + end_time += MYNEWT_VAL(BLE_PHY_EXTENDED_TIFS); } else { /* * RX shall start no later than wfr_usecs after RX enabled. @@ -734,32 +913,26 @@ ble_phy_wfr_enable(int txrx, uint8_t tx_phy_mode, uint32_t wfr_usecs) /* Adjust for delay between actual access address RX and EVENT_ADDRESS */ end_time += g_ble_phy_t_rxaddrdelay[phy]; - /* wfr_secs is the time from rxen until timeout */ - NRF_TIMER0->CC[3] = end_time; - NRF_TIMER0->EVENTS_COMPARE[3] = 0; - /* Enable wait for response PPI */ - NRF_PPI->CHENSET = (PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk); - - /* Enable the disabled interrupt so we time out on events compare */ - NRF_RADIO->INTENSET = RADIO_INTENSET_DISABLED_Msk; + NRF_TIMER0->EVENTS_COMPARE[3] = 0; + phy_ppi_wfr_enable(); + nrf_timer_cc_set(NRF_TIMER0, 3, end_time); /* - * It may happen that if CPU is halted for a brief moment (e.g. during flash - * erase or write), TIMER0 already counted past CC[3] and thus wfr will not - * fire as expected. In case this happened, let's just disable PPIs for wfr - * and trigger wfr manually (i.e. disable radio). + * It may happen that if CPU is halted for a brief moment (e.g. during + * flash, erase or write), TIMER0 already counted past CC[3] and thus wfr + * will not fire as expected. In case this happened, let's just disable + * PPIs for wfr and trigger wfr manually (i.e. disable radio). * * Note that the same applies to RX start time set in CC[0] but since it * should fire earlier than wfr, fixing wfr is enough. * - * CC[1] is only used as a reference on RX start, we do not need it here so - * it can be used to read TIMER0 counter. + * CC[1] is only used as a reference on RX start. We do not need it here, + * so we can use it as a scratch register. */ - NRF_TIMER0->TASKS_CAPTURE[1] = 1; - if (NRF_TIMER0->CC[1] > NRF_TIMER0->CC[3]) { - NRF_PPI->CHENCLR = PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk; - NRF_RADIO->TASKS_DISABLE = 1; + if (timer0_did_miss(3, 1)) { + phy_ppi_wfr_disable(); + nrf_radio_task_trigger(NRF_RADIO, NRF_RADIO_TASK_DISABLE); } } @@ -767,7 +940,7 @@ ble_phy_wfr_enable(int txrx, uint8_t tx_phy_mode, uint32_t wfr_usecs) static uint32_t ble_phy_get_ccm_datarate(void) { -#if BLE_LL_BT5_PHY_SUPPORTED +#if MYNEWT_VAL(BLE_LL_PHY) switch (g_ble_phy_data.phy_cur_phy_mode) { case BLE_PHY_MODE_1M: return CCM_MODE_DATARATE_1Mbit << CCM_MODE_DATARATE_Pos; @@ -812,8 +985,8 @@ ble_phy_rx_xcvr_setup(void) NRF_CCM->SHORTS = 0; NRF_CCM->EVENTS_ERROR = 0; NRF_CCM->EVENTS_ENDCRYPT = 0; - NRF_CCM->TASKS_KSGEN = 1; - NRF_PPI->CHENSET = PPI_CHEN_CH25_Msk; + nrf_ccm_task_trigger(NRF_CCM, NRF_CCM_TASK_KSGEN); + phy_ppi_radio_address_to_ccm_crypt_enable(); } else { NRF_RADIO->PACKETPTR = (uint32_t)dptr; } @@ -837,13 +1010,14 @@ ble_phy_rx_xcvr_setup(void) #endif /* Turn off trigger TXEN on output compare match and AAR on bcmatch */ - NRF_PPI->CHENCLR = PPI_CHEN_CH20_Msk | PPI_CHEN_CH23_Msk; + phy_ppi_timer0_compare0_to_radio_txen_disable(); + phy_ppi_radio_bcmatch_to_aar_start_disable(); /* Reset the rx started flag. Used for the wait for response */ g_ble_phy_data.phy_rx_started = 0; g_ble_phy_data.phy_state = BLE_PHY_STATE_RX; -#if BLE_LL_BT5_PHY_SUPPORTED +#if MYNEWT_VAL(BLE_LL_PHY) /* * On Coded PHY there are CI and TERM1 fields before PDU starts so we need * to take this into account when setting up BCC. @@ -859,7 +1033,7 @@ ble_phy_rx_xcvr_setup(void) #endif /* I want to know when 1st byte received (after address) */ - NRF_RADIO->BCC = 8 + g_ble_phy_data.phy_bcc_offset; /* in bits */ + nrf_radio_bcc_set(NRF_RADIO, 8 + g_ble_phy_data.phy_bcc_offset); /* in bits */ NRF_RADIO->EVENTS_ADDRESS = 0; NRF_RADIO->EVENTS_DEVMATCH = 0; NRF_RADIO->EVENTS_BCMATCH = 0; @@ -871,7 +1045,8 @@ ble_phy_rx_xcvr_setup(void) RADIO_SHORTS_ADDRESS_RSSISTART_Msk | RADIO_SHORTS_DISABLED_RSSISTOP_Msk; - NRF_RADIO->INTENSET = RADIO_INTENSET_ADDRESS_Msk; + nrf_radio_int_enable(NRF_RADIO, RADIO_INTENSET_ADDRESS_Msk | + RADIO_INTENSET_DISABLED_Msk); } /** @@ -885,7 +1060,12 @@ ble_phy_tx_end_isr(void) uint8_t was_encrypted; uint8_t transition; uint32_t rx_time; - uint32_t wfr_time; + uint32_t tx_time; +#if PHY_USE_FEM + uint32_t fem_time; +#endif + uint32_t radio_time; + uint16_t tifs; /* Store PHY on which we've just transmitted smth */ tx_phy_mode = g_ble_phy_data.phy_cur_phy_mode; @@ -897,13 +1077,6 @@ ble_phy_tx_end_isr(void) /* Better be in TX state! */ assert(g_ble_phy_data.phy_state == BLE_PHY_STATE_TX); - /* Clear events and clear interrupt on disabled event */ - NRF_RADIO->EVENTS_DISABLED = 0; - NRF_RADIO->INTENCLR = RADIO_INTENCLR_DISABLED_Msk; - NRF_RADIO->EVENTS_END = 0; - wfr_time = NRF_RADIO->SHORTS; - (void)wfr_time; - #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) /* * XXX: not sure what to do. We had a HW error during transmission. @@ -917,15 +1090,20 @@ ble_phy_tx_end_isr(void) } #endif - /* Call transmit end callback */ +#if MYNEWT_VAL(BLE_PHY_VARIABLE_TIFS) + tifs = g_ble_phy_data.tifs; + g_ble_phy_data.tifs = BLE_LL_IFS; +#else + tifs = BLE_LL_IFS; +#endif + transition = g_ble_phy_data.phy_transition; + if (g_ble_phy_data.txend_cb) { g_ble_phy_data.txend_cb(g_ble_phy_data.txend_arg); } - transition = g_ble_phy_data.phy_transition; if (transition == BLE_PHY_TRANSITION_TX_RX) { - -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) +#if MYNEWT_VAL(BLE_LL_PHY) ble_phy_mode_apply(g_ble_phy_data.phy_rx_phy_mode); #endif @@ -935,26 +1113,84 @@ ble_phy_tx_end_isr(void) ble_phy_wfr_enable(BLE_PHY_WFR_ENABLE_TXRX, tx_phy_mode, 0); /* Schedule RX exactly T_IFS after TX end captured in CC[2] */ - rx_time = NRF_TIMER0->CC[2] + BLE_LL_IFS; + rx_time = NRF_TIMER0->CC[2] + tifs; /* Adjust for delay between EVENT_END and actual TX end time */ rx_time += g_ble_phy_t_txenddelay[tx_phy_mode]; - /* Adjust for radio ramp-up */ - rx_time -= BLE_PHY_T_RXENFAST; /* Start listening a bit earlier due to allowed active clock accuracy */ rx_time -= 2; - NRF_TIMER0->CC[0] = rx_time; +#if PHY_USE_FEM_LNA + fem_time = rx_time - MYNEWT_VAL(BLE_FEM_LNA_TURN_ON_US); + NRF_TIMER0->EVENTS_COMPARE[2] = 0; + phy_fem_enable_lna(); + nrf_timer_cc_set(NRF_TIMER0, 2, fem_time); +#endif + + radio_time = rx_time - BLE_PHY_T_RXENFAST; + NRF_TIMER0->EVENTS_COMPARE[0] = 0; + phy_ppi_timer0_compare0_to_radio_rxen_enable(); + nrf_timer_cc_set(NRF_TIMER0, 0, radio_time); + + /* In case TIMER0 did already count past CC[0] and/or CC[2], radio + * and/or LNA may not be enabled. In any case we won't be stuck since + * wfr will cancel rx if needed. + * + * FIXME failing to enable LNA may result in unexpected RSSI drop in + * case we still rxd something, so perhaps we could check it here + */ + } else if (transition == BLE_PHY_TRANSITION_TX_TX) { + if (g_ble_phy_data.txtx_time_anchor) { + /* Calculate TX anchor relative to current TX end */ + + /* TX end timestamp is captured in CC[2] */ + tx_time = NRF_TIMER0->CC[2]; + /* Adjust for delay between EVENT_END and actual TX end time */ + tx_time += g_ble_phy_t_txenddelay[tx_phy_mode]; + } else { + /* Calculate TX anchor relative to current TX start */ + + /* AA timestamp is captured in CC[1] */ + tx_time = NRF_TIMER0->CC[1]; + /* Adjust for delay between EVENT_ADDRESS and actual AA time ota */ + tx_time += g_ble_phy_t_txaddrdelay[tx_phy_mode]; + /* Adjust by sync word length to get TX start time */ + tx_time -= ble_ll_pdu_syncword_us(tx_phy_mode); + } + + tx_time += g_ble_phy_data.txtx_time_us; + +#if PHY_USE_FEM_PA + fem_time = tx_time - MYNEWT_VAL(BLE_FEM_PA_TURN_ON_US); +#endif + + /* Adjust for delay between EVENT_READY and actual TX start time */ + tx_time -= g_ble_phy_t_txdelay[g_ble_phy_data.phy_cur_phy_mode]; + + radio_time = tx_time - BLE_PHY_T_TXENFAST; NRF_TIMER0->EVENTS_COMPARE[0] = 0; - NRF_PPI->CHENSET = PPI_CHEN_CH21_Msk; + phy_ppi_timer0_compare0_to_radio_txen_enable(); + nrf_timer_cc_set(NRF_TIMER0, 0, radio_time); + +#if PHY_USE_FEM_PA + NRF_TIMER0->EVENTS_COMPARE[2] = 0; + phy_fem_enable_pa(); + nrf_timer_cc_set(NRF_TIMER0, 2, fem_time); +#endif + + if (timer0_did_miss(0, 3)) { + phy_ppi_timer0_compare0_to_radio_txen_disable(); + g_ble_phy_data.phy_transition_late = 1; + } } else { /* * XXX: not sure we need to stop the timer here all the time. Or that * it should be stopped here. */ - NRF_TIMER0->TASKS_STOP = 1; + nrf_timer_task_trigger(NRF_TIMER0, NRF_TIMER_TASK_STOP); NRF_TIMER0->TASKS_SHUTDOWN = 1; - NRF_PPI->CHENCLR = PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk | - PPI_CHEN_CH20_Msk | PPI_CHEN_CH31_Msk; + phy_ppi_wfr_disable(); + phy_ppi_timer0_compare0_to_radio_txen_disable(); + phy_ppi_rtc0_compare0_to_timer0_start_disable(); assert(transition == BLE_PHY_TRANSITION_NONE); } } @@ -991,20 +1227,21 @@ ble_phy_rx_end_isr(void) uint8_t *dptr; uint8_t crcok; uint32_t tx_time; +#if PHY_USE_FEM_PA + uint32_t fem_time; +#endif + uint32_t radio_time; + uint16_t tifs; struct ble_mbuf_hdr *ble_hdr; - - /* Clear events and clear interrupt */ - NRF_RADIO->EVENTS_END = 0; - NRF_RADIO->INTENCLR = RADIO_INTENCLR_END_Msk; + bool is_late; /* Disable automatic RXEN */ - NRF_PPI->CHENCLR = PPI_CHEN_CH21_Msk; + phy_ppi_timer0_compare0_to_radio_rxen_disable(); /* Set RSSI and CRC status flag in header */ ble_hdr = &g_ble_phy_data.rxhdr; assert(NRF_RADIO->EVENTS_RSSIEND != 0); - ble_hdr->rxinfo.rssi = (-1 * NRF_RADIO->RSSISAMPLE) + - g_ble_phy_data.rx_pwr_compensation; + ble_hdr->rxinfo.rssi = (-1 * NRF_RADIO->RSSISAMPLE); dptr = (uint8_t *)&g_ble_phy_rx_buf[0]; dptr += 3; @@ -1018,6 +1255,10 @@ ble_phy_rx_end_isr(void) ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_CRC_OK; #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) if (g_ble_phy_data.phy_encrypted) { + while (NRF_CCM->EVENTS_ENDCRYPT == 0) { + /* Make sure CCM finished */ + }; + /* Only set MIC failure flag if frame is not zero length */ if ((dptr[1] != 0) && (NRF_CCM->MICSTATUS == 0)) { ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_MIC_FAILURE; @@ -1033,21 +1274,11 @@ ble_phy_rx_end_isr(void) STATS_INC(ble_phy_stats, rx_hw_err); ble_hdr->rxinfo.flags &= ~BLE_MBUF_HDR_F_CRC_OK; } - - /* - * XXX: This is a total hack work-around for now but I dont - * know what else to do. If ENDCRYPT is not set and we are - * encrypted we need to not trust this frame and drop it. - */ - if (NRF_CCM->EVENTS_ENDCRYPT == 0) { - STATS_INC(ble_phy_stats, rx_hw_err); - ble_hdr->rxinfo.flags &= ~BLE_MBUF_HDR_F_CRC_OK; - } } #endif } -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) +#if MYNEWT_VAL(BLE_LL_PHY) ble_phy_mode_apply(g_ble_phy_data.phy_tx_phy_mode); #endif @@ -1065,34 +1296,48 @@ ble_phy_rx_end_isr(void) * enough. */ +#if MYNEWT_VAL(BLE_PHY_VARIABLE_TIFS) + tifs = g_ble_phy_data.tifs; + g_ble_phy_data.tifs = BLE_LL_IFS; +#else + tifs = BLE_LL_IFS; +#endif + /* Schedule TX exactly T_IFS after RX end captured in CC[2] */ - tx_time = NRF_TIMER0->CC[2] + BLE_LL_IFS; + tx_time = NRF_TIMER0->CC[2] + tifs; /* Adjust for delay between actual RX end time and EVENT_END */ tx_time -= g_ble_phy_t_rxenddelay[ble_hdr->rxinfo.phy_mode]; - /* Adjust for radio ramp-up */ - tx_time -= BLE_PHY_T_TXENFAST; + +#if PHY_USE_FEM_PA + fem_time = tx_time - MYNEWT_VAL(BLE_FEM_PA_TURN_ON_US); +#endif + /* Adjust for delay between EVENT_READY and actual TX start time */ tx_time -= g_ble_phy_t_txdelay[g_ble_phy_data.phy_cur_phy_mode]; - NRF_TIMER0->CC[0] = tx_time; + radio_time = tx_time - BLE_PHY_T_TXENFAST; NRF_TIMER0->EVENTS_COMPARE[0] = 0; - NRF_PPI->CHENSET = PPI_CHEN_CH20_Msk; + phy_ppi_timer0_compare0_to_radio_txen_enable(); + nrf_timer_cc_set(NRF_TIMER0, 0, radio_time); - /* - * XXX: Hack warning! - * - * It may happen (during flash erase) that CPU is stopped for a moment and - * TIMER0 already counted past CC[0]. In such case we will be stuck waiting - * for TX to start since EVENTS_COMPARE[0] will not happen any time soon. - * For now let's set a flag denoting that we are late in RX-TX transition so - * ble_phy_tx() will fail - this allows everything to cleanup nicely without - * the need for extra handling in many places. +#if PHY_USE_FEM_PA + NRF_TIMER0->EVENTS_COMPARE[2] = 0; + phy_fem_enable_pa(); + nrf_timer_cc_set(NRF_TIMER0, 2, fem_time); +#endif + + /* Need to check if TIMER0 did not already count past CC[0] and/or CC[2], so + * we're not stuck waiting for events in case radio and/or PA was not + * started. If event was triggered we're fine regardless of timer value. * * Note: CC[3] is used only for wfr which we do not need here. */ - NRF_TIMER0->TASKS_CAPTURE[3] = 1; - if (NRF_TIMER0->CC[3] > NRF_TIMER0->CC[0]) { - NRF_PPI->CHENCLR = PPI_CHEN_CH20_Msk; + is_late = timer0_did_miss(0, 3); +#if PHY_USE_FEM_PA + is_late = is_late || timer0_did_miss(2, 3); +#endif + if (is_late) { + phy_ppi_timer0_compare0_to_radio_txen_disable(); g_ble_phy_data.phy_transition_late = 1; } @@ -1127,10 +1372,10 @@ ble_phy_rx_start_isr(void) /* Clear events and clear interrupt */ NRF_RADIO->EVENTS_ADDRESS = 0; + nrf_radio_int_disable(NRF_RADIO, RADIO_INTENCLR_ADDRESS_Msk); - /* Clear wfr timer channels and DISABLED interrupt */ - NRF_RADIO->INTENCLR = RADIO_INTENCLR_DISABLED_Msk | RADIO_INTENCLR_ADDRESS_Msk; - NRF_PPI->CHENCLR = PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk; + /* Clear wfr timer channels */ + phy_ppi_wfr_disable(); /* Initialize the ble mbuf header */ ble_hdr = &g_ble_phy_data.rxhdr; @@ -1186,10 +1431,14 @@ ble_phy_rx_start_isr(void) * something is wrong! */ if (state == RADIO_STATE_STATE_Disabled) { - NRF_RADIO->INTENCLR = NRF_RADIO_IRQ_MASK_ALL; + nrf_radio_int_disable(NRF_RADIO, NRF_RADIO_IRQ_MASK_ALL); NRF_RADIO->SHORTS = 0; return false; } + +#if BABBLESIM + tm_tick(); +#endif } #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) @@ -1208,9 +1457,9 @@ ble_phy_rx_start_isr(void) /* Trigger AAR after last bit of AdvA is received */ NRF_RADIO->EVENTS_BCMATCH = 0; - NRF_PPI->CHENSET = PPI_CHEN_CH23_Msk; - NRF_RADIO->BCC = (BLE_LL_PDU_HDR_LEN + adva_offset + BLE_DEV_ADDR_LEN) * 8 + - g_ble_phy_data.phy_bcc_offset; + phy_ppi_radio_bcmatch_to_aar_start_enable(); + nrf_radio_bcc_set(NRF_RADIO, (BLE_LL_PDU_HDR_LEN + adva_offset + + BLE_DEV_ADDR_LEN) * 8 + g_ble_phy_data.phy_bcc_offset); } #endif @@ -1221,7 +1470,6 @@ ble_phy_rx_start_isr(void) if (rc >= 0) { /* Set rx started flag and enable rx end ISR */ g_ble_phy_data.phy_rx_started = 1; - NRF_RADIO->INTENSET = RADIO_INTENSET_END_Msk; } else { /* Disable PHY */ ble_phy_disable(); @@ -1242,7 +1490,7 @@ ble_phy_isr(void) os_trace_isr_enter(); /* Read irq register to determine which interrupts are enabled */ - irq_en = NRF_RADIO->INTENCLR; + irq_en = NRF_RADIO->INTENSET; /* * NOTE: order of checking is important! Possible, if things get delayed, @@ -1267,116 +1515,63 @@ ble_phy_isr(void) } } - /* Check for disabled event. This only happens for transmits now */ + /* Handle disabled event. This is enabled for both TX and RX. On RX, we + * need to check phy_rx_started flag to make sure we actually were receiving + * a PDU, otherwise this is due to wfr. + */ if ((irq_en & RADIO_INTENCLR_DISABLED_Msk) && NRF_RADIO->EVENTS_DISABLED) { - if (g_ble_phy_data.phy_state == BLE_PHY_STATE_RX) { - NRF_RADIO->EVENTS_DISABLED = 0; - ble_ll_wfr_timer_exp(NULL); - } else if (g_ble_phy_data.phy_state == BLE_PHY_STATE_IDLE) { - assert(0); - } else { + BLE_LL_ASSERT(NRF_RADIO->EVENTS_END || + ((g_ble_phy_data.phy_state == BLE_PHY_STATE_RX) && + !g_ble_phy_data.phy_rx_started)); + NRF_RADIO->EVENTS_END = 0; + NRF_RADIO->EVENTS_DISABLED = 0; + nrf_radio_int_disable(NRF_RADIO, RADIO_INTENCLR_DISABLED_Msk); + + switch (g_ble_phy_data.phy_state) { + case BLE_PHY_STATE_RX: +#if MYNEWT_VAL(BLE_FEM_LNA) + phy_ppi_fem_disable(); + ble_fem_lna_disable(); +#endif + if (g_ble_phy_data.phy_rx_started) { + ble_phy_rx_end_isr(); + } else { + ble_ll_wfr_timer_exp(NULL); + } + break; + case BLE_PHY_STATE_TX: +#if MYNEWT_VAL(BLE_FEM_PA) + phy_ppi_fem_disable(); + ble_fem_pa_disable(); +#endif ble_phy_tx_end_isr(); + break; + default: + BLE_LL_ASSERT(0); } } - /* Receive packet end (we dont enable this for transmit) */ - if ((irq_en & RADIO_INTENCLR_END_Msk) && NRF_RADIO->EVENTS_END) { - ble_phy_rx_end_isr(); - } - g_ble_phy_data.phy_transition_late = 0; - /* Ensures IRQ is cleared */ - irq_en = NRF_RADIO->SHORTS; - /* Count # of interrupts */ STATS_INC(ble_phy_stats, phy_isrs); os_trace_isr_exit(); } -#if MYNEWT_VAL(BLE_PHY_DBG_TIME_TXRXEN_READY_PIN) >= 0 || \ - MYNEWT_VAL(BLE_PHY_DBG_TIME_ADDRESS_END_PIN) >= 0 || \ - MYNEWT_VAL(BLE_PHY_DBG_TIME_WFR_PIN) >= 0 -static inline void -ble_phy_dbg_time_setup_gpiote(int index, int pin) -{ - NRF_GPIO_Type *port; - -#if NRF52840_XXAA - port = pin > 31 ? NRF_P1 : NRF_P0; - pin &= 0x1f; -#else - port = NRF_P0; -#endif - - /* Configure GPIO directly to avoid dependency to hal_gpio (for porting) */ - port->DIRSET = (1 << pin); - port->OUTCLR = (1 << pin); - - NRF_GPIOTE->CONFIG[index] = - (GPIOTE_CONFIG_MODE_Task << GPIOTE_CONFIG_MODE_Pos) | - ((pin & 0x1F) << GPIOTE_CONFIG_PSEL_Pos) | -#if NRF52840_XXAA - ((port == NRF_P1) << GPIOTE_CONFIG_PORT_Pos); -#else - 0; -#endif -} -#endif - +#if PHY_USE_HEADERMASK_WORKAROUND && MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) static void -ble_phy_dbg_time_setup(void) +ble_phy_ccm_isr(void) { - int gpiote_idx __attribute__((unused)) = 8; - - /* - * We setup GPIOTE starting from last configuration index to minimize risk - * of conflict with GPIO setup via hal. It's not great solution, but since - * this is just debugging code we can live with this. - */ - -#if MYNEWT_VAL(BLE_PHY_DBG_TIME_TXRXEN_READY_PIN) >= 0 - ble_phy_dbg_time_setup_gpiote(--gpiote_idx, - MYNEWT_VAL(BLE_PHY_DBG_TIME_TXRXEN_READY_PIN)); - - NRF_PPI->CH[17].EEP = (uint32_t)&(NRF_RADIO->EVENTS_READY); - NRF_PPI->CH[17].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_CLR[gpiote_idx]); - NRF_PPI->CHENSET = PPI_CHEN_CH17_Msk; - - /* CH[20] and PPI CH[21] are on to trigger TASKS_TXEN or TASKS_RXEN */ - NRF_PPI->FORK[20].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_SET[gpiote_idx]); - NRF_PPI->FORK[21].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_SET[gpiote_idx]); -#endif + volatile uint8_t *tx_buf = (uint8_t *)g_ble_phy_tx_buf; -#if MYNEWT_VAL(BLE_PHY_DBG_TIME_ADDRESS_END_PIN) >= 0 - ble_phy_dbg_time_setup_gpiote(--gpiote_idx, - MYNEWT_VAL(BLE_PHY_DBG_TIME_ADDRESS_END_PIN)); - - /* CH[26] and CH[27] are always on for EVENT_ADDRESS and EVENT_END */ - NRF_PPI->FORK[26].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_SET[gpiote_idx]); - NRF_PPI->FORK[27].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_CLR[gpiote_idx]); -#endif - -#if MYNEWT_VAL(BLE_PHY_DBG_TIME_WFR_PIN) >= 0 - ble_phy_dbg_time_setup_gpiote(--gpiote_idx, - MYNEWT_VAL(BLE_PHY_DBG_TIME_WFR_PIN)); - -#if NRF52840_XXAA - NRF_PPI->CH[18].EEP = (uint32_t)&(NRF_RADIO->EVENTS_RXREADY); -#else - NRF_PPI->CH[18].EEP = (uint32_t)&(NRF_RADIO->EVENTS_READY); -#endif - NRF_PPI->CH[18].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_SET[gpiote_idx]); - NRF_PPI->CH[19].EEP = (uint32_t)&(NRF_RADIO->EVENTS_DISABLED); - NRF_PPI->CH[19].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_CLR[gpiote_idx]); - NRF_PPI->CHENSET = PPI_CHEN_CH18_Msk | PPI_CHEN_CH19_Msk; - - /* CH[4] and CH[5] are always on for wfr */ - NRF_PPI->FORK[4].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_CLR[gpiote_idx]); - NRF_PPI->FORK[5].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_CLR[gpiote_idx]); -#endif + if (NRF_CCM->EVENTS_ENDKSGEN) { + while (tx_buf[0] == 0xff); + tx_buf[0] = g_ble_phy_data.phy_headerbyte; + NRF_CCM->INTENCLR = CCM_INTENCLR_ENDKSGEN_Msk; + } } +#endif /** * ble phy init @@ -1395,17 +1590,40 @@ ble_phy_init(void) g_ble_phy_data.phy_tx_phy_mode = BLE_PHY_MODE_1M; g_ble_phy_data.phy_rx_phy_mode = BLE_PHY_MODE_1M; - g_ble_phy_data.rx_pwr_compensation = 0; - /* Set phy channel to an invalid channel so first set channel works */ g_ble_phy_data.phy_chan = BLE_PHY_NUM_CHANS; +#if MYNEWT_VAL(BLE_PHY_VARIABLE_TIFS) + g_ble_phy_data.tifs = BLE_LL_IFS; +#endif + /* Toggle peripheral power to reset (just in case) */ - NRF_RADIO->POWER = 0; - NRF_RADIO->POWER = 1; + nrf_radio_power_set(NRF_RADIO, false); + nrf_radio_power_set(NRF_RADIO, true); + +#ifdef NRF53_SERIES + /* Errata 158: load trim values after toggling power */ + for (uint32_t index = 0; index < 32ul && + NRF_FICR_NS->TRIMCNF[index].ADDR != 0xFFFFFFFFul; index++) { + if (((uint32_t)NRF_FICR_NS->TRIMCNF[index].ADDR & 0xFFFFF000ul) == (volatile uint32_t)NRF_RADIO_NS) { + *((volatile uint32_t *)NRF_FICR_NS->TRIMCNF[index].ADDR) = NRF_FICR_NS->TRIMCNF[index].DATA; + } + } + + *(volatile uint32_t *)(NRF_RADIO_NS_BASE + 0x774) = + (*(volatile uint32_t* )(NRF_RADIO_NS_BASE + 0x774) & 0xfffffffe) | 0x01000000; +#if NRF53_ERRATA_16_ENABLE_WORKAROUND + if (nrf53_errata_16()) { + /* [16] RADIO: POWER register is not functional */ + NRF_RADIO_NS->SUBSCRIBE_TXEN = 0; + NRF_RADIO_NS->SUBSCRIBE_RXEN = 0; + NRF_RADIO_NS->SUBSCRIBE_DISABLE = 0; + } +#endif +#endif /* Disable all interrupts */ - NRF_RADIO->INTENCLR = NRF_RADIO_IRQ_MASK_ALL; + nrf_radio_int_disable(NRF_RADIO, NRF_RADIO_IRQ_MASK_ALL); /* Set configuration registers */ NRF_RADIO->MODE = RADIO_MODE_MODE_Ble_1Mbit; @@ -1434,20 +1652,23 @@ ble_phy_init(void) /* Configure IFS */ NRF_RADIO->TIFS = BLE_LL_IFS; - /* Captures tx/rx start in timer0 cc 1 and tx/rx end in timer0 cc 2 */ - NRF_PPI->CHENSET = PPI_CHEN_CH26_Msk | PPI_CHEN_CH27_Msk; - #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) - NRF_CCM->INTENCLR = 0xffffffff; + nrf_ccm_int_disable(NRF_CCM, 0xffffffff); NRF_CCM->SHORTS = CCM_SHORTS_ENDKSGEN_CRYPT_Msk; NRF_CCM->EVENTS_ERROR = 0; memset(g_nrf_encrypt_scratchpad, 0, sizeof(g_nrf_encrypt_scratchpad)); + +#if PHY_USE_HEADERMASK_WORKAROUND + NVIC_SetVector(CCM_AAR_IRQn, (uint32_t)ble_phy_ccm_isr); + NVIC_EnableIRQ(CCM_AAR_IRQn); + NRF_CCM->INTENCLR = CCM_INTENCLR_ENDKSGEN_Msk;; +#endif #endif #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) g_ble_phy_data.phy_aar_scratch = 0; NRF_AAR->IRKPTR = (uint32_t)&g_nrf_irk_list[0]; - NRF_AAR->INTENCLR = 0xffffffff; + nrf_aar_int_disable(NRF_AAR, 0xffffffff); NRF_AAR->EVENTS_END = 0; NRF_AAR->EVENTS_RESOLVED = 0; NRF_AAR->EVENTS_NOTRESOLVED = 0; @@ -1455,28 +1676,29 @@ ble_phy_init(void) #endif /* TIMER0 setup for PHY when using RTC */ - NRF_TIMER0->TASKS_STOP = 1; + nrf_timer_task_trigger(NRF_TIMER0, NRF_TIMER_TASK_STOP); NRF_TIMER0->TASKS_SHUTDOWN = 1; NRF_TIMER0->BITMODE = 3; /* 32-bit timer */ NRF_TIMER0->MODE = 0; /* Timer mode */ NRF_TIMER0->PRESCALER = 4; /* gives us 1 MHz */ - /* - * PPI setup. - * Channel 4: Captures TIMER0 in CC[3] when EVENTS_ADDRESS occurs. Used - * to cancel the wait for response timer. - * Channel 5: TIMER0 CC[3] to TASKS_DISABLE on radio. This is the wait - * for response timer. - */ - NRF_PPI->CH[4].EEP = (uint32_t)&(NRF_RADIO->EVENTS_ADDRESS); - NRF_PPI->CH[4].TEP = (uint32_t)&(NRF_TIMER0->TASKS_CAPTURE[3]); - NRF_PPI->CH[5].EEP = (uint32_t)&(NRF_TIMER0->EVENTS_COMPARE[3]); - NRF_PPI->CH[5].TEP = (uint32_t)&(NRF_RADIO->TASKS_DISABLE); + phy_ppi_init(); + +#if PHY_USE_DEBUG + phy_debug_init(); +#endif +#if PHY_USE_FEM + phy_fem_init(); +#endif /* Set isr in vector table and enable interrupt */ #ifndef RIOT_VERSION +#ifdef FREERTOS + NVIC_SetPriority(RADIO_IRQn, 5); +#else NVIC_SetPriority(RADIO_IRQn, 0); #endif +#endif #if MYNEWT NVIC_SetVector(RADIO_IRQn, (uint32_t)ble_phy_isr); #else @@ -1496,8 +1718,6 @@ ble_phy_init(void) g_ble_phy_data.phy_stats_initialized = 1; } - ble_phy_dbg_time_setup(); - return 0; } @@ -1506,7 +1726,7 @@ ble_phy_init(void) * * @return int 0: success; BLE Phy error code otherwise */ -int +static int ble_phy_rx(void) { /* @@ -1528,7 +1748,7 @@ ble_phy_rx(void) } /* Make sure all interrupts are disabled */ - NRF_RADIO->INTENCLR = NRF_RADIO_IRQ_MASK_ALL; + nrf_radio_int_disable(NRF_RADIO, NRF_RADIO_IRQ_MASK_ALL); /* Clear events prior to enabling receive */ NRF_RADIO->EVENTS_END = 0; @@ -1537,49 +1757,54 @@ ble_phy_rx(void) /* Setup for rx */ ble_phy_rx_xcvr_setup(); - /* PPI to start radio automatically shall be set here */ - assert(NRF_PPI->CHEN & PPI_CHEN_CH21_Msk); - return 0; } #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) -/** - * Called to enable encryption at the PHY. Note that this state will persist - * in the PHY; in other words, if you call this function you have to call - * disable so that future PHY transmits/receives will not be encrypted. - * - * @param pkt_counter - * @param iv - * @param key - * @param is_master - */ void -ble_phy_encrypt_enable(uint64_t pkt_counter, uint8_t *iv, uint8_t *key, - uint8_t is_master) +ble_phy_encrypt_enable(const uint8_t *key) { memcpy(g_nrf_ccm_data.key, key, 16); - g_nrf_ccm_data.pkt_counter = pkt_counter; - memcpy(g_nrf_ccm_data.iv, iv, 8); - g_nrf_ccm_data.dir_bit = is_master; g_ble_phy_data.phy_encrypted = 1; - /* Enable the module (AAR cannot be on while CCM on) */ NRF_AAR->ENABLE = AAR_ENABLE_ENABLE_Disabled; NRF_CCM->ENABLE = CCM_ENABLE_ENABLE_Enabled; +#ifdef NRF5340_XXAA + NRF_CCM->HEADERMASK = BLE_LL_PDU_HEADERMASK_DATA; +#endif +#if PHY_USE_HEADERMASK_WORKAROUND + g_ble_phy_data.phy_headermask = BLE_LL_PDU_HEADERMASK_DATA; +#endif +} + +void +ble_phy_encrypt_header_mask_set(uint8_t mask) +{ +#ifdef NRF5340_XXAA + NRF_CCM->HEADERMASK = mask; +#endif +#if PHY_USE_HEADERMASK_WORKAROUND + g_ble_phy_data.phy_headermask = mask; +#endif +} + +void +ble_phy_encrypt_iv_set(const uint8_t *iv) +{ + memcpy(g_nrf_ccm_data.iv, iv, 8); } void -ble_phy_encrypt_set_pkt_cntr(uint64_t pkt_counter, int dir) +ble_phy_encrypt_counter_set(uint64_t counter, uint8_t dir_bit) { - g_nrf_ccm_data.pkt_counter = pkt_counter; - g_nrf_ccm_data.dir_bit = dir; + g_nrf_ccm_data.pkt_counter = counter; + g_nrf_ccm_data.dir_bit = dir_bit; } void ble_phy_encrypt_disable(void) { - NRF_PPI->CHENCLR = PPI_CHEN_CH25_Msk; - NRF_CCM->TASKS_STOP = 1; + phy_ppi_radio_address_to_ccm_crypt_disable(); + nrf_ccm_task_trigger(NRF_CCM, NRF_CCM_TASK_STOP); NRF_CCM->EVENTS_ERROR = 0; NRF_CCM->ENABLE = CCM_ENABLE_ENABLE_Disabled; @@ -1619,13 +1844,13 @@ ble_phy_tx_set_start_time(uint32_t cputime, uint8_t rem_usecs) ble_phy_trace_u32x2(BLE_PHY_TRACE_ID_START_TX, cputime, rem_usecs); -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) +#if MYNEWT_VAL(BLE_LL_PHY) ble_phy_mode_apply(g_ble_phy_data.phy_tx_phy_mode); #endif /* XXX: This should not be necessary, but paranoia is good! */ /* Clear timer0 compare to RXEN since we are transmitting */ - NRF_PPI->CHENCLR = PPI_CHEN_CH21_Msk; + phy_ppi_timer0_compare0_to_radio_rxen_disable(); if (ble_phy_set_start_time(cputime, rem_usecs, true) != 0) { STATS_INC(ble_phy_stats, tx_late); @@ -1633,9 +1858,10 @@ ble_phy_tx_set_start_time(uint32_t cputime, uint8_t rem_usecs) rc = BLE_PHY_ERR_TX_LATE; } else { /* Enable PPI to automatically start TXEN */ - NRF_PPI->CHENSET = PPI_CHEN_CH20_Msk; + phy_ppi_timer0_compare0_to_radio_txen_enable(); rc = 0; } + return rc; } @@ -1660,13 +1886,13 @@ ble_phy_rx_set_start_time(uint32_t cputime, uint8_t rem_usecs) ble_phy_trace_u32x2(BLE_PHY_TRACE_ID_START_RX, cputime, rem_usecs); -#if (BLE_LL_BT5_PHY_SUPPORTED == 1) +#if MYNEWT_VAL(BLE_LL_PHY) ble_phy_mode_apply(g_ble_phy_data.phy_rx_phy_mode); #endif /* XXX: This should not be necessary, but paranoia is good! */ /* Clear timer0 compare to TXEN since we are transmitting */ - NRF_PPI->CHENCLR = PPI_CHEN_CH20_Msk; + phy_ppi_timer0_compare0_to_radio_txen_disable(); if (ble_phy_set_start_time(cputime, rem_usecs, false) != 0) { STATS_INC(ble_phy_stats, rx_late); @@ -1678,7 +1904,7 @@ ble_phy_rx_set_start_time(uint32_t cputime, uint8_t rem_usecs) } /* Enable PPI to automatically start RXEN */ - NRF_PPI->CHENSET = PPI_CHEN_CH21_Msk; + phy_ppi_timer0_compare0_to_radio_rxen_enable(); /* Start rx */ rc = ble_phy_rx(); @@ -1724,8 +1950,9 @@ ble_phy_tx(ble_phy_tx_pducb_t pducb, void *pducb_arg, uint8_t end_trans) * paranoid, and if you are going to clear one, might as well clear them * all. */ - NRF_PPI->CHENCLR = PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk | PPI_CHEN_CH23_Msk | - PPI_CHEN_CH25_Msk; + phy_ppi_wfr_disable(); + phy_ppi_radio_bcmatch_to_aar_start_disable(); + phy_ppi_radio_address_to_ccm_crypt_disable(); #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) if (g_ble_phy_data.phy_encrypted) { @@ -1761,7 +1988,16 @@ ble_phy_tx(ble_phy_tx_pducb_t pducb, void *pducb_arg, uint8_t end_trans) #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) /* Start key-stream generation and encryption (via short) */ if (g_ble_phy_data.phy_encrypted) { - NRF_CCM->TASKS_KSGEN = 1; +#if PHY_USE_HEADERMASK_WORKAROUND + if (g_ble_phy_data.phy_headermask != BLE_LL_PDU_HEADERMASK_DATA) { + g_ble_phy_data.phy_headerbyte = dptr[0]; + dptr[0] &= g_ble_phy_data.phy_headermask; + g_ble_phy_tx_buf[0] = 0xffffffff; + NRF_CCM->EVENTS_ENDKSGEN = 0; + NRF_CCM->INTENSET = CCM_INTENSET_ENDKSGEN_Msk; + } +#endif + nrf_ccm_task_trigger(NRF_CCM, NRF_CCM_TASK_KSGEN); } #endif @@ -1775,7 +2011,7 @@ ble_phy_tx(ble_phy_tx_pducb_t pducb, void *pducb_arg, uint8_t end_trans) /* Enable shortcuts for transmit start/end. */ shortcuts = RADIO_SHORTS_END_DISABLE_Msk | RADIO_SHORTS_READY_START_Msk; NRF_RADIO->SHORTS = shortcuts; - NRF_RADIO->INTENSET = RADIO_INTENSET_DISABLED_Msk; + nrf_radio_int_enable(NRF_RADIO, RADIO_INTENSET_DISABLED_Msk); /* Set the PHY transition */ g_ble_phy_data.phy_transition = end_trans; @@ -1814,12 +2050,12 @@ ble_phy_tx(ble_phy_tx_pducb_t pducb, void *pducb_arg, uint8_t end_trans) * @return int 0: success; anything else is an error */ int -ble_phy_txpwr_set(int dbm) +ble_phy_tx_power_set(int dbm) { - /* "Rail" power level if outside supported range */ - dbm = ble_phy_txpower_round(dbm); + /* Get actual TX power supported by radio */ + dbm = phy_txpower_round(dbm); - NRF_RADIO->TXPOWER = dbm; + phy_txpower_set(dbm); g_ble_phy_data.phy_txpwr_dbm = dbm; return 0; @@ -1834,40 +2070,10 @@ ble_phy_txpwr_set(int dbm) * * @return int Rounded power in dBm */ -int ble_phy_txpower_round(int dbm) +int +ble_phy_tx_power_round(int dbm) { - /* TODO this should be per nRF52XXX */ - - /* "Rail" power level if outside supported range */ - if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Pos4dBm) { - return (int8_t)RADIO_TXPOWER_TXPOWER_Pos4dBm; - } - - if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Pos3dBm) { - return (int8_t)RADIO_TXPOWER_TXPOWER_Pos3dBm; - } - - if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_0dBm) { - return (int8_t)RADIO_TXPOWER_TXPOWER_0dBm; - } - - if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg4dBm) { - return (int8_t)RADIO_TXPOWER_TXPOWER_Neg4dBm; - } - - if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg8dBm) { - return (int8_t)RADIO_TXPOWER_TXPOWER_Neg8dBm; - } - - if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg12dBm) { - return (int8_t)RADIO_TXPOWER_TXPOWER_Neg12dBm; - } - - if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg20dBm) { - return (int8_t)RADIO_TXPOWER_TXPOWER_Neg20dBm; - } - - return (int8_t)RADIO_TXPOWER_TXPOWER_Neg40dBm; + return phy_txpower_round(dbm); } /** @@ -1887,7 +2093,20 @@ ble_phy_set_access_addr(uint32_t access_addr) g_ble_phy_data.phy_access_address = access_addr; - ble_phy_apply_errata_102_106_107(); +#if NRF52_ERRATA_102_ENABLE_WORKAROUND || \ + NRF52_ERRATA_106_ENABLE_WORKAROUND || \ + NRF52_ERRATA_107_ENABLE_WORKAROUND +#ifndef BABBLESIM + if (nrf52_errata_102() || nrf52_errata_106() || nrf52_errata_107()) { + /* [102] RADIO: PAYLOAD/END events delayed or not triggered after ADDRESS + * [106] RADIO: Higher CRC error rates for some access addresses + * [107] RADIO: Immediate address match for access addresses containing MSBs 0x00 + */ + *(volatile uint32_t *)0x40001774 = + ((*(volatile uint32_t *)0x40001774) & 0xfffffffe) | 0x01000000; + } +#endif +#endif return 0; } @@ -1900,17 +2119,11 @@ ble_phy_set_access_addr(uint32_t access_addr) * @return int The current PHY transmit power, in dBm */ int -ble_phy_txpwr_get(void) +ble_phy_tx_power_get(void) { return g_ble_phy_data.phy_txpwr_dbm; } -void -ble_phy_set_rx_pwr_compensation(int8_t compensation) -{ - g_ble_phy_data.rx_pwr_compensation = compensation; -} - /** * ble phy setchan * @@ -1949,15 +2162,21 @@ ble_phy_setchan(uint8_t chan, uint32_t access_addr, uint32_t crcinit) return 0; } +uint8_t +ble_phy_chan_get(void) +{ + return g_ble_phy_data.phy_chan; +} + /** * Stop the timer used to count microseconds when using RTC for cputime */ static void ble_phy_stop_usec_timer(void) { - NRF_TIMER0->TASKS_STOP = 1; + nrf_timer_task_trigger(NRF_TIMER0, NRF_TIMER_TASK_STOP); NRF_TIMER0->TASKS_SHUTDOWN = 1; - NRF_RTC0->EVTENCLR = RTC_EVTENSET_COMPARE0_Msk; + nrf_rtc_event_disable(NRF_RTC0, RTC_EVTENSET_COMPARE0_Msk); } /** @@ -1971,12 +2190,10 @@ ble_phy_stop_usec_timer(void) static void ble_phy_disable_irq_and_ppi(void) { - NRF_RADIO->INTENCLR = NRF_RADIO_IRQ_MASK_ALL; + nrf_radio_int_disable(NRF_RADIO, NRF_RADIO_IRQ_MASK_ALL); NRF_RADIO->SHORTS = 0; - NRF_RADIO->TASKS_DISABLE = 1; - NRF_PPI->CHENCLR = PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk | PPI_CHEN_CH20_Msk | - PPI_CHEN_CH21_Msk | PPI_CHEN_CH23_Msk | - PPI_CHEN_CH25_Msk | PPI_CHEN_CH31_Msk; + nrf_radio_task_trigger(NRF_RADIO, NRF_RADIO_TASK_DISABLE); + phy_ppi_disable(); NVIC_ClearPendingIRQ(RADIO_IRQn); g_ble_phy_data.phy_state = BLE_PHY_STATE_IDLE; } @@ -1989,7 +2206,7 @@ ble_phy_restart_rx(void) ble_phy_set_start_now(); /* Enable PPI to automatically start RXEN */ - NRF_PPI->CHENSET = PPI_CHEN_CH21_Msk; + phy_ppi_timer0_compare0_to_radio_rxen_enable(); ble_phy_rx(); } @@ -2006,8 +2223,18 @@ ble_phy_disable(void) { ble_phy_trace_void(BLE_PHY_TRACE_ID_DISABLE); +#if PHY_USE_HEADERMASK_WORKAROUND + NRF_CCM->INTENCLR = CCM_INTENCLR_ENDKSGEN_Msk; +#endif + ble_phy_stop_usec_timer(); ble_phy_disable_irq_and_ppi(); + + g_ble_phy_data.phy_transition_late = 0; + +#if PHY_USE_FEM + phy_fem_disable(); +#endif } /* Gets the current access address */ @@ -2093,24 +2320,57 @@ void ble_phy_disable_dtm(void) /* Enable whitening */ NRF_RADIO->PCNF1 |= RADIO_PCNF1_WHITEEN_Msk; } + +#if MYNEWT_VAL(BLE_LL_DTM_EXTENSIONS) +int +ble_phy_dtm_carrier(uint8_t rf_channel) +{ + /* based on Nordic DTM sample */ + ble_phy_disable(); + ble_phy_enable_dtm(); + ble_phy_mode_apply(BLE_PHY_MODE_1M); + nrf_radio_shorts_enable(NRF_RADIO, NRF_RADIO_SHORT_READY_START_MASK); + NRF_RADIO->FREQUENCY = g_ble_phy_chan_freq[rf_channel]; + nrf_radio_task_trigger(NRF_RADIO, NRF_RADIO_TASK_TXEN); + + return 0; +} +#endif #endif void ble_phy_rfclk_enable(void) { -#if MYNEWT +#if MYNEWT || defined(RIOT_VERSION) || defined(PEBBLEOS) +#ifdef NRF52_SERIES nrf52_clock_hfxo_request(); +#endif +#ifdef NRF53_SERIES + nrf5340_net_clock_hfxo_request(); +#endif #else - NRF_CLOCK->TASKS_HFCLKSTART = 1; + nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_HFCLKSTART); #endif } void ble_phy_rfclk_disable(void) { -#if MYNEWT +#if MYNEWT || defined(RIOT_VERSION) || defined(PEBBLEOS) +#ifdef NRF52_SERIES nrf52_clock_hfxo_release(); +#endif +#ifdef NRF53_SERIES + nrf5340_net_clock_hfxo_release(); +#endif #else - NRF_CLOCK->TASKS_HFCLKSTOP = 1; + nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_HFCLKSTOP); #endif } + +void +ble_phy_tifs_txtx_set(uint16_t usecs, uint8_t anchor) +{ + g_ble_phy_data.txtx_time_us = usecs; + g_ble_phy_data.txtx_time_anchor = anchor; +} diff --git a/nimble/drivers/nrf52/src/ble_phy_trace.c b/nimble/drivers/nrf5x/src/ble_phy_trace.c similarity index 100% rename from nimble/drivers/nrf52/src/ble_phy_trace.c rename to nimble/drivers/nrf5x/src/ble_phy_trace.c diff --git a/nimble/drivers/nrf5x/src/nrf52/phy.c b/nimble/drivers/nrf5x/src/nrf52/phy.c new file mode 100644 index 0000000000..30a19966b7 --- /dev/null +++ b/nimble/drivers/nrf5x/src/nrf52/phy.c @@ -0,0 +1,220 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#include "../phy_priv.h" + +#if PHY_USE_DEBUG +void +phy_debug_init(void) +{ +#if PHY_USE_DEBUG_1 + phy_gpiote_configure(PHY_GPIOTE_DEBUG_1, + MYNEWT_VAL(BLE_PHY_DBG_TIME_TXRXEN_READY_PIN)); + + nrf_ppi_channel_endpoint_setup(NRF_PPI, 17, + (uint32_t)&(NRF_RADIO->EVENTS_READY), + (uint32_t)&(NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_DEBUG_1])); + nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH17_Msk); + + /* CH[20] and PPI CH[21] are on to trigger TASKS_TXEN or TASKS_RXEN */ + nrf_ppi_fork_endpoint_setup(NRF_PPI, 20, + (uint32_t)&(NRF_GPIOTE->TASKS_SET[PHY_GPIOTE_DEBUG_1])); + nrf_ppi_fork_endpoint_setup(NRF_PPI, 21, + (uint32_t)&(NRF_GPIOTE->TASKS_SET[PHY_GPIOTE_DEBUG_1])); +#endif + +#if PHY_USE_DEBUG_2 + phy_gpiote_configure(PHY_GPIOTE_DEBUG_2, + MYNEWT_VAL(BLE_PHY_DBG_TIME_ADDRESS_END_PIN)); + + /* CH[26] and CH[27] are always on for EVENT_ADDRESS and EVENT_END */ + nrf_ppi_fork_endpoint_setup(NRF_PPI, 26, + (uint32_t)&(NRF_GPIOTE->TASKS_SET[PHY_GPIOTE_DEBUG_2])); + nrf_ppi_fork_endpoint_setup(NRF_PPI, 27, + (uint32_t)&(NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_DEBUG_2])); +#endif + +#if PHY_USE_DEBUG_3 + phy_gpiote_configure(PHY_GPIOTE_DEBUG_3, MYNEWT_VAL(BLE_PHY_DBG_TIME_WFR_PIN)); + +#if NRF52840_XXAA + nrf_ppi_channel_endpoint_setup(NRF_PPI, 18, + (uint32_t)&(NRF_RADIO->EVENTS_RXREADY), + (uint32_t)&(NRF_GPIOTE->TASKS_SET[PHY_GPIOTE_DEBUG_3])); +#else + nrf_ppi_channel_endpoint_setup(NRF_PPI, 18, + (uint32_t)&(NRF_RADIO->EVENTS_READY), + (uint32_t)&(NRF_GPIOTE->TASKS_SET[GIDX_DEBUG_3])); +#endif + nrf_ppi_channel_endpoint_setup(NRF_PPI, 19, + (uint32_t)&(NRF_RADIO->EVENTS_DISABLED), + (uint32_t)&(NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_DEBUG_3])); + nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH18_Msk | PPI_CHEN_CH19_Msk); + + /* CH[4] and CH[5] are always on for wfr */ + nrf_ppi_fork_endpoint_setup(NRF_PPI, 4, + (uint32_t)&(NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_DEBUG_3])); + nrf_ppi_fork_endpoint_setup(NRF_PPI, 5, + (uint32_t)&(NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_DEBUG_3])); +#endif +} +#endif /* PHY_USE_DEBUG */ + +#if PHY_USE_FEM +void +phy_fem_init(void) +{ +#if PHY_USE_FEM_SINGLE_GPIO +#if PHY_USE_FEM_PA + phy_gpiote_configure(PHY_GPIOTE_FEM, MYNEWT_VAL(BLE_FEM_PA_GPIO)); +#else + phy_gpiote_configure(PHY_GPIOTE_FEM, MYNEWT_VAL(BLE_FEM_LNA_GPIO)); +#endif + NRF_PPI->CH[6].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_SET[PHY_GPIOTE_FEM]); + NRF_PPI->CH[7].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_FEM]); +#else +#if PHY_USE_FEM_PA + phy_gpiote_configure(PHY_GPIOTE_FEM_PA, MYNEWT_VAL(BLE_FEM_PA_GPIO)); + NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_FEM_PA] = 1; +#endif +#if PHY_USE_FEM_LNA + phy_gpiote_configure(PHY_GPIOTE_FEM_LNA, MYNEWT_VAL(BLE_FEM_LNA_GPIO)); + NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_FEM_LNA] = 1; +#endif +#endif /* PHY_USE_FEM_SINGLE_GPIO */ + + NRF_PPI->CH[6].EEP = (uint32_t)&(NRF_TIMER0->EVENTS_COMPARE[2]); + NRF_PPI->CH[7].EEP = (uint32_t)&(NRF_RADIO->EVENTS_DISABLED); + + nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH6_Msk | PPI_CHEN_CH7_Msk); +} + +#if PHY_USE_FEM_PA +void +phy_fem_enable_pa(void) +{ + ble_fem_pa_enable(); + +#if !PHY_USE_FEM_SINGLE_GPIO + /* Switch FEM channels to control PA */ + NRF_PPI->CH[6].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_SET[PHY_GPIOTE_FEM_PA]); + NRF_PPI->CH[7].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_FEM_PA]); +#endif + + nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH6_Msk | PPI_CHEN_CH7_Msk); +} +#endif + +#if PHY_USE_FEM_LNA +void +phy_fem_enable_lna(void) +{ + ble_fem_lna_enable(); + +#if !PHY_USE_FEM_SINGLE_GPIO + /* Switch FEM channels to control LNA */ + NRF_PPI->CH[6].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_SET[PHY_GPIOTE_FEM_LNA]); + NRF_PPI->CH[7].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_FEM_LNA]); +#endif + + nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH6_Msk | PPI_CHEN_CH7_Msk); +} +#endif + +void +phy_fem_disable(void) +{ +#if PHY_USE_FEM_SINGLE_GPIO + NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_FEM] = 1; +#else +#if PHY_USE_FEM_PA + NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_FEM_PA] = 1; +#endif +#if PHY_USE_FEM_LNA + NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_FEM_LNA] = 1; +#endif +#endif +} +#endif /* PHY_USE_FEM */ + +void +phy_ppi_init(void) +{ + /* radio_address_to_timer0_capture1 */ + nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH26_Msk); + /* radio_end_to_timer0_capture2 */ + nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH27_Msk); + + /* + * PPI setup. + * Channel 4: Captures TIMER0 in CC[3] when EVENTS_ADDRESS occurs. Used + * to cancel the wait for response timer. + * Channel 5: TIMER0 CC[3] to TASKS_DISABLE on radio. This is the wait + * for response timer. + */ + nrf_ppi_channel_endpoint_setup(NRF_PPI, NRF_PPI_CHANNEL4, + (uint32_t)&(NRF_RADIO->EVENTS_ADDRESS), + (uint32_t)&(NRF_TIMER0->TASKS_CAPTURE[3])); + nrf_ppi_channel_endpoint_setup(NRF_PPI, NRF_PPI_CHANNEL5, + (uint32_t)&(NRF_TIMER0->EVENTS_COMPARE[3]), + (uint32_t)&(NRF_RADIO->TASKS_DISABLE)); +} + +void +phy_txpower_set(int8_t dbm) +{ + NRF_RADIO->TXPOWER = dbm; +} + +int8_t +phy_txpower_round(int8_t dbm) +{ + if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Pos4dBm) { + return (int8_t)RADIO_TXPOWER_TXPOWER_Pos4dBm; + } + + if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Pos3dBm) { + return (int8_t)RADIO_TXPOWER_TXPOWER_Pos3dBm; + } + + if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_0dBm) { + return (int8_t)RADIO_TXPOWER_TXPOWER_0dBm; + } + + if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg4dBm) { + return (int8_t)RADIO_TXPOWER_TXPOWER_Neg4dBm; + } + + if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg8dBm) { + return (int8_t)RADIO_TXPOWER_TXPOWER_Neg8dBm; + } + + if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg12dBm) { + return (int8_t)RADIO_TXPOWER_TXPOWER_Neg12dBm; + } + + if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg20dBm) { + return (int8_t)RADIO_TXPOWER_TXPOWER_Neg20dBm; + } + + return (int8_t)RADIO_TXPOWER_TXPOWER_Neg40dBm; +} diff --git a/nimble/drivers/nrf5x/src/nrf52/phy_ppi.h b/nimble/drivers/nrf5x/src/nrf52/phy_ppi.h new file mode 100644 index 0000000000..a77b718339 --- /dev/null +++ b/nimble/drivers/nrf5x/src/nrf52/phy_ppi.h @@ -0,0 +1,113 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_PHY_PPI_ +#define H_PHY_PPI_ + +#include + +static inline void +phy_ppi_rtc0_compare0_to_timer0_start_enable(void) +{ + nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH31_Msk); +} + +static inline void +phy_ppi_rtc0_compare0_to_timer0_start_disable(void) +{ + nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH31_Msk); +} + +static inline void +phy_ppi_timer0_compare0_to_radio_txen_enable(void) +{ + nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH20_Msk); +} + +static inline void +phy_ppi_timer0_compare0_to_radio_txen_disable(void) +{ + nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH20_Msk); +} + +static inline void +phy_ppi_timer0_compare0_to_radio_rxen_enable(void) +{ + nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH21_Msk); +} + +static inline void +phy_ppi_timer0_compare0_to_radio_rxen_disable(void) +{ + nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH21_Msk); +} + +static inline void +phy_ppi_radio_bcmatch_to_aar_start_enable(void) +{ + nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH23_Msk); +} + +static inline void +phy_ppi_radio_bcmatch_to_aar_start_disable(void) +{ + nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH23_Msk); +} + +static inline void +phy_ppi_radio_address_to_ccm_crypt_enable(void) +{ + nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH25_Msk); +} + +static inline void +phy_ppi_radio_address_to_ccm_crypt_disable(void) +{ + nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH25_Msk); +} + +static inline void +phy_ppi_wfr_enable(void) +{ + nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk); +} + +static inline void +phy_ppi_wfr_disable(void) +{ + nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk); +} + +static inline void +phy_ppi_fem_disable(void) +{ + nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH6_Msk | PPI_CHEN_CH7_Msk); +} + +static inline void +phy_ppi_disable(void) +{ + nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk | + PPI_CHEN_CH6_Msk | PPI_CHEN_CH7_Msk | + PPI_CHEN_CH20_Msk | PPI_CHEN_CH21_Msk | + PPI_CHEN_CH23_Msk | PPI_CHEN_CH25_Msk | + PPI_CHEN_CH31_Msk); +} + +#endif /* H_PHY_PPI_ */ diff --git a/nimble/drivers/nrf5x/src/nrf53/phy.c b/nimble/drivers/nrf5x/src/nrf53/phy.c new file mode 100644 index 0000000000..ceda769b0f --- /dev/null +++ b/nimble/drivers/nrf5x/src/nrf53/phy.c @@ -0,0 +1,312 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#include "../phy_priv.h" + +/* + * When the radio is operated on high voltage (see VREQCTRL - Voltage request + * control on page 62 for how to control voltage), the output power is increased + * by 3 dB. I.e. if the TXPOWER value is set to 0 dBm and high voltage is + * requested using VREQCTRL, the output power will be +3 + * */ +#define NRF_TXPOWER_VREQH 3 + +#if PHY_USE_DEBUG +void +phy_debug_init(void) +{ +#if PHY_USE_DEBUG_1 + phy_gpiote_configure(PHY_GPIOTE_DEBUG_1, + MYNEWT_VAL(BLE_PHY_DBG_TIME_TXRXEN_READY_PIN)); + + NRF_RADIO->PUBLISH_READY = DPPI_CH_PUB(RADIO_EVENTS_READY); + NRF_DPPIC->CHENSET = DPPI_CH_MASK(RADIO_EVENTS_READY); + + NRF_GPIOTE->SUBSCRIBE_SET[PHY_GPIOTE_DEBUG_1] = DPPI_CH_SUB(TIMER0_EVENTS_COMPARE_0); + NRF_GPIOTE->SUBSCRIBE_CLR[PHY_GPIOTE_DEBUG_1] = DPPI_CH_SUB(RADIO_EVENTS_READY); +#endif + +#if PHY_USE_DEBUG_2 + phy_gpiote_configure(PHY_GPIOTE_DEBUG_2, + MYNEWT_VAL(BLE_PHY_DBG_TIME_ADDRESS_END_PIN)); + + NRF_GPIOTE->SUBSCRIBE_SET[PHY_GPIOTE_DEBUG_2] = DPPI_CH_SUB(RADIO_EVENTS_ADDRESS); + NRF_GPIOTE->SUBSCRIBE_CLR[PHY_GPIOTE_DEBUG_2] = DPPI_CH_SUB(RADIO_EVENTS_END); +#endif + +#if PHY_USE_DEBUG_3 + phy_gpiote_configure(PHY_GPIOTE_DEBUG_3, MYNEWT_VAL(BLE_PHY_DBG_TIME_WFR_PIN)); + + NRF_RADIO->PUBLISH_RXREADY = DPPI_CH_PUB(RADIO_EVENTS_READY); + NRF_RADIO->PUBLISH_DISABLED = DPPI_CH_PUB(RADIO_EVENTS_DISABLED); + NRF_DPPIC->CHENSET = DPPI_CH_MASK(RADIO_EVENTS_RXREADY) | + DPPI_CH_MASK(RADIO_EVENTS_DISABLED); + + NRF_GPIOTE->SUBSCRIBE_SET[PHY_GPIOTE_DEBUG_3] = DPPI_CH_SUB(RADIO_EVENTS_RXREADY); + + /* TODO figure out how (if?) to subscribe task to multiple DPPI channels + * Currently only last one is working. Also using multiple GPIOTE for same + * PIN doesn't work... + */ + NRF_GPIOTE->SUBSCRIBE_CLR[PHY_GPIOTE_DEBUG_3] = DPPI_CH_SUB(RADIO_EVENTS_DISABLED); + NRF_GPIOTE->SUBSCRIBE_CLR[PHY_GPIOTE_DEBUG_3] = DPPI_CH_SUB(RADIO_EVENTS_ADDRESS); + NRF_GPIOTE->SUBSCRIBE_CLR[PHY_GPIOTE_DEBUG_3] = DPPI_CH_SUB(TIMER0_EVENTS_COMPARE_3); + +#endif +} +#endif /* PHY_USE_DEBUG */ + +#if PHY_USE_FEM +void +phy_fem_init() +{ + /* We can keep clear tasks subscribed and published channels always enabled, + * it's enough to just (un)subscribe set tasks when needed. + * TODO: check if this affects power consumption + */ + + NRF_TIMER0->PUBLISH_COMPARE[2] = DPPI_CH_PUB(TIMER0_EVENTS_COMPARE_2); + NRF_RADIO->PUBLISH_DISABLED = DPPI_CH_PUB(RADIO_EVENTS_DISABLED); + +#if PHY_USE_FEM_SINGLE_GPIO +#if PHY_USE_FEM_PA + phy_gpiote_configure(PHY_GPIOTE_FEM, MYNEWT_VAL(BLE_FEM_PA_GPIO)); +#else + phy_gpiote_configure(PHY_GPIOTE_FEM, MYNEWT_VAL(BLE_FEM_LNA_GPIO)); +#endif + NRF_GPIOTE->SUBSCRIBE_SET[PHY_GPIOTE_FEM] = + DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_2); + NRF_GPIOTE->SUBSCRIBE_CLR[PHY_GPIOTE_FEM] = + DPPI_CH_SUB(RADIO_EVENTS_DISABLED); + NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_FEM] = 1; +#else +#if PHY_USE_FEM_PA + phy_gpiote_configure(PHY_GPIOTE_FEM_PA, MYNEWT_VAL(BLE_FEM_PA_GPIO)); + NRF_GPIOTE->SUBSCRIBE_SET[PHY_GPIOTE_FEM_PA] = + DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_2); + NRF_GPIOTE->SUBSCRIBE_CLR[PHY_GPIOTE_FEM_PA] = + DPPI_CH_SUB(RADIO_EVENTS_DISABLED); + NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_FEM_PA] = 1; +#endif +#if PHY_USE_FEM_LNA + phy_gpiote_configure(PHY_GPIOTE_FEM_LNA, MYNEWT_VAL(BLE_FEM_LNA_GPIO)); + NRF_GPIOTE->SUBSCRIBE_SET[PHY_GPIOTE_FEM_LNA] = + DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_2); + NRF_GPIOTE->SUBSCRIBE_CLR[PHY_GPIOTE_FEM_LNA] = + DPPI_CH_SUB(RADIO_EVENTS_DISABLED); + NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_FEM_LNA] = 1; +#endif +#endif /* PHY_USE_FEM_SINGLE_GPIO */ + + NRF_DPPIC->CHENSET = DPPI_CH_MASK_FEM; +} + +#if PHY_USE_FEM_PA +void +phy_fem_enable_pa(void) +{ + ble_fem_pa_enable(); + +#if PHY_USE_FEM_SINGLE_GPIO + NRF_GPIOTE->SUBSCRIBE_SET[PHY_GPIOTE_FEM] = + DPPI_CH_SUB(TIMER0_EVENTS_COMPARE_2); +#else + NRF_GPIOTE->SUBSCRIBE_SET[PHY_GPIOTE_FEM_PA] = + DPPI_CH_SUB(TIMER0_EVENTS_COMPARE_2); +#endif +} +#endif + +#if PHY_USE_FEM_LNA +void +phy_fem_enable_lna(void) +{ + ble_fem_lna_enable(); + +#if PHY_USE_FEM_SINGLE_GPIO + NRF_GPIOTE->SUBSCRIBE_SET[PHY_GPIOTE_FEM] = + DPPI_CH_SUB(TIMER0_EVENTS_COMPARE_2); +#else + NRF_GPIOTE->SUBSCRIBE_SET[PHY_GPIOTE_FEM_LNA] = + DPPI_CH_SUB(TIMER0_EVENTS_COMPARE_2); +#endif +} +#endif + +void +phy_fem_disable(void) +{ +#if PHY_USE_FEM_SINGLE_GPIO + NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_FEM] = 1; +#else +#if PHY_USE_FEM_PA + NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_FEM_PA] = 1; +#endif +#if PHY_USE_FEM_LNA + NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_FEM_LNA] = 1; +#endif +#endif +} +#endif /* PHY_USE_FEM */ + +void +phy_ppi_init(void) +{ + /* Publish events */ + NRF_TIMER0->PUBLISH_COMPARE[0] = DPPI_CH_PUB(TIMER0_EVENTS_COMPARE_0); + NRF_TIMER0->PUBLISH_COMPARE[3] = DPPI_CH_PUB(TIMER0_EVENTS_COMPARE_3); + NRF_RADIO->PUBLISH_END = DPPI_CH_PUB(RADIO_EVENTS_END); + NRF_RADIO->PUBLISH_BCMATCH = DPPI_CH_PUB(RADIO_EVENTS_BCMATCH); + NRF_RADIO->PUBLISH_ADDRESS = DPPI_CH_PUB(RADIO_EVENTS_ADDRESS); + NRF_RTC0->PUBLISH_COMPARE[0] = DPPI_CH_PUB(RTC0_EVENTS_COMPARE_0); + + /* Enable channels we publish on */ + NRF_DPPIC->CHENSET = DPPI_CH_ENABLE_ALL; + + /* radio_address_to_timer0_capture1 */ + NRF_TIMER0->SUBSCRIBE_CAPTURE[1] = DPPI_CH_SUB(RADIO_EVENTS_ADDRESS); + /* radio_end_to_timer0_capture2 */ + NRF_TIMER0->SUBSCRIBE_CAPTURE[2] = DPPI_CH_SUB(RADIO_EVENTS_END); +} + +void +phy_txpower_set(int8_t dbm) +{ +#if MYNEWT_VAL(BLE_PHY_NRF5340_VDDH) + switch (dbm) { + case ((int8_t)RADIO_TXPOWER_TXPOWER_0dBm) + NRF_TXPOWER_VREQH: + case ((int8_t)RADIO_TXPOWER_TXPOWER_Neg1dBm) + NRF_TXPOWER_VREQH: + case ((int8_t)RADIO_TXPOWER_TXPOWER_Neg2dBm) + NRF_TXPOWER_VREQH: + case ((int8_t)RADIO_TXPOWER_TXPOWER_Neg12dBm) + NRF_TXPOWER_VREQH: + case ((int8_t)RADIO_TXPOWER_TXPOWER_Neg16dBm) + NRF_TXPOWER_VREQH: + case ((int8_t)RADIO_TXPOWER_TXPOWER_Neg20dBm) + NRF_TXPOWER_VREQH: + case ((int8_t)RADIO_TXPOWER_TXPOWER_Neg40dBm) + NRF_TXPOWER_VREQH: + NRF_VREQCTRL->VREGRADIO.VREQH = 1; + dbm -= NRF_TXPOWER_VREQH; + break; + default: + NRF_VREQCTRL->VREGRADIO.VREQH = 0; + break; + } +#endif + + NRF_RADIO->TXPOWER = dbm; +} + +int8_t +phy_txpower_round(int8_t dbm) +{ +#if MYNEWT_VAL(BLE_PHY_NRF5340_VDDH) + /* +3 dBm */ + if (dbm >= ((int8_t)RADIO_TXPOWER_TXPOWER_0dBm) + NRF_TXPOWER_VREQH) { + return ((int8_t)RADIO_TXPOWER_TXPOWER_0dBm) + NRF_TXPOWER_VREQH; + } + + /* +2 dBm */ + if (dbm >= ((int8_t)RADIO_TXPOWER_TXPOWER_Neg1dBm) + NRF_TXPOWER_VREQH) { + return ((int8_t)RADIO_TXPOWER_TXPOWER_Neg1dBm) + NRF_TXPOWER_VREQH; + } + + /* +1 dBm */ + if (dbm >= ((int8_t)RADIO_TXPOWER_TXPOWER_Neg2dBm) + NRF_TXPOWER_VREQH) { + return ((int8_t)RADIO_TXPOWER_TXPOWER_Neg2dBm) + NRF_TXPOWER_VREQH; + } +#endif + + if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_0dBm) { + return (int8_t)RADIO_TXPOWER_TXPOWER_0dBm; + } + + if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg1dBm) { + return (int8_t)RADIO_TXPOWER_TXPOWER_Neg1dBm; + } + + if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg2dBm) { + return (int8_t)RADIO_TXPOWER_TXPOWER_Neg2dBm; + } + + if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg3dBm) { + return (int8_t)RADIO_TXPOWER_TXPOWER_Neg3dBm; + } + + if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg4dBm) { + return (int8_t)RADIO_TXPOWER_TXPOWER_Neg4dBm; + } + + if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg5dBm) { + return (int8_t)RADIO_TXPOWER_TXPOWER_Neg5dBm; + } + + if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg6dBm) { + return (int8_t)RADIO_TXPOWER_TXPOWER_Neg6dBm; + } + + if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg7dBm) { + return (int8_t)RADIO_TXPOWER_TXPOWER_Neg7dBm; + } + + if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg8dBm) { + return (int8_t)RADIO_TXPOWER_TXPOWER_Neg8dBm; + } + +#if MYNEWT_VAL(BLE_PHY_NRF5340_VDDH) + /* -9 dBm */ + if (dbm >= ((int8_t)RADIO_TXPOWER_TXPOWER_Neg12dBm) + NRF_TXPOWER_VREQH) { + return ((int8_t)RADIO_TXPOWER_TXPOWER_Neg12dBm) + NRF_TXPOWER_VREQH; + } +#endif + + if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg12dBm) { + return (int8_t)RADIO_TXPOWER_TXPOWER_Neg12dBm; + } + +#if MYNEWT_VAL(BLE_PHY_NRF5340_VDDH) + /* -13 dBm */ + if (dbm >= ((int8_t)RADIO_TXPOWER_TXPOWER_Neg16dBm) + NRF_TXPOWER_VREQH) { + return ((int8_t)RADIO_TXPOWER_TXPOWER_Neg16dBm) + NRF_TXPOWER_VREQH; + } +#endif + + if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg16dBm) { + return (int8_t)RADIO_TXPOWER_TXPOWER_Neg16dBm; + } + +#if MYNEWT_VAL(BLE_PHY_NRF5340_VDDH) + /* -17 dBm */ + if (dbm >= ((int8_t)RADIO_TXPOWER_TXPOWER_Neg20dBm) + NRF_TXPOWER_VREQH) { + return ((int8_t)RADIO_TXPOWER_TXPOWER_Neg20dBm) + NRF_TXPOWER_VREQH; + } +#endif + + if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg20dBm) { + return (int8_t)RADIO_TXPOWER_TXPOWER_Neg20dBm; + } + +#if MYNEWT_VAL(BLE_PHY_NRF5340_VDDH) + /* -37 dBm */ + if (dbm >= ((int8_t)RADIO_TXPOWER_TXPOWER_Neg40dBm) + NRF_TXPOWER_VREQH) { + return ((int8_t)RADIO_TXPOWER_TXPOWER_Neg40dBm) + NRF_TXPOWER_VREQH; + } +#endif + + return (int8_t)RADIO_TXPOWER_TXPOWER_Neg40dBm; +} diff --git a/nimble/drivers/nrf5x/src/nrf53/phy_ppi.h b/nimble/drivers/nrf5x/src/nrf53/phy_ppi.h new file mode 100644 index 0000000000..6412f32753 --- /dev/null +++ b/nimble/drivers/nrf5x/src/nrf53/phy_ppi.h @@ -0,0 +1,159 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_PHY_PPI_ +#define H_PHY_PPI_ + +#define DPPI_CH_PUB(_ch) (((DPPI_CH_ ## _ch) & 0xff) | (1 << 31)) +#define DPPI_CH_SUB(_ch) (((DPPI_CH_ ## _ch) & 0xff) | (1 << 31)) +#define DPPI_CH_UNSUB(_ch) (((DPPI_CH_ ## _ch) & 0xff) | (0 << 31)) +#define DPPI_CH_MASK(_ch) (1 << (DPPI_CH_ ## _ch)) + +/* Channels 0..5 are always used. + * Channels 6 and 7 are used for PA/LNA (optionally). + * Channels 7..9 are used for GPIO debugging (optionally). + */ + +#define DPPI_CH_TIMER0_EVENTS_COMPARE_0 0 +#define DPPI_CH_TIMER0_EVENTS_COMPARE_3 1 +#define DPPI_CH_RADIO_EVENTS_END 2 +#define DPPI_CH_RADIO_EVENTS_BCMATCH 3 +#define DPPI_CH_RADIO_EVENTS_ADDRESS 4 +#define DPPI_CH_RTC0_EVENTS_COMPARE_0 5 +#define DPPI_CH_TIMER0_EVENTS_COMPARE_2 6 +#define DPPI_CH_RADIO_EVENTS_DISABLED 7 +#define DPPI_CH_RADIO_EVENTS_READY 8 +#define DPPI_CH_RADIO_EVENTS_RXREADY 9 + +#define DPPI_CH_ENABLE_ALL (DPPIC_CHEN_CH0_Msk | DPPIC_CHEN_CH1_Msk | \ + DPPIC_CHEN_CH2_Msk | DPPIC_CHEN_CH3_Msk | \ + DPPIC_CHEN_CH4_Msk | DPPIC_CHEN_CH5_Msk) + +#define DPPI_CH_MASK_FEM (DPPI_CH_MASK(TIMER0_EVENTS_COMPARE_2) | \ + DPPI_CH_MASK(RADIO_EVENTS_DISABLED)) + +static inline void +phy_ppi_rtc0_compare0_to_timer0_start_enable(void) +{ + NRF_TIMER0->SUBSCRIBE_START = DPPI_CH_SUB(RTC0_EVENTS_COMPARE_0); +} + +static inline void +phy_ppi_rtc0_compare0_to_timer0_start_disable(void) +{ + NRF_TIMER0->SUBSCRIBE_START = DPPI_CH_UNSUB(RTC0_EVENTS_COMPARE_0); + NRF_TIMER0->SUBSCRIBE_CAPTURE[3] = DPPI_CH_UNSUB(RADIO_EVENTS_ADDRESS); + NRF_RADIO->SUBSCRIBE_DISABLE = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_3); +} + +static inline void +phy_ppi_timer0_compare0_to_radio_txen_enable(void) +{ + NRF_RADIO->SUBSCRIBE_TXEN = DPPI_CH_SUB(TIMER0_EVENTS_COMPARE_0); +} + +static inline void +phy_ppi_timer0_compare0_to_radio_txen_disable(void) +{ + NRF_RADIO->SUBSCRIBE_TXEN = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_0); +} + +static inline void +phy_ppi_timer0_compare0_to_radio_rxen_enable(void) +{ + NRF_RADIO->SUBSCRIBE_RXEN = DPPI_CH_SUB(TIMER0_EVENTS_COMPARE_0); +} + +static inline void +phy_ppi_timer0_compare0_to_radio_rxen_disable(void) +{ + NRF_RADIO->SUBSCRIBE_RXEN = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_0); +} + +static inline void +phy_ppi_radio_address_to_ccm_crypt_enable(void) +{ + NRF_CCM->SUBSCRIBE_CRYPT = DPPI_CH_SUB(RADIO_EVENTS_ADDRESS); +} + +static inline void +phy_ppi_radio_address_to_ccm_crypt_disable(void) +{ + NRF_CCM->SUBSCRIBE_CRYPT = DPPI_CH_UNSUB(RADIO_EVENTS_ADDRESS); +} + +static inline void +phy_ppi_radio_bcmatch_to_aar_start_enable(void) +{ + NRF_AAR->SUBSCRIBE_START = DPPI_CH_SUB(RADIO_EVENTS_BCMATCH); +} + +static inline void +phy_ppi_radio_bcmatch_to_aar_start_disable(void) +{ + NRF_AAR->SUBSCRIBE_START = DPPI_CH_UNSUB(RADIO_EVENTS_BCMATCH); +} + +static inline void +phy_ppi_wfr_enable(void) +{ + NRF_TIMER0->SUBSCRIBE_CAPTURE[3] = DPPI_CH_SUB(RADIO_EVENTS_ADDRESS); + NRF_RADIO->SUBSCRIBE_DISABLE = DPPI_CH_SUB(TIMER0_EVENTS_COMPARE_3); +} + +static inline void +phy_ppi_wfr_disable(void) +{ + NRF_TIMER0->SUBSCRIBE_CAPTURE[3] = DPPI_CH_UNSUB(RADIO_EVENTS_ADDRESS); + NRF_RADIO->SUBSCRIBE_DISABLE = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_3); +} + +static inline void +phy_ppi_fem_disable(void) +{ +#if PHY_USE_FEM_SINGLE_GPIO + NRF_GPIOTE->SUBSCRIBE_SET[PHY_GPIOTE_FEM] = + DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_3); +#else +#if PHY_USE_FEM_PA + NRF_GPIOTE->SUBSCRIBE_SET[PHY_GPIOTE_FEM_PA] = + DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_2); +#endif +#if PHY_USE_FEM_LNA + NRF_GPIOTE->SUBSCRIBE_SET[PHY_GPIOTE_FEM_LNA] = + DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_2); +#endif +#endif +} + +static inline void +phy_ppi_disable(void) +{ + NRF_TIMER0->SUBSCRIBE_START = DPPI_CH_UNSUB(RTC0_EVENTS_COMPARE_0); + NRF_TIMER0->SUBSCRIBE_CAPTURE[3] = DPPI_CH_UNSUB(RADIO_EVENTS_ADDRESS); + NRF_RADIO->SUBSCRIBE_DISABLE = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_3); + NRF_RADIO->SUBSCRIBE_TXEN = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_0); + NRF_RADIO->SUBSCRIBE_RXEN = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_0); + NRF_AAR->SUBSCRIBE_START = DPPI_CH_UNSUB(RADIO_EVENTS_BCMATCH); + NRF_CCM->SUBSCRIBE_CRYPT = DPPI_CH_UNSUB(RADIO_EVENTS_ADDRESS); + + phy_ppi_fem_disable(); +} + +#endif /* H_PHY_PPI_ */ \ No newline at end of file diff --git a/nimble/drivers/nrf5x/src/phy_priv.h b/nimble/drivers/nrf5x/src/phy_priv.h new file mode 100644 index 0000000000..db0664da2b --- /dev/null +++ b/nimble/drivers/nrf5x/src/phy_priv.h @@ -0,0 +1,96 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_PHY_PRIV_ +#define H_PHY_PRIV_ + +#include +#include +#include + + +#if defined(NRF52840_XXAA) && MYNEWT_VAL(BLE_PHY_NRF52_HEADERMASK_WORKAROUND) +#define PHY_USE_HEADERMASK_WORKAROUND 1 +#endif + +#define PHY_USE_DEBUG_1 (MYNEWT_VAL(BLE_PHY_DBG_TIME_TXRXEN_READY_PIN) >= 0) +#define PHY_USE_DEBUG_2 (MYNEWT_VAL(BLE_PHY_DBG_TIME_ADDRESS_END_PIN) >= 0) +#define PHY_USE_DEBUG_3 (MYNEWT_VAL(BLE_PHY_DBG_TIME_WFR_PIN) >= 0) +#define PHY_USE_DEBUG (PHY_USE_DEBUG_1 || PHY_USE_DEBUG_2 || PHY_USE_DEBUG_3) + +#define PHY_USE_FEM_PA (MYNEWT_VAL(BLE_FEM_PA) != 0) +#define PHY_USE_FEM_LNA (MYNEWT_VAL(BLE_FEM_LNA) != 0) +#define PHY_USE_FEM (PHY_USE_FEM_PA || PHY_USE_FEM_LNA) +#define PHY_USE_FEM_SINGLE_GPIO \ + (PHY_USE_FEM && (!PHY_USE_FEM_PA || !PHY_USE_FEM_LNA || \ + (MYNEWT_VAL(BLE_FEM_PA_GPIO) == \ + MYNEWT_VAL(BLE_FEM_LNA_GPIO)))) + +/* GPIOTE indexes, start assigning from last one */ +#define PHY_GPIOTE_DEBUG_1 (8 - PHY_USE_DEBUG_1) +#define PHY_GPIOTE_DEBUG_2 (PHY_GPIOTE_DEBUG_1 - PHY_USE_DEBUG_2) +#define PHY_GPIOTE_DEBUG_3 (PHY_GPIOTE_DEBUG_2 - PHY_USE_DEBUG_3) +#if PHY_USE_FEM_SINGLE_GPIO +#define PHY_GPIOTE_FEM (PHY_GPIOTE_DEBUG_3 - PHY_USE_FEM) +#else +#define PHY_GPIOTE_FEM_PA (PHY_GPIOTE_DEBUG_3 - PHY_USE_FEM_PA) +#define PHY_GPIOTE_FEM_LNA (PHY_GPIOTE_FEM_PA - PHY_USE_FEM_LNA) +#endif + +static inline void +phy_gpiote_configure(int idx, int pin) +{ + nrf_gpio_cfg_output(pin); + nrf_gpiote_task_configure(NRF_GPIOTE, idx, pin, NRF_GPIOTE_POLARITY_NONE, + NRF_GPIOTE_INITIAL_VALUE_LOW); + nrf_gpiote_task_enable(NRF_GPIOTE, idx); +} + +#if PHY_USE_DEBUG +void phy_debug_init(void); +#endif + +#if PHY_USE_FEM +void phy_fem_init(void); +#if PHY_USE_FEM_PA +void phy_fem_enable_pa(void); +#endif +#if PHY_USE_FEM_LNA +void phy_fem_enable_lna(void); +#endif +void phy_fem_disable(void); +#endif + +void phy_ppi_init(void); + +#ifdef NRF52_SERIES +#include "nrf52/phy_ppi.h" +#endif + +void phy_txpower_set(int8_t dbm); +int8_t phy_txpower_round(int8_t dbm); + +#ifdef NRF52_SERIES +#include "nrf52/phy_ppi.h" +#endif +#ifdef NRF53_SERIES +#include "nrf53/phy_ppi.h" +#endif + +#endif /* H_PHY_PRIV_ */ diff --git a/nimble/drivers/nrf52/syscfg.yml b/nimble/drivers/nrf5x/syscfg.yml similarity index 50% rename from nimble/drivers/nrf52/syscfg.yml rename to nimble/drivers/nrf5x/syscfg.yml index ce5123721a..f5a227305c 100644 --- a/nimble/drivers/nrf52/syscfg.yml +++ b/nimble/drivers/nrf5x/syscfg.yml @@ -17,21 +17,30 @@ # syscfg.defs: - BLE_PHY_SYSVIEW: + BLE_PHY_VARIABLE_TIFS: description: > - Enable SystemView tracing module for radio driver. + Enables API to set custom T_ifs (inter-frame spacing) for each + transition. T_ifs is reset to default value after each transition. + When disabled, 150us is always used which enables some build-time + optimizations by compiler. + experimental: 1 value: 0 - BLE_PHY_CODED_RX_IFS_EXTRA_MARGIN: + BLE_PHY_EXTENDED_TIFS: + description: > + This allows to extend T_ifs (inter-frame spacing) by additional + microseconds to improve interoperability with peripherals that + send packets too late (eg 153us). This prolongs reception time by + additional microseconds. Defaults to 2us to improve operations with + devices already on the market. + range: 0..4 + value: 2 + + BLE_PHY_SYSVIEW: description: > - This defines additional margin for T_IFS tolerance while in - RX on coded phy to allow maintaining connections with some - controllers that exceed proper T_IFS (150 usecs) by more - than allowed 2 usecs. - This value shall be only used for debugging purposes. It is - strongly recommended to keep this settings at default value - to ensure compliance with specification. + Enable SystemView tracing module for radio driver. value: 0 + BLE_PHY_DBG_TIME_TXRXEN_READY_PIN: description: > When set to proper GPIO pin number, this pin will be set @@ -56,20 +65,32 @@ syscfg.defs: This can be used to check if wfr is calculated properly. value: -1 - BLE_PHY_NRF52840_ERRATA_164: + BLE_PHY_NRF52_HEADERMASK_WORKAROUND: description: > - Enable workaround for anomaly 164 found in nRF52840. - "[164] RADIO: Low selectivity in long range mode" - This shall be only enabled for: - - nRF52840 Engineering A + This enables workaround for lack of HEADERMASK register on some + nRF52 family MCUs (notably nRF52840) which is required for enabling + encryption for ISO PDUs. + Note: this requires exclusive access to CCM_AAR interrupt and only + works for TX (i.e. ISO Broadcaster). value: 0 - BLE_PHY_NRF52840_ERRATA_191: + BLE_PHY_NRF5340_VDDH: + description: > + This indicates if VDDH pin of nRF5340 is connected to external + power source. If connected PHY driver will make use of high voltage + operation mode for additional TX power levels (+3, +2, +1, -9, -13, + -17, -37). + value: 0 + + BLE_PHY_UBLOX_BMD345_PUBLIC_ADDR: description: > - Enable workaround for anomaly 191 found in nRF52840. - "[191] RADIO: High packet error rate in BLE Long Range mode" - This shall be only enabled for: - - nRF52840 Engineering B - - nRF52840 Engineering C - - nRF52840 Rev 1 (final silicon) - value: 1 + Ublox BMD-345 modules come with public address preprogrammed + in UICR register. If enabled public address will be read from + custom UICR instead of FICR register. + value: 0 + +syscfg.restrictions: + # code supports turn on times up to 90us due to some optimizations, but it + # should be enough for most (all?) cases + - "!BLE_FEM_PA || BLE_FEM_PA_TURN_ON_US <= 90" + - "!BLE_FEM_LNA || BLE_FEM_LNA_TURN_ON_US <= 90" diff --git a/nimble/host/audio/include/audio/ble_audio.h b/nimble/host/audio/include/audio/ble_audio.h new file mode 100644 index 0000000000..6fb5f295ed --- /dev/null +++ b/nimble/host/audio/include/audio/ble_audio.h @@ -0,0 +1,1053 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_BLE_AUDIO_ +#define H_BLE_AUDIO_ + +#include +#include + +/** + * @file ble_audio.h + * + * @brief Bluetooth Low Energy Audio API + * + * @defgroup bt_le_audio Bluetooth LE Audio + * @ingroup bt_host + * @{ + */ + +/** + * @cond + * Helper macros for BLE_AUDIO_BUILD_CODEC_CONFIG + * @private @{ + */ +#define FIELD_LEN_2(_len, _type, _field) _len, _type, _field, +#define FIELD_LEN_5(_len, _type, _field) _len, _type, _field, \ + _field >> 8, _field >> 16, \ + _field >> 24, + +#define FIELD_TESTED_0(_len, _type, _field) +#define FIELD_TESTED_1(_len, _type, _field) FIELD_LEN_ ## _len(_len, \ + _type, \ + _field) +#define EMPTY() FIELD_TESTED_0 +#define PRESENT(X) FIELD_TESTED_1 +#define TEST(x, A, FUNC, ...) FUNC +#define TEST_FIELD(...) TEST(, ## __VA_ARGS__, \ + PRESENT(__VA_ARGS__), \ + EMPTY(__VA_ARGS__)) +#define FIELD_TESTED(_test, _len, _type, _field) _test(_len, _type, _field) +#define OPTIONAL_FIELD(_len, _type, ...) FIELD_TESTED(TEST_FIELD \ + (__VA_ARGS__), \ + _len, \ + _type, \ + __VA_ARGS__) + +/** + * @} + * @endcond + */ + +/** Broadcast Audio Broadcast Code Size. */ +#define BLE_AUDIO_BROADCAST_CODE_SIZE 16 + +/** Basic Audio Announcement Service UUID. */ +#define BLE_BASIC_AUDIO_ANNOUNCEMENT_SVC_UUID 0x1851 + +/** Broadcast Audio Announcement Service UUID. */ +#define BLE_BROADCAST_AUDIO_ANNOUNCEMENT_SVC_UUID 0x1852 + +/** Public Broadcast Announcement Service UUID. */ +#define BLE_BROADCAST_PUB_ANNOUNCEMENT_SVC_UUID 0x1856 + +/** + * @defgroup ble_audio_codec_formats Bluetooth Low Energy Audio Codec Formats + * @{ + */ + +/** BLE Audio codec format - Îŧ-law log */ +#define BLE_AUDIO_CODEC_FORMAT_MU_LAW_LOG 0x00 + +/** BLE Audio codec format - A-law log */ +#define BLE_AUDIO_CODEC_FORMAT_A_LAW_LOG 0x01 + +/** BLE Audio codec format - CVSD */ +#define BLE_AUDIO_CODEC_FORMAT_CVSD 0x02 + +/** BLE Audio codec format - Transparent */ +#define BLE_AUDIO_CODEC_FORMAT_TRANSPARENT 0x03 + +/** BLE Audio codec format - Linear PCM */ +#define BLE_AUDIO_CODEC_FORMAT_LINEAR_PCM 0x04 + +/** BLE Audio codec format - mSBC */ +#define BLE_AUDIO_CODEC_FORMAT_MSBC 0x05 + +/** BLE Audio codec format - LC3 */ +#define BLE_AUDIO_CODEC_FORMAT_LC3 0x06 + +/** BLE Audio codec format - G.729A */ +#define BLE_AUDIO_CODEC_FORMAT_G_729A 0x07 + +/** BLE Audio codec format - Vendor Specific */ +#define BLE_AUDIO_CODEC_FORMAT_VENDOR_SPECIFIC 0xFF + +/** @} */ + +/** + * @defgroup ble_audio_sampling_rates Bluetooth Low Energy Audio Sampling Rates + * @{ + */ + +/** LE Audio Sampling Rate: 8000 Hz. */ +#define BLE_AUDIO_SAMPLING_RATE_8000_HZ 0x01 + +/** LE Audio Sampling Rate: 11025 Hz. */ +#define BLE_AUDIO_SAMPLING_RATE_11025_HZ 0x02 + +/** LE Audio Sampling Rate: 16000 Hz. */ +#define BLE_AUDIO_SAMPLING_RATE_16000_HZ 0x03 + +/** LE Audio Sampling Rate: 22050 Hz. */ +#define BLE_AUDIO_SAMPLING_RATE_22050_HZ 0x04 + +/** LE Audio Sampling Rate: 24000 Hz. */ +#define BLE_AUDIO_SAMPLING_RATE_24000_HZ 0x05 + +/** LE Audio Sampling Rate: 32000 Hz. */ +#define BLE_AUDIO_SAMPLING_RATE_32000_HZ 0x06 + +/** LE Audio Sampling Rate: 44100 Hz. */ +#define BLE_AUDIO_SAMPLING_RATE_44100_HZ 0x07 + +/** LE Audio Sampling Rate: 48000 Hz. */ +#define BLE_AUDIO_SAMPLING_RATE_48000_HZ 0x08 + +/** LE Audio Sampling Rate: 88200 Hz. */ +#define BLE_AUDIO_SAMPLING_RATE_88200_HZ 0x09 + +/** LE Audio Sampling Rate: 96000 Hz. */ +#define BLE_AUDIO_SAMPLING_RATE_96000_HZ 0x0A + +/** LE Audio Sampling Rate: 176400 Hz. */ +#define BLE_AUDIO_SAMPLING_RATE_176400_HZ 0x0B + +/** LE Audio Sampling Rate: 192000 Hz. */ +#define BLE_AUDIO_SAMPLING_RATE_192000_HZ 0x0C + +/** LE Audio Sampling Rate: 384000 Hz. */ +#define BLE_AUDIO_SAMPLING_RATE_384000_HZ 0x0D + +/** @} */ + +/** + * @defgroup ble_audio_frame_durations Bluetooth Low Energy Audio Frame Durations + * @{ + */ + +/** LE Audio Frame Duration: 7.5 ms. */ +#define BLE_AUDIO_SELECTED_FRAME_DURATION_7_5_MS 0x00 + +/** LE Audio Frame Duration: 10 ms. */ +#define BLE_AUDIO_SELECTED_FRAME_DURATION_10_MS 0x01 + +/** @} */ + +/** + * @defgroup ble_audio_locations Bluetooth Low Energy Audio Locations + * @{ + */ + +/** LE Audio Location: Front Left. */ +#define BLE_AUDIO_LOCATION_FRONT_LEFT (1ULL) + +/** LE Audio Location: Front Right. */ +#define BLE_AUDIO_LOCATION_FRONT_RIGHT (1ULL << 1) + +/** LE Audio Location: Front Center. */ +#define BLE_AUDIO_LOCATION_FRONT_CENTER (1ULL << 2) + +/** LE Audio Location: Low Frequency Effects 1. */ +#define BLE_AUDIO_LOCATION_LOW_FREQ_EFFECTS_1 (1ULL << 3) + +/** LE Audio Location: Back Left. */ +#define BLE_AUDIO_LOCATION_BACK_LEFT (1ULL << 4) + +/** LE Audio Location: Front Left Center. */ +#define BLE_AUDIO_LOCATION_FRONT_LEFT_CENTER (1ULL << 5) + +/** LE Audio Location: Front Right Center. */ +#define BLE_AUDIO_LOCATION_FRONT_RIGHT_CENTER (1ULL << 6) + +/** LE Audio Location: Back Center. */ +#define BLE_AUDIO_LOCATION_BACK_CENTER (1ULL << 7) + +/** LE Audio Location: Low Frequency Effects 2. */ +#define BLE_AUDIO_LOCATION_LOW_FREQ_EFFECTS_2 (1ULL << 8) + +/** LE Audio Location: Side Left. */ +#define BLE_AUDIO_LOCATION_SIDE_LEFT (1ULL << 9) + +/** LE Audio Location: Side Right. */ +#define BLE_AUDIO_LOCATION_SIDE_RIGHT (1ULL << 10) + +/** LE Audio Location: Top Front Left. */ +#define BLE_AUDIO_LOCATION_TOP_FRONT_LEFT (1ULL << 11) + +/** LE Audio Location: Top Front Right. */ +#define BLE_AUDIO_LOCATION_TOP_FRONT_RIGHT (1ULL << 12) + +/** LE Audio Location: Top Front Center. */ +#define BLE_AUDIO_LOCATION_TOP_FRONT_CENTER (1ULL << 13) + +/** LE Audio Location: Top Center. */ +#define BLE_AUDIO_LOCATION_TOP_CENTER (1ULL << 14) + +/** LE Audio Location: Top Back Left. */ +#define BLE_AUDIO_LOCATION_TOP_BACK_LEFT (1ULL << 15) + +/** LE Audio Location: Top Back Right. */ +#define BLE_AUDIO_LOCATION_TOP_BACK_RIGHT (1ULL << 16) + +/** LE Audio Location: Top Side Left. */ +#define BLE_AUDIO_LOCATION_TOP_SIDE_LEFT (1ULL << 17) + +/** LE Audio Location: Top Side Right. */ +#define BLE_AUDIO_LOCATION_TOP_SIDE_RIGHT (1ULL << 18) + +/** LE Audio Location: Top Back Center. */ +#define BLE_AUDIO_LOCATION_TOP_BACK_CENTER (1ULL << 19) + +/** LE Audio Location: Bottom Front Center. */ +#define BLE_AUDIO_LOCATION_BOTTOM_FRONT_CENTER (1ULL << 20) + +/** LE Audio Location: Bottom Front Left. */ +#define BLE_AUDIO_LOCATION_BOTTOM_FRONT_LEFT (1ULL << 21) + +/** LE Audio Location: Bottom Front Right. */ +#define BLE_AUDIO_LOCATION_BOTTOM_FRONT_RIGHT (1ULL << 22) + +/** LE Audio Location: Left Surround. */ +#define BLE_AUDIO_LOCATION_LEFT_SURROUND (1ULL << 23) + +/** LE Audio Location: Right Surround. */ +#define BLE_AUDIO_LOCATION_RIGHT_SURROUND (1ULL << 24) + +/** @} */ + +/** + * @defgroup ble_audio_codec_config Bluetooth Low Energy Audio Codec Specific Config + * @{ + */ + +/** LE Audio Codec Config Type: Sampling Frequency. */ +#define BLE_AUDIO_CODEC_CONF_SAMPLING_FREQ_TYPE 0x01 + +/** LE Audio Codec Config Type: Frame Duration. */ +#define BLE_AUDIO_CODEC_CONF_FRAME_DURATION_TYPE 0x02 + +/** LE Audio Codec Config Type: Channel Allocation. */ +#define BLE_AUDIO_CODEC_CONF_AUDIO_CHANNEL_ALLOCATION_TYPE 0x03 + +/** LE Audio Codec Config Type: Octets Per Codec Frame. */ +#define BLE_AUDIO_CODEC_CONF_OCTETS_PER_CODEC_FRAME_TYPE 0x04 + +/** LE Audio Codec Config Type: Frame Blocks Per SDU. */ +#define BLE_AUDIO_CODEC_CONF_FRAME_BLOCKS_PER_SDU_TYPE 0x05 + +/** @} */ + +/** + * @defgroup ble_audio_codec_caps Bluetooth Low Energy Audio Codec Specific Capabilities + * @{ + */ + + +/** LE Audio Codec Specific Capability: Supported Sampling Frequencies. */ +#define BLE_AUDIO_CODEC_CAPS_SAMPLING_FREQ_TYPE 0x01 + +/** LE Audio Codec Specific Capability: Supported Frame Durations. */ +#define BLE_AUDIO_CODEC_CAPS_FRAME_DURATION_TYPE 0x02 + +/** LE Audio Codec Specific Capability: Supported Audio Channel Counts. */ +#define BLE_AUDIO_CODEC_CAPS_SUP_AUDIO_CHANNEL_COUNTS_TYPE 0x03 + +/** LE Audio Codec Specific Capability: Supported Octets Per Codec Frame. */ +#define BLE_AUDIO_CODEC_CAPS_OCTETS_PER_CODEC_FRAME_TYPE 0x04 + +/** LE Audio Codec Specific Capability: Supported Codec Frames Per SDU. */ +#define BLE_AUDIO_CODEC_CAPS_FRAMES_PER_SDU_TYPE 0x05 + +/** @} */ + +/** + * @defgroup ble_audio_contexts Bluetooth Low Energy Audio Context Types + * @{ + */ + +/** LE Audio Codec Context Type: Prohibited. */ +#define BLE_AUDIO_CONTEXT_TYPE_PROHIBITED 0x0000 + +/** LE Audio Codec Context Type: Unspecified. */ +#define BLE_AUDIO_CONTEXT_TYPE_UNSPECIFIED 0x0001 + +/** LE Audio Codec Context Type: Conversational. */ +#define BLE_AUDIO_CONTEXT_TYPE_CONVERSATIONAL 0x0002 + +/** LE Audio Codec Context Type: Media. */ +#define BLE_AUDIO_CONTEXT_TYPE_MEDIA 0x0004 + +/** LE Audio Codec Context Type: Game. */ +#define BLE_AUDIO_CONTEXT_TYPE_GAME 0x0008 + +/** LE Audio Codec Context Type: Instructional. */ +#define BLE_AUDIO_CONTEXT_TYPE_INSTRUCTIONAL 0x0010 + +/** LE Audio Codec Context Type: Voice Assistants. */ +#define BLE_AUDIO_CONTEXT_TYPE_VOICE_ASSISTANTS 0x0020 + +/** LE Audio Codec Context Type: Live. */ +#define BLE_AUDIO_CONTEXT_TYPE_LIVE 0x0040 + +/** LE Audio Codec Context Type: Sound Effects. */ +#define BLE_AUDIO_CONTEXT_TYPE_SOUND_EFFECTS 0x0080 + +/** LE Audio Codec Context Type: Notifications. */ +#define BLE_AUDIO_CONTEXT_TYPE_NOTIFICATIONS 0x0100 + +/** LE Audio Codec Context Type: Ringtone. */ +#define BLE_AUDIO_CONTEXT_TYPE_RINGTONE 0x0200 + +/** LE Audio Codec Context Type: Alerts. */ +#define BLE_AUDIO_CONTEXT_TYPE_ALERTS 0x0400 + +/** LE Audio Codec Context Type: EmergencyAlarm. */ +#define BLE_AUDIO_CONTEXT_TYPE_EMERGENCY_ALARM 0x0800 + +/** @} */ + +/** + * @defgroup ble_audio_sup_frame_durations Bluetooth Low Energy Audio Supported Frame Durations + * @{ + */ + +/** LE Audio Codec Supported Frame Duration: 7.5 ms frame duration. */ +#define BLE_AUDIO_CODEC_SUPPORTED_FRAME_DURATION_7_5_MS 0x0001 + +/** LE Audio Codec Supported Frame Duration: 10 ms frame duration. */ +#define BLE_AUDIO_CODEC_SUPPORTED_FRAME_DURATION_10_MS 0x0002 + +/** LE Audio Codec Supported Frame Duration: 7.5 ms preferred. */ +#define BLE_AUDIO_CODEC_PREFERED_FRAME_DURATION_7_5_MS 0x0010 + +/** LE Audio Codec Supported Frame Duration: 10 ms preferred. */ +#define BLE_AUDIO_CODEC_PREFERED_FRAME_DURATION_10_MS 0x0020 + +/** @} */ + +/** + * @defgroup ble_audio_sup_sampling_freqs Bluetooth Low Energy Audio Supported Sampling Frequencies + * @{ + */ + +/** LE Audio Codec Supported Sampling Frequency: 8000 Hz. */ +#define BLE_AUDIO_CODEC_SUPPORTED_SAMPLING_RATE_8000_HZ (1ULL << 0) + +/** LE Audio Codec Supported Sampling Frequency: 11025 Hz. */ +#define BLE_AUDIO_CODEC_SUPPORTED_SAMPLING_RATE_11025_HZ (1ULL << 1) + +/** LE Audio Codec Supported Sampling Frequency: 16000 Hz. */ +#define BLE_AUDIO_CODEC_SUPPORTED_SAMPLING_RATE_16000_HZ (1ULL << 2) + +/** LE Audio Codec Supported Sampling Frequency: 22050 Hz. */ +#define BLE_AUDIO_CODEC_SUPPORTED_SAMPLING_RATE_22050_HZ (1ULL << 3) + +/** LE Audio Codec Supported Sampling Frequency: 24000 Hz. */ +#define BLE_AUDIO_CODEC_SUPPORTED_SAMPLING_RATE_24000_HZ (1ULL << 4) + +/** LE Audio Codec Supported Sampling Frequency: 32000 Hz. */ +#define BLE_AUDIO_CODEC_SUPPORTED_SAMPLING_RATE_32000_HZ (1ULL << 5) + +/** LE Audio Codec Supported Sampling Frequency: 44100 Hz. */ +#define BLE_AUDIO_CODEC_SUPPORTED_SAMPLING_RATE_44100_HZ (1ULL << 6) + +/** LE Audio Codec Supported Sampling Frequency: 48000 Hz. */ +#define BLE_AUDIO_CODEC_SUPPORTED_SAMPLING_RATE_48000_HZ (1ULL << 7) + +/** LE Audio Codec Supported Sampling Frequency: 88200 Hz. */ +#define BLE_AUDIO_CODEC_SUPPORTED_SAMPLING_RATE_88200_HZ (1ULL << 8) + +/** LE Audio Codec Supported Sampling Frequency: 96000 Hz. */ +#define BLE_AUDIO_CODEC_SUPPORTED_SAMPLING_RATE_96000_HZ (1ULL << 9) + +/** LE Audio Codec Supported Sampling Frequency: 176400 Hz. */ +#define BLE_AUDIO_CODEC_SUPPORTED_SAMPLING_RATE_176400_HZ (1ULL << 10) + +/** LE Audio Codec Supported Sampling Frequency: 192000 Hz. */ +#define BLE_AUDIO_CODEC_SUPPORTED_SAMPLING_RATE_192000_HZ (1ULL << 11) + +/** LE Audio Codec Supported Sampling Frequency: 384000 Hz. */ +#define BLE_AUDIO_CODEC_SUPPORTED_SAMPLING_RATE_384000_HZ (1ULL << 12) + +/** @} */ + +/** + * @defgroup ble_audio_sup_chan_counts Bluetooth Low Energy Audio Supported Channel Counts + * @{ + */ + +/** LE Audio Codec Supported Channel Count: 1. */ +#define BLE_AUDIO_CODEC_SUPPORTED_CHANNEL_COUNT_1 0x0001 + +/** LE Audio Codec Supported Channel Count: 2. */ +#define BLE_AUDIO_CODEC_SUPPORTED_CHANNEL_COUNT_2 0x0002 + +/** LE Audio Codec Supported Channel Count: 3. */ +#define BLE_AUDIO_CODEC_SUPPORTED_CHANNEL_COUNT_3 0x0004 + +/** LE Audio Codec Supported Channel Count: 4. */ +#define BLE_AUDIO_CODEC_SUPPORTED_CHANNEL_COUNT_4 0x0008 + +/** LE Audio Codec Supported Channel Count: 5. */ +#define BLE_AUDIO_CODEC_SUPPORTED_CHANNEL_COUNT_5 0x0010 + +/** LE Audio Codec Supported Channel Count: 6. */ +#define BLE_AUDIO_CODEC_SUPPORTED_CHANNEL_COUNT_6 0x0020 + +/** LE Audio Codec Supported Channel Count: 7. */ +#define BLE_AUDIO_CODEC_SUPPORTED_CHANNEL_COUNT_7 0x0040 + +/** LE Audio Codec Supported Channel Count: 8. */ +#define BLE_AUDIO_CODEC_SUPPORTED_CHANNEL_COUNT_8 0x0080 + +/** @} */ + +/** + * @brief Helper macro used to build LTV array of Codec_Specific_Configuration. + * + * @param _sampling_freq Sampling_Frequency - single octet value + * @param _frame_duration Frame_Duration - single octet value + * @param _audio_channel_alloc Audio_Channel_Allocation - + * four octet value + * @param _octets_per_codec_frame Octets_Per_Codec_Frame - + * two octet value + * @param _codec_frame_blocks_per_sdu Codec_Frame_Blocks_Per_SDU - + * single octet value + * + * @return Pointer to a `ble_uuid16_t` structure. + */ +#define BLE_AUDIO_BUILD_CODEC_CONFIG(_sampling_freq, \ + _frame_duration, \ + _audio_channel_alloc, \ + _octets_per_codec_frame, \ + _codec_frame_blocks_per_sdu) \ + { \ + 2, BLE_AUDIO_CODEC_CONF_SAMPLING_FREQ_TYPE, _sampling_freq, \ + 2, BLE_AUDIO_CODEC_CONF_FRAME_DURATION_TYPE, _frame_duration, \ + OPTIONAL_FIELD(5, BLE_AUDIO_CODEC_CONF_AUDIO_CHANNEL_ALLOCATION_TYPE, \ + _audio_channel_alloc) \ + 3, BLE_AUDIO_CODEC_CONF_OCTETS_PER_CODEC_FRAME_TYPE, \ + (_octets_per_codec_frame), ((_octets_per_codec_frame) >> 8), \ + OPTIONAL_FIELD(2, BLE_AUDIO_CODEC_CONF_FRAME_BLOCKS_PER_SDU_TYPE, \ + _codec_frame_blocks_per_sdu) \ + } + +/** + * @brief Helper macro used to build LTV array of Codec_Specific_Capabilities. + * + * @param _sampling_freq Supported_Sampling_Frequencies - + * two octet value + * @param _frame_duration Supported_Frame_Durations - single + * octet value + * @param _audio_channel_counts Supported_Audio_Channel_Counts - + * single octet value + * @param _min_octets_per_codec_frame minimum value of + * Supported_Octets_Per_Codec_Frame - + * two octet value + * @param _max_octets_per_codec_frame maximum value of + * Supported_Octets_Per_Codec_Frame - + * two octet value + * @param _codec_frames_per_sdu Supported_Max_Codec_Frames_Per_SDU - + * single octet value + * + * @return Pointer to a `ble_uuid16_t` structure. + */ +#define BLE_AUDIO_BUILD_CODEC_CAPS(_sampling_freq, \ + _frame_duration, \ + _audio_channel_counts, \ + _min_octets_per_codec_frame, \ + _max_octets_per_codec_frame, \ + _codec_frames_per_sdu) \ + { \ + 3, BLE_AUDIO_CODEC_CAPS_SAMPLING_FREQ_TYPE, \ + (_sampling_freq), ((_sampling_freq) >> 8), \ + 2, BLE_AUDIO_CODEC_CAPS_FRAME_DURATION_TYPE, _frame_duration, \ + OPTIONAL_FIELD(2, BLE_AUDIO_CODEC_CAPS_SUP_AUDIO_CHANNEL_COUNTS_TYPE, \ + _audio_channel_counts) \ + 5, BLE_AUDIO_CODEC_CAPS_OCTETS_PER_CODEC_FRAME_TYPE, \ + (_min_octets_per_codec_frame), ((_min_octets_per_codec_frame) >> 8), \ + (_max_octets_per_codec_frame), ((_max_octets_per_codec_frame) >> 8), \ + OPTIONAL_FIELD(2, BLE_AUDIO_CODEC_CAPS_FRAMES_PER_SDU_TYPE, \ + _codec_frames_per_sdu) \ + } + +/** Codec Information */ +struct ble_audio_codec_id { + /** Coding Format */ + uint8_t format; + + /** Company ID */ + uint16_t company_id; + + /** Vendor Specific Codec ID */ + uint16_t vendor_specific; +}; + +/** @brief Public Broadcast Announcement features bits */ +enum ble_audio_pub_broadcast_announcement_feat { + /** Broadcast Stream Encryption */ + BLE_AUDIO_PUB_BROADCAST_ANNOUNCEMENT_FEAT_ENCRYPTION = 1 << 0, + + /** Standard Quality Public Broadcast Audio */ + BLE_AUDIO_PUB_BROADCAST_ANNOUNCEMENT_FEAT_SQ = 1 << 1, + + /** High Quality Public Broadcast Audio */ + BLE_AUDIO_PUB_BROADCAST_ANNOUNCEMENT_FEAT_HQ = 1 << 2, +}; + +/** @brief Public Broadcast Announcement structure */ +struct ble_audio_pub_broadcast_announcement { + /** Public Broadcast Announcement features bitfield */ + enum ble_audio_pub_broadcast_announcement_feat features; + + /** Metadata length */ + uint8_t metadata_len; + + /** Metadata */ + const uint8_t *metadata; +}; + +/** Broadcast Name */ +struct ble_audio_broadcast_name { + /** Broadcast Name length */ + uint8_t name_len; + + /** Broadcast Name */ + const char *name; +}; + +/** + * @defgroup ble_audio_events Bluetooth Low Energy Audio Events + * @{ + */ + +/** BLE Audio event: Broadcast Announcement */ +#define BLE_AUDIO_EVENT_BROADCAST_ANNOUNCEMENT 0 + +/** BLE Audio event: Codec Registered */ +#define BLE_AUDIO_EVENT_CODEC_REGISTERED 1 + +/** BLE Audio event: Codec Unregistered */ +#define BLE_AUDIO_EVENT_CODEC_UNREGISTERED 2 + +/** BLE Audio event: BASS - Remote Scan Stopped */ +#define BLE_AUDIO_EVENT_BASS_REMOTE_SCAN_STOPPED 3 + +/** BLE Audio event: BASS - Remote Scan Started */ +#define BLE_AUDIO_EVENT_BASS_REMOTE_SCAN_STARTED 4 + +/** BLE Audio event: BASS - Operation status */ +#define BLE_AUDIO_EVENT_BASS_OPERATION_STATUS 5 + +/** BLE Audio event: BASS - Set Broadcast Code */ +#define BLE_AUDIO_EVENT_BASS_BROADCAST_CODE_SET 6 + +/** BLE Audio event: Broadcast Sink - PA Sync state */ +#define BLE_AUDIO_EVENT_BROADCAST_SINK_PA_SYNC_STATE 7 + +/** BLE Audio event: Broadcast Sink - BIS Sync state */ +#define BLE_AUDIO_EVENT_BROADCAST_SINK_BIS_SYNC_STATE 8 + +/** BLE Audio event: Broadcast Sink - Metadata Updated */ +#define BLE_AUDIO_EVENT_BROADCAST_SINK_METADATA 9 + +/** @} */ + +/** @brief Broadcast Announcement */ +struct ble_audio_event_broadcast_announcement { + /** Extended advertising report */ + const struct ble_gap_ext_disc_desc *ext_disc; + + /** Broadcast ID */ + uint32_t broadcast_id; + + /** Additional service data included in Broadcast Audio Announcement */ + const uint8_t *svc_data; + + /** Additional service data length */ + uint16_t svc_data_len; + + /** Optional Public Broadcast Announcement data */ + struct ble_audio_pub_broadcast_announcement *pub_announcement_data; + + /** Optional Broadcast Name */ + struct ble_audio_broadcast_name *name; +}; + +/** @brief Codec Registered */ +struct ble_audio_event_codec_registered { + /** Codec Record */ + const struct ble_audio_codec_record *record; +}; + +/** @brief Codec Unregistered */ +struct ble_audio_event_codec_unregistered { + /** Codec Record */ + const struct ble_audio_codec_record *record; +}; + +/** @brief BASS Source Removed */ +struct ble_audio_event_bass_remote_scan { + /** Connection Handle of Broadcast Assistant that is performing Scan procedure for us */ + uint16_t conn_handle; +}; + +/** BASS Operation status OP code */ +enum ble_audio_event_bass_operation_statu_op { + /** BLE Audio event: BASS - Add Source */ + BLE_AUDIO_EVENT_BASS_SOURCE_ADDED, + + /** BLE Audio event: BASS - Modify Source */ + BLE_AUDIO_EVENT_BASS_SOURCE_MODIFIED, + + /** BLE Audio event: BASS - Remove Source */ + BLE_AUDIO_EVENT_BASS_SOURCE_REMOVED, +}; + +/** @brief BASS operation status */ +struct ble_audio_event_bass_op_status { + /** Source ID */ + uint8_t source_id; + + /** Operation */ + enum ble_audio_event_bass_operation_statu_op op; + + /** Event status. 0 on success, BLE_HS Error code otherwise */ + uint8_t status; +}; + +/** @brief BASS Set Broadcast Code */ +struct ble_audio_event_bass_set_broadcast_code { + /** Source ID */ + uint8_t source_id; + + /** Source ID */ + uint8_t broadcast_code[BLE_AUDIO_BROADCAST_CODE_SIZE]; +}; + +enum ble_audio_broadcast_sink_sync_state { + /** Broadcast Sink Sync State: Not Synced */ + BLE_AUDIO_BROADCAST_SINK_SYNC_STATE_NOT_SYNCED, + + /** Broadcast Sink Sync State: Sync initiated */ + BLE_AUDIO_BROADCAST_SINK_SYNC_STATE_INITIATED, + + /** Broadcast Sink Sync State: Sync established */ + BLE_AUDIO_BROADCAST_SINK_SYNC_STATE_ESTABLISHED, +}; + +/** @brief PA Synchronization state */ +struct ble_audio_event_broadcast_sink_pa_sync_state { + /** Source ID */ + uint8_t source_id; + + /** Sync state */ + enum ble_audio_broadcast_sink_sync_state state; +}; + +/** @brief BIS Synchronization state */ +struct ble_audio_event_broadcast_sink_bis_sync_state { + /** Source ID */ + uint8_t source_id; + + /** BIS Index */ + uint8_t bis_index; + + /** Sync state */ + enum ble_audio_broadcast_sink_sync_state state; + + /** Connection Handle. Valid if `state` is @ref BLE_AUDIO_BROADCAST_SINK_SYNC_STATE_ESTABLISHED */ + uint16_t conn_handle; +}; + +/** @brief Broadcast Sink Metadata changed */ +struct ble_audio_event_broadcast_sink_metadata { + /** Source ID */ + uint8_t source_id; + + /** BIS Index Mask */ + uint8_t bis_sync; + + /** Scan Delegator Subgroup: Metadata */ + const uint8_t *metadata; + + /** Scan Delegator Subgroup: Metadata length */ + uint8_t metadata_length; +}; + +/** + * Represents a BLE Audio related event. When such an event occurs, the host + * notifies the application by passing an instance of this structure to an + * application-specified callback. + */ +struct ble_audio_event { + /** + * Indicates the type of BLE Audio event that occurred. This is one of the + * BLE_AUDIO_EVENT codes. + */ + uint8_t type; + + /** + * A discriminated union containing additional details concerning the event. + * The 'type' field indicates which member of the union is valid. + */ + union { + /** + * @ref BLE_AUDIO_EVENT_BROADCAST_ANNOUNCEMENT + * + * Represents a received Broadcast Announcement. + */ + struct ble_audio_event_broadcast_announcement broadcast_announcement; + + /** + * @ref BLE_AUDIO_EVENT_CODEC_REGISTERED + * + * Represents a codec registration. + */ + struct ble_audio_event_codec_registered codec_registered; + + /** + * @ref BLE_AUDIO_EVENT_CODEC_UNREGISTERED + * + * Represents a codec registration. + */ + struct ble_audio_event_codec_unregistered codec_unregistered; + + /** + * @ref BLE_AUDIO_EVENT_BASS_REMOTE_SCAN_STOPPED + * + * Represents a Scan procedure termination by Broadcast Assistant. + */ + struct ble_audio_event_bass_remote_scan remote_scan_stopped; + + /** + * @ref BLE_AUDIO_EVENT_BASS_REMOTE_SCAN_STARTED + * + * Represents a Scan procedure start by Broadcast Assistant. + */ + struct ble_audio_event_bass_remote_scan remote_scan_started; + + /** + * @ref BLE_AUDIO_EVENT_BASS_SOURCE_ADDED + * + * Represents a Broadcast Source being added to BASS. + */ + struct ble_audio_event_bass_op_status bass_operation_status; + + /** + * @ref BLE_AUDIO_EVENT_BASS_BROADCAST_CODE_SET + * + * Represents a Broadcast Code baing set in BASS. + */ + struct ble_audio_event_bass_set_broadcast_code bass_set_broadcast_code; + + /** + * @ref BLE_AUDIO_EVENT_BROADCAST_SINK_PA_SYNC_STATE + * + * Represents a update of Broadcast Sink PA sync state. + */ + struct ble_audio_event_broadcast_sink_pa_sync_state broadcast_sink_pa_sync_state; + + /** + * @ref BLE_AUDIO_EVENT_BROADCAST_SINK_BIS_SYNC_STATE + * + * Represents an update of Broadcast Sink BIS sync state. + */ + struct ble_audio_event_broadcast_sink_bis_sync_state broadcast_sink_bis_sync_state; + + /** + * @ref BLE_AUDIO_EVENT_BROADCAST_SINK_METADATA + * + * Represents an update in Broadcast Sink Metadata. + */ + struct ble_audio_event_broadcast_sink_metadata broadcast_sink_metadata; + }; +}; + +/** Callback function type for handling BLE Audio events. */ +typedef int ble_audio_event_fn(struct ble_audio_event *event, void *arg); + +/** + * Event listener structure + * + * This should be used as an opaque structure and not modified manually. + */ +struct ble_audio_event_listener { + /** The function to call when a BLE Audio event occurs. */ + ble_audio_event_fn *fn; + + /** An optional argument to pass to the event handler function. */ + void *arg; + + /** Singly-linked list entry. */ + SLIST_ENTRY(ble_audio_event_listener) next; +}; + +/** + * Registers listener for BLE Audio events + * + * On success listener structure will be initialized automatically and does not + * need to be initialized prior to calling this function. To change callback + * and/or argument unregister listener first and register it again. + * + * @param[in] listener Listener structure + * @param[in] fn Callback function + * @param[in] arg Optional callback argument + * + * @return 0 on success + * BLE_HS_EINVAL if no callback is specified + * BLE_HS_EALREADY if listener is already registered + */ +int ble_audio_event_listener_register(struct ble_audio_event_listener *listener, + ble_audio_event_fn *fn, void *arg); + +/** + * Unregisters listener for BLE Audio events + * + * @param[in] listener Listener structure + * + * @return 0 on success + * BLE_HS_ENOENT if listener was not registered + */ +int ble_audio_event_listener_unregister(struct ble_audio_event_listener *listener); + +/** + * BASE iterator + * + * The iterator structure used by @ref ble_audio_base_subgroup_iter and + * @ref ble_audio_base_bis_iter functions to iterate the BASE Level 2 and 3 elements + * (Subgroups and BISes). + * This should be used as an opaque structure and not modified manually. + * + * Example: + * @code{.c} + * struct ble_audio_base_iter subgroup_iter; + * struct ble_audio_base_iter bis_iter; + * struct ble_audio_base_group group; + * struct ble_audio_base_subgroup subgroup; + * struct ble_audio_base_bis bis; + * + * rc = ble_audio_base_parse(data, data_size, &group, &subgroup_iter); + * if (rc == 0) { + * for (uint8_t i = 0; i < group->num_subgroups; i++) { + * rc = ble_audio_base_subgroup_iter(&subgroup_iter, &subgroup, &bis_iter); + * if (rc == 0) { + * for (uint8_t j = 0; j < subgroup->num_bis; j++) { + * rc = ble_audio_base_bis_iter(&bis_iter, &bis); + * if (rc == 0) { + * foo(&group, &subgroup, &bis); + * } + * } + * } + * } + * } + * @endcode + */ +struct ble_audio_base_iter { + /** Data pointer */ + const uint8_t *data; + + /** Base length */ + uint8_t buf_len; + + /** Original BASE pointer */ + const uint8_t *buf; + + /** Remaining number of elements */ + uint8_t num_elements; +}; + +/** @brief Broadcast Audio Source Endpoint Group structure */ +struct ble_audio_base_group { + /** Presentation Delay */ + uint32_t presentation_delay; + + /** Number of subgroups */ + uint8_t num_subgroups; +}; + +/** + * Parse the BASE received from Basic Audio Announcement data. + * + * @param[in] data Pointer to the BASE data buffer to parse. + * @param[in] data_len Length of the BASE data buffer. + * @param[out] group Group object. + * @param[out] subgroup_iter Subgroup iterator object. + * + * @return 0 on success; nonzero on failure. + */ +int ble_audio_base_parse(const uint8_t *data, uint8_t data_len, + struct ble_audio_base_group *group, + struct ble_audio_base_iter *subgroup_iter); + +/** @brief Broadcast Audio Source Endpoint Subgroup structure */ +struct ble_audio_base_subgroup { + /** Codec information for the subgroup */ + struct ble_audio_codec_id codec_id; + + /** Length of the Codec Specific Configuration for the subgroup */ + uint8_t codec_spec_config_len; + + /** Codec Specific Configuration for the subgroup */ + const uint8_t *codec_spec_config; + + /** Length of the Metadata for the subgroup */ + uint8_t metadata_len; + + /** Series of LTV structures containing Metadata */ + const uint8_t *metadata; + + /** Number of BISes in the subgroup */ + uint8_t num_bis; +}; + +/** + * @brief Basic Audio Announcement Subgroup information + * + * @param[in] subgroup_iter Subgroup iterator object. + * @param[out] subgroup Subgroup object. + * @param[out] bis_iter BIS iterator object. + * + * @return 0 on success; + * A non-zero value on failure. + */ +int ble_audio_base_subgroup_iter(struct ble_audio_base_iter *subgroup_iter, + struct ble_audio_base_subgroup *subgroup, + struct ble_audio_base_iter *bis_iter); + +/** @brief Broadcast Audio Source Endpoint BIS structure */ +struct ble_audio_base_bis { + /** BIS_index value for the BIS */ + uint8_t index; + + /** Length of the Codec Specific Configuration for the BIS */ + uint8_t codec_spec_config_len; + + /** Codec Specific Configuration for the BIS */ + const uint8_t *codec_spec_config; +}; + +/** + * @brief Basic Audio Announcement Subgroup information + * + * @param[in] bis_iter BIS iterator object. + * @param[out] bis BIS object. + * + * @return 0 on success; + * A non-zero value on failure. + */ +int ble_audio_base_bis_iter(struct ble_audio_base_iter *bis_iter, + struct ble_audio_base_bis *bis); + +/** Broadcast Isochronous Streams (BIS) */ +struct ble_audio_bis { + /** Pointer to next BIS in subgroup */ + STAILQ_ENTRY(ble_audio_bis) next; + + /** BIS index */ + uint8_t idx; + + /** BIS level Codec Specific Configuration length */ + uint8_t codec_spec_config_len; + + /** BIS level Codec Specific Configuration */ + uint8_t *codec_spec_config; +}; + +/** Broadcast Isochronous Group (BIG) Subgroup */ +struct ble_audio_big_subgroup { + /** Pointer to next subgroup in BIG */ + STAILQ_ENTRY(ble_audio_big_subgroup) next; + + /** Number of BISes in subgroup */ + uint8_t bis_cnt; + + /** Codec ID */ + struct ble_audio_codec_id codec_id; + + /** Subgroup level Codec Specific Configuration */ + uint8_t *codec_spec_config; + + /** Subgroup level Codec Specific Configuration length */ + uint8_t codec_spec_config_len; + + /** Subgroup Metadata */ + uint8_t *metadata; + + /** Subgroup Metadata length*/ + uint8_t metadata_len; + + /** Link list of BISes */ + STAILQ_HEAD(, ble_audio_bis) bises; +}; + +/** Broadcast Audio Source Endpoint */ +struct ble_audio_base { + /** Broadcast ID */ + uint32_t broadcast_id; + + /** Presentation Delay */ + uint32_t presentation_delay; + + /** Number of subgroups in BIG */ + uint8_t num_subgroups; + + /** Link list of subgroups */ + STAILQ_HEAD(, ble_audio_big_subgroup) subs; +}; + +static inline const char * +ble_audio_broadcast_sink_sync_state_str(enum ble_audio_broadcast_sink_sync_state state) +{ + switch (state) { + case BLE_AUDIO_BROADCAST_SINK_SYNC_STATE_NOT_SYNCED: + return "not synced"; + case BLE_AUDIO_BROADCAST_SINK_SYNC_STATE_INITIATED: + return "initiated"; + case BLE_AUDIO_BROADCAST_SINK_SYNC_STATE_ESTABLISHED: + return "established"; + default: + return "invalid"; + } +} + +/** @} */ + +#endif /* H_BLE_AUDIO_ */ diff --git a/nimble/host/audio/include/audio/ble_audio_broadcast_sink.h b/nimble/host/audio/include/audio/ble_audio_broadcast_sink.h new file mode 100644 index 0000000000..36da4e6c10 --- /dev/null +++ b/nimble/host/audio/include/audio/ble_audio_broadcast_sink.h @@ -0,0 +1,281 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_BLE_AUDIO_BROADCAST_SINK_ +#define H_BLE_AUDIO_BROADCAST_SINK_ + +/** + * @file ble_audio_broadcast_sink.h + * + * @brief Bluetooth LE Audio BAP Broadcast Sink API + * + * @defgroup ble_audio_broadcast_sink Bluetooth LE Audio BAP Broadcast Sink + * @ingroup bt_host + * @{ + * + */ + +#include +#include "host/ble_gap.h" +#include "host/ble_iso.h" +#include "audio/ble_audio.h" +#include "audio/ble_audio_scan_delegator.h" +#include "nimble/ble.h" + +enum ble_audio_broadcast_sink_action_type { + /** Broadcast Sink Action Type: PA sync */ + BLE_AUDIO_BROADCAST_SINK_ACTION_PA_SYNC, + + /** Broadcast Sink Action Type: BIG sync */ + BLE_AUDIO_BROADCAST_SINK_ACTION_BIG_SYNC, + + /** Broadcast Sink Action Type: BIS sync */ + BLE_AUDIO_BROADCAST_SINK_ACTION_BIS_SYNC, + + /** Broadcast Sink Action Type: Start discovery (scan) */ + BLE_AUDIO_BROADCAST_SINK_ACTION_DISC_START, + + /** Broadcast Sink Action Type: Start discovery (scan) */ + BLE_AUDIO_BROADCAST_SINK_ACTION_DISC_STOP, +}; + +struct ble_audio_broadcast_sink_action { + /** + * Indicates the type of action that is requested. + */ + enum ble_audio_broadcast_sink_action_type type; + + /** + * A discriminated union containing additional details concerning the action. + * The 'type' field indicates which member of the union is valid. + */ + union { + /** + * Represents PA Sync parameters request. + * + * The action triggered on locally or remotely initiated PA synchronization request. + * The application should initialize the `out_parameters`, or abort the process. + * + * Valid for the following action types: + * o BLE_AUDIO_BROADCAST_SINK_ACTION_PA_SYNC + * + * Return: + * o 0 on success; + * o A non-zero value to abort. + */ + struct { + /** Pointer to Periodic Sync parameters to initialize. */ + struct ble_gap_periodic_sync_params *out_params; + } pa_sync; + + /** + * Represents BIG Sync request. + * + * The action triggered on locally or remotely initiated BIG synchronization request. + * The application should provide the `out_mse` and `out_sync_timeout`, + * or reject the request. + * + * Valid for the following action types: + * o BLE_AUDIO_BROADCAST_SINK_ACTION_BIG_SYNC + * + * Return: + * o 0 on success; + * o A non-zero value to abort. + */ + struct { + /** Source ID. */ + uint8_t source_id; + + /** ISO Interval. */ + uint16_t iso_interval; + + /** Presentation delay. */ + uint32_t presentation_delay; + + /** Number of SubEvents. The total number of subevents that are used to transmit BIS Data. */ + uint8_t nse; + + /** Burst Number. The number of new payloads for each BIS in a BIS event. */ + uint8_t bn; + + /** + * Pointer to Maximum subevents value to initialize. + * Range: 0x00 to 0x1F. + * Default: 0x00, meaning the Controller can schedule reception of any number of subevents up to NSE. + */ + uint8_t *out_mse; + + /** + * Pointer to Sync Timeout value to initialize. + * Range: 0x000A to 0x4000. + * Default: @ref iso_interval * 6. + */ + uint16_t *out_sync_timeout; + } big_sync; + + /** + * Represents BIS Sync request. + * + * The action triggered on locally or remotely initiated BIS synchronization request. + * The application should provide the `out_cb` and optionally `out_cb_arg`, + * or reject the request. + * + * @note The `subgroup` object as well as it's `base` object, + * therefore must be copied to in order to cache its information. + * + * Valid for the following action types: + * o BLE_AUDIO_BROADCAST_SINK_ACTION_BIS_SYNC + * + * Return: + * o 0 on success; + * o A non-zero value to abort. + */ + struct { + /** Source ID. */ + uint8_t source_id; + + /** Subgroup index. */ + uint8_t subgroup_index; + + /** Broadcast Audio Source Endpoint BIS. */ + const struct ble_audio_base_bis *bis; + + /** Broadcast Audio Source Endpoint Subgroup. */ + const struct ble_audio_base_subgroup *subgroup; + } bis_sync; + + /** + * Represents discovery start request. + * + * The action triggered on locally as part of PA synchronization process. + * + * Valid for the following action types: + * o BLE_AUDIO_BROADCAST_SINK_ACTION_SCAN_START + * + * Return: + * o 0 on success; + * o A non-zero value to abort. + */ + struct { + /** Preferred extended discovery parameters. */ + const struct ble_gap_ext_disc_params *params_preferred; + } disc_start; + }; +}; + +/** + * Prototype of Broadcast Sink action callback. + * This function shall return 0 if operation is accepted, and error code if rejected. + */ +typedef int ble_audio_broadcast_sink_action_fn(struct ble_audio_broadcast_sink_action *action, + void *arg); + +/** + * @brief Sets the application callback function. + * + * This function sets the callback function and its argument that will be called + * when a Broadcast Sink action is triggered. + * + * @param cb Pointer to the callback function of type ble_audio_scan_delegator_ev_cb. + * @param arg Pointer to the argument to be passed to the callback function. + * + * @return Returns 0 on success, or a non-zero error code otherwise. + */ +int ble_audio_broadcast_sink_cb_set(ble_audio_broadcast_sink_action_fn *cb, void *arg); + +/** Sink Add function parameters */ +struct ble_audio_broadcast_sink_add_params { + /** Broadcast Code */ + uint8_t broadcast_code[BLE_AUDIO_BROADCAST_CODE_SIZE]; + + /** Broadcast Code parameter is valid */ + uint8_t broadcast_code_is_valid : 1; +}; + +/** + * @brief Start audio broadcast sink synchronization with the source. + * + * This function synchronizes the audio broadcast sink with the source + * identified by the given source ID. + * The source can be added locally using @ref ble_svc_audio_bass_receive_state_add function + * or requested by remote device. + * + * @param source_id Source ID of Broadcast Source to synchronize to. + * @param params Parameters to be used. + * + * @return 0 on success; + * BLE_HS_ENOENT if the source ID is invalid; + * BLE_HS_EDONE if synced already; + * BLE_HS_EALREADY if the synchronization is in progress; + * BLE_HS_ENOMEM if memory allocation fails; + * Any other non-zero value on failure. + */ +int ble_audio_broadcast_sink_start(uint8_t source_id, + const struct ble_audio_broadcast_sink_add_params *params); + +/** + * @brief Stop audio broadcast sink synchronization. + * + * This function terminates or aborts the pending synchronization with the source + * identified by the given source ID. + * + * @param source_id Source ID of Broadcast Source to synchronize to. + * + * @return 0 on success; + * BLE_HS_ENOENT if the source ID is invalid; + * Any other non-zero value on failure. + */ +int ble_audio_broadcast_sink_stop(uint8_t source_id); + +/** Metadata Update function parameters */ +struct ble_audio_broadcast_sink_metadata_update_params { + /** Subgroup index */ + uint8_t subgroup_index; + + /** Scan Delegator Subgroup: Metadata */ + uint8_t *metadata; + + /** Scan Delegator Subgroup: Metadata length */ + uint8_t metadata_length; +}; + +/** + * @brief Sets audio broadcast sink metadata. + * + * This function updates the broadcast sink metadata identified by the given source ID. + * + * @param source_id Source ID of Broadcast Source. + * @param params Parameters to be used. + * + * @return 0 on success; + * BLE_HS_ENOENT if the source ID is invalid; + * Any other non-zero value on failure. + */ +int ble_audio_broadcast_sink_metadata_update(uint8_t source_id, + const struct ble_audio_broadcast_sink_metadata_update_params *params); + +/** + * @brief Initialize Broadcast Sink + * + * This function is restricted to be called by sysinit. + * + * @return Returns 0 on success, or a non-zero error code otherwise. + */ +int ble_audio_broadcast_sink_init(void); +#endif /* H_BLE_AUDIO_BROADCAST_SINK_ */ diff --git a/nimble/host/audio/include/audio/ble_audio_broadcast_source.h b/nimble/host/audio/include/audio/ble_audio_broadcast_source.h new file mode 100644 index 0000000000..839449cbe3 --- /dev/null +++ b/nimble/host/audio/include/audio/ble_audio_broadcast_source.h @@ -0,0 +1,270 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_BLE_AUDIO_BROADCAST_SOURCE_ +#define H_BLE_AUDIO_BROADCAST_SOURCE_ + +/** + * @file ble_audio_broadcast.h + * + * @brief Bluetooth Low Energy Audio Broadcast API + * + * @defgroup bt_le_audio_broadcast Bluetooth LE Audio Broadcast + * @ingroup bt_host + * @{ + */ + +#include +#include "host/ble_gap.h" +#include "host/ble_iso.h" +#include "ble_audio.h" + +/** Parameters used for creating BASE configuration. */ +struct ble_broadcast_create_params { + /** Broadcast Audio Source Endpoint */ + struct ble_audio_base *base; + + /** Parameters used to configure Extended advertising */ + struct ble_gap_ext_adv_params *extended_params; + + /** Parameters used to configure Periodic advertising */ + struct ble_gap_periodic_adv_params *periodic_params; + + /** Broadcast name - null terminated. + * Set NULL to not include in advertising. + * Length must be in range of 4 to 32 chars. + */ + const char *name; + + /** Advertising instance */ + uint8_t adv_instance; + + /** BIG parameters. These parameters are not copied and shall be valid for the lifetime + * of the broadcast. + */ + struct ble_iso_big_params *big_params; + + /** Additional data to include in Extended Advertising */ + uint8_t *svc_data; + + /** Additional data length */ + uint16_t svc_data_len; +}; + +/** Parameters used for updating BASE configuration. */ +struct ble_broadcast_update_params { + /** Broadcast name - null terminated. + * Set NULL to not include in advertising + */ + const char *name; + + /** Advertising instance */ + uint8_t adv_instance; + + /** Additional data to include in Extended Advertising */ + uint8_t *svc_data; + + /** Additional data length */ + uint16_t svc_data_len; + + /** Broadcast ID */ + uint32_t broadcast_id; +}; + +/** Function prototype for broadcast destroy callback. */ +typedef int ble_audio_broadcast_destroy_fn(struct ble_audio_base *base, + void *args); + +/** + * @brief Create Broadcast Audio Source Endpoint and configure advertising + * instance + * + * This function configures advertising instance for extended and periodic + * advertisements to be ready for broadcast with BASE configuration. + * + * @param[in] params Pointer to a `ble_broadcast_base_params` + * structure that defines BASE, extended + * advertising and periodic advertising + * configuration. + * @param[in] destroy_cb Optional callback to be invoked on + * `ble_audio_broadcast_destroy` call. + * @param[in] args Optional arguments to be passed to `destroy_cb` + * @param[in] gap_cb GAP event callback to be associated with BASE + * advertisement. + * + * @return 0 on success; + * A non-zero value on failure. + */ +int ble_audio_broadcast_create(const struct ble_broadcast_create_params + *params, + ble_audio_broadcast_destroy_fn *destroy_cb, + void *args, + ble_gap_event_fn *gap_cb); + +/** + * @brief Start advertisements for given BASE configuration + * + * This function starts BASE advertisement by enabling extended, periodic + * and BIGInfo advertisements for this instance. + * + * @param[in] adv_instance Advertising instance used by broadcast. + * @param[in] cb Pointer to an ISO event handler. + * @param[in] cb_arg Arguments to an ISO event handler. + * + * @return 0 on success; + * A non-zero value on failure. + */ +int ble_audio_broadcast_start(uint8_t adv_instance, + ble_iso_event_fn *cb, void *cb_arg); + +/** + * @brief Stop advertisements for given BASE configuration + * + * This function stops BASE advertisement by disabling extended and periodic + * advertising. Advertising instance is still configured and ready for resume. + * + * @param[in] adv_instance Advertising instance used by broadcast. + * + * @return 0 on success; + * A non-zero value on failure. + */ +int ble_audio_broadcast_stop(uint8_t adv_instance); + +/** + * @brief Destroy advertisements for given BASE configuration + * + * This function terminates BASE advertisement instance. + * After return advertising instance is free and must be configured again + * for future advertisements. + * + * @param[in] adv_instance Advertising instance used by broadcast. + * + * @return 0 on success; + * A non-zero value on failure. + */ +int ble_audio_broadcast_destroy(uint8_t adv_instance); + +/** + * @brief Update advertisements for given BASE configuration + * + * This function updates extended advertisements. + * + * @param[in] params Pointer to structure with new advertising data + * @return 0 on success; + * A non-zero value on failure. + */ +int ble_audio_broadcast_update(const struct ble_broadcast_update_params + *params); + +/** BIG Subgroup parameters */ +struct ble_broadcast_subgroup_params { + /** Subgroup level Codec information */ + struct ble_audio_codec_id *codec_id; + + /** Subgroup level Codec Specific Configuration */ + uint8_t *codec_spec_config; + + /** Subgroup level Codec Specific Configuration length */ + uint8_t codec_spec_config_len; + + /** Subgroup Metadata */ + uint8_t *metadata; + + /** Subgroup Metadata length*/ + uint8_t metadata_len; +}; + +/** + * @brief Build BIG subgroup structure + * + * This is a helper function can be used to fill out `ble_audio_big_subgroup` + * structure. Created subgroup extends subgroup list in provided BASE. + * This function increases `num_subgroups` in BASE structure. + * + * @param[in,out] base Pointer to a `ble_audio_base` structure, + * that will be extended by the new subgroup. + * In case of error, filled out data may be + * erroneous. + * @param[out] subgroup Pointer to a `ble_audio_big_subgroup` + * structure, that will be filled out with + * supplied configuration. In case of error, + * filled out data may be erroneous. + * @param[in] params Pointer to a `ble_broadcast_subgroup_params` + * structure, containing information about new + * subgroup + * + * @return 0 on success; + * A non-zero value on failure. + */ +int ble_audio_broadcast_build_sub(struct ble_audio_base *base, + struct ble_audio_big_subgroup *subgroup, + const struct ble_broadcast_subgroup_params + *params); + +/** BIS parameters */ +struct ble_broadcast_bis_params { + /** BIS index */ + uint8_t idx; + + /** BIS level Codec Specific Configuration */ + uint8_t *codec_spec_config; + + /** BIS level Codec Specific Configuration length */ + uint8_t codec_spec_config_len; +}; + +/** + * @brief Build BIS structure + * + * This is a helper function can be used to fill out `ble_broadcast_bis` + * structure. Created BIS extends BIS list in provided subgroup. + * This function increases `bis_cnt` in subgroup structure. + * + * @param[in,out] subgroup Pointer to a updated `ble_audio_big_subgroup` + * structure, that will be extended by the new + * BIS. In case of error, filled out data may be + * erroneous. + * @param[out] bis Pointer to a `ble_broadcast_bis` + * structure, that will be filled out with + * supplied configuration. In case of error, + * filled out data may be erroneous. + * @param[in] params Pointer to a `ble_broadcast_bis_params` + * structure, containing information about new + * BIS + * + * @return 0 on success; + * A non-zero value on failure. + */ +int ble_audio_broadcast_build_bis(struct ble_audio_big_subgroup *subgroup, + struct ble_audio_bis *bis, + const struct ble_broadcast_bis_params + *params); + +/** + * Initializes memory for LE Audio Broadcast. + * + * @return 0 on success + */ +int ble_audio_broadcast_init(void); + +/** + * @} + */ + +#endif /* H_BLE_AUDIO_BROADCAST_*/ diff --git a/nimble/host/audio/include/audio/ble_audio_codec.h b/nimble/host/audio/include/audio/ble_audio_codec.h new file mode 100644 index 0000000000..dcb1df9d34 --- /dev/null +++ b/nimble/host/audio/include/audio/ble_audio_codec.h @@ -0,0 +1,146 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_BLE_AUDIO_CODEC_ +#define H_BLE_AUDIO_CODEC_ + +/** + * @file ble_audio_codec.h + * + * @brief Bluetooth LE Audio Codec + * + * This header file provides the public API for managing LE Audio Codecs + * + * @defgroup ble_audio_codec Bluetooth LE Audio Codec + * @ingroup bt_host + * @{ + * + * This API allows to create and manage list of LE Audio codecs with their capabilities and + * metadata. This list can be used by higher level services, like PACS. Memory management of + * codec entries is left to application and neither static nor dynamic allocation is enforced. + * + */ + +#include "stdint.h" +#include "ble_audio.h" + +/** Bit describing direction of codec configuration - source */ +#define BLE_AUDIO_CODEC_DIR_SOURCE_BIT (1 << 0) +/** Bit describing direction of codec configuration - sink */ +#define BLE_AUDIO_CODEC_DIR_SINK_BIT (1 << 1) + +/** Codec list entry */ +struct ble_audio_codec_record { + /* Pointer to next codec list entry */ + STAILQ_ENTRY(ble_audio_codec_record) next; + + /* Codec ID */ + struct ble_audio_codec_id codec_id; + + /* Length of Codec Specific Capabilities */ + uint8_t codec_spec_caps_len; + + /* Codec Specific Capabilities data */ + const uint8_t *codec_spec_caps; + + /* Metadata length */ + uint8_t metadata_len; + + /* Metadata */ + const uint8_t *metadata; + + /* Bitfield describing direction that codec is acting on. It is a logical OR of: + * - BLE_AUDIO_CODEC_DIR_SOURCE_BIT + * - BLE_AUDIO_CODEC_DIR_SINK_BIT + */ + uint8_t direction; +}; + +/** Type definition codec iteration callback function. */ +typedef int ble_audio_codec_foreach_fn(const struct ble_audio_codec_record *record, void *arg); + +struct ble_audio_codec_register_params { + /* Codec ID structure */ + struct ble_audio_codec_id codec_id; + + /* Codec Specific Capabilities length */ + uint8_t codec_spec_caps_len; + + /* Codec Specific Capabilities data */ + uint8_t *codec_spec_caps; + + /* Metadata length */ + uint8_t metadata_len; + + /* Metadata */ + uint8_t *metadata; + + /* Bitfield describing direction that codec is acting on. It is a logical OR of: + * - BLE_AUDIO_CODEC_DIR_SOURCE_BIT + * - BLE_AUDIO_CODEC_DIR_SINK_BIT + */ + uint8_t direction; +}; + +/** + * @brief Register codec entry + * + * @param[in] params Pointer to a `ble_audio_codec_register_params` + * structure that defines Codec Specific Capabilities + * @param[out] out_record Pointer to registered codec entry. + * + * @return 0 on success; + * A non-zero value on failure. + */ +int ble_audio_codec_register(const struct ble_audio_codec_register_params + *params, + struct ble_audio_codec_record *out_record); +/** + * @brief Remove codec entry from register + * + * @param[in] codec_record Pointer to registered codec entry. + * + * @return 0 on success; + * A non-zero value on failure. + */ +int ble_audio_codec_unregister(struct ble_audio_codec_record *codec_record); + +/** + * @brief Iterate through all registered codecs and call function on every + * one of them. + * + * @param[in] direction Codec entry direction. It is any + * combination of following bits: + * - BLE_AUDIO_CODEC_DIR_SOURCE_BIT + * - BLE_AUDIO_CODEC_DIR_SINK_BIT + * This filters entries so the callback is called + * only on these have matching direction bit set. + * @param[in] cb Callback to be called on codec entries. + * @param[in] arg Optional callback argument. + * + * @return 0 on success; + * A non-zero value on failure. + */ +int ble_audio_codec_foreach(uint8_t direction, ble_audio_codec_foreach_fn *cb, void *arg); + +/** + * @} + */ + +#endif /* H_BLE_AUDIO_CODEC_ */ diff --git a/nimble/host/audio/include/audio/ble_audio_scan_delegator.h b/nimble/host/audio/include/audio/ble_audio_scan_delegator.h new file mode 100644 index 0000000000..5c9aa66053 --- /dev/null +++ b/nimble/host/audio/include/audio/ble_audio_scan_delegator.h @@ -0,0 +1,393 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_BLE_AUDIO_SCAN_DELEGATOR_ +#define H_BLE_AUDIO_SCAN_DELEGATOR_ + +/** + * @file ble_audio_scan_delegator.h + * + * @brief Bluetooth LE Audio BAP Scan Delegator API + * + * @defgroup ble_audio_scan_delegator Bluetooth LE Audio BAP Scan Delegator + * @ingroup bt_host + * @{ + * + */ + +#include +#include "audio/ble_audio.h" +#include "nimble/ble.h" + +#if MYNEWT_VAL(BLE_AUDIO_SCAN_DELEGATOR) +#define BLE_AUDIO_SCAN_DELEGATOR_SUBGROUP_MAX \ + MYNEWT_VAL(BLE_AUDIO_SCAN_DELEGATOR_SUBGROUP_MAX) +#else +#define BLE_AUDIO_SCAN_DELEGATOR_SUBGROUP_MAX 0 +#endif /* BLE_AUDIO_SCAN_DELEGATOR */ + +/** No preferred BIS Synchronization. Decision is left to application. */ +#define BLE_AUDIO_SCAN_DELEGATOR_BIS_SYNC_ANY 0xFFFFFFFF + +/** Unknown PA Interval */ +#define BLE_AUDIO_SCAN_DELEGATOR_PA_SYNC_UNKNOWN 0xFFFF + +/** Scan Delegator Source descriptor */ +struct ble_audio_scan_delegator_source_desc { + /** Scan Delegator Source: BLE Address */ + ble_addr_t addr; + + /** Scan Delegator Source: Advertising SID */ + uint8_t adv_sid; + + /** Scan Delegator Source: Broadcast ID */ + uint32_t broadcast_id; +}; + +/** Scan Delegator Broadcast Encryption States */ +enum ble_audio_scan_delegator_big_enc { + /** Scan Delegator BIG Encryption: Not Encrypted */ + BLE_AUDIO_SCAN_DELEGATOR_BIG_ENC_NONE, + + /** Scan Delegator BIG Encryption: Broadcast Code Required */ + BLE_AUDIO_SCAN_DELEGATOR_BIG_ENC_BROADCAST_CODE_MISSING, + + /** Scan Delegator BIG Encryption: Decrypting */ + BLE_AUDIO_SCAN_DELEGATOR_BIG_ENC_DECRYPTING, + + /** Scan Delegator BIG Encryption: Bad Code */ + BLE_AUDIO_SCAN_DELEGATOR_BIG_ENC_BROADCAST_CODE_INVALID +}; + +/** Scan Delegator PA Sync States */ +enum ble_audio_scan_delegator_pa_sync_state { + /** Scan Delegator PA Sync State: Not synchronized to PA */ + BLE_AUDIO_SCAN_DELEGATOR_PA_SYNC_STATE_NOT_SYNCED, + + /** Scan Delegator PA Sync State: SyncInfo Request */ + BLE_AUDIO_SCAN_DELEGATOR_PA_SYNC_STATE_SYNC_INFO_REQ, + + /** Scan Delegator PA Sync State: Synchronized to PA */ + BLE_AUDIO_SCAN_DELEGATOR_PA_SYNC_STATE_SYNCED, + + /** Scan Delegator PA Sync State: Failed to synchronize to PAA */ + BLE_AUDIO_SCAN_DELEGATOR_PA_SYNC_STATE_ERROR, + + /** Scan Delegator PA Sync State: No PAST */ + BLE_AUDIO_SCAN_DELEGATOR_PA_SYNC_STATE_NO_PAST +}; + +/** Scan Delegator Subgroup definition */ +struct ble_audio_scan_delegator_subgroup { + /** Scan Delegator Subgroup: BIS Synchronization */ + uint32_t bis_sync; + + /** Scan Delegator Subgroup: Metadata */ + uint8_t *metadata; + + /** Scan Delegator Subgroup: Metadata length */ + uint8_t metadata_length; +}; + +/** Scan Delegator PA Sync option */ +enum ble_audio_scan_delegator_pa_sync { + /** Scan Delegator PA Sync: Do not synchronize to PA */ + BLE_AUDIO_SCAN_DELEGATOR_PA_SYNC_DO_NOT_SYNC, + + /** Scan Delegator PA Sync: Synchronize to PA – PAST available */ + BLE_AUDIO_SCAN_DELEGATOR_PA_SYNC_PAST_AVAILABLE, + + /** Scan Delegator PA Sync: Synchronize to PA – PAST not available */ + BLE_AUDIO_SCAN_DELEGATOR_PA_SYNC_PAST_NOT_AVAILABLE, +}; + +/** Scan Delegator Broadcast Source Synchronization option */ +struct ble_audio_scan_delegator_sync_opt { + /** PA Sync option */ + enum ble_audio_scan_delegator_pa_sync pa_sync; + + /** PA Sync interval */ + uint16_t pa_interval; + + /** Number of Subgroups */ + uint8_t num_subgroups; + + /** Subgroup sync option */ + struct ble_audio_scan_delegator_subgroup subgroups[ + BLE_AUDIO_SCAN_DELEGATOR_SUBGROUP_MAX]; +}; + +enum ble_audio_scan_delegator_action_type { + /** Scan Delegator Action Type: Add Source */ + BLE_AUDIO_SCAN_DELEGATOR_ACTION_SOURCE_ADD, + + /** Scan Delegator Action Type: Modify Source */ + BLE_AUDIO_SCAN_DELEGATOR_ACTION_SOURCE_MODIFY, + + /** Scan Delegator Action Type: Remove Source */ + BLE_AUDIO_SCAN_DELEGATOR_ACTION_SOURCE_REMOVE, +}; + +struct ble_audio_scan_delegator_action { + /** + * Indicates the type of action that is requested. + */ + enum ble_audio_scan_delegator_action_type type; + + /** + * A union containing additional details concerning the action. + * The 'type' field indicates which member of the union is valid. + */ + union { + /** + * Represents remote Add Source operation request. + * + * Valid for the following action types: + * o BLE_AUDIO_SCAN_DELEGATOR_ACTION_SOURCE_ADD + * + * @note The @ref ble_audio_scan_delegator_subgroup.metadata object is temporary, therefore must be copied to in + * order to cache its information. + * + * Return: + * o 0 on success; + * o A non-zero value to reject. + */ + struct { + /** Source ID */ + uint8_t source_id; + + /** Broadcast Source descriptor */ + struct ble_audio_scan_delegator_source_desc source_desc; + + /** Broadcast synchronization option */ + struct ble_audio_scan_delegator_sync_opt sync_opt; + + /** + * Valid pointer to provide source ID to be swapped or NULL. + * + * If there are insufficient resources to handle the operation, the application is requested to provide + * source ID to be removed once accepted. + */ + uint8_t *out_source_id_to_swap; + } source_add; + + /** + * Represents remote Modify Source operation request. + * + * Valid for the following action types: + * o BLE_AUDIO_SCAN_DELEGATOR_ACTION_SOURCE_MODIFY + * + * @note The @ref ble_audio_scan_delegator_subgroup.metadata object is temporary, therefore must be copied to in + * order to cache its information. + * + * Return: + * o 0 on success; + * o A non-zero value to reject. + */ + struct { + /** Source ID */ + uint8_t source_id; + + /** Broadcast synchronization option */ + struct ble_audio_scan_delegator_sync_opt sync_opt; + } source_modify; + + /** + * Represents remote Remove Source operation request. + * + * Valid for the following action types: + * o BLE_AUDIO_SCAN_DELEGATOR_ACTION_SOURCE_REMOVE + * + * Return: + * o 0 on success; + * o A non-zero value to reject. + */ + struct { + /** Source ID */ + uint8_t source_id; + } source_remove; + + /** + * Represents remote Broadcast Code Set operation request. + * + * Valid for the following action types: + * o BLE_AUDIO_SCAN_DELEGATOR_ACTION_BROADCAST_CODE + * + * Return: + * o 0 on success; + * o A non-zero value on failure. + */ + struct { + /** Source ID */ + uint8_t source_id; + + /** Broadcast Code value to be stored. */ + const uint8_t value[BLE_AUDIO_BROADCAST_CODE_SIZE]; + } broadcast_code; + }; +}; + +/** + * Prototype of Scan Delegator action callback. + * This function shall return 0 if operation is accepted, and error code if rejected. + */ +typedef int ble_audio_scan_delegator_action_fn( + struct ble_audio_scan_delegator_action *action, void *arg); + +/** + * @brief Sets the application callback function. + * + * This function sets the callback function that will be called on remote device request. + * + * @param[in] cb Pointer to the callback function. + * @param[in] arg Pointer to any additional arguments that need to + * be passed to the callback function. + * + * @return 0 on success; + * A non-zero value on failure. + */ +int ble_audio_scan_delegator_action_fn_set(ble_audio_scan_delegator_action_fn *cb, void *arg); + +/** Scan Delegator Receive State definition */ +struct ble_audio_scan_delegator_receive_state { + /** Scan Delegator Receive State: PA Sync state */ + enum ble_audio_scan_delegator_pa_sync_state pa_sync_state; + + /** Scan Delegator Receive State: BIG Encryption */ + enum ble_audio_scan_delegator_big_enc big_enc; + + /** + * Incorrect Bad Broadcast Code. + * Valid for @ref BLE_AUDIO_SCAN_DELEGATOR_BIG_ENC_BROADCAST_CODE_INVALID. + */ + uint8_t bad_code[BLE_AUDIO_BROADCAST_CODE_SIZE]; + + /** Scan Delegator Receive State: Number of subgroups */ + uint8_t num_subgroups; + + /** Scan Delegator Receive State: subgroup entries */ + struct ble_audio_scan_delegator_subgroup subgroups[ + MYNEWT_VAL(BLE_AUDIO_SCAN_DELEGATOR_SUBGROUP_MAX)]; +}; + +/** Receive State Add function parameters */ +struct ble_audio_scan_delegator_receive_state_add_params { + /** Broadcast Source descriptor */ + struct ble_audio_scan_delegator_source_desc source_desc; + + /** Receive state */ + struct ble_audio_scan_delegator_receive_state state; +}; + +/** + * @brief Adds the receive state. + * + * This function allocates receive state and returns it's source ID. + * + * @param[in] params Parameters to be used. + * @param[in,out] source_id Unique source ID of receive state added. + * + * @return 0 on success; + * A non-zero value on failure. + */ +int ble_audio_scan_delegator_receive_state_add(const struct ble_audio_scan_delegator_receive_state_add_params *params, + uint8_t *source_id); + +/** + * @brief Removes the receive state. + * + * This function removes the specific receive state identified by source ID. + * + * @param[in] source_id Source ID of receive state to be removed. + * @param[in] params Parameters to be used. + * + * @return 0 on success; + * A non-zero value on failure. + */ +int ble_audio_scan_delegator_receive_state_remove(uint8_t source_id); + +/** + * @brief Set the receive state. + * + * This function updates the specific receive state identified by source ID. + * + * @param[in] source_id Source ID of receive state to be updated. + * @param[in] state Receive state to be set. + * + * @return 0 on success; + * A non-zero value on failure. + */ +int ble_audio_scan_delegator_receive_state_set(uint8_t source_id, + const struct ble_audio_scan_delegator_receive_state *state); + +/** + * @brief get the receive state. + * + * This function returns the specific receive state identified by source ID. + * + * @param[in] source_id Source ID of receive state to be updated. + * @param[in,out] state Pointer to receive state to be populate. + * + * @return 0 on success; + * A non-zero value on failure. + */ +int ble_audio_scan_delegator_receive_state_get(uint8_t source_id, + struct ble_audio_scan_delegator_receive_state *state); + +/** Scan Delegator Receive State entry definition */ +struct ble_audio_scan_delegator_receive_state_entry { + /** Source ID */ + uint8_t source_id; + + /** Broadcast Source descriptor */ + struct ble_audio_scan_delegator_source_desc source_desc; + + /** Receive state */ + struct ble_audio_scan_delegator_receive_state state; +}; + +/** + * Type definition Receive State iteration callback function. + * + * @note Return 0 to continue, or a non-zero to abort foreach loop. + */ +typedef int ble_audio_scan_delegator_receive_state_foreach_fn( + struct ble_audio_scan_delegator_receive_state_entry *entry, void *arg); + +/** + * @brief Iterate receive states. + * + * @param[in] cb Callback to be called on codec entries. + * @param[in] arg Optional callback argument. + * + * @return 0 on success; + * A non-zero value on failure. + */ +void ble_audio_scan_delegator_receive_state_foreach(ble_audio_scan_delegator_receive_state_foreach_fn *cb, void *arg); + +/** + * @brief Initialize Scan Delegator + * + * This function is restricted to be called by sysinit. + * + * @return 0 on success; + * A non-zero value on failure. + */ +int ble_audio_scan_delegator_init(void); +#endif /* H_BLE_AUDIO_SCAN_DELEGATOR_ */ diff --git a/nimble/host/audio/pkg.yml b/nimble/host/audio/pkg.yml new file mode 100644 index 0000000000..43385d2718 --- /dev/null +++ b/nimble/host/audio/pkg.yml @@ -0,0 +1,44 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +pkg.name: nimble/host/audio +pkg.description: Bluetooth LE Audio +pkg.author: "Apache Mynewt " +pkg.homepage: "http://mynewt.apache.org/" +pkg.experimental: 1 +pkg.keywords: + - ble + - bluetooth + - audio + +pkg.deps: + - nimble + - nimble/host + +pkg.deps.BLE_AUDIO_BROADCAST_SINK: + - nimble/host/audio/services/pacs/lc3 + +pkg.deps.BLE_AUDIO_SCAN_DELEGATOR: + - nimble/host/audio/services/bass + +pkg.init.BLE_AUDIO_BROADCAST_SINK: + ble_audio_broadcast_sink_init: 'MYNEWT_VAL(BLE_AUDIO_BROADCAST_SINK_SYSINIT_STAGE)' + +pkg.init.BLE_AUDIO_SCAN_DELEGATOR: + ble_audio_scan_delegator_init: 'MYNEWT_VAL(BLE_AUDIO_SCAN_DELEGATOR_SYSINIT_STAGE)' diff --git a/nimble/host/audio/services/auracast/include/services/auracast/ble_svc_auracast.h b/nimble/host/audio/services/auracast/include/services/auracast/ble_svc_auracast.h new file mode 100644 index 0000000000..900b6fddaa --- /dev/null +++ b/nimble/host/audio/services/auracast/include/services/auracast/ble_svc_auracast.h @@ -0,0 +1,132 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include "host/ble_gap.h" +#include "audio/ble_audio.h" +#include "audio/ble_audio_broadcast_source.h" + +struct ble_svc_auracast_create_params { + /** Broadcast Audio Source Endpoint */ + struct ble_audio_base *base; + + /** BIG parameters */ + struct ble_iso_big_params *big_params; + + /** Broadcast name - null terminated. + * Set NULL to not include in advertising. + * Length must be in range of 4 to 32 chars. + */ + const char *name; + + /** Own address type to be used by advertising instance */ + uint8_t own_addr_type; + + /** PHY to be used for auxiliary advertisements */ + uint8_t secondary_phy; + + /** Advertising Set ID */ + uint8_t sid; + + /** Frame duration, in us */ + uint16_t frame_duration; + + /** sampling frequency, in Hz */ + uint16_t sampling_frequency; + + /** bitrate, in Hz */ + uint32_t bitrate; + + /** Program info - null terminated. + * Set NULL to not include in advertising. + */ + const char *program_info; +}; + +/** + * @brief Create Auracast Endpoint and configure advertising instance + * + * This function configures advertising instance for extended and periodic + * advertisements to be ready for Auracast broadcast. + * + * @param[in] params Pointer to a `ble_svc_auracast_create_params` + * structure that defines BIG and broadcast name. + * @param[out] auracast_instance Pointer to a advertising instance used by + * created Auracast. + * @param[in] destroy_cb Optional callback to be called when Auracast + * advertisement is destroyed. + * @param[in] args Optional arguments to be passed to `destroy_cb` + * @param[in] gap_cb GAP event callback to be associated with + * Auracast advertisement. + * + * @return 0 on success; + * A non-zero value on failure. + */ +int ble_svc_auracast_create(const struct + ble_svc_auracast_create_params *params, + uint8_t *auracast_instance, + ble_audio_broadcast_destroy_fn *destroy_cb, + void *args, + ble_gap_event_fn *gap_cb); +/** + * @brief Terminate all active advertisements and free resources associated + * with given Auracast broadcast. + * + * This function stops Auracast advertisement by disabling extended and + * periodic advertising and terminates them. After return advertising instance + * is free and must be configured again for future advertisements. + * + * @param[in] auracast_instance Pointer to a advertising instance used by + * Auracast. + * + * @return 0 on success; + * A non-zero value on failure. + */ +int ble_svc_auracast_terminate(uint8_t auracast_instance); + +/** + * @brief Start advertisements for given Auracast broadcast + * + * This function starts Auracast broadcast on by enabling extended and periodic + * advertising. + * + * @param[in] auracast_instance Pointer to a advertising instance used by + * Auracast. + * @param[in] cb Pointer to an ISO event handler. + * @param[in] cb_arg Arguments to an ISO event handler. + * + * @return 0 on success; + * A non-zero value on failure. + */ +int ble_svc_auracast_start(uint8_t auracast_instance, + ble_iso_event_fn *cb, void *cb_arg); + +/** + * @brief Stop advertisements for given Auracast broadcast + * + * This function stops Auracast broadcast by disabling extended and periodic + * advertising. Advertising instance is still configured and ready for resume. + * + * @param[in] auracast_instance Pointer to a advertising instance used by + * Auracast. + * + * @return 0 on success; + * A non-zero value on failure. + */ +int ble_svc_auracast_stop(uint8_t auracast_instance); diff --git a/nimble/transport/dialog_cmac/cmac_driver/diag/pkg.yml b/nimble/host/audio/services/auracast/pkg.yml similarity index 82% rename from nimble/transport/dialog_cmac/cmac_driver/diag/pkg.yml rename to nimble/host/audio/services/auracast/pkg.yml index 9b9ee83eb6..a2533b29da 100644 --- a/nimble/transport/dialog_cmac/cmac_driver/diag/pkg.yml +++ b/nimble/host/audio/services/auracast/pkg.yml @@ -1,4 +1,3 @@ -# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information @@ -17,12 +16,16 @@ # under the License. # -pkg.name: nimble/transport/dialog_cmac/cmac_driver/diag -pkg.description: Default diag configuration for CMAC +pkg.name: nimble/host/audio/services/auracast +pkg.description: Implements Auracast service pkg.author: "Apache Mynewt " pkg.homepage: "http://mynewt.apache.org/" pkg.keywords: - - dialog - - da1469x - - cmac -pkg.apis: dialog_cmac_diag + - ble + - bluetooth + - auracast + - nimble + +pkg.deps: + - nimble/host + - nimble/host/audio diff --git a/nimble/host/audio/services/auracast/src/ble_svc_auracast.c b/nimble/host/audio/services/auracast/src/ble_svc_auracast.c new file mode 100644 index 0000000000..b323e64bf0 --- /dev/null +++ b/nimble/host/audio/services/auracast/src/ble_svc_auracast.c @@ -0,0 +1,130 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "syscfg/syscfg.h" + +#include "host/ble_gap.h" +#include "host/ble_hs.h" +#include "audio/ble_audio_broadcast_source.h" +#include "services/auracast/ble_svc_auracast.h" + +int +ble_svc_auracast_create(const struct ble_svc_auracast_create_params *params, + uint8_t *auracast_instance, + ble_audio_broadcast_destroy_fn *destroy_cb, + void *args, ble_gap_event_fn *gap_cb) +{ + struct ble_broadcast_create_params create_params; + struct ble_gap_periodic_adv_params periodic_params = { 0 }; + struct ble_gap_ext_adv_params extended_params = { + .scannable = 0, + .connectable = 0, + .primary_phy = BLE_HCI_LE_PHY_1M, + }; + uint8_t adv_instance; + uint8_t auracast_svc_data[251] = { 0 }; + uint8_t data_offset = 1; + + uint8_t features = 0; + int rc; + + features |= params->big_params->encryption; + + if ((params->frame_duration == 10000) && + (((params->sampling_frequency == 16000) && + (params->bitrate == 32000)) || + ((params->sampling_frequency == 24000) && + (params->bitrate == 48000)))) { + features |= 0x02; + } + + if (params->sampling_frequency == 48000) { + features |= 0x04; + } + + + auracast_svc_data[data_offset] = BLE_HS_ADV_TYPE_SVC_DATA_UUID16; + data_offset++; + put_le16(&auracast_svc_data[data_offset], + BLE_BROADCAST_PUB_ANNOUNCEMENT_SVC_UUID); + data_offset += 2; + auracast_svc_data[data_offset] = features; + data_offset++; + /** Metadata */ + if (params->program_info != NULL) { + auracast_svc_data[data_offset] = strlen(params->program_info) + 2; + data_offset++; + auracast_svc_data[data_offset] = strlen(params->program_info) + 1; + data_offset++; + auracast_svc_data[data_offset] = 3; + data_offset++; + memcpy(&auracast_svc_data[data_offset], params->program_info, + strlen(params->program_info)); + data_offset += strlen(params->program_info); + } + + auracast_svc_data[0] = data_offset - 1; + + rc = ble_gap_adv_get_free_instance(&adv_instance); + if (rc) { + return BLE_HS_ENOENT; + } + + if (params->secondary_phy == BLE_HCI_LE_PHY_2M && + !MYNEWT_VAL(BLE_PHY_2M)) { + return BLE_HS_EINVAL; + } + + extended_params.own_addr_type = params->own_addr_type; + extended_params.sid = params->sid; + extended_params.secondary_phy = params->secondary_phy; + + create_params.base = params->base; + create_params.extended_params = &extended_params; + create_params.periodic_params = &periodic_params; + create_params.name = params->name; + create_params.adv_instance = adv_instance; + create_params.big_params = params->big_params; + create_params.svc_data = auracast_svc_data; + create_params.svc_data_len = data_offset; + + *auracast_instance = adv_instance; + + return ble_audio_broadcast_create(&create_params, + destroy_cb, args, gap_cb); +} + +int +ble_svc_auracast_terminate(uint8_t auracast_instance) +{ + return ble_audio_broadcast_destroy(auracast_instance); +} + +int +ble_svc_auracast_start(uint8_t auracast_instance, ble_iso_event_fn *cb, void *cb_arg) +{ + + return ble_audio_broadcast_start(auracast_instance, cb, cb_arg); +} + +int +ble_svc_auracast_stop(uint8_t auracast_instance) +{ + return ble_audio_broadcast_stop(auracast_instance); +} diff --git a/nimble/host/audio/services/bass/include/services/bass/ble_audio_svc_bass.h b/nimble/host/audio/services/bass/include/services/bass/ble_audio_svc_bass.h new file mode 100644 index 0000000000..873ac7ae62 --- /dev/null +++ b/nimble/host/audio/services/bass/include/services/bass/ble_audio_svc_bass.h @@ -0,0 +1,470 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_BLE_AUDIO_SVC_BASS_ +#define H_BLE_AUDIO_SVC_BASS_ + +#include +#include "audio/ble_audio.h" +#include "syscfg/syscfg.h" + +/** + * @file ble_audio_svc_bass.h + * + * @brief Bluetooth LE Audio BAS Service + * + * This header file provides the public API for interacting with the BASS package. + * + * @defgroup ble_audio_svc_bass Bluetooth LE Audio BASS package + * @ingroup bt_host + * @{ + * + * This package implements BASS service. Receiver states can be modified with setter functions + * or GATT writes to Control Point characteristic. Operations on Control Point like Add Source or + * Modify Source can be accepted or rejected by application by registering accept function callback. + * Accessing Control Point characteristic, or Successful modification or Receiver State will lead to + * emission of one of BLE_SVC_AUDIO_BASS events. + * + */ + +/** BLE AUDIO BASS Maximum Subgroup Number */ +#define BLE_SVC_AUDIO_BASS_SUB_NUM_MAX \ + MYNEWT_VAL(BLE_SVC_AUDIO_BASS_SUB_NUM_MAX) + +/** BLE AUDIO BASS characteristic UUID */ +#define BLE_SVC_AUDIO_BASS_UUID16 0x184F + +/** BLE AUDIO BASS Control Point characteristic UUID */ +#define BLE_SVC_AUDIO_BASS_CHR_UUID16_BASS_CP 0x2BC7 + +/** BLE AUDIO BASS Broadcast Receiver State characteristic UUID */ +#define BLE_SVC_AUDIO_BASS_CHR_UUID16_BROADCAST_RECEIVE_STATE 0x2BC8 + +/** BLE AUDIO BASS Add Source operation OP code */ +#define BLE_SVC_AUDIO_BASS_OPERATION_ADD_SOURCE 0x01 + +/** BLE AUDIO BASS Modify Source operation OP code */ +#define BLE_SVC_AUDIO_BASS_OPERATION_MODIFY_SOURCE 0x02 + +/** BLE AUDIO BASS Remove Source operation OP code */ +#define BLE_SVC_AUDIO_BASS_OPERATION_REMOVE_SOURCE 0x03 + +/** BLE AUDIO BASS Error: OP Code not supported */ +#define BLE_SVC_AUDIO_BASS_ERR_OPCODE_NOT_SUPPORTED 0x80 + +/** BLE AUDIO BASS Error: Invalid Source ID */ +#define BLE_SVC_AUDIO_BASS_ERR_INVALID_SOURCE_ID 0x81 + +/** BLE AUDIO BASS ADVERTISING SID MAX VALUE */ +#define BLE_SVC_AUDIO_BASS_ADV_SID_MAX_VAL 0x0F + +/** BLE AUDIO BASS Encryption States */ +enum ble_svc_audio_bass_big_enc { + /** BLE AUDIO BASS BIG Encryption: Not Encrypted */ + BLE_SVC_AUDIO_BASS_BIG_ENC_NOT_ENCRYPTED, + + /** BLE AUDIO BASS BIG Encryption: Broadcast Code Required */ + BLE_SVC_AUDIO_BASS_BIG_ENC_BROADCAST_CODE_REQ, + + /** BLE AUDIO BASS BIG Encryption: Decrypting */ + BLE_SVC_AUDIO_BASS_BIG_ENC_DECRYPTING, + + /** BLE AUDIO BASS BIG Encryption: Bad Code */ + BLE_SVC_AUDIO_BASS_BIG_ENC_BAD_CODE +}; + +/** BLE AUDIO BASS PA Sync parameters, valid fo Modify Source operation */ +enum ble_svc_audio_bass_pa_sync { + /** BLE AUDIO BASS PA Sync: Do not synchronize to PA */ + BLE_SVC_AUDIO_BASS_PA_SYNC_DO_NOT_SYNC, + + /** BLE AUDIO BASS PA Sync: Synchronize to PA – PAST available */ + BLE_SVC_AUDIO_BASS_PA_SYNC_SYNC_PAST_AVAILABLE, + + /** BLE AUDIO BASS PA Sync: Synchronize to PA – PAST not available */ + BLE_SVC_AUDIO_BASS_PA_SYNC_SYNC_PAST_NOT_AVAILABLE, + + /** + * BLE AUDIO BASS PA Sync: reserved for future use. + * This shall be always last value in this enum + */ + BLE_SVC_AUDIO_BASS_PA_SYNC_RFU +}; + +/** BLE AUDIO BASS Broadcast Receiver: PA Sync States */ +enum ble_svc_audio_bass_pa_sync_state { + /** BLE AUDIO BASS PA Sync State: Not synchronized to PA */ + BLE_SVC_AUDIO_BASS_PA_SYNC_STATE_NOT_SYNCED, + + /** BLE AUDIO BASS PA Sync State: SyncInfo Request */ + BLE_SVC_AUDIO_BASS_PA_SYNC_STATE_SYNC_INFO_REQ, + + /** BLE AUDIO BASS PA Sync State: Synchronized to PA */ + BLE_SVC_AUDIO_BASS_PA_SYNC_STATE_SYNCED, + + /** BLE AUDIO BASS PA Sync State: Failed to synchronize to PAA */ + BLE_SVC_AUDIO_BASS_PA_SYNC_STATE_SYNCED_FAILED, + + /** BLE AUDIO BASS PA Sync State: No PAST */ + BLE_SVC_AUDIO_BASS_PA_SYNC_STATE_NO_PAST +}; + +/** BLE AUDIO BASS Broadcast Receiver State: Subgroup entry */ +struct ble_svc_audio_bass_subgroup { + /** BLE AUDIO BASS Subgroup entry: Bis Synchronization State */ + uint32_t bis_sync_state; + + /** BLE AUDIO BASS Subgroup entry: Metadata length */ + uint8_t metadata_length; + + /** BLE AUDIO BASS Subgroup entry: Metadata */ + uint8_t *metadata; +}; + +/** BLE AUDIO BASS Broadcast Receiver State */ +struct ble_svc_audio_bass_receiver_state { + /** BLE AUDIO BASS Broadcast Receiver State: Source ID */ + uint8_t source_id; + + /** BLE AUDIO BASS Broadcast Receiver State: Source BLE Address */ + ble_addr_t source_addr; + + /** BLE AUDIO BASS Broadcast Receiver State: Source Advertising SID */ + uint8_t source_adv_sid; + + /** BLE AUDIO BASS Broadcast Receiver State: Broadcast ID */ + uint32_t broadcast_id; + + /** BLE AUDIO BASS Broadcast Receiver State: PA Sync state */ + enum ble_svc_audio_bass_pa_sync_state pa_sync_state; + + /** BLE AUDIO BASS Broadcast Receiver State: BIG Encryption */ + enum ble_svc_audio_bass_big_enc big_encryption; + + /** + * BLE AUDIO BASS Broadcast Receiver State: Bad Code. + * On GATT Read access, this value is ignored if big_encryption + * is not set to BLE_SVC_AUDIO_BASS_BIG_ENC_BAD_CODE + */ + uint8_t bad_code[BLE_AUDIO_BROADCAST_CODE_SIZE]; + + /** BLE AUDIO BASS Broadcast Receiver State: Number of subgroups */ + uint8_t num_subgroups; + + /** BLE AUDIO BASS Broadcast Receiver State: subgroup entries */ + struct ble_svc_audio_bass_subgroup + subgroups[BLE_SVC_AUDIO_BASS_SUB_NUM_MAX]; +}; + +/** BLE AUDIO BASS Broadcast Receiver State add parameters */ +struct ble_svc_audio_bass_receiver_state_add_params { + /** BLE AUDIO BASS Broadcast Receiver State: Source BLE Address */ + ble_addr_t source_addr; + + /** BLE AUDIO BASS Broadcast Receiver State: Source Advertising SID */ + uint8_t source_adv_sid; + + /** BLE AUDIO BASS Broadcast Receiver State: Broadcast ID */ + uint32_t broadcast_id; + + /** BLE AUDIO BASS Broadcast Receiver State: PA Sync state */ + enum ble_svc_audio_bass_pa_sync_state pa_sync_state; + + /** BLE AUDIO BASS Broadcast Receiver State: BIG Encryption */ + enum ble_svc_audio_bass_big_enc big_encryption; + + /** + * BLE AUDIO BASS Broadcast Receiver State: Bad Code. + * On GATT Read access, this value is ignored if big_encryption + * is not set to BLE_SVC_AUDIO_BASS_BIG_ENC_BAD_CODE + */ + const uint8_t *bad_code; + + /** BLE AUDIO BASS Broadcast Receiver State: Number of subgroups */ + uint8_t num_subgroups; + + /** BLE AUDIO BASS Broadcast Receiver State: subgroup entries */ + struct ble_svc_audio_bass_subgroup + subgroups[BLE_SVC_AUDIO_BASS_SUB_NUM_MAX]; +}; + +/** Parameters used for updating Metadata in Receiver State. */ +struct ble_svc_audio_bass_metadata_params { + /** Subgroup index */ + uint8_t subgroup_idx; + + /** Metadata length */ + uint8_t metadata_length; + + /** Metadata */ + const uint8_t *metadata; +}; + +/** Parameters used for updating Receiver State. */ +struct ble_svc_audio_bass_update_params { + /** PA Sync state */ + enum ble_svc_audio_bass_pa_sync_state pa_sync_state; + + /** BIG encryption state */ + enum ble_svc_audio_bass_big_enc big_encryption; + + /** Incorrect Bad Broadcast Code. Valid for BLE_SVC_AUDIO_BASS_BIG_ENC_BAD_CODE */ + const uint8_t *bad_code; + + /** BLE AUDIO BASS Broadcast Receiver State: Number of subgroups */ + uint8_t num_subgroups; + + /** BLE AUDIO BASS Broadcast Receiver State: subgroup entries */ + struct ble_svc_audio_bass_subgroup + subgroups[BLE_SVC_AUDIO_BASS_SUB_NUM_MAX]; +}; + +/** + * Structure describing operation attempted by write on + * BASS Control Point characteristic + */ +struct ble_svc_audio_bass_operation { + /** + * Indicates the type of BASS operation that occurred. This is one of the + * ble_svc_audio_bass_operation codes. + */ + uint8_t op; + + /** Connection handle for which the operation was performed */ + uint16_t conn_handle; + + /** + * A discriminated union containing additional details concerning the BASS Control Point + * event. The 'type' field indicates which member of the union is valid. + */ + union { + /** + * Represents Add Source operation. Valid for the following event + * types: + * o BLE_SVC_AUDIO_BASS_OPERATION_ADD_SOURCE + * Application can accept or reject Add Source operation. If no application callback is set + * and free Receive State characteristic exists operation is automatically accepted. + * If application callback exists and returns 0 operation is accepted. + * Otherwise, operation is rejected. + * If operation is accepted by application, it may select receiver state to be filled. + * If application doesnt select characteristic, BASS Server falls back + * to searching free one. If none is found, operation is rejected. + * After Add Source operation is accepted, BLE_AUDIO_EVENT is emitted. + */ + struct { + /** Source ID */ + uint8_t source_id; + + /** Advertiser Address */ + ble_addr_t adv_addr; + + /** Advertising SID */ + uint8_t adv_sid; + + /** Broadcast ID */ + uint32_t broadcast_id : 24; + + /** PA Sync */ + enum ble_svc_audio_bass_pa_sync pa_sync; + + /** PA Interval */ + uint16_t pa_interval; + + /** Number of subgroups */ + uint8_t num_subgroups; + + /** Subgroup entries */ + struct ble_svc_audio_bass_subgroup + subgroups[BLE_SVC_AUDIO_BASS_SUB_NUM_MAX]; + + /** + * Pointer to provide source ID to be swapped or NULL. + * + * Valid only if all other receive states are used. + * + * If there are insufficient resources to handle the operation, + * the application is requested to provide source ID to be + * removed once accepted. + */ + uint8_t *out_source_id_to_swap; + } add_source; + + /** + * Represents Modify Source operation. Valid for the following event + * types: + * o BLE_SVC_AUDIO_BASS_OPERATION_MODIFY_SOURCE + * Application can accept or reject Add Source operation. + * If no application callback is set + * or application callback returns 0 operation is automatically accepted. + * If application callback returns non-zero value operation is rejected. + */ + struct { + /** Source ID */ + uint8_t source_id; + + /** PA Sync */ + enum ble_svc_audio_bass_pa_sync pa_sync; + + /** PA Interval */ + uint16_t pa_interval; + + /** Number of subgroups */ + uint16_t num_subgroups; + + /** Subgroup entries */ + struct ble_svc_audio_bass_subgroup + subgroups[BLE_SVC_AUDIO_BASS_SUB_NUM_MAX]; + } modify_source; + + /** + * Represents Remove Source operation. Valid for the following event + * types: + * o BLE_SVC_AUDIO_BASS_OPERATION_REMOVE_SOURCE + */ + struct { + /** Source ID */ + uint8_t source_id; + } remove_source; + }; +}; + +/** + * Prototype of Accept Function callback for BASS Control Point operations. + * This function shall return 0 if operation is accepted, + * and error code if rejected. + */ +typedef int ble_svc_audio_bass_accept_fn(struct ble_svc_audio_bass_operation + *operation, void *arg); + +/** + * @brief Set Accept Function callback. + * + * Set Accept Function callback that will be used to accept or reject + * operations queried on BASS Control Point characteristic. If no function + * is registered, operations are accepted by default. Only one Accept + * Function can be registered at once. + * + * @param[in] fn ble_svc_audio_bass_accept_fn + * to be registered. + * @param[in] arg Optional ble_svc_audio_bass_accept_fn + * argument. + * + * @return 0 on success; + * A non-zero value on failure. + */ +int +ble_svc_audio_bass_accept_fn_set(ble_svc_audio_bass_accept_fn *fn, void *arg); + +/** + * @brief Add Broadcast Receive State. + * + * Add new Broadcast Receive State to BASS. + * + * @param[in] params Parameters of new + * Broadcast Receive State. + * @param[out] source_id Source ID assigned by BASS to new + * Broadcast Receive State + * + * @return 0 on success; + * A non-zero value on failure. + */ +int +ble_svc_audio_bass_receive_state_add(const struct ble_svc_audio_bass_receiver_state_add_params *params, + uint8_t *source_id); + +/** + * @brief Remove Broadcast Receive State. + * + * Remove Broadcast Receive State from BASS. + * + * @param[in] source_id Source ID of Broadcast Receive State + * to be removed + * + * @return 0 on success; + * A non-zero value on failure. + */ +int +ble_svc_audio_bass_receive_state_remove(uint8_t source_id); + +/** + * @brief Update Broadcast Receive State metadata. + * + * Set Broadcast Receive State metadata to new value. + * + * @param[in] params Parameter structure with new metadata. + * @param[in] source_id Source ID of Broadcast Receive State + * + * @return 0 on success; + * A non-zero value on failure. + */ +int +ble_svc_audio_bass_update_metadata(const struct ble_svc_audio_bass_metadata_params *params, + uint8_t source_id); + +/** + * @brief Update Broadcast Receive State. + * + * Set Broadcast Receive State to new value. + * + * @param[in] params Parameter structure with new + * Receive State. + * @param[in] source_id Source ID of Broadcast Receive State + * + * @return 0 on success; + * A non-zero value on failure. + */ +int +ble_svc_audio_bass_receive_state_update(const struct + ble_svc_audio_bass_update_params *params, + uint8_t source_id); + +/** + * @brief Find Broadcast Receive State by Source ID. + * + * Get Broadcast Receive State characteristic value by Source ID. + * + * @param[in] source_id Source ID of Broadcast Receive State + * @param[out] state Pointer to Broadcast Receive State + * characteristic value + * + * @return 0 on success; + * A non-zero value on failure. + */ +int +ble_svc_audio_bass_receiver_state_get(uint8_t source_id, + struct ble_svc_audio_bass_receiver_state **state); + +/** + * @brief Get the source ID for given Receive State index. + * + * @param[in] index Receive State index. + * @param[in,out] source_id Pointer to the variable where the + * Source ID will be stored. + * + * @return 0 on success; + * A non-zero value on failure. + */ +int +ble_svc_audio_bass_source_id_get(uint8_t index, uint8_t *source_id); + +/** + * @} + */ + +#endif /* H_BLE_AUDIO_SVC_BASS_ */ diff --git a/nimble/host/audio/services/bass/pkg.yml b/nimble/host/audio/services/bass/pkg.yml new file mode 100644 index 0000000000..1546b2640e --- /dev/null +++ b/nimble/host/audio/services/bass/pkg.yml @@ -0,0 +1,33 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +pkg.name: nimble/host/audio/services/bass +pkg.description: Broadcast Audio Scan Service +pkg.author: "Apache Mynewt " +pkg.homepage: "http://mynewt.apache.org/" +pkg.keywords: + - ble + - bluetooth + - bass + - nimble + +pkg.deps: + - nimble/host + - nimble/host/services/gatt + +pkg.init: + ble_svc_audio_bass_init: 'MYNEWT_VAL(BLE_SVC_AUDIO_BASS_SYSINIT_STAGE)' diff --git a/nimble/host/audio/services/bass/src/ble_audio_svc_bass.c b/nimble/host/audio/services/bass/src/ble_audio_svc_bass.c new file mode 100644 index 0000000000..61c03f8c36 --- /dev/null +++ b/nimble/host/audio/services/bass/src/ble_audio_svc_bass.c @@ -0,0 +1,948 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "host/ble_hs.h" +#include "host/ble_gatt.h" +#include "../../host/src/ble_gatt_priv.h" +#include "../../host/src/ble_att_priv.h" +#include "services/bass/ble_audio_svc_bass.h" +#include "../../../src/ble_audio_priv.h" + +#define BLE_SVC_AUDIO_BASS_CHR_LEN_UNLIMITED (-1) +#define BLE_SVC_AUDIO_BASS_RECEIVE_STATE_SRC_ID_NONE 0xFF + +const ble_uuid_t * bass_receive_state_uuid = + BLE_UUID16_DECLARE(BLE_SVC_AUDIO_BASS_CHR_UUID16_BROADCAST_RECEIVE_STATE); +const ble_uuid_t * bass_cp_uuid = + BLE_UUID16_DECLARE(BLE_SVC_AUDIO_BASS_CHR_UUID16_BASS_CP); + +enum ble_svc_audio_bass_ctrl_point_op_code { + BLE_AUDIO_SVC_BASS_REMOTE_SCAN_STOPPED, + BLE_AUDIO_SVC_BASS_REMOTE_SCAN_STARTED, + BLE_AUDIO_SVC_BASS_ADD_SOURCE, + BLE_AUDIO_SVC_BASS_MODIFY_SOURCE, + BLE_AUDIO_SVC_BASS_SET_BROADCAST_CODE, + BLE_AUDIO_SVC_BASS_REMOVE_SOURCE +}; + +typedef int ble_svc_audio_bass_ctrl_point_handler_cb(uint8_t *data, + uint16_t data_len, + uint16_t conn_handle); + +static struct ble_svc_audio_bass_ctrl_point_ev { + ble_svc_audio_bass_accept_fn *ctrl_point_ev_fn; + void *arg; +} accept_fn; + +struct ble_svc_audio_bass_rcv_state_entry { + uint8_t source_id; + uint16_t chr_val; + struct ble_svc_audio_bass_receiver_state state; +}; + +static struct ble_svc_audio_bass_rcv_state_entry + receiver_states[MYNEWT_VAL(BLE_SVC_AUDIO_BASS_RECEIVE_STATE_MAX)] = { + [0 ... MYNEWT_VAL(BLE_SVC_AUDIO_BASS_RECEIVE_STATE_MAX) - 1] = { + .source_id = BLE_SVC_AUDIO_BASS_RECEIVE_STATE_SRC_ID_NONE + } +}; + +static struct os_mempool ble_audio_svc_bass_metadata_pool; +static os_membuf_t ble_audio_svc_bass_metadata_mem[ + OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_SVC_AUDIO_BASS_RECEIVE_STATE_MAX) * + BLE_SVC_AUDIO_BASS_SUB_NUM_MAX, + MYNEWT_VAL(BLE_SVC_AUDIO_BASS_METADATA_MAX_SZ))]; + +static int +ble_svc_audio_bass_remote_scan_stopped(uint8_t *data, uint16_t data_len, uint16_t conn_handle); +static int +ble_svc_audio_bass_remote_scan_started(uint8_t *data, uint16_t data_len, uint16_t conn_handle); +static int +ble_svc_audio_bass_add_source(uint8_t *data, uint16_t data_len, uint16_t conn_handle); +static int +ble_svc_audio_bass_modify_source(uint8_t *data, uint16_t data_len, uint16_t conn_handle); +static int +ble_svc_audio_bass_set_broadcast_code(uint8_t *data, uint16_t data_len, uint16_t conn_handle); +static int +ble_svc_audio_bass_remove_source(uint8_t *data, uint16_t data_len, uint16_t conn_handle); + +static int +ble_svc_audio_bass_ctrl_point_write_access(struct ble_gatt_access_ctxt *ctxt, uint16_t conn_handle); +static int +ble_svc_audio_bass_rcv_state_read_access(struct ble_gatt_access_ctxt *ctxt, void *arg); + +static struct ble_svc_audio_bass_ctrl_point_handler { + uint8_t op_code; + int16_t length_min; + int16_t length_max; + ble_svc_audio_bass_ctrl_point_handler_cb *handler_cb; +} ble_svc_audio_bass_ctrl_point_handlers[] = { + { + .op_code = BLE_AUDIO_SVC_BASS_REMOTE_SCAN_STOPPED, + .length_min = 0, + .length_max = 0, + .handler_cb = ble_svc_audio_bass_remote_scan_stopped + }, { + .op_code = BLE_AUDIO_SVC_BASS_REMOTE_SCAN_STARTED, + .length_min = 0, + .length_max = 0, + .handler_cb = ble_svc_audio_bass_remote_scan_started + }, { + .op_code = BLE_AUDIO_SVC_BASS_ADD_SOURCE, + .length_min = 15, + .length_max = BLE_SVC_AUDIO_BASS_CHR_LEN_UNLIMITED, + .handler_cb = ble_svc_audio_bass_add_source + }, { + .op_code = BLE_AUDIO_SVC_BASS_MODIFY_SOURCE, + .length_min = 5, + .length_max = BLE_SVC_AUDIO_BASS_CHR_LEN_UNLIMITED, + .handler_cb = ble_svc_audio_bass_modify_source + }, { + .op_code = BLE_AUDIO_SVC_BASS_SET_BROADCAST_CODE, + .length_min = 17, + .length_max = 17, + .handler_cb = ble_svc_audio_bass_set_broadcast_code + }, { + .op_code = BLE_AUDIO_SVC_BASS_REMOVE_SOURCE, + .length_min = 1, + .length_max = 1, + .handler_cb = ble_svc_audio_bass_remove_source + } +}; + +static struct ble_gatt_chr_def ble_svc_audio_bass_chrs[MYNEWT_VAL(BLE_SVC_AUDIO_BASS_RECEIVE_STATE_MAX) + 2]; + +static const struct ble_gatt_svc_def ble_svc_audio_bass_defs[MYNEWT_VAL(BLE_SVC_AUDIO_BASS_RECEIVE_STATE_MAX) + 2] = { + { /*** Service: Published Audio Capabilities Service (bass) */ + .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid = BLE_UUID16_DECLARE(BLE_SVC_AUDIO_BASS_UUID16), + .characteristics = ble_svc_audio_bass_chrs, + }, + { + 0, /* No more services. */ + }, +}; + +static uint8_t free_source_id = 0; + +static int +ble_svc_audio_bass_access(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, void *arg) +{ + uint16_t uuid16 = ble_uuid_u16(ctxt->chr->uuid); + int rc; + + switch (uuid16) { + case BLE_SVC_AUDIO_BASS_CHR_UUID16_BASS_CP: + if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) { + rc = ble_svc_audio_bass_ctrl_point_write_access(ctxt, conn_handle); + } else { + assert(0); + } + return rc; + case BLE_SVC_AUDIO_BASS_CHR_UUID16_BROADCAST_RECEIVE_STATE: + if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) { + rc = ble_svc_audio_bass_rcv_state_read_access(ctxt, arg); + } else { + assert(0); + } + return rc; + default: + assert(0); + } +} + +static bool +ble_svc_audio_bass_source_id_free(uint8_t source_id) +{ + int i; + for (i = 0; i < MYNEWT_VAL(BLE_SVC_AUDIO_BASS_RECEIVE_STATE_MAX); i++) { + if (receiver_states[i].source_id == source_id) { + return false; + } + } + + return true; +}; + +static uint8_t +ble_svc_audio_bass_get_new_source_id(void) +{ + /** Wrap around after all Source IDs were used */ + if (free_source_id == BLE_SVC_AUDIO_BASS_RECEIVE_STATE_SRC_ID_NONE) { + free_source_id = 0; + } + + while (!ble_svc_audio_bass_source_id_free(free_source_id)) { + free_source_id++; + } + + return free_source_id; +} + +static int +ble_svc_audio_bass_receive_state_notify(struct ble_svc_audio_bass_rcv_state_entry *state) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(ble_svc_audio_bass_chrs); i++) { + if (ble_svc_audio_bass_chrs[i].arg == state) { + ble_gatts_chr_updated(*ble_svc_audio_bass_chrs[i].val_handle); + return 0; + } + } + + return BLE_HS_ENOENT; +} + +static int +ble_svc_audio_bass_receive_state_find_by_source_id(struct ble_svc_audio_bass_rcv_state_entry **out_state, + uint8_t source_id) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(receiver_states); i++) { + if (receiver_states[i].source_id == source_id) { + *out_state = &receiver_states[i]; + return 0; + } + } + + return BLE_HS_ENOMEM; +} + +int +ble_svc_audio_bass_receive_state_find_free(struct ble_svc_audio_bass_rcv_state_entry **out_state) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(receiver_states); i++) { + if (receiver_states[i].source_id == BLE_SVC_AUDIO_BASS_RECEIVE_STATE_SRC_ID_NONE) { + *out_state = &receiver_states[i]; + return 0; + } + } + + return BLE_HS_ENOMEM; +} + +static void +ble_svc_audio_bass_receive_state_free(struct ble_svc_audio_bass_rcv_state_entry *state) +{ + memset(&state->state, 0, sizeof(state->state)); + state->source_id = BLE_SVC_AUDIO_BASS_RECEIVE_STATE_SRC_ID_NONE; + /* state->chr_val shall not be cleared */ +} + +static int +ble_svc_audio_bass_remote_scan_stopped(uint8_t *data, uint16_t data_len, uint16_t conn_handle) +{ + if (data_len > 1) { + return BLE_ATT_ERR_WRITE_REQ_REJECTED; + } + + struct ble_audio_event ev = { + .type = BLE_AUDIO_EVENT_BASS_REMOTE_SCAN_STOPPED + }; + + ev.remote_scan_stopped.conn_handle = conn_handle; + ble_audio_event_listener_call(&ev); + + return 0; +} + +static int +ble_svc_audio_bass_remote_scan_started(uint8_t *data, uint16_t data_len, uint16_t conn_handle) +{ + if (data_len > 1) { + return BLE_ATT_ERR_WRITE_REQ_REJECTED; + } + + struct ble_audio_event ev = { + .type = BLE_AUDIO_EVENT_BASS_REMOTE_SCAN_STARTED + }; + + ev.remote_scan_started.conn_handle = conn_handle; + ble_audio_event_listener_call(&ev); + + return 0; +} + +static int +check_bis_sync(uint16_t num_subgroups, struct ble_svc_audio_bass_subgroup *subgroups) +{ + uint32_t bis_sync_mask = 0; + int i; + int j; + + for (i = 0; i < num_subgroups; i++) { + if (subgroups[i].bis_sync_state != 0xFFFFFFFF) { + for (j = 0; j < num_subgroups; j++) { + if (subgroups[i].bis_sync_state & bis_sync_mask) { + return BLE_HS_EINVAL; + } + + bis_sync_mask |= subgroups[i].bis_sync_state; + } + } + } + + return 0; +} + +static int +ble_svc_audio_bass_add_source(uint8_t *data, uint16_t data_len, uint16_t conn_handle) +{ + struct ble_audio_event ev = { + .type = BLE_AUDIO_EVENT_BASS_OPERATION_STATUS, + .bass_operation_status = { + .op = BLE_AUDIO_EVENT_BASS_SOURCE_ADDED, + .status = 0 + } + }; + struct ble_svc_audio_bass_operation operation; + struct ble_svc_audio_bass_rcv_state_entry *rcv_state = NULL; + uint8_t offset = 0; + uint8_t *metadata_ptr; + uint8_t source_id_new; + uint8_t source_id_to_remove = BLE_SVC_AUDIO_BASS_RECEIVE_STATE_SRC_ID_NONE; + int rc = 0; + int i; + + memset(&operation, 0, sizeof(operation)); + + operation.op = BLE_SVC_AUDIO_BASS_OPERATION_ADD_SOURCE; + operation.conn_handle = conn_handle; + + operation.add_source.adv_addr.type = data[offset++]; + + if (operation.add_source.adv_addr.type != BLE_ADDR_PUBLIC && + operation.add_source.adv_addr.type != BLE_ADDR_RANDOM) { + rc = BLE_HS_EINVAL; + ev.bass_operation_status.status = BLE_HS_EINVAL; + goto done; + } + memcpy(operation.add_source.adv_addr.val, &data[offset], 6); + offset += 6; + operation.add_source.adv_sid = data[offset++]; + if (operation.add_source.adv_sid > BLE_SVC_AUDIO_BASS_ADV_SID_MAX_VAL) { + rc = BLE_HS_EINVAL; + ev.bass_operation_status.status = BLE_HS_EINVAL; + goto done; + } + + operation.add_source.broadcast_id = get_le24(&data[offset]); + offset += 3; + operation.add_source.pa_sync = data[offset++]; + if (operation.add_source.pa_sync >= BLE_SVC_AUDIO_BASS_PA_SYNC_RFU) { + rc = BLE_HS_EINVAL; + ev.bass_operation_status.status = BLE_HS_EINVAL; + goto done; + } + + operation.add_source.pa_interval = get_le16(&data[offset]); + offset += 2; + operation.add_source.num_subgroups = data[offset++]; + + /** + * Previous data was checked for it's size in `ble_svc_audio_bass_ctrl_point_write_access`. + * As bis_sync_state array may be of variable length, we need to check it separately + */ + data_len -= offset; + for (i = 0; i < operation.add_source.num_subgroups; i++) { + if (data_len < sizeof(uint32_t)) { + rc = BLE_ATT_ERR_WRITE_REQ_REJECTED; + ev.bass_operation_status.status = BLE_HS_EREJECT; + goto done; + } + operation.add_source.subgroups[i].bis_sync_state = get_le32(&data[offset]); + offset += 4; + operation.add_source.subgroups[i].metadata_length = data[offset++]; + data_len -= 5; + if (data_len < operation.add_source.subgroups[i].metadata_length) { + rc = BLE_ATT_ERR_WRITE_REQ_REJECTED; + ev.bass_operation_status.status = BLE_HS_EREJECT; + goto done; + } + operation.add_source.subgroups[i].metadata = &data[offset]; + offset += operation.add_source.subgroups[i].metadata_length; + data_len -= operation.add_source.subgroups[i].metadata_length; + + if (check_bis_sync(operation.add_source.num_subgroups, + operation.add_source.subgroups)) { + rc = BLE_HS_EINVAL; + ev.bass_operation_status.status = BLE_HS_EREJECT; + goto done; + } + } + + source_id_new = ble_svc_audio_bass_get_new_source_id(); + operation.add_source.source_id = source_id_new; + + ble_svc_audio_bass_receive_state_find_free(&rcv_state); + if (rcv_state == NULL) { + operation.add_source.out_source_id_to_swap = &source_id_to_remove; + } else { + operation.add_source.out_source_id_to_swap = NULL; + rcv_state->source_id = operation.add_source.source_id; + } + + if (accept_fn.ctrl_point_ev_fn) { + rc = accept_fn.ctrl_point_ev_fn(&operation, accept_fn.arg); + if (rc != 0) { + if (rcv_state != NULL) { + ble_svc_audio_bass_receive_state_free(rcv_state); + } + rc = BLE_ATT_ERR_WRITE_REQ_REJECTED; + ev.bass_operation_status.status = BLE_HS_EREJECT; + goto done; + } + } + + if (rcv_state == NULL) { + if (source_id_to_remove != BLE_SVC_AUDIO_BASS_RECEIVE_STATE_SRC_ID_NONE) { + ble_svc_audio_bass_receive_state_find_by_source_id(&rcv_state, source_id_to_remove); + if (rcv_state == NULL) { + rc = BLE_HS_EAPP; + ev.bass_operation_status.status = BLE_HS_EAPP; + goto done; + } + + /* Swap Source ID */ + rcv_state->source_id = operation.add_source.source_id; + } else { + rc = BLE_HS_ENOMEM; + ev.bass_operation_status.status = BLE_HS_ENOMEM; + goto done; + } + } else { + rcv_state->source_id = operation.add_source.source_id; + } + + ev.bass_operation_status.source_id = rcv_state->source_id; + rcv_state->state.source_addr.type = operation.add_source.adv_addr.type; + memcpy(&rcv_state->state.source_addr.val, operation.add_source.adv_addr.val, 6); + rcv_state->state.source_adv_sid = operation.add_source.adv_sid; + rcv_state->state.broadcast_id = operation.add_source.broadcast_id; + rcv_state->state.num_subgroups = operation.add_source.num_subgroups; + + for (i = 0; i < operation.add_source.num_subgroups; i++) { + metadata_ptr = os_memblock_get(&ble_audio_svc_bass_metadata_pool); + if (!metadata_ptr) { + rc = BLE_HS_ENOMEM; + ev.bass_operation_status.status = BLE_HS_ENOMEM; + goto done; + } + rcv_state->state.subgroups[i].metadata_length = operation.add_source.subgroups[i].metadata_length; + memcpy(metadata_ptr, operation.add_source.subgroups[i].metadata, + min(operation.add_source.subgroups[i].metadata_length, + MYNEWT_VAL(BLE_SVC_AUDIO_BASS_METADATA_MAX_SZ))); + + rcv_state->state.subgroups[i].metadata = metadata_ptr; + } + +done: + if (!rc) { + rc = ble_svc_audio_bass_receive_state_notify(rcv_state); + ev.bass_operation_status.status = rc; + } + + ble_audio_event_listener_call(&ev); + + return rc; +} + +static int +ble_svc_audio_bass_modify_source(uint8_t *data, uint16_t data_len, uint16_t conn_handle) +{ + struct ble_svc_audio_bass_operation operation; + struct ble_svc_audio_bass_rcv_state_entry *rcv_state = NULL; + struct ble_audio_event ev = { + .type = BLE_AUDIO_EVENT_BASS_OPERATION_STATUS, + .bass_operation_status = { + .op = BLE_AUDIO_EVENT_BASS_SOURCE_MODIFIED, + .status = 0 + } + }; + uint8_t *metadata_ptr; + uint8_t offset = 0; + int rc = 0; + int i; + + memset(&operation, 0, sizeof(operation)); + + operation.op = BLE_SVC_AUDIO_BASS_OPERATION_MODIFY_SOURCE; + operation.conn_handle = conn_handle; + + operation.modify_source.source_id = data[offset++]; + + ble_svc_audio_bass_receive_state_find_by_source_id(&rcv_state, + operation.modify_source.source_id); + if (rcv_state == NULL) { + rc = BLE_SVC_AUDIO_BASS_ERR_INVALID_SOURCE_ID; + ev.bass_operation_status.status = BLE_HS_EINVAL; + goto done; + } + + operation.modify_source.pa_sync = data[offset++]; + if (operation.modify_source.pa_sync >= BLE_SVC_AUDIO_BASS_PA_SYNC_RFU) { + rc = BLE_HS_EINVAL; + ev.bass_operation_status.status = BLE_HS_EREJECT; + goto done; + } + + operation.modify_source.pa_interval = get_le16(&data[offset]); + offset += 2; + operation.modify_source.num_subgroups = get_le16(&data[offset]); + offset += 2; + + data_len -= offset; + if (data_len < operation.modify_source.num_subgroups * sizeof(uint32_t)) { + rc = BLE_ATT_ERR_WRITE_REQ_REJECTED; + ev.bass_operation_status.status = BLE_HS_EREJECT; + goto done; + } + + for (i = 0; i < operation.modify_source.num_subgroups; i++) { + operation.modify_source.subgroups[i].bis_sync_state = get_le32(&data[offset]); + offset += 4; + operation.modify_source.subgroups[i].metadata_length = data[offset++]; + data_len -= 5; + if (data_len < operation.modify_source.subgroups[i].metadata_length) { + rc = BLE_ATT_ERR_WRITE_REQ_REJECTED; + ev.bass_operation_status.status = BLE_HS_EREJECT; + goto done; + } + operation.modify_source.subgroups[i].metadata = &data[offset]; + offset += operation.modify_source.subgroups[i].metadata_length; + data_len -= operation.modify_source.subgroups[i].metadata_length; + } + + if (check_bis_sync(operation.modify_source.num_subgroups, + operation.modify_source.subgroups)) { + rc = BLE_HS_EINVAL; + ev.bass_operation_status.status = BLE_HS_EREJECT; + goto done; + } + + for (i = 0; i < operation.modify_source.num_subgroups; i++) { + metadata_ptr = os_memblock_get(&ble_audio_svc_bass_metadata_pool); + if (metadata_ptr == NULL) { + rc = BLE_HS_ENOMEM; + ev.bass_operation_status.status = BLE_HS_ENOMEM; + goto done; + } + memcpy(metadata_ptr, operation.modify_source.subgroups[i].metadata, + min(operation.modify_source.subgroups[i].metadata_length, + MYNEWT_VAL(BLE_SVC_AUDIO_BASS_METADATA_MAX_SZ))); + } + + if (accept_fn.ctrl_point_ev_fn) { + rc = accept_fn.ctrl_point_ev_fn(&operation, accept_fn.arg); + if (rc != 0) { + rc = BLE_ATT_ERR_WRITE_REQ_REJECTED; + ev.bass_operation_status.status = BLE_HS_EREJECT; + goto done; + } + } + + ev.bass_operation_status.source_id = operation.modify_source.source_id; + +done: + if (!rc) { + rc = ble_svc_audio_bass_receive_state_notify(rcv_state); + ev.bass_operation_status.status = rc; + } + + ble_audio_event_listener_call(&ev); + + return rc; +} + +static int +ble_svc_audio_bass_set_broadcast_code(uint8_t *data, uint16_t data_len, uint16_t conn_handle) +{ + struct ble_svc_audio_bass_rcv_state_entry *rcv_state = NULL; + struct ble_audio_event ev = { + .type = BLE_AUDIO_EVENT_BASS_BROADCAST_CODE_SET, + }; + + ev.bass_set_broadcast_code.source_id = data[0]; + + ble_svc_audio_bass_receive_state_find_by_source_id(&rcv_state, + ev.bass_set_broadcast_code.source_id); + if (rcv_state == NULL) { + return BLE_SVC_AUDIO_BASS_ERR_INVALID_SOURCE_ID; + } + + memcpy(ev.bass_set_broadcast_code.broadcast_code, &data[1], BLE_AUDIO_BROADCAST_CODE_SIZE); + + ble_audio_event_listener_call(&ev); + + return 0; +} + +static int +ble_svc_audio_bass_remove_source(uint8_t *data, uint16_t data_len, uint16_t conn_handle) +{ + struct ble_audio_event ev = { + .type = BLE_AUDIO_EVENT_BASS_OPERATION_STATUS, + .bass_operation_status = { + .op = BLE_AUDIO_EVENT_BASS_SOURCE_REMOVED, + .status = 0 + } + }; + struct ble_svc_audio_bass_rcv_state_entry *rcv_state = NULL; + struct ble_svc_audio_bass_operation operation; + int rc = 0; + int i; + + ev.bass_set_broadcast_code.source_id = data[0]; + operation.op = BLE_SVC_AUDIO_BASS_OPERATION_REMOVE_SOURCE; + + ble_svc_audio_bass_receive_state_find_by_source_id(&rcv_state, + ev.bass_operation_status.source_id); + if (rcv_state == NULL) { + rc = BLE_SVC_AUDIO_BASS_ERR_INVALID_SOURCE_ID; + ev.bass_operation_status.status = BLE_HS_ENOENT; + goto done; + } + + operation.remove_source.source_id = ev.bass_operation_status.source_id; + operation.conn_handle = conn_handle; + if (accept_fn.ctrl_point_ev_fn) { + rc = accept_fn.ctrl_point_ev_fn(&operation, accept_fn.arg); + if (rc != 0) { + rc = BLE_HS_EREJECT; + ev.bass_operation_status.status = BLE_HS_EREJECT; + goto done; + } + } + + for (i = 0; i < rcv_state->state.num_subgroups; i++) { + os_memblock_put(&ble_audio_svc_bass_metadata_pool, rcv_state->state.subgroups[i].metadata); + } + + ble_svc_audio_bass_receive_state_free(rcv_state); + +done: + if (!rc) { + rc = ble_svc_audio_bass_receive_state_notify(rcv_state); + ev.bass_operation_status.status = rc; + } + + ble_audio_event_listener_call(&ev); + + return rc; +} + +static struct ble_svc_audio_bass_ctrl_point_handler * +ble_svc_audio_bass_find_handler(uint8_t opcode) +{ + int i; + + for (i = 0; i < sizeof(ble_svc_audio_bass_ctrl_point_handlers); i++) { + if (ble_svc_audio_bass_ctrl_point_handlers[i].op_code == opcode) { + return &ble_svc_audio_bass_ctrl_point_handlers[i]; + } + } + + return NULL; +} + +static int +ble_svc_audio_bass_ctrl_point_write_access(struct ble_gatt_access_ctxt *ctxt, uint16_t conn_handle) +{ + uint8_t opcode; + struct ble_svc_audio_bass_ctrl_point_handler *handler; + + ctxt->om = os_mbuf_pullup(ctxt->om, OS_MBUF_PKTLEN(ctxt->om)); + if (!ctxt->om) { + return BLE_ATT_ERR_UNLIKELY; + } + + opcode = ctxt->om->om_data[0]; + os_mbuf_adj(ctxt->om, sizeof(opcode)); + + handler = ble_svc_audio_bass_find_handler(opcode); + + if (handler == NULL) { + return BLE_SVC_AUDIO_BASS_ERR_OPCODE_NOT_SUPPORTED; + } + + if ((handler->length_min != BLE_SVC_AUDIO_BASS_CHR_LEN_UNLIMITED && (ctxt->om->om_len < handler->length_min)) || + (handler->length_max != BLE_SVC_AUDIO_BASS_CHR_LEN_UNLIMITED && (ctxt->om->om_len > handler->length_max))) { + return BLE_ATT_ERR_WRITE_REQ_REJECTED; + } + + return handler->handler_cb(ctxt->om->om_data, OS_MBUF_PKTLEN(ctxt->om), conn_handle); +} + +static int +ble_svc_audio_bass_rcv_state_read_access(struct ble_gatt_access_ctxt *ctxt, void *arg) +{ + struct ble_svc_audio_bass_rcv_state_entry *state = arg; + uint8_t *buf; + int i; + + /* Nothing set, return empty buffer */ + if (state->source_id == BLE_SVC_AUDIO_BASS_RECEIVE_STATE_SRC_ID_NONE) { + return 0; + } + + os_mbuf_append(ctxt->om, &state->source_id, 1); + os_mbuf_append(ctxt->om, &state->state.source_addr.type, 1); + os_mbuf_append(ctxt->om, &state->state.source_addr.val, 6); + os_mbuf_append(ctxt->om, &state->state.source_adv_sid, 1); + buf = os_mbuf_extend(ctxt->om, 3); + if (buf == NULL) { + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + + put_le24(buf, state->state.broadcast_id); + os_mbuf_append(ctxt->om, &state->state.pa_sync_state, 1); + os_mbuf_append(ctxt->om, &state->state.big_encryption, 1); + + if (state->state.big_encryption == BLE_SVC_AUDIO_BASS_BIG_ENC_BAD_CODE) { + os_mbuf_append(ctxt->om, &state->state.bad_code, BLE_AUDIO_BROADCAST_CODE_SIZE); + } + + os_mbuf_append(ctxt->om, &state->state.num_subgroups, 1); + + for (i = 0; i < state->state.num_subgroups; i++) { + buf = os_mbuf_extend(ctxt->om, 4); + if (buf == NULL) { + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + + put_le32(buf, state->state.subgroups[i].bis_sync_state); + os_mbuf_append(ctxt->om, &state->state.subgroups[i].metadata_length, 1); + os_mbuf_append(ctxt->om, state->state.subgroups[i].metadata, + state->state.subgroups[i].metadata_length); + } + + return 0; +} + +int +ble_svc_audio_bass_accept_fn_set(ble_svc_audio_bass_accept_fn *fn, void *arg) +{ + if (accept_fn.ctrl_point_ev_fn) { + return BLE_HS_EALREADY; + } + + accept_fn.ctrl_point_ev_fn = fn; + accept_fn.arg = arg; + return 0; +} + +int +ble_svc_audio_bass_receive_state_add(const struct ble_svc_audio_bass_receiver_state_add_params *params, + uint8_t *source_id) +{ + struct ble_svc_audio_bass_rcv_state_entry *rcv_state; + int i; + int rc; + + rc = ble_svc_audio_bass_receive_state_find_free(&rcv_state); + if (rc) { + return rc; + } + + rcv_state->source_id = ble_svc_audio_bass_get_new_source_id(); + rcv_state->state.source_addr = params->source_addr; + rcv_state->state.source_adv_sid = params->source_adv_sid; + rcv_state->state.broadcast_id = params->broadcast_id; + rcv_state->state.pa_sync_state = params->pa_sync_state; + rcv_state->state.big_encryption = params->big_encryption; + if (rcv_state->state.big_encryption == + BLE_SVC_AUDIO_BASS_BIG_ENC_BAD_CODE) { + memcpy(&rcv_state->state.bad_code, params->bad_code, + BLE_AUDIO_BROADCAST_CODE_SIZE); + } + rcv_state->state.num_subgroups = params->num_subgroups; + + for (i = 0; i < rcv_state->state.num_subgroups; i++) { + rcv_state->state.subgroups[i].metadata = + os_memblock_get(&ble_audio_svc_bass_metadata_pool); + + if (!rcv_state->state.subgroups[i].metadata) { + return 0; + } + + rcv_state->state.subgroups[i].metadata_length = + min(params->subgroups[i].metadata_length, + ble_audio_svc_bass_metadata_pool.mp_block_size); + memcpy(rcv_state->state.subgroups[i].metadata, params->subgroups[i].metadata, + rcv_state->state.subgroups[i].metadata_length); + } + + *source_id = rcv_state->source_id; + + return ble_svc_audio_bass_receive_state_notify(rcv_state); +} + +int +ble_svc_audio_bass_receive_state_remove(uint8_t source_id) +{ + struct ble_svc_audio_bass_rcv_state_entry *rcv_state = NULL; + int rc, i; + + rc = ble_svc_audio_bass_receive_state_find_by_source_id(&rcv_state, source_id); + if (rc) { + return rc; + } + + ble_svc_audio_bass_receive_state_free(rcv_state); + + for (i = 0; i < rcv_state->state.num_subgroups; i++) { + os_memblock_put(&ble_audio_svc_bass_metadata_pool, rcv_state->state.subgroups[i].metadata); + } + + return ble_svc_audio_bass_receive_state_notify(rcv_state); +} + +int +ble_svc_audio_bass_update_metadata(const struct ble_svc_audio_bass_metadata_params *params, + uint8_t source_id) +{ + struct ble_svc_audio_bass_rcv_state_entry *rcv_state = NULL; + int rc; + + rc = ble_svc_audio_bass_receive_state_find_by_source_id(&rcv_state, source_id); + if (rc) { + return rc; + } + + rcv_state->state.subgroups[params->subgroup_idx].metadata_length = params->metadata_length; + memcpy(rcv_state->state.subgroups[params->subgroup_idx].metadata, + params->metadata, params->metadata_length); + + return ble_svc_audio_bass_receive_state_notify(rcv_state); +} + +int +ble_svc_audio_bass_receive_state_update(const struct + ble_svc_audio_bass_update_params *params, + uint8_t source_id) +{ + struct ble_svc_audio_bass_rcv_state_entry *rcv_state = NULL; + int rc; + + rc = ble_svc_audio_bass_receive_state_find_by_source_id(&rcv_state, + source_id); + if (rc) { + return rc; + } + + if (rcv_state->state.num_subgroups < params->num_subgroups) { + return BLE_HS_ENOMEM; + } + + rcv_state->state.pa_sync_state = params->pa_sync_state; + rcv_state->state.big_encryption = params->big_encryption; + if (params->bad_code) { + memcpy(rcv_state->state.bad_code, + params->bad_code, + BLE_AUDIO_BROADCAST_CODE_SIZE); + } + + int i; + for (i = 0; i < params->num_subgroups; i++) { + rcv_state->state.subgroups[i].bis_sync_state = + params->subgroups[i].bis_sync_state; + memcpy(rcv_state->state.subgroups[i].metadata, + params->subgroups[i].metadata, + params->subgroups[i].metadata_length); + } + + return ble_svc_audio_bass_receive_state_notify(rcv_state); +} + +int +ble_svc_audio_bass_receiver_state_get(uint8_t source_id, + struct ble_svc_audio_bass_receiver_state **state) +{ + struct ble_svc_audio_bass_rcv_state_entry *rcv_state = NULL; + + ble_svc_audio_bass_receive_state_find_by_source_id(&rcv_state, source_id); + + if (!rcv_state) { + return BLE_HS_ENOENT; + } + + *state = &rcv_state->state; + + return 0; +} + +int +ble_svc_audio_bass_source_id_get(uint8_t index, uint8_t *source_id) +{ + if (index >= ARRAY_SIZE(receiver_states) || + receiver_states[index].source_id == + BLE_SVC_AUDIO_BASS_RECEIVE_STATE_SRC_ID_NONE) { + return BLE_HS_ENOENT; + } + + *source_id = receiver_states[index].source_id; + + return 0; +} + +void +ble_svc_audio_bass_init(void) +{ + int rc; + int i; + + /* Ensure this function only gets called by sysinit. */ + SYSINIT_ASSERT_ACTIVE(); + + ble_svc_audio_bass_chrs[0].uuid = bass_cp_uuid; + ble_svc_audio_bass_chrs[0].access_cb = ble_svc_audio_bass_access; + ble_svc_audio_bass_chrs[0].flags = BLE_GATT_CHR_F_WRITE_NO_RSP | + BLE_GATT_CHR_F_WRITE | + BLE_GATT_CHR_F_WRITE_ENC; + + for (i = 1; i <= MYNEWT_VAL(BLE_SVC_AUDIO_BASS_RECEIVE_STATE_MAX); i++) { + ble_svc_audio_bass_chrs[i].uuid = bass_receive_state_uuid; + ble_svc_audio_bass_chrs[i].access_cb = ble_svc_audio_bass_access; + ble_svc_audio_bass_chrs[i].arg = &receiver_states[i-1]; + ble_svc_audio_bass_chrs[i].val_handle = &receiver_states[i-1].chr_val; + ble_svc_audio_bass_chrs[i].flags = BLE_GATT_CHR_F_READ | + BLE_GATT_CHR_F_READ_ENC | + BLE_GATT_CHR_F_NOTIFY; + } + + rc = ble_gatts_count_cfg(ble_svc_audio_bass_defs); + SYSINIT_PANIC_ASSERT(rc == 0); + + rc = ble_gatts_add_svcs(ble_svc_audio_bass_defs); + SYSINIT_PANIC_ASSERT(rc == 0); + + rc = os_mempool_init(&ble_audio_svc_bass_metadata_pool, + MYNEWT_VAL(BLE_SVC_AUDIO_BASS_RECEIVE_STATE_MAX) * + BLE_SVC_AUDIO_BASS_SUB_NUM_MAX, + MYNEWT_VAL(BLE_SVC_AUDIO_BASS_METADATA_MAX_SZ), + ble_audio_svc_bass_metadata_mem, "ble_audio_svc_bass_metadata_pool"); + SYSINIT_PANIC_ASSERT(rc == 0); + + (void)rc; +} diff --git a/nimble/transport/dialog_cmac/syscfg.yml b/nimble/host/audio/services/bass/syscfg.yml similarity index 54% rename from nimble/transport/dialog_cmac/syscfg.yml rename to nimble/host/audio/services/bass/syscfg.yml index c44773efcd..f125115e1f 100644 --- a/nimble/transport/dialog_cmac/syscfg.yml +++ b/nimble/host/audio/services/bass/syscfg.yml @@ -14,30 +14,25 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -# syscfg.defs: - BLE_HCI_EVT_HI_BUF_COUNT: - description: 'Number of high-priority event buffers.' - value: 2 - - BLE_HCI_EVT_LO_BUF_COUNT: - description: 'Number of low-priority event buffers.' - value: 8 - - BLE_HCI_EVT_BUF_SIZE: - description: 'Size of each event buffer, in bytes.' - value: 70 - - BLE_ACL_BUF_COUNT: - description: 'The number of ACL data buffers' - value: 4 - - BLE_ACL_BUF_SIZE: + BLE_SVC_AUDIO_BASS_SYSINIT_STAGE: + description: > + Sysinit stage for Broadcast Audio Scan Service. + value: 303 + BLE_SVC_AUDIO_BASS_RECEIVE_STATE_MAX: + description: > + Maximum number of Broadcast Receive State characteristics. + value: 2 + BLE_SVC_AUDIO_BASS_METADATA_MAX_SZ: + description: > + Maximum size of metadata that can be saved for subgroup. If set to 0 metadata is + not being saved. + value: 32 + BLE_SVC_AUDIO_BASS_SUB_NUM_MAX: description: > - This is the maximum size of the data portion of HCI ACL data - packets. It does not include the HCI data header (of 4 bytes). - value: 255 + Maximum number of Subgroups supported per Receive State. + value: 3 -syscfg.vals.'BLE_EXT_ADV || BLE_LL_CFG_FEAT_LL_EXT_ADV': - BLE_HCI_EVT_BUF_SIZE: 257 +syscfg.restrictions: + - 'BLE_SVC_AUDIO_BASS_RECEIVE_STATE_MAX < 0xFE' diff --git a/nimble/host/audio/services/pacs/include/services/pacs/ble_audio_svc_pacs.h b/nimble/host/audio/services/pacs/include/services/pacs/ble_audio_svc_pacs.h new file mode 100644 index 0000000000..1949297d84 --- /dev/null +++ b/nimble/host/audio/services/pacs/include/services/pacs/ble_audio_svc_pacs.h @@ -0,0 +1,108 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_BLE_AUDIO_SVC_PACS_ +#define H_BLE_AUDIO_SVC_PACS_ + +/** + * @file ble_audio_svc_pacs.h + * + * @brief Bluetooth LE Audio PAC Service + * + * This header file provides the public API for interacting with the PACS package. + * + * @defgroup ble_audio_svc_pacs Bluetooth LE Audio PACS package + * @ingroup bt_host + * @{ + * + * This package is used to setup PACS for codecs registered with ble_audio_codec. + * To register a codec create it's definition as `ble_audio_codec_record` structure and register it + * using `ble_audio_codec_register()`. Up to BLE_AUDIO_MAX_CODEC_RECORDS entries may be registered. + * Registering and unregistering codecs, as well as setting PACS parameters will trigger sending + * notifications, if their support is enabled (see pacs/syscfg.yml). + * + */ + +/** BLE Audio Published Audio Capabilities Service UUID */ +#define BLE_SVC_AUDIO_PACS_UUID16 0x1850 + +/** BLE Audio Published Audio Capabilities Service Sink PAC characteristic UUID */ +#define BLE_SVC_AUDIO_PACS_CHR_UUID16_SINK_PAC 0x2BC9 + +/** BLE Audio Published Audio Capabilities Service Sink Audio Locations characteristic UUID */ +#define BLE_SVC_AUDIO_PACS_CHR_UUID16_SINK_AUDIO_LOCATIONS 0x2BCA + +/** BLE Audio Published Audio Capabilities Service Source PAC characteristic UUID */ +#define BLE_SVC_AUDIO_PACS_CHR_UUID16_SOURCE_PAC 0x2BCB + +/** BLE Audio Published Audio Capabilities Service Source Audio Locations characteristic UUID */ +#define BLE_SVC_AUDIO_PACS_CHR_UUID16_SOURCE_AUDIO_LOCATIONS 0x2BCC + +/** BLE Audio Published Audio Capabilities Service Available Audio Contexts characteristic UUID */ +#define BLE_SVC_AUDIO_PACS_CHR_UUID16_AVAILABLE_AUDIO_CONTEXTS 0x2BCD + +/** BLE Audio Published Audio Capabilities Service Supported Audio Contexts characteristic UUID */ +#define BLE_SVC_AUDIO_PACS_CHR_UUID16_SUPPORTED_AUDIO_CONTEXTS 0x2BCE + +/** Parameters used for setting supported Audio Locations and Contexts. */ +struct ble_svc_audio_pacs_set_param { + /** Supported Audio Locations */ + uint32_t audio_locations; + + /** Supported Contexts */ + uint16_t supported_contexts; +}; + +/** + * @brief Set PACS params. + * + * Set device capabilities reported in Published Audio Capabilities Service. + * + * @param[in] flags Flags that define if capabilities being set are for + * Sink or Source. Valid values are either + * `BLE_AUDIO_CODEC_FLAG_SOURCE` or `BLE_AUDIO_CODEC_FLAG_SINK` + * @param[in] param Pointer to a `ble_svc_audio_pacs_set_param` + * structure that defines capabilities supported by + * device. + * + * @return 0 on success; + * A non-zero value on failure. + */ +int ble_svc_audio_pacs_set(uint8_t flags, const struct ble_svc_audio_pacs_set_param *param); + +/** + * @brief Set available context types. + * + * @param[in] conn_handle Connection handle identifying connection for which contexts + * being set + * @param[in] sink_contexts Available Sink Contexts + * @param[in] source_contexts Available Source Contexts + * + * @return 0 on success; + * A non-zero value on failure. + */ +int ble_svc_audio_pacs_avail_contexts_set(uint16_t conn_handle, + uint16_t sink_contexts, + uint16_t source_contexts); + +/** + * @} + */ + +#endif /* H_BLE_AUDIO_SVC_PACS_ */ diff --git a/nimble/host/audio/services/pacs/lc3/include/services/pacs/ble_audio_svc_pacs_lc3.h b/nimble/host/audio/services/pacs/lc3/include/services/pacs/ble_audio_svc_pacs_lc3.h new file mode 100644 index 0000000000..ddd6f546c2 --- /dev/null +++ b/nimble/host/audio/services/pacs/lc3/include/services/pacs/ble_audio_svc_pacs_lc3.h @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_BLE_AUDIO_SVC_PACS_LC3_ +#define H_BLE_AUDIO_SVC_PACS_LC3_ + + +/** + * @file ble_audio_svc_pacs_lc3.h + * + * @brief Bluetooth PAC Service for LC3 Codec + * + * This header file provides the public API for interacting with the PACS LC3 package, that + * registers PAC entry for LC3 codec with configurations contained in system configuration file + * + * @defgroup ble_audio_svc_pacs_lc3 Bluetooth LE Audio PACS LC3 package + * @ingroup ble_audio_svc_pacs + * @{ + * + * This package is an example how to register codec entry that PACS can use to construct its entries + * for GATT database. This is high level package that can be used to construct basic PACS setup for + * LC3 codec. This package creates only single PAC entry per source and sink. If more PAC entries + * need to be created, with more advanced setup, @ref ble_audio_svc_pacs service shall be used in + * combination with @ref ble_audio_codec API. + * + */ + +/** + * @brief Set available context types. + * + * @param[in] conn_handle Connection handle identifying connection for which contexts + * being set + * @param[in] sink_contexts Available Sink Contexts + * @param[in] source_contexts Available Source Contexts + * + * @return 0 on success; + * A non-zero value on failure. + */ +int ble_svc_audio_pacs_lc3_set_avail_contexts(uint16_t conn_handle, + uint16_t sink_contexts, + uint16_t source_contexts); + +/** + * @} + */ + +#endif /* H_BLE_AUDIO_SVC_PACS_LC3_ */ diff --git a/nimble/host/audio/services/pacs/lc3/pkg.yml b/nimble/host/audio/services/pacs/lc3/pkg.yml new file mode 100644 index 0000000000..eb8f6b67ed --- /dev/null +++ b/nimble/host/audio/services/pacs/lc3/pkg.yml @@ -0,0 +1,34 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +pkg.name: nimble/host/audio/services/pacs/lc3 +pkg.description: LC3 codec entry for Published Audio Capabilities Service +pkg.author: "Apache Mynewt " +pkg.homepage: "https://mynewt.apache.org/" +pkg.keywords: + - ble + - bluetooth + - pacs + - nimble + +pkg.deps: + - nimble/host/audio/services/pacs + - nimble/host + +pkg.init: + ble_svc_audio_pacs_lc3_init: + - $after:ble_svc_audio_pacs_init diff --git a/nimble/host/audio/services/pacs/lc3/src/ble_audio_svc_pacs_lc3.c b/nimble/host/audio/services/pacs/lc3/src/ble_audio_svc_pacs_lc3.c new file mode 100644 index 0000000000..61c703629c --- /dev/null +++ b/nimble/host/audio/services/pacs/lc3/src/ble_audio_svc_pacs_lc3.c @@ -0,0 +1,153 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "audio/ble_audio_codec.h" +#include "services/pacs/ble_audio_svc_pacs.h" +#include "syscfg/syscfg.h" +#include "host/ble_hs.h" + +/* Below is to unmangle comma separated Metadata octets from MYNEWT_VAL */ +#define _Args(...) __VA_ARGS__ +#define STRIP_PARENS(X) X +#define UNMANGLE_MYNEWT_VAL(X) STRIP_PARENS(_Args X) + +#define BLE_SVC_AUDIO_PACS_LC3_CODEC_ID 0x06 + +static uint8_t ble_svc_audio_pacs_lc3_src_codec_spec_caps[] = BLE_AUDIO_BUILD_CODEC_CAPS( + MYNEWT_VAL(BLE_SVC_AUDIO_PACS_LC3_SRC_SAMPLING_FREQUENCIES), + MYNEWT_VAL(BLE_SVC_AUDIO_PACS_LC3_SRC_FRAME_DURATIONS), +#ifdef MYNEWT_VAL_BLE_SVC_AUDIO_PACS_LC3_SRC_AUDIO_CHANNEL_COUNTS + MYNEWT_VAL(BLE_SVC_AUDIO_PACS_LC3_SRC_AUDIO_CHANNEL_COUNTS), +#else + , +#endif + MYNEWT_VAL(BLE_SVC_AUDIO_PACS_LC3_SRC_MIN_OCTETS_PER_CODEC_FRAME), + MYNEWT_VAL(BLE_SVC_AUDIO_PACS_LC3_SRC_MAX_OCTETS_PER_CODEC_FRAME), +#ifdef MYNEWT_VAL_BLE_SVC_AUDIO_PACS_LC3_SRC_MAX_CODEC_FRAMES_PER_SDU + MYNEWT_VAL(BLE_SVC_AUDIO_PACS_LC3_SRC_MAX_CODEC_FRAMES_PER_SDU), +#endif +); + +static uint8_t ble_svc_audio_pacs_lc3_snk_codec_spec_caps[] = BLE_AUDIO_BUILD_CODEC_CAPS( + MYNEWT_VAL(BLE_SVC_AUDIO_PACS_LC3_SNK_SAMPLING_FREQUENCIES), + MYNEWT_VAL(BLE_SVC_AUDIO_PACS_LC3_SNK_FRAME_DURATIONS), + #ifdef MYNEWT_VAL_BLE_SVC_AUDIO_PACS_LC3_SRC_AUDIO_CHANNEL_COUNTS + MYNEWT_VAL(BLE_SVC_AUDIO_PACS_LC3_SNK_AUDIO_CHANNEL_COUNTS), + #else + , + #endif + MYNEWT_VAL(BLE_SVC_AUDIO_PACS_LC3_SNK_MIN_OCTETS_PER_CODEC_FRAME), + MYNEWT_VAL(BLE_SVC_AUDIO_PACS_LC3_SRC_MAX_OCTETS_PER_CODEC_FRAME), + #ifdef MYNEWT_VAL_BLE_SVC_AUDIO_PACS_LC3_SRC_MAX_CODEC_FRAMES_PER_SDU + MYNEWT_VAL(BLE_SVC_AUDIO_PACS_LC3_SNK_MAX_CODEC_FRAMES_PER_SDU), + #endif +); + +#ifdef MYNEWT_VAL_BLE_SVC_AUDIO_PACS_LC3_SRC_METADATA +static uint8_t ble_svc_audio_pacs_lc3_src_metadata[] = +{ UNMANGLE_MYNEWT_VAL(MYNEWT_VAL(BLE_SVC_AUDIO_PACS_LC3_SRC_METADATA)) }; +#endif + +#ifdef MYNEWT_VAL_BLE_SVC_AUDIO_PACS_LC3_SNK_METADATA +static uint8_t ble_svc_audio_pacs_lc3_snk_metadata[] = +{ UNMANGLE_MYNEWT_VAL(MYNEWT_VAL(BLE_SVC_AUDIO_PACS_LC3_SNK_METADATA)) }; +#endif + +static struct ble_audio_codec_register_params src_codec_params = { + .codec_id = { + .format = BLE_SVC_AUDIO_PACS_LC3_CODEC_ID, + .company_id = 0x00, + .vendor_specific = 0x00 + }, + .codec_spec_caps_len = sizeof(ble_svc_audio_pacs_lc3_src_codec_spec_caps), + .codec_spec_caps = ble_svc_audio_pacs_lc3_src_codec_spec_caps, +#ifdef MYNEWT_VAL_BLE_SVC_AUDIO_PACS_LC3_SRC_METADATA + .metadata_len = sizeof(ble_svc_audio_pacs_lc3_src_metadata), + .metadata = ble_svc_audio_pacs_lc3_src_metadata, +#else + .metadata_len = 0, +#endif + .direction = BLE_AUDIO_CODEC_DIR_SOURCE_BIT +}; + +static struct ble_audio_codec_register_params snk_codec_params = { + .codec_id = { + .format = BLE_SVC_AUDIO_PACS_LC3_CODEC_ID, + .company_id = 0x00, + .vendor_specific = 0x00 + }, + .codec_spec_caps_len = sizeof(ble_svc_audio_pacs_lc3_snk_codec_spec_caps), + .codec_spec_caps = ble_svc_audio_pacs_lc3_snk_codec_spec_caps, +#ifdef MYNEWT_VAL_BLE_SVC_AUDIO_PACS_LC3_SNK_METADATA + .metadata_len = sizeof(ble_svc_audio_pacs_lc3_snk_metadata), + .metadata = ble_svc_audio_pacs_lc3_snk_metadata, +#else + .metadata_len = 0, +#endif + + .direction = BLE_AUDIO_CODEC_DIR_SINK_BIT +}; + +static int +codec_register(void) +{ + int rc; + + rc = ble_audio_codec_register(&src_codec_params, NULL); + SYSINIT_PANIC_ASSERT(rc == 0); + + rc = ble_audio_codec_register(&snk_codec_params, NULL); + SYSINIT_PANIC_ASSERT(rc == 0); + + return 0; +} + +int +ble_svc_audio_pacs_lc3_set_avail_contexts(uint16_t conn_handle, + uint16_t sink_contexts, + uint16_t source_contexts) +{ + return ble_svc_audio_pacs_avail_contexts_set(conn_handle, sink_contexts, + source_contexts); +} + +void +ble_svc_audio_pacs_lc3_init(void) +{ + struct ble_svc_audio_pacs_set_param src_params = { + .audio_locations = MYNEWT_VAL(BLE_SVC_AUDIO_PACS_LC3_SRC_AUDIO_LOCATIONS), + .supported_contexts = MYNEWT_VAL(BLE_SVC_AUDIO_PACS_LC3_SRC_SUP_CONTEXTS) + }; + struct ble_svc_audio_pacs_set_param snk_params = { + .audio_locations = MYNEWT_VAL(BLE_SVC_AUDIO_PACS_LC3_SNK_SUP_AUDIO_LOCATIONS), + .supported_contexts = MYNEWT_VAL(BLE_SVC_AUDIO_PACS_LC3_SNK_SUP_CONTEXTS) + }; + int rc; + + rc = codec_register(); + SYSINIT_PANIC_ASSERT(rc == 0); + + rc = ble_svc_audio_pacs_set(BLE_AUDIO_CODEC_DIR_SOURCE_BIT, &src_params); + SYSINIT_PANIC_ASSERT(rc == 0); + + rc = ble_svc_audio_pacs_set(BLE_AUDIO_CODEC_DIR_SINK_BIT, &snk_params); + SYSINIT_PANIC_ASSERT(rc == 0); + + (void)rc; +} diff --git a/nimble/host/audio/services/pacs/lc3/syscfg.yml b/nimble/host/audio/services/pacs/lc3/syscfg.yml new file mode 100644 index 0000000000..2a12d89b50 --- /dev/null +++ b/nimble/host/audio/services/pacs/lc3/syscfg.yml @@ -0,0 +1,140 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +syscfg.defs: + BLE_SVC_AUDIO_PACS_LC3_SRC_SAMPLING_FREQUENCIES: + description: > + Sampling frequencies supported by LC3 codec, as source. This setting is mandatory. + Accepts any combination of values defined in Bluetooth Assigned Numbers 6.12.4.1. + Default value: 48000Hz + value: 0x80 + restrictions: + - $notnull + BLE_SVC_AUDIO_PACS_LC3_SRC_FRAME_DURATIONS: + description: > + Frame Durations supported by LC3 codec, as source. This setting is mandatory. + Accepts any combination of values defined in Bluetooth Assigned Numbers 6.12.4.2. + Default value: 7.5ms and 10ms supported, 10ms preferred. + value: 0x23 + restrictions: + - $notnull + BLE_SVC_AUDIO_PACS_LC3_SRC_AUDIO_CHANNEL_COUNTS: + description: > + Audio Channel Counts supported by LC3 codec, as source. This setting is optional. + Accepts any combination of values defined in Bluetooth Assigned Numbers 6.12.4.3. + value: + BLE_SVC_AUDIO_PACS_LC3_SRC_MIN_OCTETS_PER_CODEC_FRAME: + description: > + Minimum number of Octets Per Codec Frame supported by LC3 codec, as source. + This setting is mandatory. Default value: 80 + value: 80 + restrictions: + - $notnull + BLE_SVC_AUDIO_PACS_LC3_SRC_MAX_OCTETS_PER_CODEC_FRAME: + description: > + Maximum number of Octets Per Codec Frame supported by LC3 codec, as source. + This setting is mandatory. Default value: 120 + value: 120 + restrictions: + - $notnull + BLE_SVC_AUDIO_PACS_LC3_SRC_MAX_CODEC_FRAMES_PER_SDU: + description: > + Maximum number of Codec Frames Per SDU supported by LC3 codec, as source. + This setting is optional. + value: + BLE_SVC_AUDIO_PACS_LC3_SRC_METADATA: + description: > + Optional Metadata to be attached to source codec capabilities. This value shall be in + form of bytes forming LTVs of Metadata. Example: '0x03, 0x01, 0x00, 0x08' + (lenght = 3, type = 0x01 (Preferred_Audio_Contexts), 0x00, 0x04 (Media)) + value: + BLE_SVC_AUDIO_PACS_LC3_SRC_AUDIO_LOCATIONS: + description: > + Audio Locations supported by source codec. Value is an any combination of values defined + in Bluetooth Assigned Numbers 6.12.1. Default: Front Left and Front Right + value: 0x00000003 + BLE_SVC_AUDIO_PACS_LC3_SRC_SUP_CONTEXTS: + description: > + Audio Locations supported by source codec. Value is an any combination of values defined + in Bluetooth Assigned Numbers 6.12.3. Default: Media + value: 0x0004 + + BLE_SVC_AUDIO_PACS_LC3_SNK_SAMPLING_FREQUENCIES: + description: > + Sampling frequencies supported by LC3 codec, as sink. This setting is mandatory. + Accepts any combination of values defined in Bluetooth Assigned Numbers 6.12.4.1. + Default value: 48000Hz + value: 0x80 + restrictions: + - $notnull + BLE_SVC_AUDIO_PACS_LC3_SNK_FRAME_DURATIONS: + description: > + Frame Durations supported by LC3 codec, as sink. This setting is mandatory. + Accepts any combination of values defined in Bluetooth Assigned Numbers 6.12.4.2. + Default value: 7.5ms and 10ms supported, 10ms preferred. + value: 0x23 + restrictions: + - $notnull + BLE_SVC_AUDIO_PACS_LC3_SNK_AUDIO_CHANNEL_COUNTS: + description: > + Audio Channel Counts supported by LC3 codec, as sink. This setting is optional. + Accepts any combination of values defined in Bluetooth Assigned Numbers 6.12.4.3. + value: + BLE_SVC_AUDIO_PACS_LC3_SNK_MIN_OCTETS_PER_CODEC_FRAME: + description: > + Minimum number of Octets Per Codec Frame supported by LC3 codec, as source. + This setting is mandatory. Default value: 80 + value: 80 + restrictions: + - $notnull + BLE_SVC_AUDIO_PACS_LC3_SNK_MAX_OCTETS_PER_CODEC_FRAME: + description: > + Maximum number of Octets Per Codec Frame supported by LC3 codec, as sink. + This setting is mandatory. Default value: 120 + value: 120 + restrictions: + - $notnull + BLE_SVC_AUDIO_PACS_LC3_SNK_MAX_CODEC_FRAMES_PER_SDU: + description: > + Maximum number of Codec Frames Per SDU supported by LC3 codec, as sink. + This setting is optional. + value: + BLE_SVC_AUDIO_PACS_LC3_SNK_METADATA: + description: > + Optional Metadata to be attached to sink codec capabilities. This value shall be in + form of bytes forming LTVs of Metadata. Example: '0x03, 0x01, 0x00, 0x08' + (lenght = 3, type = 0x01 (Preferred_Audio_Contexts), 0x00, 0x04 (Media)) + value: + BLE_SVC_AUDIO_PACS_LC3_SNK_SUP_AUDIO_LOCATIONS: + description: > + Audio Locations supported by sink codec. Value is an any combination of values defined + in Bluetooth Assigned Numbers 6.12.1. Default: Front Left and Front Right + value: 0x00000003 + BLE_SVC_AUDIO_PACS_LC3_SNK_SUP_CONTEXTS: + description: > + Audio Locations supported by sink codec. Value is an any combination of values defined + in Bluetooth Assigned Numbers 6.12.3. Default: Media + value: 0x0004 + +syscfg.vals.BLE_AUDIO_BROADCAST_SINK: + BLE_SVC_AUDIO_PACS_LC3_SNK_SAMPLING_FREQUENCIES: > + BLE_AUDIO_CODEC_SUPPORTED_SAMPLING_RATE_16000_HZ || BLE_AUDIO_CODEC_SUPPORTED_SAMPLING_RATE_24000_HZ + BLE_SVC_AUDIO_PACS_LC3_SNK_FRAME_DURATIONS: BLE_AUDIO_CODEC_SUPPORTED_FRAME_DURATION_10_MS + BLE_SVC_AUDIO_PACS_LC3_SNK_AUDIO_CHANNEL_COUNTS: BLE_AUDIO_CODEC_SUPPORTED_CHANNEL_COUNT_1 + BLE_SVC_AUDIO_PACS_LC3_SNK_MIN_OCTETS_PER_CODEC_FRAME: 40 + BLE_SVC_AUDIO_PACS_LC3_SNK_MAX_OCTETS_PER_CODEC_FRAME: 60 + BLE_SVC_AUDIO_PACS_LC3_SNK_MAX_CODEC_FRAMES_PER_SDU: 1 diff --git a/nimble/host/audio/services/pacs/pkg.yml b/nimble/host/audio/services/pacs/pkg.yml new file mode 100644 index 0000000000..799378d7e7 --- /dev/null +++ b/nimble/host/audio/services/pacs/pkg.yml @@ -0,0 +1,33 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +pkg.name: nimble/host/audio/services/pacs +pkg.description: Published Audio Capabilities Service +pkg.author: "Apache Mynewt " +pkg.homepage: "https://mynewt.apache.org/" +pkg.keywords: + - ble + - bluetooth + - pacs + - nimble + +pkg.deps: + - nimble/host + - nimble/host/services/gatt + +pkg.init: + ble_svc_audio_pacs_init: 'MYNEWT_VAL(BLE_SVC_AUDIO_PACS_SYSINIT_STAGE)' diff --git a/nimble/host/audio/services/pacs/src/ble_audio_svc_pacs.c b/nimble/host/audio/services/pacs/src/ble_audio_svc_pacs.c new file mode 100644 index 0000000000..ef53f94ac5 --- /dev/null +++ b/nimble/host/audio/services/pacs/src/ble_audio_svc_pacs.c @@ -0,0 +1,513 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "audio/ble_audio.h" +#include "host/ble_hs.h" +#include "host/ble_gatt.h" +#include "audio/ble_audio_codec.h" +#include "services/pacs/ble_audio_svc_pacs.h" + +static uint32_t ble_svc_audio_pacs_sink_audio_locations; +static uint32_t ble_svc_audio_pacs_source_audio_locations; +static struct available_ctx { + uint16_t conn_handle; + uint16_t ble_svc_audio_pacs_avail_sink_contexts; + uint16_t ble_svc_audio_pacs_avail_source_contexts; + uint8_t val_changed; +} ble_svc_audio_pacs_avail_contexts[MYNEWT_VAL(BLE_MAX_CONNECTIONS)] = { + [0 ... MYNEWT_VAL(BLE_MAX_CONNECTIONS) - 1] = { + .conn_handle = BLE_HS_CONN_HANDLE_NONE, + .ble_svc_audio_pacs_avail_sink_contexts = 0, + .ble_svc_audio_pacs_avail_source_contexts = 0 + } +}; +static uint16_t ble_svc_audio_pacs_sup_sink_contexts; +static uint16_t ble_svc_audio_pacs_sup_source_contexts; + +static struct ble_gap_event_listener ble_pacs_listener; +static struct ble_audio_event_listener ble_audio_listener; + +struct pac_read_cb_arg { + struct os_mbuf *om; + uint8_t pac_count; +}; + +static int +ble_svc_audio_pacs_access(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, void *arg); + +static const struct ble_gatt_svc_def ble_svc_audio_pacs_defs[] = { + { /*** Service: Published Audio Capabilities Service (PACS) */ + .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid = BLE_UUID16_DECLARE(BLE_SVC_AUDIO_PACS_UUID16), + .characteristics = (struct ble_gatt_chr_def[]) { +#if MYNEWT_VAL(BLE_SVC_AUDIO_PACS_SINK_PAC) + { + .uuid = BLE_UUID16_DECLARE(BLE_SVC_AUDIO_PACS_CHR_UUID16_SINK_PAC), + .access_cb = ble_svc_audio_pacs_access, + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC +#if MYNEWT_VAL(BLE_SVC_AUDIO_PACS_SINK_PAC_NOTIFY) + | BLE_GATT_CHR_F_NOTIFY +#endif + }, +#endif +#if MYNEWT_VAL(BLE_SVC_AUDIO_PACS_SINK_AUDIO_LOCATIONS) + { + .uuid = BLE_UUID16_DECLARE( + BLE_SVC_AUDIO_PACS_CHR_UUID16_SINK_AUDIO_LOCATIONS), + .access_cb = ble_svc_audio_pacs_access, + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC +#if MYNEWT_VAL(BLE_SVC_AUDIO_PACS_SINK_AUDIO_LOCATIONS_NOTIFY) + | BLE_GATT_CHR_F_NOTIFY +#endif + }, +#endif +#if MYNEWT_VAL(BLE_SVC_AUDIO_PACS_SOURCE_PAC) + { + .uuid = BLE_UUID16_DECLARE( + BLE_SVC_AUDIO_PACS_CHR_UUID16_SOURCE_PAC), + .access_cb = ble_svc_audio_pacs_access, + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC +#if MYNEWT_VAL(BLE_SVC_AUDIO_PACS_SOURCE_PAC_NOTIFY) + | BLE_GATT_CHR_F_NOTIFY +#endif + }, +#endif +#if MYNEWT_VAL(BLE_SVC_AUDIO_PACS_SOURCE_AUDIO_LOCATIONS) + { + .uuid = BLE_UUID16_DECLARE( + BLE_SVC_AUDIO_PACS_CHR_UUID16_SOURCE_AUDIO_LOCATIONS), + .access_cb = ble_svc_audio_pacs_access, + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC +#if MYNEWT_VAL(BLE_SVC_AUDIO_PACS_SOURCE_AUDIO_LOCATIONS_NOTIFY) + | BLE_GATT_CHR_F_NOTIFY +#endif + }, +#endif + { + .uuid = BLE_UUID16_DECLARE( + BLE_SVC_AUDIO_PACS_CHR_UUID16_AVAILABLE_AUDIO_CONTEXTS), + .access_cb = ble_svc_audio_pacs_access, + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC | BLE_GATT_CHR_F_NOTIFY, + }, { + .uuid = BLE_UUID16_DECLARE( + BLE_SVC_AUDIO_PACS_CHR_UUID16_SUPPORTED_AUDIO_CONTEXTS), + .access_cb = ble_svc_audio_pacs_access, + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC +#if MYNEWT_VAL(BLE_SVC_AUDIO_PACS_SUP_AUDIO_CTX_NOTIFY) + | BLE_GATT_CHR_F_NOTIFY +#endif + }, { + 0, /* No more characteristics in this service */ + } + } + }, + { + 0, /* No more services. */ + }, +}; + +static int +codec_record_to_pacs_entry(const struct ble_audio_codec_record *record, void *arg) +{ + struct pac_read_cb_arg *cb_arg = (struct pac_read_cb_arg *)arg; + uint8_t *buf; + int rc; + + rc = os_mbuf_append(cb_arg->om, &record->codec_id.format, sizeof(uint8_t)); + if (rc) { + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + + buf = os_mbuf_extend(cb_arg->om, 4); + if (buf == NULL) { + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + put_le16(buf + 0, record->codec_id.company_id); + put_le16(buf + 2, record->codec_id.vendor_specific); + + rc = os_mbuf_append(cb_arg->om, &record->codec_spec_caps_len, sizeof(uint8_t)); + if (rc) { + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + + rc = os_mbuf_append(cb_arg->om, record->codec_spec_caps, record->codec_spec_caps_len); + if (rc) { + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + + rc = os_mbuf_append(cb_arg->om, &record->metadata_len, sizeof(uint8_t)); + if (rc) { + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + + rc = os_mbuf_append(cb_arg->om, record->metadata, record->metadata_len); + if (rc) { + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + + cb_arg->pac_count++; + + return 0; +} + +static int +ble_svc_audio_pacs_sink_pac_read_access(struct ble_gatt_access_ctxt *ctxt) +{ + struct pac_read_cb_arg cb_arg = { + .om = ctxt->om, + .pac_count = 0 + }; + int rc; + uint8_t *pac_count; + + pac_count = os_mbuf_extend(ctxt->om, sizeof(uint8_t)); + rc = ble_audio_codec_foreach(BLE_AUDIO_CODEC_DIR_SINK_BIT, + codec_record_to_pacs_entry, (void *)&cb_arg); + + *pac_count = cb_arg.pac_count; + + return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; +} + +static int +ble_svc_audio_pacs_source_pac_read_access(struct ble_gatt_access_ctxt *ctxt) +{ + struct pac_read_cb_arg cb_arg = { + .om = ctxt->om, + .pac_count = 0 + }; + int rc; + uint8_t *pac_count; + + pac_count = os_mbuf_extend(ctxt->om, sizeof(uint8_t)); + rc = ble_audio_codec_foreach(BLE_AUDIO_CODEC_DIR_SOURCE_BIT, + codec_record_to_pacs_entry, (void *)&cb_arg); + + *pac_count = cb_arg.pac_count; + + return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES; +} + +static int +ble_svc_audio_pacs_sink_audio_loc_read_access(struct ble_gatt_access_ctxt * + ctxt) +{ + uint8_t *buf; + + buf = os_mbuf_extend(ctxt->om, 4); + if (buf == NULL) { + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + + put_le32(buf + 0, ble_svc_audio_pacs_sink_audio_locations); + + return 0; +} + +static int +ble_svc_audio_pacs_source_audio_loc_read_access(struct ble_gatt_access_ctxt * + ctxt) +{ + uint8_t *buf; + + buf = os_mbuf_extend(ctxt->om, 4); + if (buf == NULL) { + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + + put_le32(buf + 0, ble_svc_audio_pacs_source_audio_locations); + + return 0; +} + +static struct available_ctx * +ble_svc_audio_pacs_find_avail_ctx(uint16_t conn_handle) +{ + int i; + + for (i = 0; i < MYNEWT_VAL(BLE_MAX_CONNECTIONS); i++) { + if (ble_svc_audio_pacs_avail_contexts[i].conn_handle == conn_handle) { + return &ble_svc_audio_pacs_avail_contexts[i]; + } + } + return NULL; +} + +static int +ble_svc_audio_pacs_avail_audio_ctx_read_access(uint16_t conn_handle, + struct ble_gatt_access_ctxt *ctxt) +{ + struct available_ctx *avail_ctx = NULL; + uint8_t *buf; + int i; + + if (conn_handle == BLE_HS_CONN_HANDLE_NONE) { + for (i = 0; i < MYNEWT_VAL(BLE_MAX_CONNECTIONS); i++) { + if (ble_svc_audio_pacs_avail_contexts[i].val_changed) { + avail_ctx = &ble_svc_audio_pacs_avail_contexts[i]; + avail_ctx->val_changed = false; + break; + } + } + } else { + avail_ctx = ble_svc_audio_pacs_find_avail_ctx(conn_handle); + } + + buf = os_mbuf_extend(ctxt->om, 4); + if (buf == NULL) { + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + + if (!avail_ctx) { + put_le32(buf + 0, 0); + return 0; + } + + put_le16(buf + 0, avail_ctx->ble_svc_audio_pacs_avail_sink_contexts); + put_le16(buf + 2, avail_ctx->ble_svc_audio_pacs_avail_source_contexts); + + return 0; +} + +static int +ble_svc_audio_pacs_sup_audio_ctx_read_access(struct ble_gatt_access_ctxt + *ctxt) +{ + uint8_t *buf; + + buf = os_mbuf_extend(ctxt->om, 4); + if (buf == NULL) { + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + + put_le16(buf + 0, ble_svc_audio_pacs_sup_sink_contexts); + put_le16(buf + 2, ble_svc_audio_pacs_sup_source_contexts); + + return 0; +} + +static int +ble_svc_audio_pacs_access(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, void *arg) +{ + uint16_t uuid16 = ble_uuid_u16(ctxt->chr->uuid); + int rc; + + switch (uuid16) { + case BLE_SVC_AUDIO_PACS_CHR_UUID16_SINK_PAC: + if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) { + rc = ble_svc_audio_pacs_sink_pac_read_access(ctxt); + } else { + assert(0); + rc = BLE_ATT_ERR_UNLIKELY; + } + return rc; + case BLE_SVC_AUDIO_PACS_CHR_UUID16_SINK_AUDIO_LOCATIONS: + if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) { + rc = ble_svc_audio_pacs_sink_audio_loc_read_access(ctxt); + } else { + rc = BLE_ATT_ERR_REQ_NOT_SUPPORTED; + } + return rc; + case BLE_SVC_AUDIO_PACS_CHR_UUID16_SOURCE_PAC: + if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) { + rc = ble_svc_audio_pacs_source_pac_read_access(ctxt); + } else { + assert(0); + rc = BLE_ATT_ERR_UNLIKELY; + } + return rc; + case BLE_SVC_AUDIO_PACS_CHR_UUID16_SOURCE_AUDIO_LOCATIONS: + if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) { + rc = ble_svc_audio_pacs_source_audio_loc_read_access(ctxt); + } else { + rc = BLE_ATT_ERR_REQ_NOT_SUPPORTED; + } + return rc; + case BLE_SVC_AUDIO_PACS_CHR_UUID16_AVAILABLE_AUDIO_CONTEXTS: + if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) { + rc = ble_svc_audio_pacs_avail_audio_ctx_read_access(conn_handle, + ctxt); + } else { + assert(0); + rc = BLE_ATT_ERR_UNLIKELY; + } + return rc; + case BLE_SVC_AUDIO_PACS_CHR_UUID16_SUPPORTED_AUDIO_CONTEXTS: + if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) { + rc = ble_svc_audio_pacs_sup_audio_ctx_read_access(ctxt); + } else { + assert(0); + rc = BLE_ATT_ERR_UNLIKELY; + } + return rc; + default: + assert(0); + return BLE_ATT_ERR_UNLIKELY; + } +} + +static int +pac_notify(uint16_t chrc_uuid) +{ + uint16_t chr_val_handle; + int rc; + + if (!ble_hs_is_enabled()) { + /* Do not notify if host has not started yet */ + return 0; + } + + rc = ble_gatts_find_chr(BLE_UUID16_DECLARE(BLE_SVC_AUDIO_PACS_UUID16), + BLE_UUID16_DECLARE(chrc_uuid), NULL, &chr_val_handle); + + if (!rc) { + ble_gatts_chr_updated(chr_val_handle); + } + + return rc; +} + +int +ble_svc_audio_pacs_set(uint8_t flags, const struct ble_svc_audio_pacs_set_param *param) +{ + int rc; + + if (flags & BLE_AUDIO_CODEC_DIR_SOURCE_BIT) { + ble_svc_audio_pacs_source_audio_locations = param->audio_locations; + ble_svc_audio_pacs_sup_source_contexts = param->supported_contexts; + rc = pac_notify(BLE_SVC_AUDIO_PACS_CHR_UUID16_SOURCE_AUDIO_LOCATIONS); + if (rc != 0) { + return rc; + } + } + + if (flags & BLE_AUDIO_CODEC_DIR_SINK_BIT) { + ble_svc_audio_pacs_sink_audio_locations = param->audio_locations; + ble_svc_audio_pacs_sup_sink_contexts = param->supported_contexts; + rc = pac_notify(BLE_SVC_AUDIO_PACS_CHR_UUID16_SINK_AUDIO_LOCATIONS); + if (rc != 0) { + return rc; + } + } + + return pac_notify(BLE_SVC_AUDIO_PACS_CHR_UUID16_SUPPORTED_AUDIO_CONTEXTS); +} + +int +ble_svc_audio_pacs_avail_contexts_set(uint16_t conn_handle, + uint16_t sink_contexts, + uint16_t source_contexts) +{ + struct available_ctx *avail_ctx = ble_svc_audio_pacs_find_avail_ctx(conn_handle); + if (!avail_ctx) { + return BLE_HS_ENOENT; + } + + if ((sink_contexts & ble_svc_audio_pacs_sup_sink_contexts) != sink_contexts || + (source_contexts & ble_svc_audio_pacs_sup_source_contexts) != source_contexts) { + return BLE_HS_ENOTSUP; + } + + avail_ctx->ble_svc_audio_pacs_avail_sink_contexts = sink_contexts; + avail_ctx->ble_svc_audio_pacs_avail_source_contexts = source_contexts; + avail_ctx->val_changed = true; + + return pac_notify(BLE_SVC_AUDIO_PACS_CHR_UUID16_AVAILABLE_AUDIO_CONTEXTS); +} + +static int +ble_pacs_audio_event(struct ble_audio_event *event, void *arg) +{ + uint8_t codec_dir; + + if (event->type == BLE_AUDIO_EVENT_CODEC_REGISTERED || + event->type == BLE_AUDIO_EVENT_CODEC_UNREGISTERED) { + codec_dir = event->type == BLE_AUDIO_EVENT_CODEC_REGISTERED ? + event->codec_registered.record->direction : + event->codec_unregistered.record->direction; + + if (codec_dir & BLE_AUDIO_CODEC_DIR_SOURCE_BIT) { + pac_notify(BLE_SVC_AUDIO_PACS_CHR_UUID16_SOURCE_PAC); + } + + if (codec_dir & BLE_AUDIO_CODEC_DIR_SINK_BIT) { + pac_notify(BLE_SVC_AUDIO_PACS_CHR_UUID16_SINK_PAC); + } + } + + return 0; +} + +static int +ble_pacs_gap_event(struct ble_gap_event *event, void *arg) +{ + struct available_ctx *avail_ctx; + + switch (event->type) { + case BLE_GAP_EVENT_CONNECT: + if (event->connect.status != 0) { + break; + } + avail_ctx = ble_svc_audio_pacs_find_avail_ctx(BLE_HS_CONN_HANDLE_NONE); + if (!avail_ctx) { + return BLE_HS_ENOENT; + } + + avail_ctx->conn_handle = event->connect.conn_handle; + break; + case BLE_GAP_EVENT_DISCONNECT: + avail_ctx = ble_svc_audio_pacs_find_avail_ctx(event->disconnect.conn.conn_handle); + if (!avail_ctx) { + return BLE_HS_ENOENT; + } + + if (avail_ctx >= 0) { + avail_ctx->conn_handle = BLE_HS_CONN_HANDLE_NONE; + } + break; + default: + break; + } + return 0; +} + +void +ble_svc_audio_pacs_init(void) +{ + int rc; + + /* Ensure this function only gets called by sysinit. */ + SYSINIT_ASSERT_ACTIVE(); + + rc = ble_gatts_count_cfg(ble_svc_audio_pacs_defs); + SYSINIT_PANIC_ASSERT(rc == 0); + + rc = ble_gatts_add_svcs(ble_svc_audio_pacs_defs); + SYSINIT_PANIC_ASSERT(rc == 0); + + rc = ble_gap_event_listener_register(&ble_pacs_listener, + ble_pacs_gap_event, NULL); + SYSINIT_PANIC_ASSERT(rc == 0); + + rc = ble_audio_event_listener_register(&ble_audio_listener, ble_pacs_audio_event, NULL); + SYSINIT_PANIC_ASSERT(rc == 0); + (void)rc; +} diff --git a/nimble/host/audio/services/pacs/syscfg.yml b/nimble/host/audio/services/pacs/syscfg.yml new file mode 100644 index 0000000000..01481c0cee --- /dev/null +++ b/nimble/host/audio/services/pacs/syscfg.yml @@ -0,0 +1,69 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +syscfg.defs: + BLE_SVC_AUDIO_PACS_SYSINIT_STAGE: + description: > + Sysinit stage for Published Audio Capabilities Service. + value: 303 + BLE_SVC_AUDIO_PACS_SINK_PAC: + description: > + Enable Sink PAC characteristic. + If disabled, BLE_SVC_AUDIO_PACS_SOURCE_PAC must be enabled. + value: 1 + BLE_SVC_AUDIO_PACS_SINK_PAC_NOTIFY: + description: > + Enable Sink PAC characteristic notifications. + value: 1 + restrictions: BLE_SVC_AUDIO_PACS_SINK_PAC + BLE_SVC_AUDIO_PACS_SINK_AUDIO_LOCATIONS: + description: > + Enable SOURCE Sink Audio Locations characteristic. + value: 1 + restrictions: BLE_SVC_AUDIO_PACS_SINK_PAC + BLE_SVC_AUDIO_PACS_SINK_AUDIO_LOCATIONS_NOTIFY: + description: > + Enable SOURCE Sink Audio Locations characteristic notifications. + value: 1 + restrictions: BLE_SVC_AUDIO_PACS_SINK_AUDIO_LOCATIONS + BLE_SVC_AUDIO_PACS_SOURCE_PAC: + description: > + Enable Source PAC characteristic. + If disabled, BLE_SVC_AUDIO_PACS_SINK_PAC must be enabled. + value: 1 + BLE_SVC_AUDIO_PACS_SOURCE_PAC_NOTIFY: + description: > + Enable Source PAC characteristic notifications. + value: 1 + restrictions: BLE_SVC_AUDIO_PACS_SOURCE_PAC + BLE_SVC_AUDIO_PACS_SOURCE_AUDIO_LOCATIONS: + description: > + Enable Source Audio Locations characteristic. + value: 1 + restrictions: BLE_SVC_AUDIO_PACS_SOURCE_PAC + BLE_SVC_AUDIO_PACS_SOURCE_AUDIO_LOCATIONS_NOTIFY: + description: > + Enable Source Audio Locations characteristic notifications. + value: 1 + restrictions: BLE_SVC_AUDIO_PACS_SOURCE_AUDIO_LOCATIONS + BLE_SVC_AUDIO_PACS_SUP_AUDIO_CTX_NOTIFY: + description: > + Enable Supported Audio Contexts characteristic notifications. + value: 1 + +syscfg.restrictions: + - 'BLE_SVC_AUDIO_PACS_SINK_PAC == 1 || BLE_SVC_AUDIO_PACS_SOURCE_PAC == 1' diff --git a/nimble/host/audio/src/ble_audio.c b/nimble/host/audio/src/ble_audio.c new file mode 100644 index 0000000000..f601a07fb4 --- /dev/null +++ b/nimble/host/audio/src/ble_audio.c @@ -0,0 +1,529 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include + +#include "host/ble_hs.h" +#include "audio/ble_audio.h" + +#include "ble_audio_priv.h" + +static struct ble_gap_event_listener ble_audio_gap_event_listener; +static SLIST_HEAD(, ble_audio_event_listener) ble_audio_event_listener_list = + SLIST_HEAD_INITIALIZER(ble_audio_event_listener_list); + +struct ble_audio_adv_parse_broadcast_announcement_data { + struct ble_audio_event event; + struct ble_audio_pub_broadcast_announcement pub; + struct ble_audio_broadcast_name name; + bool success; +}; + +static int +ble_audio_adv_parse_broadcast_announcement(const struct ble_hs_adv_field *field, void *user_data) +{ + struct ble_audio_adv_parse_broadcast_announcement_data *data = user_data; + struct ble_audio_event_broadcast_announcement *event; + const uint8_t value_len = field->length - sizeof(field->length); + ble_uuid16_t uuid16 = BLE_UUID16_INIT(0); + uint8_t offset = 0; + + event = &data->event.broadcast_announcement; + + switch (field->type) { + case BLE_HS_ADV_TYPE_SVC_DATA_UUID16: + if (value_len < 2) { + break; + } + + uuid16.value = get_le16(&field->value[offset]); + offset += 2; + + switch (uuid16.value) { + case BLE_BROADCAST_AUDIO_ANNOUNCEMENT_SVC_UUID: + if ((value_len - offset) < 3) { + /* Stop parsing */ + data->success = false; + return 0; + } + + event->broadcast_id = get_le24(&field->value[offset]); + offset += 3; + + if (value_len > offset) { + event->svc_data = &field->value[offset]; + event->svc_data_len = value_len - offset; + } + + data->success = true; + break; + + case BLE_BROADCAST_PUB_ANNOUNCEMENT_SVC_UUID: + if (event->pub_announcement_data != NULL) { + /* Ignore */ + break; + } + + if ((value_len - offset) < 2) { + /* Stop parsing */ + data->success = false; + return 0; + } + + data->pub.features = field->value[offset++]; + data->pub.metadata_len = field->value[offset++]; + + if ((value_len - offset) < data->pub.metadata_len) { + break; + } + + data->pub.metadata = &field->value[offset]; + + event->pub_announcement_data = &data->pub; + break; + + default: + break; + } + + break; + + case BLE_HS_ADV_TYPE_BROADCAST_NAME: + if (event->name != NULL) { + /* Ignore */ + break; + } + + if (value_len < 4 || value_len > 32) { + /* Stop parsing */ + data->success = false; + return 0; + } + + data->name.name = (char *)field->value; + data->name.name_len = value_len; + + event->name = &data->name; + break; + + default: + break; + } + + /* Continue parsing */ + return BLE_HS_ENOENT; +} + +static int +ble_audio_gap_event(struct ble_gap_event *gap_event, void *arg) +{ + switch (gap_event->type) { + case BLE_GAP_EVENT_EXT_DISC: { + struct ble_audio_adv_parse_broadcast_announcement_data data = { + .success = false, + }; + int rc; + + rc = ble_hs_adv_parse(gap_event->ext_disc.data, + gap_event->ext_disc.length_data, + ble_audio_adv_parse_broadcast_announcement, &data); + if (rc == 0 && data.success) { + data.event.type = BLE_AUDIO_EVENT_BROADCAST_ANNOUNCEMENT; + data.event.broadcast_announcement.ext_disc = &gap_event->ext_disc; + + (void)ble_audio_event_listener_call(&data.event); + } + break; + } + + default: + break; + } + + return 0; +} + +int +ble_audio_event_listener_register(struct ble_audio_event_listener *listener, + ble_audio_event_fn *fn, void *arg) +{ + struct ble_audio_event_listener *evl = NULL; + int rc; + + if (listener == NULL) { + BLE_HS_LOG_ERROR("NULL listener!\n"); + return BLE_HS_EINVAL; + } + + if (fn == NULL) { + BLE_HS_LOG_ERROR("NULL fn!\n"); + return BLE_HS_EINVAL; + } + + SLIST_FOREACH(evl, &ble_audio_event_listener_list, next) { + if (evl == listener) { + break; + } + } + + if (evl) { + return BLE_HS_EALREADY; + } + + if (SLIST_EMPTY(&ble_audio_event_listener_list)) { + rc = ble_gap_event_listener_register( + &ble_audio_gap_event_listener, + ble_audio_gap_event, NULL); + if (rc != 0) { + return rc; + } + } + + memset(listener, 0, sizeof(*listener)); + listener->fn = fn; + listener->arg = arg; + SLIST_INSERT_HEAD(&ble_audio_event_listener_list, listener, next); + + return 0; +} + +int +ble_audio_event_listener_unregister(struct ble_audio_event_listener *listener) +{ + struct ble_audio_event_listener *evl = NULL; + int rc; + + if (listener == NULL) { + BLE_HS_LOG_ERROR("NULL listener!\n"); + return BLE_HS_EINVAL; + } + + /* We check if element exists on the list only for sanity to let caller + * know whether it registered its listener before. + */ + SLIST_FOREACH(evl, &ble_audio_event_listener_list, next) { + if (evl == listener) { + break; + } + } + + if (!evl) { + return BLE_HS_ENOENT; + } + + SLIST_REMOVE(&ble_audio_event_listener_list, listener, + ble_audio_event_listener, next); + + if (SLIST_EMPTY(&ble_audio_event_listener_list)) { + rc = ble_gap_event_listener_unregister( + &ble_audio_gap_event_listener); + if (rc != 0) { + return rc; + } + } + + return 0; +} + +int +ble_audio_event_listener_call(struct ble_audio_event *event) +{ + struct ble_audio_event_listener *evl = NULL; + + SLIST_FOREACH(evl, &ble_audio_event_listener_list, next) { + evl->fn(event, evl->arg); + } + + return 0; +} + +/* Get the next subgroup data pointer */ +static const uint8_t * +ble_audio_base_subgroup_next(uint8_t num_bis, const uint8_t *data, + uint8_t data_len) +{ + uint8_t offset = 0; + + for (uint8_t i = 0; i < num_bis; i++) { + uint8_t codec_specific_config_len; + + /* BIS_index[i[k]] + Codec_Specific_Configuration_Length[i[k]] */ + if ((data_len - offset) < 2) { + return NULL; + } + + /* Skip BIS_index[i[k]] */ + offset++; + + codec_specific_config_len = data[offset]; + offset++; + + if ((data_len - offset) < codec_specific_config_len) { + return NULL; + } + + offset += codec_specific_config_len; + } + + return &data[offset]; +} + +int +ble_audio_base_parse(const uint8_t *data, uint8_t data_len, + struct ble_audio_base_group *group, + struct ble_audio_base_iter *subgroup_iter) +{ + uint8_t offset = 0; + + if (data == NULL) { + BLE_HS_LOG_ERROR("NULL data!\n"); + return BLE_HS_EINVAL; + } + + if (group == NULL) { + BLE_HS_LOG_ERROR("NULL group!\n"); + return BLE_HS_EINVAL; + } + + /* Presentation_Delay + Num_Subgroups */ + if (data_len < 4) { + return BLE_HS_EMSGSIZE; + } + + group->presentation_delay = get_le24(data); + offset += 3; + + group->num_subgroups = data[offset]; + offset++; + + if (group->num_subgroups < 1) { + BLE_HS_LOG_ERROR("Invalid BASE: no subgroups!\n"); + return BLE_HS_EINVAL; + } + + if (subgroup_iter != NULL) { + subgroup_iter->data = &data[offset]; + subgroup_iter->buf_len = data_len; + subgroup_iter->buf = data; + subgroup_iter->num_elements = group->num_subgroups; + } + + return 0; +} + +int +ble_audio_base_subgroup_iter(struct ble_audio_base_iter *subgroup_iter, + struct ble_audio_base_subgroup *subgroup, + struct ble_audio_base_iter *bis_iter) +{ + const uint8_t *data; + uint8_t data_len; + ptrdiff_t offset; + uint8_t num_subgroups; + + if (subgroup_iter == NULL) { + BLE_HS_LOG_ERROR("NULL subgroup_iter!\n"); + return BLE_HS_EINVAL; + } + + if (subgroup == NULL) { + BLE_HS_LOG_ERROR("NULL subgroup!\n"); + return BLE_HS_EINVAL; + } + + data = subgroup_iter->data; + if (data == NULL) { + return BLE_HS_ENOENT; + } + + offset = data - subgroup_iter->buf; + if (offset < 0 || offset > subgroup_iter->buf_len) { + return BLE_HS_EINVAL; + } + + num_subgroups = subgroup_iter->num_elements; + if (num_subgroups == 0) { + /* All subgroups have been parsed */ + return BLE_HS_ENOENT; + } + + data_len = subgroup_iter->buf_len - offset; + + /* Reset the offset */ + offset = 0; + + memset(subgroup, 0, sizeof(*subgroup)); + + /* Num_BIS + Codec_ID + Codec_Specific_Configuration_Length[i] */ + if (data_len < 7) { + return BLE_HS_EMSGSIZE; + } + + subgroup->num_bis = data[offset]; + offset++; + + if (subgroup->num_bis < 1) { + BLE_HS_LOG_ERROR("Invalid BASE: no BISes!\n"); + return BLE_HS_EINVAL; + } + + subgroup->codec_id.format = data[offset]; + offset++; + + subgroup->codec_id.company_id = get_le16(&data[offset]); + offset += 2; + + subgroup->codec_id.vendor_specific = get_le16(&data[offset]); + offset += 2; + + subgroup->codec_spec_config_len = data[offset]; + offset++; + + if (subgroup->codec_spec_config_len < 1) { + BLE_HS_LOG_DEBUG("Rule 4: Codec_Specific_Configuration parameters shall" + "be present at Level 2\n"); + } + + if ((data_len - offset) < subgroup->codec_spec_config_len) { + return BLE_HS_EMSGSIZE; + } + + subgroup->codec_spec_config = &data[offset]; + offset += subgroup->codec_spec_config_len; + + /* Metadata_Length[i] */ + if ((data_len - offset) < 1) { + return BLE_HS_EMSGSIZE; + } + + subgroup->metadata_len = data[offset]; + offset++; + + if (subgroup->metadata_len > 0) { + if ((data_len - offset) < subgroup->metadata_len) { + return BLE_HS_EMSGSIZE; + } + + subgroup->metadata = &data[offset]; + offset += subgroup->metadata_len; + } else { + subgroup->metadata = NULL; + } + + if (bis_iter != 0) { + bis_iter->data = &data[offset]; + bis_iter->buf_len = subgroup_iter->buf_len; + bis_iter->buf = subgroup_iter->buf; + bis_iter->num_elements = subgroup->num_bis; + } + + num_subgroups--; + + /* Update iterator */ + subgroup_iter->num_elements = num_subgroups; + + if (num_subgroups > 0) { + subgroup_iter->data = ble_audio_base_subgroup_next(subgroup->num_bis, + &data[offset], + data_len - offset); + } else { + subgroup_iter->data = NULL; + } + + return 0; +} + +int +ble_audio_base_bis_iter(struct ble_audio_base_iter *bis_iter, + struct ble_audio_base_bis *bis) +{ + const uint8_t *data; + uint8_t data_len; + ptrdiff_t offset; + uint8_t num_bis; + + if (bis_iter == NULL) { + BLE_HS_LOG_ERROR("NULL bis_iter!\n"); + return BLE_HS_EINVAL; + } + + if (bis == NULL) { + BLE_HS_LOG_ERROR("NULL bis!\n"); + return BLE_HS_EINVAL; + } + + data = bis_iter->data; + if (data == NULL) { + return BLE_HS_ENOENT; + } + + offset = data - bis_iter->buf; + if (offset < 0 || offset > bis_iter->buf_len) { + return BLE_HS_EINVAL; + } + + num_bis = bis_iter->num_elements; + if (num_bis == 0) { + /* All BISes have been parsed */ + return BLE_HS_ENOENT; + } + + data_len = bis_iter->buf_len - offset; + + /* Reset the offset */ + offset = 0; + + memset(bis, 0, sizeof(*bis)); + + /* BIS_index[i[k]] + Codec_Specific_Configuration_Length[i[k]] */ + if (data_len < 2) { + return BLE_HS_EMSGSIZE; + } + + bis->index = data[0]; + offset++; + + bis->codec_spec_config_len = data[offset]; + offset++; + + if (bis->codec_spec_config_len > 0) { + if ((data_len - offset) < bis->codec_spec_config_len) { + return BLE_HS_EMSGSIZE; + } + + bis->codec_spec_config = &data[offset]; + offset += bis->codec_spec_config_len; + } else { + bis->codec_spec_config = NULL; + } + + num_bis--; + + /* Update iterator */ + bis_iter->num_elements = num_bis; + + if (num_bis > 0) { + bis_iter->data = &data[offset]; + } else { + bis_iter->data = NULL; + } + + return 0; +} diff --git a/nimble/host/audio/src/ble_audio_broadcast_sink.c b/nimble/host/audio/src/ble_audio_broadcast_sink.c new file mode 100644 index 0000000000..8c2f05451d --- /dev/null +++ b/nimble/host/audio/src/ble_audio_broadcast_sink.c @@ -0,0 +1,1647 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "sysinit/sysinit.h" + +#if MYNEWT_VAL(BLE_AUDIO_BROADCAST_SINK) +#include "stdlib.h" + +#include "audio/ble_audio.h" +#include "audio/ble_audio_broadcast_sink.h" +#include "audio/ble_audio_scan_delegator.h" +#include "host/ble_gap.h" +#include "host/ble_hs.h" +#include "host/ble_iso.h" +#include "host/ble_uuid.h" + +#include "ble_audio_priv.h" +#include "ble_audio_scan_delegator_priv.h" + +#define CLAMP(_n, _min, _max) (MAX(_min, MIN(_n, _max))) +#define BROADCAST_ID_INVALID 0xFFFFFFFF +#define BIS_INDEX_TEST(_bis_sync, _index) (((_bis_sync) & (1 << ((_index) - 1))) > 0) +#define BIS_INDEX_SET(_bis_sync, _index) ((_bis_sync) |= (1 << ((_index) - 1))) +#define BIS_INDEX_CLEAR(_bis_sync, _index) ((_bis_sync) &= ~(1 << ((_index) - 1))) + +static struct { + ble_audio_broadcast_sink_action_fn *fn; + void *arg; +} action_cb; + +enum pa_sync_state_internal { + PA_SYNC_STATE_IDLE, + PA_SYNC_STATE_PENDING_DISC, + PA_SYNC_STATE_PENDING_PAST, + PA_SYNC_STATE_PENDING_SYNC, + PA_SYNC_STATE_ACTIVE, + PA_SYNC_STATE_ERROR, + PA_SYNC_STATE_TIMEOUT, +}; + +enum big_sync_state_internal { + BIG_SYNC_STATE_IDLE, + BIG_SYNC_STATE_PENDING_BIG_INFO, + BIG_SYNC_STATE_PENDING_CODE, + BIG_SYNC_STATE_PENDING_BASE, + BIG_SYNC_STATE_PENDING_SYNC, + BIG_SYNC_STATE_FAILED, + BIG_SYNC_STATE_ACTIVE, +}; + +struct ble_audio_broadcast_sink { + /** Instance ID, same as BASS Source ID */ + uint8_t source_id; + + /** Internal PA sync state */ + enum pa_sync_state_internal pa_sync_state; + + /** Internal BIG sync state */ + enum big_sync_state_internal big_sync_state; + + /** Periodic sync handle */ + uint16_t pa_sync_handle; + + /** Connection handle or @ref BLE_HS_CONN_HANDLE_NONE */ + uint16_t past_conn_handle; + + /** BIG Handle */ + uint8_t big_handle; + + /** ISO Interval */ + uint16_t iso_interval; + + /** Burst Number */ + uint8_t bn; + + /** Number of SubEvents */ + uint8_t nse; + + /** Callback function */ + ble_audio_event_fn *cb; + + /** Broadcast code */ + uint8_t broadcast_code[BLE_AUDIO_BROADCAST_CODE_SIZE]; + + /** The optional argument to pass to the callback function. */ + void *cb_arg; + + /** BIG Sync Parameters */ + struct ble_audio_broadcast_sink_big_sync_params *big_sync_params; + + /** If true, the broadcast is encrypted and requires broadcast_code */ + uint8_t is_encrypted : 1; + /** If true, the broadcast_code value is valid */ + uint8_t broadcast_code_is_valid : 1; + + /** Internal subgroups state */ + uint8_t num_subgroups; + struct { + uint32_t bis_sync; + } subgroups[MYNEWT_VAL(BLE_AUDIO_SCAN_DELEGATOR_SUBGROUP_MAX)]; + + /** Singly-linked list entry. */ + SLIST_ENTRY(ble_audio_broadcast_sink) next; +}; + +static SLIST_HEAD(, ble_audio_broadcast_sink) ble_audio_broadcast_sink_list; +static struct os_mempool ble_audio_broadcast_sink_pool; +static os_membuf_t ble_audio_broadcast_sink_mem[ + OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_AUDIO_BROADCAST_SINK_MAX), + sizeof(struct ble_audio_broadcast_sink))]; + +/** If true, the discovery was started by us, otherwise by someone else */ +static bool disc_self_initiated; + +/** If true, the Periodic Advertising Sync is pending */ +static bool periodic_adv_sync_in_progress; + +static int gap_event_handler(struct ble_gap_event *event, void *arg); +static int iso_event_handler(struct ble_iso_event *event, void *arg); +static void big_sync_state_set(struct ble_audio_broadcast_sink *sink, enum big_sync_state_internal state_internal); +static void pa_sync_state_set(struct ble_audio_broadcast_sink *sink, enum pa_sync_state_internal state_internal); + +static struct ble_audio_broadcast_sink * +broadcast_sink_get(uint8_t source_id) +{ + struct ble_audio_broadcast_sink *sink; + + SLIST_FOREACH(sink, &ble_audio_broadcast_sink_list, next) { + if (source_id == sink->source_id) { + return sink; + } + } + + return NULL; +} + +static struct ble_audio_broadcast_sink * +broadcast_lookup_pa_sync_handle(uint16_t pa_sync_handle) +{ + struct ble_audio_broadcast_sink *sink; + + SLIST_FOREACH(sink, &ble_audio_broadcast_sink_list, next) { + if (pa_sync_handle == sink->pa_sync_handle) { + return sink; + } + } + + return NULL; +} + +static struct ble_audio_broadcast_sink * +broadcast_sink_lookup_adv_sid_broadcast_id_pair(uint8_t adv_sid, uint32_t broadcast_id) +{ + struct ble_audio_scan_delegator_source_desc source_desc; + struct ble_audio_broadcast_sink *sink; + int rc; + + SLIST_FOREACH(sink, &ble_audio_broadcast_sink_list, next) { + rc = ble_audio_scan_delegator_source_desc_get(sink->source_id, &source_desc); + if (rc != 0) { + BLE_HS_LOG_ERROR("source desc get failed (%d)\n", rc); + continue; + } + + if (source_desc.adv_sid == adv_sid && source_desc.broadcast_id == broadcast_id) { + return sink; + } + } + + return NULL; +} + +static struct ble_audio_broadcast_sink * +broadcast_sink_lookup_addr_adv_sid_pair(const ble_addr_t *addr, uint8_t adv_sid) +{ + struct ble_audio_scan_delegator_source_desc source_desc; + struct ble_audio_broadcast_sink *sink; + int rc; + + SLIST_FOREACH(sink, &ble_audio_broadcast_sink_list, next) { + rc = ble_audio_scan_delegator_source_desc_get(sink->source_id, &source_desc); + if (rc != 0) { + BLE_HS_LOG_ERROR("source desc get failed (%d)\n", rc); + continue; + } + + if (source_desc.adv_sid == adv_sid && ble_addr_cmp(&source_desc.addr, addr) == 0) { + return sink; + } + } + + return NULL; +} + +static struct ble_audio_broadcast_sink * +broadcast_sink_lookup_pa_sync_state(enum pa_sync_state_internal state_internal) +{ + struct ble_audio_broadcast_sink *sink; + + SLIST_FOREACH(sink, &ble_audio_broadcast_sink_list, next) { + if (sink->pa_sync_state == state_internal) { + return sink; + } + } + + return NULL; +} + +static int +disc_start(void) +{ + struct ble_audio_broadcast_sink_action action; + struct ble_gap_ext_disc_params disc_params; + int rc; + + if (ble_gap_disc_active()) { + return 0; + } + + disc_params.itvl = BLE_GAP_SCAN_FAST_INTERVAL_MIN; + disc_params.window = BLE_GAP_SCAN_FAST_WINDOW; + disc_params.passive = true; + + action.type = BLE_AUDIO_BROADCAST_SINK_ACTION_DISC_START; + action.disc_start.params_preferred = &disc_params; + + rc = action_cb.fn(&action, action_cb.arg); + if (rc != 0) { + BLE_HS_LOG_WARN("disc start rejected by user (%d)\n", rc); + } else { + disc_self_initiated = true; + } + + return rc; +} + +static void +disc_stop(void) +{ + struct ble_audio_broadcast_sink_action action; + int rc; + + if (!disc_self_initiated || !ble_gap_disc_active()) { + return; + } + + action.type = BLE_AUDIO_BROADCAST_SINK_ACTION_DISC_STOP; + + rc = action_cb.fn(&action, action_cb.arg); + if (rc != 0) { + BLE_HS_LOG_WARN("disc stop rejected by user (%d)\n", rc); + } + + disc_self_initiated = false; +} + +struct basic_audio_announcement_svc_data { + /** BASE length */ + uint8_t length; + + /** BASE */ + const uint8_t *base; +}; + +struct service_data_uuid16 { + struct basic_audio_announcement_svc_data basic_audio_announcement; +}; + +static void +service_data_uuid16_parse(const uint16_t uuid16, const uint8_t * const value, const uint8_t value_len, + void *user_data) +{ + struct service_data_uuid16 *data = user_data; + + if (uuid16 == BLE_BASIC_AUDIO_ANNOUNCEMENT_SVC_UUID) { + data->basic_audio_announcement.base = value; + data->basic_audio_announcement.length = value_len; + } +} + +struct periodic_report { + struct service_data_uuid16 uuid16; +}; + +static int +periodic_report_parse(const struct ble_hs_adv_field *field, void *user_data) +{ + struct periodic_report *report = user_data; + const uint8_t value_len = field->length - sizeof(field->length); + ble_uuid16_t uuid16 = BLE_UUID16_INIT(0); + uint8_t offset = 0; + + switch (field->type) { + case BLE_HS_ADV_TYPE_SVC_DATA_UUID16: + if (value_len < 2) { + break; + } + + uuid16.value = get_le16(&field->value[offset]); + offset += 2; + + service_data_uuid16_parse(uuid16.value, &field->value[offset], value_len - offset, &report->uuid16); + break; + + default: + /* Continue */ + return BLE_HS_ENOENT; + } + + /* Stop */ + return 0; +} + +static uint32_t +subgroup_bis_sync_get(struct ble_audio_broadcast_sink *sink, uint8_t subgroup_index) +{ + if (subgroup_index > sink->num_subgroups) { + return 0; + } + + return sink->subgroups[subgroup_index].bis_sync; +} + +static void +bass_big_state_update(struct ble_audio_broadcast_sink *sink, enum big_sync_state_internal from, + enum big_sync_state_internal to) +{ + struct ble_audio_scan_delegator_receive_state receive_state = {0}; + int rc; + + rc = ble_audio_scan_delegator_receive_state_get(sink->source_id, &receive_state); + if (rc != 0) { + BLE_HS_LOG_ERROR("receive state get failed (%d)\n", rc); + return; + } + + switch (to) { + case BIG_SYNC_STATE_PENDING_CODE: + receive_state.big_enc = BLE_AUDIO_SCAN_DELEGATOR_BIG_ENC_BROADCAST_CODE_MISSING; + break; + + case BIG_SYNC_STATE_IDLE: + if (from == BIG_SYNC_STATE_PENDING_CODE) { + /* FIXME: this does not seem to be right */ + receive_state.big_enc = BLE_AUDIO_SCAN_DELEGATOR_BIG_ENC_BROADCAST_CODE_INVALID; + memcpy(receive_state.bad_code, sink->broadcast_code, sizeof(receive_state.bad_code)); + } else if (from == BIG_SYNC_STATE_ACTIVE || from == BIG_SYNC_STATE_FAILED) { + /* Iterate subgroup indexes to update the BIS Sync state */ + for (uint8_t index = 0; index < receive_state.num_subgroups; index++) { + receive_state.subgroups[index].bis_sync = 0; + } + } + /* fallthrough */ + + case BIG_SYNC_STATE_PENDING_BIG_INFO: + case BIG_SYNC_STATE_PENDING_BASE: + case BIG_SYNC_STATE_PENDING_SYNC: + receive_state.big_enc = BLE_AUDIO_SCAN_DELEGATOR_BIG_ENC_NONE; + break; + + case BIG_SYNC_STATE_FAILED: + receive_state.big_enc = BLE_AUDIO_SCAN_DELEGATOR_BIG_ENC_NONE; + + /* BASS v1.0 3.1.1.4 Add Source operation + * "(...) if the server fails to synchronize to the BIG, the server shall write a value of + * 0xFFFFFFFF (Failed to synchronize to BIG) to the BIS_Sync_State field + */ + for (uint8_t index = 0; index < receive_state.num_subgroups; index++) { + receive_state.subgroups[index].bis_sync = BLE_AUDIO_SCAN_DELEGATOR_BIS_SYNC_ANY; + } + break; + + case BIG_SYNC_STATE_ACTIVE: + if (sink->is_encrypted) { + receive_state.big_enc = BLE_AUDIO_SCAN_DELEGATOR_BIG_ENC_DECRYPTING; + } else { + receive_state.big_enc = BLE_AUDIO_SCAN_DELEGATOR_BIG_ENC_NONE; + } + + /* Iterate subgroup indexes to update the BIS Sync state */ + for (uint8_t index = 0; index < receive_state.num_subgroups; index++) { + receive_state.subgroups[index].bis_sync = subgroup_bis_sync_get(sink, index); + } + break; + } + + rc = ble_audio_scan_delegator_receive_state_set(sink->source_id, &receive_state); + if (rc != 0) { + BLE_HS_LOG_ERROR("receive state update failed (%d)\n", rc); + } +} + +static enum ble_audio_broadcast_sink_sync_state +big_state_internal_to_api(enum big_sync_state_internal state_internal) +{ + switch (state_internal) { + case BIG_SYNC_STATE_PENDING_CODE: + case BIG_SYNC_STATE_PENDING_BIG_INFO: + case BIG_SYNC_STATE_PENDING_BASE: + case BIG_SYNC_STATE_PENDING_SYNC: + return BLE_AUDIO_BROADCAST_SINK_SYNC_STATE_INITIATED; + + case BIG_SYNC_STATE_ACTIVE: + return BLE_AUDIO_BROADCAST_SINK_SYNC_STATE_ESTABLISHED; + + default: + return BLE_AUDIO_BROADCAST_SINK_SYNC_STATE_NOT_SYNCED; + } +} + +static void +api_bis_state_update(struct ble_audio_broadcast_sink *sink, enum big_sync_state_internal from, + enum big_sync_state_internal to) +{ + struct ble_audio_event event; + + if (to == BIG_SYNC_STATE_ACTIVE) { + /* special case. event already sent from big_sync_established_handler() */ + return; + } + + event.type = BLE_AUDIO_EVENT_BROADCAST_SINK_BIS_SYNC_STATE; + event.broadcast_sink_bis_sync_state.source_id = sink->source_id; + event.broadcast_sink_bis_sync_state.state = big_state_internal_to_api(to); + event.broadcast_sink_bis_sync_state.conn_handle = BLE_HS_CONN_HANDLE_NONE; + + for (uint8_t subgroup_index = 0; subgroup_index < sink->num_subgroups; subgroup_index++) { + uint32_t bis_sync = sink->subgroups[subgroup_index].bis_sync; + + if (bis_sync != BLE_AUDIO_SCAN_DELEGATOR_BIS_SYNC_ANY) { + for (uint8_t bis_index = 0; bis_sync > 0; bis_index++) { + if (BIS_INDEX_TEST(bis_sync, bis_index)) { + event.broadcast_sink_bis_sync_state.bis_index = bis_index; + ble_audio_event_listener_call(&event); + BIS_INDEX_CLEAR(bis_sync, bis_index); + } + } + } + } +} + +static void +big_sync_state_set(struct ble_audio_broadcast_sink *sink, enum big_sync_state_internal state_internal) +{ + enum big_sync_state_internal state_internal_old = sink->big_sync_state; + + if (state_internal == state_internal_old) { + return; + } + + sink->big_sync_state = state_internal; + + api_bis_state_update(sink, state_internal_old, state_internal); + bass_big_state_update(sink, state_internal_old, state_internal); +} + +static void +bass_pa_state_update(struct ble_audio_broadcast_sink *sink, enum pa_sync_state_internal from, + enum pa_sync_state_internal to) +{ + struct ble_audio_scan_delegator_receive_state receive_state; + int rc; + + rc = ble_audio_scan_delegator_receive_state_get(sink->source_id, &receive_state); + if (rc != 0) { + BLE_HS_LOG_ERROR("receive state get failed (%d)\n", rc); + return; + } + + switch (to) { + case PA_SYNC_STATE_IDLE: + case PA_SYNC_STATE_PENDING_DISC: + case PA_SYNC_STATE_PENDING_SYNC: + receive_state.pa_sync_state = BLE_AUDIO_SCAN_DELEGATOR_PA_SYNC_STATE_NOT_SYNCED; + break; + + case PA_SYNC_STATE_PENDING_PAST: + receive_state.pa_sync_state = BLE_AUDIO_SCAN_DELEGATOR_PA_SYNC_STATE_SYNC_INFO_REQ; + break; + + case PA_SYNC_STATE_ACTIVE: + receive_state.pa_sync_state = BLE_AUDIO_SCAN_DELEGATOR_PA_SYNC_STATE_SYNCED; + break; + + case PA_SYNC_STATE_ERROR: + receive_state.pa_sync_state = BLE_AUDIO_SCAN_DELEGATOR_PA_SYNC_STATE_ERROR; + break; + + case PA_SYNC_STATE_TIMEOUT: + if (from == PA_SYNC_STATE_PENDING_PAST) { + receive_state.pa_sync_state = BLE_AUDIO_SCAN_DELEGATOR_PA_SYNC_STATE_NO_PAST; + } else { + receive_state.pa_sync_state = BLE_AUDIO_SCAN_DELEGATOR_PA_SYNC_STATE_ERROR; + } + break; + } + + rc = ble_audio_scan_delegator_receive_state_set(sink->source_id, &receive_state); + if (rc != 0) { + BLE_HS_LOG_ERROR("receive state set failed (%d)\n", rc); + } +} + +static enum ble_audio_broadcast_sink_sync_state +pa_state_internal_to_api(enum pa_sync_state_internal state_internal) +{ + switch (state_internal) { + case PA_SYNC_STATE_PENDING_DISC: + case PA_SYNC_STATE_PENDING_SYNC: + case PA_SYNC_STATE_PENDING_PAST: + return BLE_AUDIO_BROADCAST_SINK_SYNC_STATE_INITIATED; + + case PA_SYNC_STATE_ACTIVE: + return BLE_AUDIO_BROADCAST_SINK_SYNC_STATE_ESTABLISHED; + + default: + return BLE_AUDIO_BROADCAST_SINK_SYNC_STATE_NOT_SYNCED; + } +} + +static void +api_pa_state_update(struct ble_audio_broadcast_sink *sink, enum pa_sync_state_internal from, + enum pa_sync_state_internal to) +{ + struct ble_audio_event event; + + event.type = BLE_AUDIO_EVENT_BROADCAST_SINK_PA_SYNC_STATE; + event.broadcast_sink_pa_sync_state.source_id = sink->source_id; + event.broadcast_sink_pa_sync_state.state = pa_state_internal_to_api(to); + + if (event.broadcast_sink_pa_sync_state.state != pa_state_internal_to_api(from)) { + ble_audio_event_listener_call(&event); + } +} + +static void +pa_sync_state_set(struct ble_audio_broadcast_sink *sink, enum pa_sync_state_internal state_internal) +{ + enum pa_sync_state_internal state_internal_old = sink->pa_sync_state; + + if (state_internal == state_internal_old) { + return; + } + + sink->pa_sync_state = state_internal; + api_pa_state_update(sink, state_internal_old, state_internal); + bass_pa_state_update(sink, state_internal_old, state_internal); +} + +static uint32_t +group_bis_sync_get(struct ble_audio_broadcast_sink *sink) +{ + uint32_t bis_sync_flat = 0; + + for (uint8_t subgroup_index = 0; subgroup_index < sink->num_subgroups; subgroup_index++) { + bis_sync_flat |= sink->subgroups[subgroup_index].bis_sync; + } + + return bis_sync_flat; +} + +static void +pa_sync_create(void) +{ + struct ble_gap_periodic_sync_params periodic_sync_params = {0}; + struct ble_audio_broadcast_sink_action action; + int rc; + + if (periodic_adv_sync_in_progress) { + return; + } + + action.type = BLE_AUDIO_BROADCAST_SINK_ACTION_PA_SYNC; + action.pa_sync.out_params = &periodic_sync_params; + + rc = action_cb.fn(&action, action_cb.arg); + if (rc != 0) { + BLE_HS_LOG_WARN("rejected by user (%d)\n", rc); + return; + } + + rc = ble_gap_periodic_adv_sync_create(NULL, 0, &periodic_sync_params, + gap_event_handler, NULL); + if (rc != 0) { + BLE_HS_LOG_ERROR("adv sync create failed (%d)\n", rc); + } else { + periodic_adv_sync_in_progress = true; + } +} + +static void +big_sync_established_handler(uint8_t source_id, uint8_t status, const struct ble_iso_big_desc *desc) +{ + struct ble_audio_broadcast_sink *sink; + uint32_t bis_sync_state = 0; + uint32_t group_bis_sync; + uint8_t bis_index; + + /* Restart scan if needed */ + if (broadcast_sink_lookup_pa_sync_state(PA_SYNC_STATE_PENDING_SYNC) != NULL) { + pa_sync_create(); + disc_start(); + } else if (broadcast_sink_lookup_pa_sync_state(PA_SYNC_STATE_PENDING_DISC) != NULL) { + disc_start(); + } + + sink = broadcast_sink_get(source_id); + if (sink == NULL) { + BLE_HS_LOG_DEBUG("Unknown source_id %u\n", source_id); + return; + } + + if (status != 0) { + big_sync_state_set(sink, BIG_SYNC_STATE_FAILED); + return; + } + + bis_index = 0; + group_bis_sync = group_bis_sync_get(sink); + + for (uint8_t i = 0; i < desc->num_bis; i++) { + uint16_t conn_handle = desc->conn_handle[i]; + + for (; group_bis_sync > 0; bis_index++) { + if (BIS_INDEX_TEST(group_bis_sync, bis_index)) { + struct ble_audio_event event; + + event.type = BLE_AUDIO_EVENT_BROADCAST_SINK_BIS_SYNC_STATE; + event.broadcast_sink_bis_sync_state.source_id = sink->source_id; + event.broadcast_sink_bis_sync_state.bis_index = bis_index; + event.broadcast_sink_bis_sync_state.state = BLE_AUDIO_BROADCAST_SINK_SYNC_STATE_ESTABLISHED; + event.broadcast_sink_bis_sync_state.conn_handle = conn_handle; + + ble_audio_event_listener_call(&event); + + BIS_INDEX_SET(bis_sync_state, bis_index); + BIS_INDEX_CLEAR(group_bis_sync, bis_index); + break; + } + } + } + + /* Check whether all BISes got conn handle */ + group_bis_sync = group_bis_sync_get(sink); + if (bis_sync_state != group_bis_sync) { + BLE_HS_LOG_WARN("not all BISes synced"); + + for (uint8_t subgroup_index = 0; subgroup_index < sink->num_subgroups; subgroup_index++) { + uint32_t bis_sync_missing; + + bis_sync_missing = sink->subgroups[subgroup_index].bis_sync & ~bis_sync_state; + if (bis_sync_missing == 0) { + continue; + } + + for (bis_index = 0; bis_sync_missing > 0; bis_index++) { + if (BIS_INDEX_TEST(bis_sync_missing, bis_index)) { + struct ble_audio_event event; + + event.type = BLE_AUDIO_EVENT_BROADCAST_SINK_BIS_SYNC_STATE; + event.broadcast_sink_bis_sync_state.source_id = sink->source_id; + event.broadcast_sink_bis_sync_state.bis_index = bis_index; + event.broadcast_sink_bis_sync_state.state = BLE_AUDIO_BROADCAST_SINK_SYNC_STATE_NOT_SYNCED; + event.broadcast_sink_bis_sync_state.conn_handle = BLE_HS_CONN_HANDLE_NONE; + + ble_audio_event_listener_call(&event); + + BIS_INDEX_CLEAR(bis_sync_missing, bis_index); + } + } + + sink->subgroups[subgroup_index].bis_sync &= bis_sync_state; + } + } + + big_sync_state_set(sink, BIG_SYNC_STATE_ACTIVE); +} + +static void +big_sync_terminated_handler(uint8_t source_id, uint8_t reason) +{ + struct ble_audio_broadcast_sink *sink; + + sink = broadcast_sink_get(source_id); + if (sink == NULL) { + BLE_HS_LOG_DEBUG("Unknown source_id %u\n", source_id); + return; + } + + big_sync_state_set(sink, BIG_SYNC_STATE_IDLE); +} + +static int +iso_event_handler(struct ble_iso_event *event, void *arg) +{ + switch (event->type) { + case BLE_ISO_EVENT_BIG_SYNC_ESTABLISHED: + big_sync_established_handler(POINTER_TO_UINT(arg), event->big_sync_established.status, + &event->big_sync_established.desc); + break; + + case BLE_ISO_EVENT_BIG_SYNC_TERMINATED: + big_sync_terminated_handler(POINTER_TO_UINT(arg), event->big_terminated.reason); + break; + + default: + break; + } + + return 0; +} + +static int +pa_sync_create_cancel(void) +{ + int rc; + + if (!periodic_adv_sync_in_progress) { + return 0; + } + + rc = ble_gap_periodic_adv_sync_create_cancel(); + if (rc != 0) { + BLE_HS_LOG_ERROR("adv sync create cancel failed (%d)\n", rc); + } else { + periodic_adv_sync_in_progress = false; + } + + return rc; +} + +static int +pa_sync_add(const ble_addr_t *addr, uint8_t adv_sid) +{ + int rc; + + if (periodic_adv_sync_in_progress) { + rc = pa_sync_create_cancel(); + if (rc != 0) { + return rc; + } + } + + rc = ble_gap_add_dev_to_periodic_adv_list(addr, adv_sid); + if (rc != 0) { + BLE_HS_LOG_ERROR("add dev to periodic adv list failed (%d)\n", rc); + /* TODO: destroy sink */ + return rc; + } + + (void)pa_sync_create(); + + return rc; +} + +static int +pa_sync_remove(const ble_addr_t *addr, uint8_t adv_sid) +{ + int rc; + + if (periodic_adv_sync_in_progress) { + rc = pa_sync_create_cancel(); + if (rc != 0) { + return rc; + } + } + + rc = ble_gap_rem_dev_from_periodic_adv_list(addr, adv_sid); + if (rc != 0) { + BLE_HS_LOG_ERROR("rem dev from periodic adv list failed (%d)\n", rc); + } + + return rc; +} + +static void +periodic_sync_handler(const ble_addr_t *addr, uint8_t adv_sid, uint8_t status, uint16_t pa_sync_handle) +{ + struct ble_audio_broadcast_sink *sink; + + periodic_adv_sync_in_progress = false; + + sink = broadcast_sink_lookup_addr_adv_sid_pair(addr, adv_sid); + if (sink == NULL) { + BLE_HS_LOG_DEBUG("sink not found\n"); + } else { + (void)pa_sync_remove(addr, adv_sid); + + if (status == BLE_ERR_SUCCESS) { + sink->pa_sync_handle = pa_sync_handle; + pa_sync_state_set(sink, PA_SYNC_STATE_ACTIVE); + } else if (status == BLE_ERR_OPERATION_CANCELLED) { + pa_sync_state_set(sink, PA_SYNC_STATE_IDLE); + } else if (status == BLE_ERR_CONN_ESTABLISHMENT) { + pa_sync_state_set(sink, PA_SYNC_STATE_TIMEOUT); + } else { + pa_sync_state_set(sink, PA_SYNC_STATE_ERROR); + } + } + + sink = broadcast_sink_lookup_pa_sync_state(PA_SYNC_STATE_PENDING_SYNC); + if (sink != NULL) { + pa_sync_create(); + disc_start(); + } else { + disc_stop(); + } +} + +static void +periodic_sync_lost_handler(uint16_t sync_handle, int reason) +{ + struct ble_audio_broadcast_sink *sink; + + sink = broadcast_lookup_pa_sync_handle(sync_handle); + if (sink == NULL) { + BLE_HS_LOG_DEBUG("Unknown sync_handle %u\n", sync_handle); + return; + } + + if (reason == BLE_HS_EDONE) { + pa_sync_state_set(sink, PA_SYNC_STATE_IDLE); + } else if (reason == BLE_HS_ETIMEOUT) { + pa_sync_state_set(sink, PA_SYNC_STATE_TIMEOUT); + } else { + pa_sync_state_set(sink, PA_SYNC_STATE_ERROR); + } +} + +static void +biginfo_report_handler(uint16_t pa_sync_handle, uint16_t iso_interval, uint8_t nse, uint8_t bn, uint8_t encryption) +{ + struct ble_audio_broadcast_sink *sink; + + sink = broadcast_lookup_pa_sync_handle(pa_sync_handle); + if (sink == NULL) { + BLE_HS_LOG_DEBUG("Unknown pa_sync_handle %u\n", pa_sync_handle); + return; + } + + if (sink->big_sync_state == BIG_SYNC_STATE_PENDING_BIG_INFO) { + sink->is_encrypted = encryption; + sink->iso_interval = iso_interval; + sink->nse = nse; + sink->bn = bn; + + if (sink->is_encrypted && !sink->broadcast_code_is_valid) { + big_sync_state_set(sink, BIG_SYNC_STATE_PENDING_CODE); + } else { + big_sync_state_set(sink, BIG_SYNC_STATE_PENDING_BASE); + } + } +} + +static int +bis_params_get(struct ble_audio_broadcast_sink *sink, struct ble_audio_base_group *group, + struct ble_audio_base_iter *subgroup_iter, + struct ble_iso_bis_params bis_params[MYNEWT_VAL(BLE_ISO_MAX_BISES)], uint8_t *out_bis_cnt) +{ + uint8_t subgroup_index; + uint32_t group_bis_sync = 0; + uint8_t bis_cnt = 0; + int rc = 0; + + if (action_cb.fn == NULL) { + BLE_HS_LOG_ERROR("action_cb.fn is NULL\n"); + return BLE_HS_EAPP; + } + + for (subgroup_index = 0; subgroup_index < group->num_subgroups; subgroup_index++) { + struct ble_audio_base_subgroup subgroup; + struct ble_audio_base_iter bis_iter; + uint32_t subgroup_bis_sync_req; + + rc = ble_audio_base_subgroup_iter(subgroup_iter, &subgroup, &bis_iter); + if (rc != 0) { + break; + } + + subgroup_bis_sync_req = subgroup_bis_sync_get(sink, subgroup_index); + if (subgroup_bis_sync_req == 0) { + /* No BISes requested for this subgroup */ + continue; + } + + sink->subgroups[subgroup_index].bis_sync = 0; + + for (uint8_t i = 0; i < subgroup.num_bis && bis_cnt < MYNEWT_VAL(BLE_ISO_MAX_BISES); i++) { + struct ble_audio_broadcast_sink_action action = {0}; + struct ble_audio_base_bis bis; + + rc = ble_audio_base_bis_iter(&bis_iter, &bis); + if (rc != 0) { + break; + } + + /* Core 5.4 | Vol 4, Part E; 7.8.106 LE BIG Create Sync command + * BIS[i]: 0x01 to 0x1F + */ + if (bis.index < 0x01 || bis.index > 0x7F) { + continue; + } + + if (BIS_INDEX_TEST(group_bis_sync, bis.index)) { + /* BAP_v1.0.1; 3.7.2.2 Basic Audio Announcements + * + * Rule 3: Every BIS in the BIG, denoted by its BIS_index value, + * shall only be present in one subgroup. + */ + BLE_HS_LOG_WARN("duplicated bis index 0x%02x", bis.index); + continue; + } + + if (!BIS_INDEX_TEST(subgroup_bis_sync_req, bis.index)) { + continue; + } + + action.type = BLE_AUDIO_BROADCAST_SINK_ACTION_BIS_SYNC; + action.bis_sync.source_id = sink->source_id; + action.bis_sync.subgroup_index = subgroup_index; + action.bis_sync.bis = &bis; + action.bis_sync.subgroup = &subgroup; + + rc = action_cb.fn(&action, action_cb.arg); + if (rc != 0) { + BLE_HS_LOG_WARN("bis sync rejected by user (%d)\n", rc); + } else { + BIS_INDEX_SET(sink->subgroups[subgroup_index].bis_sync, bis.index); + bis_params[bis_cnt].bis_index = bis.index; + bis_cnt++; + } + } + + group_bis_sync |= sink->subgroups[subgroup_index].bis_sync; + } + + sink->num_subgroups = subgroup_index; + + *out_bis_cnt = bis_cnt; + return rc; +} + +static int +bis_params_bis_index_cmp(const void *p1, const void *p2) +{ + const struct ble_iso_bis_params *bis_params_1 = p1; + const struct ble_iso_bis_params *bis_params_2 = p2; + + return bis_params_1->bis_index - bis_params_2->bis_index; +} + +static void +big_sync(struct ble_audio_broadcast_sink *sink, const uint8_t *base, uint8_t base_len) +{ + struct ble_audio_broadcast_sink_action action; + struct ble_audio_base_group group; + struct ble_audio_base_iter subgroup_iter; + struct ble_iso_big_sync_create_params big_sync_create_params; + struct ble_iso_bis_params bis_params[MYNEWT_VAL(BLE_ISO_MAX_BISES)]; + char broadcast_code[BLE_AUDIO_BROADCAST_CODE_SIZE + 1]; + uint8_t bis_cnt = 0; + int rc; + + rc = ble_audio_base_parse(base, base_len, &group, &subgroup_iter); + if (rc != 0) { + BLE_HS_LOG_ERROR("base parse failed (%d)\n", rc); + ble_audio_broadcast_sink_stop(sink->source_id); + return; + } + + /* By default, the controller can schedule reception of any number of subevents up to NSE */ + big_sync_create_params.mse = 0x00; + + /* By default, (6 * ISO_Interval * 1.25) / 10 = 3/4 * ISO_Interval */ + big_sync_create_params.sync_timeout = (uint16_t)((3.0 * sink->iso_interval) / 4.0); + big_sync_create_params.sync_timeout = CLAMP(big_sync_create_params.sync_timeout, 0x000A, 0x4000); + + action.type = BLE_AUDIO_BROADCAST_SINK_ACTION_BIG_SYNC; + action.big_sync.source_id = sink->source_id; + action.big_sync.iso_interval = sink->iso_interval; + action.big_sync.nse = sink->nse; + action.big_sync.bn = sink->bn; + action.big_sync.presentation_delay = group.presentation_delay; + action.big_sync.out_mse = &big_sync_create_params.mse; + action.big_sync.out_sync_timeout = &big_sync_create_params.sync_timeout; + + if (action_cb.fn == NULL) { + BLE_HS_LOG_ERROR("action_cb.fn is NULL\n"); + ble_audio_broadcast_sink_stop(sink->source_id); + return; + } + + rc = action_cb.fn(&action, action_cb.arg); + if (rc != 0) { + BLE_HS_LOG_WARN("big sync rejected by user (%d)\n", rc); + ble_audio_broadcast_sink_stop(sink->source_id); + return; + } + + if (sink->broadcast_code_is_valid) { + memcpy(broadcast_code, sink->broadcast_code, BLE_AUDIO_BROADCAST_CODE_SIZE); + broadcast_code[BLE_AUDIO_BROADCAST_CODE_SIZE] = '\0'; + big_sync_create_params.broadcast_code = broadcast_code; + } else { + big_sync_create_params.broadcast_code = NULL; + } + + big_sync_create_params.sync_handle = sink->pa_sync_handle; + big_sync_create_params.cb = iso_event_handler; + big_sync_create_params.cb_arg = UINT_TO_POINTER(sink->source_id); + big_sync_create_params.bis_params = bis_params; + + rc = bis_params_get(sink, &group, &subgroup_iter, bis_params, &bis_cnt); + if (rc != 0 || bis_cnt == 0) { + ble_audio_broadcast_sink_stop(sink->source_id); + return; + } + + /* Sort the parameters by BIS index in ascending order. It is required to properly match the + * BIS index with conn handle in BIG Sync Established event handler. + */ + qsort(bis_params, bis_cnt, sizeof(*bis_params), bis_params_bis_index_cmp); + + big_sync_create_params.bis_cnt = bis_cnt; + + /* Stop scan first */ + disc_stop(); + + rc = ble_iso_big_sync_create(&big_sync_create_params, &sink->big_handle); + if (rc != 0) { + BLE_HS_LOG_ERROR("big sync failed (%d)\n", rc); + return; + } + + big_sync_state_set(sink, BIG_SYNC_STATE_PENDING_SYNC); +} + +static void +metadata_update(struct ble_audio_broadcast_sink *sink, const uint8_t *base, uint8_t base_len) +{ + struct ble_audio_event event; + struct ble_audio_base_group group; + struct ble_audio_base_iter subgroup_iter; + int rc = 0; + + rc = ble_audio_base_parse(base, base_len, &group, &subgroup_iter); + if (rc != 0) { + BLE_HS_LOG_WARN("base parse failed (%d)\n", rc); + return; + } + + for (uint8_t subgroup_index = 0; subgroup_index < group.num_subgroups; subgroup_index++) { + struct ble_audio_base_subgroup subgroup; + uint32_t bis_sync_state; + + rc = ble_audio_base_subgroup_iter(&subgroup_iter, &subgroup, NULL); + if (rc != 0) { + break; + } + + bis_sync_state = subgroup_bis_sync_get(sink, subgroup_index); + if (bis_sync_state == 0) { + /* No BISes synced for this subgroup */ + continue; + } + + event.type = BLE_AUDIO_EVENT_BROADCAST_SINK_METADATA; + event.broadcast_sink_metadata.source_id = sink->source_id; + event.broadcast_sink_metadata.bis_sync = bis_sync_state; + event.broadcast_sink_metadata.metadata = subgroup.metadata; + event.broadcast_sink_metadata.metadata_length = subgroup.metadata_len; + + /* TODO: filter duplicates */ + + ble_audio_event_listener_call(&event); + } +} + +static void +periodic_report_handler(uint16_t pa_sync_handle, const uint8_t *data, uint8_t data_length, uint8_t data_status, + int8_t rssi, int8_t tx_power) +{ + struct ble_audio_broadcast_sink *sink; + struct periodic_report report = {0}; + int rc; + + if (data_status != BLE_HCI_PERIODIC_DATA_STATUS_COMPLETE) { + return; + } + + sink = broadcast_lookup_pa_sync_handle(pa_sync_handle); + if (sink == NULL) { + BLE_HS_LOG_DEBUG("Unknown pa_sync_handle %u\n", pa_sync_handle); + return; + } + + if (sink->big_sync_state == BIG_SYNC_STATE_PENDING_BASE) { + rc = ble_hs_adv_parse(data, data_length, periodic_report_parse, &report); + if (rc != 0 || report.uuid16.basic_audio_announcement.length == 0) { + BLE_HS_LOG_WARN("source_id %u incorrectly formatted BASE\n", sink->source_id); + ble_audio_broadcast_sink_stop(sink->source_id); + return; + } + + big_sync(sink, report.uuid16.basic_audio_announcement.base, report.uuid16.basic_audio_announcement.length); + } else if (sink->big_sync_state == BIG_SYNC_STATE_ACTIVE) { + rc = ble_hs_adv_parse(data, data_length, periodic_report_parse, &report); + if (rc != 0 || report.uuid16.basic_audio_announcement.length == 0) { + BLE_HS_LOG_WARN("source_id %u incorrectly formatted BASE\n", sink->source_id); + return; + } + + metadata_update(sink, report.uuid16.basic_audio_announcement.base, + report.uuid16.basic_audio_announcement.length); + } +} + +static int +broadcast_id_parse_from_adv(const struct ble_hs_adv_field *field, void *user_data) +{ + const uint8_t value_len = field->length - sizeof(field->length); + uint32_t *broadcast_id = user_data; + + if (field->type == BLE_HS_ADV_TYPE_SVC_DATA_UUID16) { + ble_uuid16_t uuid16 = BLE_UUID16_INIT(0); + uint8_t offset = 0; + + if (value_len < 2) { + /* Continue parsing */ + return BLE_HS_ENOENT; + } + + uuid16.value = get_le16(&field->value[offset]); + offset += 2; + + if (uuid16.value == BLE_BROADCAST_AUDIO_ANNOUNCEMENT_SVC_UUID) { + if ((value_len - offset) >= 3) { + *broadcast_id = get_le24(&field->value[offset]); + } + + /* stop parsing */ + return 0; + } + } + + /* continue parsing */ + return BLE_HS_ENOENT; +} + +static void +ext_disc_handler(const ble_addr_t *addr, uint8_t adv_sid, const uint8_t *data, uint8_t data_length) +{ + uint32_t broadcast_id = BROADCAST_ID_INVALID; + struct ble_audio_broadcast_sink *sink; + int rc; + + if (broadcast_sink_lookup_pa_sync_state(PA_SYNC_STATE_PENDING_DISC) == NULL) { + return; + } + + rc = ble_hs_adv_parse(data, data_length, broadcast_id_parse_from_adv, &broadcast_id); + if (rc != 0 || broadcast_id == BROADCAST_ID_INVALID) { + return; + } + + sink = broadcast_sink_lookup_adv_sid_broadcast_id_pair(adv_sid, broadcast_id); + if (sink == NULL) { + return; + } + + if (sink->pa_sync_state == PA_SYNC_STATE_PENDING_DISC) { + rc = pa_sync_add(addr, adv_sid); + if (rc != 0) { + /* TODO: */ + } else { + pa_sync_state_set(sink, PA_SYNC_STATE_PENDING_SYNC); + } + } +} + +static int +gap_event_handler(struct ble_gap_event *event, void *arg) +{ + switch (event->type) { + case BLE_GAP_EVENT_PERIODIC_SYNC: + periodic_sync_handler(&event->periodic_sync.adv_addr, event->periodic_sync.sid, + event->periodic_sync.status, event->periodic_sync.sync_handle); + break; + + case BLE_GAP_EVENT_PERIODIC_SYNC_LOST: + periodic_sync_lost_handler(event->periodic_sync_lost.sync_handle, event->periodic_sync_lost.reason); + break; + + case BLE_GAP_EVENT_PERIODIC_TRANSFER: + periodic_sync_handler(&event->periodic_transfer.adv_addr, event->periodic_transfer.sid, + event->periodic_transfer.status, event->periodic_transfer.sync_handle); + break; + + case BLE_GAP_EVENT_BIGINFO_REPORT: + biginfo_report_handler(event->biginfo_report.sync_handle, event->biginfo_report.iso_interval, + event->biginfo_report.nse, event->biginfo_report.bn, event->biginfo_report.encryption); + + break; + + case BLE_GAP_EVENT_PERIODIC_REPORT: + periodic_report_handler(event->periodic_report.sync_handle, event->periodic_report.data, + event->periodic_report.data_length, + event->periodic_report.data_status, event->periodic_report.rssi, + event->periodic_report.tx_power); + break; + + case BLE_GAP_EVENT_EXT_DISC: + ext_disc_handler(&event->ext_disc.addr, event->ext_disc.sid, event->ext_disc.data, + event->ext_disc.length_data); + break; + + default: + break; + } + + return 0; +} + +int +ble_audio_broadcast_sink_cb_set(ble_audio_broadcast_sink_action_fn *cb, void *arg) +{ + if (action_cb.fn != NULL) { + return BLE_HS_EALREADY; + } + + action_cb.fn = cb; + action_cb.arg = arg; + + return 0; +} + +void +ble_audio_broadcast_sink_code_set(uint8_t source_id, const uint8_t broadcast_code[BLE_AUDIO_BROADCAST_CODE_SIZE]) +{ + struct ble_audio_broadcast_sink *sink; + + BLE_AUDIO_DBG_ASSERT(broadcast_code != NULL); + + sink = broadcast_sink_get(source_id); + if (sink == NULL) { + BLE_HS_LOG_DEBUG("Unknown source_id %u\n", source_id); + return; + } + + if (sink->big_sync_state == BIG_SYNC_STATE_PENDING_CODE) { + memcpy(sink->broadcast_code, broadcast_code, BLE_AUDIO_BROADCAST_CODE_SIZE); + + big_sync_state_set(sink, BIG_SYNC_STATE_PENDING_BASE); + } +} + +static struct ble_audio_broadcast_sink * +broadcast_sink_new(uint8_t source_id) +{ + struct ble_audio_broadcast_sink *sink; + + sink = os_memblock_get(&ble_audio_broadcast_sink_pool); + if (sink == NULL) { + BLE_HS_LOG_WARN("Out of memory\n"); + return NULL; + } + + memset(sink, 0, sizeof(*sink)); + + sink->source_id = source_id; + + SLIST_INSERT_HEAD(&ble_audio_broadcast_sink_list, sink, next); + + return sink; +} + +static int +pa_sync_receive(struct ble_audio_broadcast_sink *sink, const uint16_t *conn_handle) +{ + struct ble_audio_broadcast_sink_action action; + struct ble_audio_scan_delegator_source_desc source_desc; + struct ble_gap_periodic_sync_params periodic_sync_params = {0}; + int rc; + + rc = ble_audio_scan_delegator_source_desc_get(sink->source_id, &source_desc); + if (rc != 0) { + BLE_HS_LOG_ERROR("source desc get failed (%d)\n", rc); + return rc; + } + + if (action_cb.fn == NULL) { + BLE_HS_LOG_ERROR("action_cb.fn is NULL\n"); + return BLE_HS_EAPP; + } + + action.type = BLE_AUDIO_BROADCAST_SINK_ACTION_PA_SYNC; + action.pa_sync.out_params = &periodic_sync_params; + + rc = action_cb.fn(&action, action_cb.arg); + if (rc != 0) { + BLE_HS_LOG_WARN("pa sync rejected by user (%d)\n", rc); + return rc; + } + + rc = ble_gap_periodic_adv_sync_receive( + *conn_handle, &periodic_sync_params, gap_event_handler, NULL); + if (rc != 0) { + BLE_HS_LOG_ERROR("sync receive failed (%d)\n", rc); + return rc; + } + + return 0; +} + +static int +broadcast_sink_start(uint8_t source_id, const uint8_t *broadcast_code, uint16_t *conn_handle) +{ + struct ble_audio_scan_delegator_source_desc source_desc; + struct ble_audio_broadcast_sink *sink; + int rc; + + rc = ble_audio_scan_delegator_source_desc_get(source_id, &source_desc); + if (rc != 0) { + BLE_HS_LOG_ERROR("source desc get failed (%d)\n", rc); + return rc; + } + + sink = broadcast_sink_get(source_id); + if (sink == NULL) { + sink = broadcast_sink_new(source_id); + if (sink == NULL) { + return BLE_HS_ENOMEM; + } + } + + if (broadcast_code != NULL) { + memcpy(sink->broadcast_code, broadcast_code, BLE_AUDIO_BROADCAST_CODE_SIZE); + sink->broadcast_code_is_valid = true; + } + + /* If not previously set, let the application decide which BISes to sync */ + if (sink->num_subgroups == 0) { + sink->num_subgroups = ARRAY_SIZE(sink->subgroups); + for (uint8_t i = 0; i < sink->num_subgroups; i++) { + sink->subgroups[i].bis_sync = BLE_AUDIO_SCAN_DELEGATOR_BIS_SYNC_ANY; + } + } + + switch (sink->pa_sync_state) { + case PA_SYNC_STATE_PENDING_PAST: + case PA_SYNC_STATE_PENDING_DISC: + case PA_SYNC_STATE_PENDING_SYNC: + case PA_SYNC_STATE_ACTIVE: + break; + + case PA_SYNC_STATE_IDLE: + case PA_SYNC_STATE_ERROR: + case PA_SYNC_STATE_TIMEOUT: + if (conn_handle != NULL) { + /* sync using PAST procedure */ + rc = pa_sync_receive(sink, conn_handle); + if (rc != 0) { + return rc; + } + pa_sync_state_set(sink, PA_SYNC_STATE_PENDING_PAST); + } else if (source_desc.addr.type == BLE_ADDR_PUBLIC) { + /* sync to public address (we don't need to scan, as the address won't change) */ + rc = pa_sync_add(&source_desc.addr, source_desc.adv_sid); + if (rc != 0) { + return rc; + } + pa_sync_state_set(sink, PA_SYNC_STATE_PENDING_SYNC); + } else { + /* scan to find broadcaster using Adv SID and Broadcast ID */ + rc = disc_start(); + if (rc != 0) { + return rc; + } + pa_sync_state_set(sink, PA_SYNC_STATE_PENDING_DISC); + } + break; + + default: + BLE_AUDIO_DBG_ASSERT(false); + ble_audio_broadcast_sink_stop(source_id); + return BLE_HS_EAGAIN; + } + + switch (sink->big_sync_state) { + case BIG_SYNC_STATE_ACTIVE: + case BIG_SYNC_STATE_PENDING_BIG_INFO: + case BIG_SYNC_STATE_PENDING_SYNC: + case BIG_SYNC_STATE_PENDING_BASE: + break; + + case BIG_SYNC_STATE_PENDING_CODE: + if (broadcast_code != NULL) { + big_sync_state_set(sink, BIG_SYNC_STATE_PENDING_BASE); + } + break; + + case BIG_SYNC_STATE_FAILED: + case BIG_SYNC_STATE_IDLE: + big_sync_state_set(sink, BIG_SYNC_STATE_PENDING_BIG_INFO); + break; + + default: + BLE_AUDIO_DBG_ASSERT(false); + ble_audio_broadcast_sink_stop(source_id); + return BLE_HS_EAGAIN; + } + + if (sink->pa_sync_state == PA_SYNC_STATE_ACTIVE && + sink->big_sync_state == BIG_SYNC_STATE_ACTIVE) { + return BLE_HS_EDONE; + } + + return 0; +} + +int +ble_audio_broadcast_sink_start(uint8_t source_id, const struct ble_audio_broadcast_sink_add_params *params) +{ + return broadcast_sink_start(source_id, + params->broadcast_code_is_valid ? params->broadcast_code : NULL, + NULL); +} + +static void +ble_audio_broadcast_sink_destroy(struct ble_audio_broadcast_sink *sink) +{ + os_error_t os_error; + + os_error = os_memblock_put(&ble_audio_broadcast_sink_pool, sink); + if (os_error != OS_OK) { + BLE_HS_LOG_ERROR("Failed to put memory block (os_error %d)\n", os_error); + return; + } + + SLIST_REMOVE(&ble_audio_broadcast_sink_list, sink, ble_audio_broadcast_sink, next); +} + +static int +pa_sync_term(struct ble_audio_broadcast_sink *sink) +{ + int rc; + + switch (sink->pa_sync_state) { + case PA_SYNC_STATE_ACTIVE: + rc = ble_gap_periodic_adv_sync_terminate(sink->pa_sync_handle); + if (rc != 0) { + BLE_HS_LOG_ERROR("adv sync terminate failed (%d)\n", rc); + return rc; + } + break; + + case PA_SYNC_STATE_PENDING_PAST: + rc = ble_gap_periodic_adv_sync_receive(sink->past_conn_handle, NULL, gap_event_handler, NULL); + if (rc != 0) { + BLE_HS_LOG_ERROR("adv sync receive cancel failed (%d)\n", rc); + return rc; + } + break; + + case PA_SYNC_STATE_PENDING_SYNC: { + struct ble_audio_scan_delegator_source_desc source_desc; + + rc = ble_audio_scan_delegator_source_desc_get(sink->source_id, &source_desc); + if (rc != 0) { + BLE_HS_LOG_ERROR("source desc get failed (%d)\n", rc); + return rc; + } + + rc = pa_sync_remove(&source_desc.addr, source_desc.adv_sid); + if (rc != 0) { + return rc; + } + break; + } + + default: + break; + } + + pa_sync_state_set(sink, PA_SYNC_STATE_IDLE); + + return 0; +} + +static int +big_sync_term(struct ble_audio_broadcast_sink *sink) +{ + int rc; + + switch (sink->big_sync_state) { + case BIG_SYNC_STATE_ACTIVE: + case BIG_SYNC_STATE_PENDING_SYNC: + rc = ble_iso_big_sync_terminate(sink->big_handle); + if (rc != 0) { + BLE_HS_LOG_ERROR("big sync terminate failed (%d)\n", rc); + return rc; + } + break; + + case BIG_SYNC_STATE_IDLE: + case BIG_SYNC_STATE_FAILED: + case BIG_SYNC_STATE_PENDING_CODE: + case BIG_SYNC_STATE_PENDING_BASE: + case BIG_SYNC_STATE_PENDING_BIG_INFO: + break; + } + + big_sync_state_set(sink, BIG_SYNC_STATE_IDLE); + + return 0; +} + +int +ble_audio_broadcast_sink_stop(uint8_t source_id) +{ + struct ble_audio_broadcast_sink *sink; + int rc; + + sink = broadcast_sink_get(source_id); + if (sink == NULL) { + BLE_HS_LOG_WARN("no sink with source_id=0x%02x\n", source_id); + return 0; + } + + rc = pa_sync_term(sink); + if (rc != 0) { + return rc; + } + + rc = big_sync_term(sink); + if (rc != 0) { + return rc; + } + + ble_audio_broadcast_sink_destroy(sink); + + return 0; +} + +int +ble_audio_broadcast_sink_metadata_update(uint8_t source_id, + const struct ble_audio_broadcast_sink_metadata_update_params *params) +{ + struct ble_audio_broadcast_sink *sink; + + sink = broadcast_sink_get(source_id); + if (sink == NULL) { + BLE_HS_LOG_WARN("no sink with source_id=0x%02x\n", source_id); + return 0; + } + + return ble_audio_scan_delegator_metadata_update(sink->source_id, params->subgroup_index, params->metadata, + params->metadata_length); +} + +int +ble_audio_broadcast_sink_config(uint8_t source_id, uint16_t conn_handle, + const struct ble_audio_scan_delegator_sync_opt *sync_opt) +{ + struct ble_audio_broadcast_sink *sink; + int rc; + + BLE_AUDIO_DBG_ASSERT(sync_opt != NULL); + + sink = broadcast_sink_get(source_id); + if (sink == NULL) { + if (sync_opt->pa_sync != BLE_AUDIO_SCAN_DELEGATOR_PA_SYNC_DO_NOT_SYNC) { + sink = broadcast_sink_new(source_id); + if (sink == NULL) { + return BLE_HS_ENOMEM; + } + } else { + /* nothing to do */ + return 0; + } + } + + if (sync_opt->pa_sync != BLE_AUDIO_SCAN_DELEGATOR_PA_SYNC_DO_NOT_SYNC) { + /* TODO: Skip if the BIS Sync is same */ + if (sink->num_subgroups != 0) { + rc = big_sync_term(sink); + if (rc != 0) { + return rc; + } + } + + sink->num_subgroups = sync_opt->num_subgroups; + + for (uint8_t subgroup_index = 0; subgroup_index < sink->num_subgroups; subgroup_index++) { + sink->subgroups[subgroup_index].bis_sync = sync_opt->subgroups[subgroup_index].bis_sync; + } + + if (sync_opt->pa_sync == BLE_AUDIO_SCAN_DELEGATOR_PA_SYNC_PAST_NOT_AVAILABLE) { + rc = broadcast_sink_start(source_id, NULL, NULL); + } else { + rc = broadcast_sink_start(source_id, NULL, &conn_handle); + } + } else { + rc = pa_sync_term(sink); + } + + return rc; +} + +int +ble_audio_broadcast_sink_init(void) +{ + static struct ble_gap_event_listener gap_event_listener; + int rc; + + /* Ensure this function only gets called by sysinit. */ + SYSINIT_ASSERT_ACTIVE(); + + rc = os_mempool_init(&ble_audio_broadcast_sink_pool, + MYNEWT_VAL(BLE_AUDIO_BROADCAST_SINK_MAX), + sizeof(struct ble_audio_broadcast_sink), + ble_audio_broadcast_sink_mem, + "ble_audio_broadcast_sink_pool"); + SYSINIT_PANIC_ASSERT(rc == 0); + + rc = ble_gap_event_listener_register(&gap_event_listener, gap_event_handler, NULL); + SYSINIT_PANIC_ASSERT(rc == 0); + + return 0; +} +#endif /* BLE_AUDIO_BROADCAST_SINK */ diff --git a/nimble/host/audio/src/ble_audio_broadcast_sink_priv.h b/nimble/host/audio/src/ble_audio_broadcast_sink_priv.h new file mode 100644 index 0000000000..ad7990144d --- /dev/null +++ b/nimble/host/audio/src/ble_audio_broadcast_sink_priv.h @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_BLE_AUDIO_BROADCAST_SINK_PRIV_ +#define H_BLE_AUDIO_BROADCAST_SINK_PRIV_ + +#include +#include "audio/ble_audio.h" +#include "audio/ble_audio_broadcast_sink.h" +#include "audio/ble_audio_scan_delegator.h" + +int ble_audio_broadcast_sink_config( + uint8_t source_id, uint16_t conn_handle, + const struct ble_audio_scan_delegator_sync_opt *sync_opt); +void ble_audio_broadcast_sink_code_set( + uint8_t source_id, const uint8_t broadcast_code[16]); + +#endif /* H_BLE_AUDIO_BROADCAST_SINK_PRIV_ */ diff --git a/nimble/host/audio/src/ble_audio_broadcast_source.c b/nimble/host/audio/src/ble_audio_broadcast_source.c new file mode 100644 index 0000000000..210536f7ee --- /dev/null +++ b/nimble/host/audio/src/ble_audio_broadcast_source.c @@ -0,0 +1,497 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "host/ble_uuid.h" +#include "audio/ble_audio_broadcast_source.h" + +#include "os/util.h" + +#if MYNEWT_VAL(BLE_AUDIO) +#if MYNEWT_VAL(BLE_ISO_BROADCAST_SOURCE) +struct ble_audio_broadcast { + SLIST_ENTRY(ble_audio_broadcast) next; + uint8_t big_handle; + uint8_t adv_instance; + struct ble_audio_base *base; + struct ble_iso_big_params *big_params; + ble_audio_broadcast_destroy_fn *destroy_cb; + void *args; +}; + +static SLIST_HEAD(, ble_audio_broadcast) ble_audio_broadcasts; +static struct os_mempool ble_audio_broadcast_pool; +static os_membuf_t ble_audio_broadcast_mem[ + OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_ISO_MAX_BIGS), + sizeof(struct ble_audio_broadcast))]; + +static bool +broadcast_bis_idx_ok(uint8_t bis_idx, struct ble_audio_base *base) +{ + struct ble_audio_big_subgroup *big; + struct ble_audio_bis *bis; + uint8_t idx_cnt = 0; + + STAILQ_FOREACH(big, &base->subs, next) { + STAILQ_FOREACH(bis, &big->bises, next) { + if (bis_idx == bis->idx) { + idx_cnt++; + } + } + } + + return idx_cnt == 1; +} + +static bool +broadcast_ltv_ok(uint8_t total_len, uint8_t *data) +{ + if (total_len == 0 && data == NULL) { + return true; + } + uint8_t len = data[0]; + uint8_t sum_len = 0; + + while (total_len > sum_len) { + sum_len += len + 1; + len = data[sum_len]; + } + + return total_len == sum_len; +} + +static struct ble_audio_broadcast * +ble_audio_broadcast_find(uint8_t adv_instance) +{ + struct ble_audio_broadcast *broadcast; + + SLIST_FOREACH(broadcast, &ble_audio_broadcasts, next) { + if (broadcast->adv_instance == adv_instance) { + return broadcast; + } + } + + return NULL; +} + +static struct ble_audio_broadcast * +ble_audio_broadcast_find_last() +{ + struct ble_audio_broadcast *broadcast; + + SLIST_FOREACH(broadcast, &ble_audio_broadcasts, next) { + } + + return broadcast; +} + +int +ble_audio_broadcast_create(const struct ble_broadcast_create_params *params, + ble_audio_broadcast_destroy_fn *destroy_cb, + void *args, + ble_gap_event_fn *gap_cb) +{ + int rc; + uint8_t offset = 2; + uint8_t service_data[5] = {0x52, 0x18 }; + uint8_t per_svc_data[MYNEWT_VAL(BLE_EXT_ADV_MAX_SIZE)] = { 0x51, 0x18 }; + struct ble_audio_big_subgroup *subgroup; + struct ble_audio_bis *bis; + struct ble_hs_adv_fields adv_fields = { + .broadcast_name = (uint8_t *) params->name, + .broadcast_name_len = params->name != NULL ? strlen(params->name) : 0, + .svc_data_uuid16 = service_data, + .svc_data_uuid16_len = sizeof(service_data), + }; + struct ble_hs_adv_fields per_adv_fields = { 0 }; + struct os_mbuf *adv_data; + ble_uuid16_t audio_announcement_uuid[1]; + uint8_t broadcast_id[3]; + struct ble_audio_broadcast *broadcast; + + if (params->adv_instance >= BLE_ADV_INSTANCES) { + BLE_HS_LOG_ERROR("Invalid advertising instance"); + return BLE_HS_EINVAL; + } + + if (strlen(params->name) < 4 || strlen(params->name) > 32) { + return BLE_HS_EINVAL; + } + + broadcast = ble_audio_broadcast_find(params->adv_instance); + if (broadcast) { + BLE_HS_LOG_ERROR("Advertising instance (%d) already in use", + params->adv_instance); + return BLE_HS_EALREADY; + } + + ble_hs_hci_rand(broadcast_id, 3); + params->base->broadcast_id = get_le24(broadcast_id); + + broadcast = os_memblock_get(&ble_audio_broadcast_pool); + + broadcast->adv_instance = params->adv_instance; + broadcast->base = params->base; + broadcast->big_params = params->big_params; + broadcast->destroy_cb = destroy_cb; + broadcast->args = args; + + if (SLIST_EMPTY(&ble_audio_broadcasts)) { + SLIST_INSERT_HEAD(&ble_audio_broadcasts, broadcast, next); + } else { + SLIST_INSERT_AFTER(ble_audio_broadcast_find_last(), broadcast, next); + } + + if (params->base->num_subgroups == 0) { + /** + * BAP specification 3.7.2.2 Basic Audio Announcements: + * Rule 1: There shall be at least one subgroup. + */ + BLE_HS_LOG_ERROR("No subgroups in BASE!\n"); + return BLE_HS_EINVAL; + } + + put_le24(&service_data[2], broadcast->base->broadcast_id); + put_le24(&per_svc_data[offset], params->base->presentation_delay); + offset += 3; + per_svc_data[offset] = params->base->num_subgroups; + offset++; + + STAILQ_FOREACH(subgroup, ¶ms->base->subs, next) { + if (subgroup->bis_cnt == 0) { + /** + * BAP specification 3.7.2.2 Basic Audio Announcements: + * Rule 2: There shall be at least one BIS per subgroup. + */ + BLE_HS_LOG_ERROR("No BIS in BIG!\n"); + return BLE_HS_EINVAL; + } + + if (!broadcast_ltv_ok(subgroup->metadata_len, subgroup->metadata)) { + BLE_HS_LOG_ERROR("Invalid Metadata!\n"); + return BLE_HS_EINVAL; + } + + if (!broadcast_ltv_ok(subgroup->codec_spec_config_len, subgroup->codec_spec_config)) { + BLE_HS_LOG_ERROR("Invalid Codec Configuration in subgroup!\n"); + return BLE_HS_EINVAL; + } + + per_svc_data[offset] = subgroup->bis_cnt; + offset++; + memcpy(&per_svc_data[offset], &subgroup->codec_id, 5); + offset += 5; + per_svc_data[offset] = subgroup->codec_spec_config_len; + offset++; + memcpy(&per_svc_data[offset], &subgroup->codec_spec_config, + subgroup->codec_spec_config_len); + offset += subgroup->codec_spec_config_len; + per_svc_data[offset] = subgroup->metadata_len; + offset++; + memcpy(&per_svc_data[offset], &subgroup->metadata, + subgroup->metadata_len); + offset += subgroup->metadata_len; + STAILQ_FOREACH(bis, &subgroup->bises, next) { + if (!broadcast_bis_idx_ok(bis->idx, params->base)) { + /** + * BAP specification 3.7.2.2 Basic Audio Announcements: + * Rule 3: Every BIS in the BIG, denoted by its BIS_index + * value, shall only be present in one subgroup. + */ + BLE_HS_LOG_ERROR("Duplicated BIS index!\n"); + return BLE_HS_EINVAL; + } + + if (!broadcast_ltv_ok(bis->codec_spec_config_len, + bis->codec_spec_config)) { + BLE_HS_LOG_ERROR("Invalid Codec Configuration in BIS!\n"); + return BLE_HS_EINVAL; + } + per_svc_data[offset] = bis->idx; + offset++; + per_svc_data[offset] = bis->codec_spec_config_len; + offset++; + memcpy(&per_svc_data[offset], bis->codec_spec_config, + bis->codec_spec_config_len); + offset += bis->codec_spec_config_len; + } + } + + audio_announcement_uuid[0] = (ble_uuid16_t) BLE_UUID16_INIT(BLE_BROADCAST_AUDIO_ANNOUNCEMENT_SVC_UUID); + per_adv_fields.uuids16 = audio_announcement_uuid; + per_adv_fields.num_uuids16 = 1; + per_adv_fields.uuids16_is_complete = 1; + per_adv_fields.svc_data_uuid16 = per_svc_data; + per_adv_fields.svc_data_uuid16_len = offset; + + rc = ble_gap_ext_adv_configure(params->adv_instance, + params->extended_params, 0, + gap_cb, NULL); + if (rc) { + BLE_HS_LOG_ERROR("Could not configure the broadcast (rc=%d)\n", rc); + return 0; + } + + adv_data = os_msys_get_pkthdr(BLE_HCI_MAX_EXT_ADV_DATA_LEN, 0); + if (!adv_data) { + BLE_HS_LOG_ERROR("No memory\n"); + return BLE_HS_ENOMEM; + } + + /* Set ext advertising data */ + rc = ble_hs_adv_set_fields_mbuf(&adv_fields, adv_data); + if (rc) { + BLE_HS_LOG_ERROR("Failed to set extended advertising fields" + "(rc=%d)\n", rc); + return rc; + } + + os_mbuf_append(adv_data, params->svc_data, params->svc_data_len); + + rc = ble_gap_ext_adv_set_data(params->adv_instance, adv_data); + if (rc) { + BLE_HS_LOG_ERROR("Failed to set extended advertising data" + "(rc=%d)\n", rc); + return rc; + } + + /* Clear buffer */ + adv_data = os_msys_get_pkthdr(BLE_HCI_MAX_EXT_ADV_DATA_LEN, 0); + if (!adv_data) { + BLE_HS_LOG_ERROR("No memory\n"); + return BLE_HS_ENOMEM; + } + + rc = ble_gap_periodic_adv_configure(params->adv_instance, params->periodic_params); + if (rc) { + BLE_HS_LOG_ERROR("failed to configure periodic advertising" + "(rc=%d)\n", rc); + return rc; + } + + rc = ble_hs_adv_set_fields_mbuf(&per_adv_fields, adv_data); + if (rc) { + BLE_HS_LOG_ERROR("Failed to set periodic advertising fields" + "(rc=%d)\n", rc); + return rc; + } + + rc = ble_gap_periodic_adv_set_data(params->adv_instance, adv_data, NULL); + if (rc) { + BLE_HS_LOG_ERROR("Failed to set periodic advertising data" + "(rc=%d)\n", rc); + } + + return rc; +} + +int +ble_audio_broadcast_start(uint8_t adv_instance, + ble_iso_event_fn *cb, void *cb_arg) +{ + struct ble_audio_big_subgroup *subgroup; + struct ble_iso_create_big_params create_big_params = { 0 }; + struct ble_audio_broadcast *broadcast; + int rc; + + broadcast = ble_audio_broadcast_find(adv_instance); + if (!broadcast) { + return BLE_HS_ENOENT; + } + + STAILQ_FOREACH(subgroup, &broadcast->base->subs, next) { + create_big_params.bis_cnt += subgroup->bis_cnt; + } + + create_big_params.adv_handle = broadcast->adv_instance; + create_big_params.cb = cb; + create_big_params.cb_arg = cb_arg; + + rc = ble_gap_ext_adv_start(broadcast->adv_instance, 0, 0); + if (rc) { + BLE_HS_LOG_ERROR("Failed to start extended advertising (rc=%d)\n", rc); + return rc; + } + + rc = ble_gap_periodic_adv_start(broadcast->adv_instance, NULL); + if (rc) { + BLE_HS_LOG_ERROR("Failed to start periodic advertising (rc=%d)\n", rc); + return rc; + } + + rc = ble_iso_create_big(&create_big_params, broadcast->big_params, + &broadcast->big_handle); + if (rc) { + BLE_HS_LOG_ERROR("Failed to create BIG (rc=%d)\n", rc); + return rc; + } + + return 0; +} + +int +ble_audio_broadcast_stop(uint8_t adv_instance) +{ + int rc; + + rc = ble_gap_ext_adv_stop(adv_instance); + if (rc) { + BLE_HS_LOG_ERROR("Failed to stop extended advertising (rc=%d)\n", rc); + return rc; + } + + rc = ble_gap_periodic_adv_stop(adv_instance); + if (rc) { + BLE_HS_LOG_ERROR("Failed to stop periodic advertising (rc=%d)\n", rc); + return rc; + } + + return 0; +} + +int +ble_audio_broadcast_destroy(uint8_t adv_instance) +{ + struct ble_audio_broadcast *broadcast; + int rc; + + broadcast = ble_audio_broadcast_find(adv_instance); + if (!broadcast) { + return BLE_HS_ENOENT; + } + + rc = ble_gap_ext_adv_remove(adv_instance); + if (rc) { + BLE_HS_LOG_ERROR("Failed to remove extended advertising\n"); + return rc; + } + + rc = ble_iso_terminate_big(broadcast->big_handle); + if (rc) { + BLE_HS_LOG_ERROR("Failed to terminate BIG\n"); + return rc; + } + + os_memblock_put(&ble_audio_broadcast_pool, broadcast); + SLIST_REMOVE(&ble_audio_broadcasts, broadcast, ble_audio_broadcast, next); + + return 0; +} + +int +ble_audio_broadcast_update(const struct ble_broadcast_update_params *params) +{ + uint8_t service_data[5] = {0x52, 0x18 }; + struct ble_hs_adv_fields adv_fields = { + .broadcast_name = (uint8_t *) params->name, + .broadcast_name_len = params->name != NULL ? strlen(params->name) : 0, + .svc_data_uuid16 = service_data, + .svc_data_uuid16_len = sizeof(service_data) + }; + struct os_mbuf *adv_data; + int rc; + + if (strlen(params->name) < 4 || strlen(params->name) > 32) { + return BLE_HS_EINVAL; + } + + memcpy(&service_data[2], ¶ms->broadcast_id, 3); + + adv_data = os_msys_get_pkthdr(BLE_HCI_MAX_EXT_ADV_DATA_LEN, 0); + + os_mbuf_append(adv_data, params->svc_data, params->svc_data_len); + + /* Set ext advertising data */ + rc = ble_hs_adv_set_fields_mbuf(&adv_fields, adv_data); + if (rc) { + BLE_HS_LOG_ERROR("Failed to set extended advertising fields\n"); + return rc; + } + + rc = ble_gap_ext_adv_set_data(params->adv_instance, adv_data); + if (rc) { + BLE_HS_LOG_ERROR("Failed to set extended advertising data\n"); + return rc; + } + + return 0; +} + +int +ble_audio_broadcast_build_sub(struct ble_audio_base *base, + struct ble_audio_big_subgroup *sub, + const struct ble_broadcast_subgroup_params + *params) +{ + sub->codec_id = *params->codec_id; + memcpy(sub->codec_spec_config, params->codec_spec_config, + params->codec_spec_config_len); + sub->codec_spec_config_len = params->codec_spec_config_len; + memcpy(sub->metadata, params->metadata, + params->metadata_len); + sub->metadata_len = params->metadata_len; + + if (STAILQ_EMPTY(&base->subs)) { + STAILQ_INSERT_HEAD(&base->subs, sub, next); + } else { + STAILQ_INSERT_TAIL(&base->subs, sub, next); + } + + base->num_subgroups++; + return 0; +} + +int +ble_audio_broadcast_build_bis(struct ble_audio_big_subgroup *sub, + struct ble_audio_bis *bis, + const struct ble_broadcast_bis_params + *params) +{ + bis->idx = params->idx; + memcpy(bis->codec_spec_config, params->codec_spec_config, + params->codec_spec_config_len); + bis->codec_spec_config_len = params->codec_spec_config_len; + + if (STAILQ_EMPTY(&sub->bises)) { + STAILQ_INSERT_HEAD(&sub->bises, bis, next); + } else { + STAILQ_INSERT_TAIL(&sub->bises, bis, next); + } + + sub->bis_cnt++; + return 0; +} + + +int +ble_audio_broadcast_init(void) +{ + int rc; + + SLIST_INIT(&ble_audio_broadcasts); + + rc = os_mempool_init(&ble_audio_broadcast_pool, + MYNEWT_VAL(BLE_ISO_MAX_BIGS), + sizeof(struct ble_audio_broadcast), + ble_audio_broadcast_mem, "ble_audio_broadcast_pool"); + SYSINIT_PANIC_ASSERT(rc == 0); + + return 0; +} +#endif /* BLE_ISO_BROADCAST_SOURCE */ +#endif /* BLE_AUDIO */ diff --git a/nimble/host/audio/src/ble_audio_codec.c b/nimble/host/audio/src/ble_audio_codec.c new file mode 100644 index 0000000000..df244f96ff --- /dev/null +++ b/nimble/host/audio/src/ble_audio_codec.c @@ -0,0 +1,138 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "syscfg/syscfg.h" + +#if MYNEWT_VAL(BLE_AUDIO_MAX_CODEC_RECORDS) +#include "os/os.h" +#include "audio/ble_audio.h" +#include "audio/ble_audio_codec.h" +#include "ble_audio_priv.h" +#include "host/ble_hs.h" +#include "sysinit/sysinit.h" + +static STAILQ_HEAD(, ble_audio_codec_record) ble_audio_codec_records; +static struct os_mempool ble_audio_codec_pool; + +static os_membuf_t ble_audio_svc_pacs_pac_elem_mem[ + OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_AUDIO_MAX_CODEC_RECORDS), + sizeof (struct ble_audio_codec_record)) +]; + +int +ble_audio_codec_register(const struct ble_audio_codec_register_params *params, + struct ble_audio_codec_record *out_record) +{ + struct ble_audio_event codec_event = { + .type = BLE_AUDIO_EVENT_CODEC_REGISTERED + }; + + struct ble_audio_codec_record *record = + os_memblock_get(&ble_audio_codec_pool); + if (!record) { + return BLE_HS_ENOMEM; + } + + record->codec_id = params->codec_id; + record->codec_spec_caps_len = params->codec_spec_caps_len; + record->codec_spec_caps = params->codec_spec_caps; + record->metadata_len = params->metadata_len; + record->metadata = params->metadata; + record->direction = params->direction; + + if (STAILQ_EMPTY(&ble_audio_codec_records)) { + STAILQ_INSERT_HEAD(&ble_audio_codec_records, record, next); + } else { + STAILQ_INSERT_TAIL(&ble_audio_codec_records, record, next); + } + + out_record = record; + + codec_event.codec_registered.record = record; + (void)ble_audio_event_listener_call(&codec_event); + + return 0; +} + +int +ble_audio_codec_unregister(struct ble_audio_codec_record *codec_record) +{ + struct ble_audio_event codec_event = { + .type = BLE_AUDIO_EVENT_CODEC_UNREGISTERED + }; + + STAILQ_REMOVE(&ble_audio_codec_records, codec_record, + ble_audio_codec_record, next); + + codec_event.codec_unregistered.record = codec_record; + (void)ble_audio_event_listener_call(&codec_event); + + return 0; +} + +int +ble_audio_codec_foreach(uint8_t flags, ble_audio_codec_foreach_fn *cb, void *arg) +{ + struct ble_audio_codec_record *record; + int rc; + + STAILQ_FOREACH(record, &ble_audio_codec_records, next) { + if (record->direction & flags) { + rc = cb(record, arg); + if (rc != 0) { + return rc; + } + } + } + return 0; +} + +struct ble_audio_codec_record * +ble_audio_codec_find(struct ble_audio_codec_id codec_id, uint8_t flag) +{ + struct ble_audio_codec_record *record; + + STAILQ_FOREACH(record, &ble_audio_codec_records, next) { + if (!memcmp(&record->codec_id, &codec_id, + sizeof(struct ble_audio_codec_id)) && + (flag ? (record->direction & flag) : 1)) { + return record; + } + } + + return NULL; +} + +int +ble_audio_codec_init(void) +{ + int rc; + + STAILQ_INIT(&ble_audio_codec_records); + + rc = os_mempool_init(&ble_audio_codec_pool, + MYNEWT_VAL(BLE_AUDIO_MAX_CODEC_RECORDS), + sizeof(struct ble_audio_codec_record), + ble_audio_svc_pacs_pac_elem_mem, + "ble_audio_codec_pool"); + SYSINIT_PANIC_ASSERT(rc == 0); + + return 0; +} +#endif diff --git a/nimble/host/audio/src/ble_audio_priv.h b/nimble/host/audio/src/ble_audio_priv.h new file mode 100644 index 0000000000..d575c54969 --- /dev/null +++ b/nimble/host/audio/src/ble_audio_priv.h @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_BLE_AUDIO_PRIV_ +#define H_BLE_AUDIO_PRIV_ + +#include "audio/ble_audio.h" + +#define MIN(_a, _b) ((_a) < (_b) ? (_a) : (_b)) +#define MAX(_a, _b) ((_a) > (_b) ? (_a) : (_b)) + +#if MYNEWT_VAL(BLE_HS_DEBUG) +#define BLE_AUDIO_DBG_ASSERT(x) assert(x) +#define BLE_AUDIO_DBG_ASSERT_EVAL(x) assert(x) +#else +#define BLE_AUDIO_DBG_ASSERT(x) +#define BLE_AUDIO_DBG_ASSERT_EVAL(x) ((void)(x)) +#endif + +int ble_audio_event_listener_call(struct ble_audio_event *event); + +#endif /* H_BLE_AUDIO_PRIV_ */ diff --git a/nimble/host/audio/src/ble_audio_scan_delegator.c b/nimble/host/audio/src/ble_audio_scan_delegator.c new file mode 100644 index 0000000000..08a5ac645d --- /dev/null +++ b/nimble/host/audio/src/ble_audio_scan_delegator.c @@ -0,0 +1,461 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "sysinit/sysinit.h" + +#if MYNEWT_VAL(BLE_AUDIO_SCAN_DELEGATOR) +#include "audio/ble_audio.h" +#include "audio/ble_audio_broadcast_sink.h" +#include "audio/ble_audio_scan_delegator.h" +#include "host/ble_hs.h" +#include "host/ble_uuid.h" + +#include "../services/bass/include/services/bass/ble_audio_svc_bass.h" + +#include "ble_audio_priv.h" +#include "ble_audio_broadcast_sink_priv.h" + +static ble_audio_scan_delegator_action_fn *action_cb; + +int +ble_audio_scan_delegator_source_desc_get(uint8_t source_id, struct ble_audio_scan_delegator_source_desc *source_desc) +{ + struct ble_svc_audio_bass_receiver_state *state; + int rc; + + rc = ble_svc_audio_bass_receiver_state_get(source_id, &state); + if (rc != 0) { + BLE_HS_LOG_ERROR("bass receiver state get failed (%d)\n", rc); + return rc; + } + + source_desc->addr = state->source_addr; + source_desc->adv_sid = state->source_adv_sid; + source_desc->broadcast_id = state->broadcast_id; + + return 0; +} + +int +ble_audio_scan_delegator_receive_state_get(uint8_t source_id, struct ble_audio_scan_delegator_receive_state *out_state) +{ + struct ble_svc_audio_bass_receiver_state *state; + int rc; + + rc = ble_svc_audio_bass_receiver_state_get(source_id, &state); + if (rc != 0) { + BLE_HS_LOG_ERROR("bass receiver state get failed (%d)\n", rc); + return rc; + } + + out_state->pa_sync_state = (uint8_t)state->pa_sync_state; + out_state->big_enc = (uint8_t)state->big_encryption; + if (out_state->big_enc == BLE_AUDIO_SCAN_DELEGATOR_BIG_ENC_BROADCAST_CODE_INVALID) { + memcpy(out_state->bad_code, state->bad_code, sizeof(out_state->bad_code)); + } + out_state->num_subgroups = state->num_subgroups; + for (uint8_t i = 0; i < out_state->num_subgroups; i++) { + out_state->subgroups[i].bis_sync = state->subgroups[i].bis_sync_state; + out_state->subgroups[i].metadata = state->subgroups[i].metadata; + out_state->subgroups[i].metadata_length = state->subgroups[i].metadata_length; + } + + return 0; +} + +int +ble_audio_scan_delegator_metadata_update(uint8_t source_id, uint8_t subgroup_index, const uint8_t *metadata, + uint8_t metadata_length) +{ + struct ble_svc_audio_bass_metadata_params params; + + params.subgroup_idx = subgroup_index; + params.metadata = metadata; + params.metadata_length = metadata_length; + + return ble_svc_audio_bass_update_metadata(¶ms, source_id); +} + +static int +action_call(struct ble_audio_scan_delegator_action *action, void *arg) +{ + int rc; + + if (action_cb == NULL) { + BLE_HS_LOG_ERROR("callback is NULL\n"); + return BLE_HS_EAPP; + } + + rc = action_cb(action, arg); + if (rc != 0) { + return rc; + } + + return 0; +} + +static void +source_desc_init(struct ble_audio_scan_delegator_source_desc *source_desc, const ble_addr_t *addr, uint8_t adv_sid, + uint32_t broadcast_id) +{ + source_desc->addr = *addr; + source_desc->adv_sid = adv_sid; + source_desc->broadcast_id = broadcast_id; +} + +static void +subgroups_init(struct ble_audio_scan_delegator_subgroup *subgroups, + const struct ble_svc_audio_bass_subgroup *bass_subgroups, uint8_t num_subgroups) +{ + BLE_AUDIO_DBG_ASSERT(num_subgroups < MYNEWT_VAL(BLE_AUDIO_SCAN_DELEGATOR_SUBGROUP_MAX)); + + for (uint8_t i = 0; i < num_subgroups; i++) { + subgroups[i].bis_sync = bass_subgroups[i].bis_sync_state; + subgroups[i].metadata_length = bass_subgroups[i].metadata_length; + subgroups[i].metadata = bass_subgroups[i].metadata; + } +} + +static void +sync_opt_init(struct ble_audio_scan_delegator_sync_opt *sync_opt, enum ble_svc_audio_bass_pa_sync pa_sync, + uint16_t pa_interval, const struct ble_svc_audio_bass_subgroup *bass_subgroups, uint8_t num_subgroups) +{ + sync_opt->pa_sync = (uint8_t)pa_sync; + sync_opt->pa_interval = pa_interval; + sync_opt->num_subgroups = num_subgroups; + if (sync_opt->num_subgroups > 0) { + subgroups_init(sync_opt->subgroups, bass_subgroups, num_subgroups); + } +} + +static int +bass_add_source_op_handler(struct ble_svc_audio_bass_operation *op, void *arg) +{ + struct ble_audio_scan_delegator_action action = {0}; + const uint8_t source_id = op->add_source.source_id; + int rc; + + source_desc_init(&action.source_add.source_desc, &op->add_source.adv_addr, + op->add_source.adv_sid, op->add_source.broadcast_id); + sync_opt_init(&action.source_add.sync_opt, op->add_source.pa_sync, op->add_source.pa_interval, + op->add_source.subgroups, op->add_source.num_subgroups); + + action.type = BLE_AUDIO_SCAN_DELEGATOR_ACTION_SOURCE_ADD; + action.source_add.source_id = source_id; + action.source_add.out_source_id_to_swap = op->add_source.out_source_id_to_swap; + + rc = action_call(&action, arg); + if (rc != 0) { + BLE_HS_LOG_DEBUG("API callback (%d)\n", rc); + return rc; + } + +#if MYNEWT_VAL(BLE_AUDIO_BROADCAST_SINK) + if (op->add_source.out_source_id_to_swap != NULL) { + rc = ble_audio_broadcast_sink_stop(*op->add_source.out_source_id_to_swap); + if (rc != 0) { + BLE_HS_LOG_WARN("sink stop failed (%d)\n", rc); + } + } + + rc = ble_audio_broadcast_sink_config(source_id, op->conn_handle, &action.source_add.sync_opt); + if (rc != 0) { + BLE_HS_LOG_WARN("sink config failed (%d)\n", rc); + } +#endif /* BLE_AUDIO_BROADCAST_SINK */ + + return 0; +} + +static int +bass_modify_source_op_handler(struct ble_svc_audio_bass_operation *op, void *arg) +{ + struct ble_audio_scan_delegator_action action = {0}; + struct ble_audio_scan_delegator_sync_opt *sync_opt; + const uint8_t source_id = op->modify_source.source_id; + int rc; + + sync_opt = &action.source_modify.sync_opt; + sync_opt_init(sync_opt, op->modify_source.pa_sync, op->modify_source.pa_interval, NULL, 0); + + BLE_AUDIO_DBG_ASSERT(sync_opt->num_subgroups < ARRAY_SIZE(sync_opt->subgroups)); + + for (uint8_t i = 0; i < sync_opt->num_subgroups; i++) { + sync_opt->subgroups[i].bis_sync = op->modify_source.subgroups[i].bis_sync_state; + sync_opt->subgroups[i].metadata_length = op->modify_source.subgroups[i].metadata_length; + sync_opt->subgroups[i].metadata = op->modify_source.subgroups[i].metadata; + } + + action.type = BLE_AUDIO_SCAN_DELEGATOR_ACTION_SOURCE_MODIFY; + action.source_modify.source_id = source_id; + + rc = action_call(&action, arg); + if (rc != 0) { + return rc; + } + +#if MYNEWT_VAL(BLE_AUDIO_BROADCAST_SINK) + rc = ble_audio_broadcast_sink_config(source_id, op->conn_handle, sync_opt); + if (rc != 0) { + BLE_HS_LOG_WARN("sink config failed (%d)\n", rc); + } +#endif /* BLE_AUDIO_BROADCAST_SINK */ + + return 0; +} + +static int +bass_remove_source_op_handler(struct ble_svc_audio_bass_operation *op, void *arg) +{ + struct ble_audio_scan_delegator_action action; + const uint8_t source_id = op->remove_source.source_id; + int rc; + + action.type = BLE_AUDIO_SCAN_DELEGATOR_ACTION_SOURCE_REMOVE; + action.source_remove.source_id = source_id; + + rc = action_call(&action, arg); + if (rc != 0) { + return rc; + } + +#if MYNEWT_VAL(BLE_AUDIO_BROADCAST_SINK) + rc = ble_audio_broadcast_sink_stop(source_id); + if (rc != 0) { + BLE_HS_LOG_WARN("sink stop failed (%d)\n", rc); + } +#endif /* BLE_AUDIO_BROADCAST_SINK */ + + return 0; +} + +static int +bass_accept_fn(struct ble_svc_audio_bass_operation *op, void *arg) +{ + switch (op->op) { + case BLE_SVC_AUDIO_BASS_OPERATION_ADD_SOURCE: + return bass_add_source_op_handler(op, arg); + + case BLE_SVC_AUDIO_BASS_OPERATION_MODIFY_SOURCE: + return bass_modify_source_op_handler(op, arg); + + case BLE_SVC_AUDIO_BASS_OPERATION_REMOVE_SOURCE: + return bass_remove_source_op_handler(op, arg); + + default: + return BLE_HS_ENOTSUP; + } +} + +int +ble_audio_scan_delegator_action_fn_set(ble_audio_scan_delegator_action_fn *fn, void *arg) +{ + int rc; + + if (fn == NULL) { + BLE_HS_LOG_ERROR("callback is NULL\n"); + return BLE_HS_EINVAL; + } + + if (action_cb != NULL) { + return BLE_HS_EALREADY; + } + + action_cb = fn; + + rc = ble_svc_audio_bass_accept_fn_set(bass_accept_fn, arg); + if (rc != 0) { + action_cb = NULL; + } + + return 0; +} + +int +ble_audio_scan_delegator_receive_state_add(const struct ble_audio_scan_delegator_receive_state_add_params *params, + uint8_t *source_id) +{ + struct ble_svc_audio_bass_receiver_state_add_params bass_params = {0}; + + if (params == NULL) { + BLE_HS_LOG_ERROR("NULL params\n"); + return BLE_HS_EINVAL; + } + + if (source_id == NULL) { + BLE_HS_LOG_ERROR("NULL source_id\n"); + return BLE_HS_EINVAL; + } + + bass_params.source_addr = params->source_desc.addr; + bass_params.source_adv_sid = params->source_desc.adv_sid; + bass_params.broadcast_id = params->source_desc.broadcast_id; + bass_params.pa_sync_state = (uint8_t)params->state.pa_sync_state; + bass_params.big_encryption = (uint8_t)params->state.big_enc; + + if (params->state.big_enc == BLE_AUDIO_SCAN_DELEGATOR_BIG_ENC_BROADCAST_CODE_INVALID) { + bass_params.bad_code = params->state.bad_code; + } else { + bass_params.bad_code = NULL; + } + + bass_params.num_subgroups = params->state.num_subgroups; + if (bass_params.num_subgroups > BLE_SVC_AUDIO_BASS_SUB_NUM_MAX) { + BLE_HS_LOG_ERROR("num_subgroups above the limit\n"); + return BLE_HS_ENOMEM; + } + + for (uint8_t i = 0; i < bass_params.num_subgroups; i++) { + bass_params.subgroups[i].bis_sync_state = params->state.subgroups->bis_sync; + bass_params.subgroups[i].metadata_length = params->state.subgroups->metadata_length; + bass_params.subgroups[i].metadata = params->state.subgroups->metadata; + } + + return ble_svc_audio_bass_receive_state_add(&bass_params, source_id); +} + +int +ble_audio_scan_delegator_receive_state_remove(uint8_t source_id) +{ + int rc; + +#if MYNEWT_VAL(BLE_AUDIO_BROADCAST_SINK) + rc = ble_audio_broadcast_sink_stop(source_id); + if (rc != 0) { + BLE_HS_LOG_WARN("sink stop failed (%d)\n", rc); + } +#endif /* BLE_AUDIO_BROADCAST_SINK */ + + return ble_svc_audio_bass_receive_state_remove(source_id); +} + +int +ble_audio_scan_delegator_receive_state_set(uint8_t source_id, + const struct ble_audio_scan_delegator_receive_state *state) +{ + struct ble_svc_audio_bass_update_params bass_params; + int rc; + + if (state == NULL) { + BLE_HS_LOG_ERROR("NULL state\n"); + return BLE_HS_EINVAL; + } + + bass_params.pa_sync_state = (uint8_t)state->pa_sync_state; + bass_params.big_encryption = (uint8_t)state->big_enc; + + if (state->big_enc == BLE_AUDIO_SCAN_DELEGATOR_BIG_ENC_BROADCAST_CODE_INVALID) { + bass_params.bad_code = state->bad_code; + } else { + bass_params.bad_code = NULL; + } + + bass_params.num_subgroups = state->num_subgroups; + if (bass_params.num_subgroups > BLE_SVC_AUDIO_BASS_SUB_NUM_MAX) { + BLE_HS_LOG_ERROR("num_subgroups above the limit\n"); + return BLE_HS_ENOMEM; + } + + for (uint8_t i = 0; i < bass_params.num_subgroups; i++) { + bass_params.subgroups[i].bis_sync_state = state->subgroups[i].bis_sync; + bass_params.subgroups[i].metadata_length = state->subgroups[i].metadata_length; + bass_params.subgroups[i].metadata = state->subgroups[i].metadata; + } + + rc = ble_svc_audio_bass_receive_state_update(&bass_params, source_id); + if (rc != 0) { + BLE_HS_LOG_ERROR("Failed to update receive state (rc %d)\n", rc); + } + + return 0; +} + +void +ble_audio_scan_delegator_receive_state_foreach(ble_audio_scan_delegator_receive_state_foreach_fn *fn, void *arg) +{ + struct ble_audio_scan_delegator_receive_state_entry entry; + int rc; + + if (fn == NULL) { + BLE_HS_LOG_ERROR("callback is NULL\n"); + return; + } + + for (int i = 0; i < MYNEWT_VAL(BLE_AUDIO_SCAN_DELEGATOR_RECEIVE_STATE_MAX); i++) { + struct ble_svc_audio_bass_receiver_state *state; + uint8_t source_id; + + rc = ble_svc_audio_bass_source_id_get(i, &source_id); + if (rc != 0) { + continue; + } + + rc = ble_svc_audio_bass_receiver_state_get(source_id, &state); + if (rc != 0) { + BLE_HS_LOG_ERROR("Failed to get receiver state (rc %d)\n", rc); + continue; + } + + entry.source_id = source_id; + source_desc_init(&entry.source_desc, &state->source_addr, state->source_adv_sid, state->source_adv_sid); + entry.state.pa_sync_state = (uint8_t)state->pa_sync_state; + entry.state.big_enc = (uint8_t)state->big_encryption; + if (entry.state.big_enc == BLE_AUDIO_SCAN_DELEGATOR_BIG_ENC_BROADCAST_CODE_INVALID) { + memcpy(entry.state.bad_code, state->bad_code, sizeof(entry.state.bad_code)); + } + entry.state.num_subgroups = state->num_subgroups; + subgroups_init(entry.state.subgroups, state->subgroups, state->num_subgroups); + + if (fn(&entry, arg) != 0) { + break; + } + } +} + +#if MYNEWT_VAL(BLE_AUDIO_BROADCAST_SINK) +static int +audio_event_handler(struct ble_audio_event *event, void *arg) +{ + if (event->type == BLE_AUDIO_EVENT_BASS_BROADCAST_CODE_SET) { + ble_audio_broadcast_sink_code_set(event->bass_set_broadcast_code.source_id, + event->bass_set_broadcast_code.broadcast_code); + } + + return 0; +} +#endif /* BLE_AUDIO_BROADCAST_SINK */ + +int +ble_audio_scan_delegator_init(void) +{ + int rc; + + /* Ensure this function only gets called by sysinit. */ + SYSINIT_ASSERT_ACTIVE(); + +#if MYNEWT_VAL(BLE_AUDIO_BROADCAST_SINK) + static struct ble_audio_event_listener listener; + + rc = ble_audio_event_listener_register(&listener, audio_event_handler, NULL); + SYSINIT_PANIC_ASSERT(rc == 0); +#endif /* BLE_AUDIO_BROADCAST_SINK */ + + return rc; +} +#endif /* BLE_AUDIO_SCAN_DELEGATOR */ diff --git a/nimble/host/audio/src/ble_audio_scan_delegator_priv.h b/nimble/host/audio/src/ble_audio_scan_delegator_priv.h new file mode 100644 index 0000000000..ae5fc6510d --- /dev/null +++ b/nimble/host/audio/src/ble_audio_scan_delegator_priv.h @@ -0,0 +1,33 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_BLE_AUDIO_SCAN_DELEGATOR_PRIV_ +#define H_BLE_AUDIO_SCAN_DELEGATOR_PRIV_ + +#include +#include "audio/ble_audio.h" +#include "audio/ble_audio_scan_delegator.h" + +int ble_audio_scan_delegator_source_desc_get( + uint8_t source_id, struct ble_audio_scan_delegator_source_desc *source_desc); +int ble_audio_scan_delegator_metadata_update( + uint8_t source_id, uint8_t subgroup_index, const uint8_t *metadata, + uint8_t metadata_length); + +#endif /* H_BLE_AUDIO_SCAN_DELEGATOR_PRIV_ */ diff --git a/nimble/host/audio/syscfg.yml b/nimble/host/audio/syscfg.yml new file mode 100644 index 0000000000..a5c8907f69 --- /dev/null +++ b/nimble/host/audio/syscfg.yml @@ -0,0 +1,103 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +# syscfg.defs section +syscfg.defs: + BLE_AUDIO_MAX_CODEC_RECORDS: + description: > + Maximum number of registered audio codecs. + value: 0 + + BLE_AUDIO_BROADCAST_SINK: + description: > + This option enables BLE Audio Sink support. + value: 0 + restrictions: + - '(BLE_ISO_BROADCAST_SINK > 0) if 1' + + BLE_AUDIO_SCAN_DELEGATOR: + description: > + This option enables BLE Audio Scan Delegator support. + value: 0 + +syscfg.defs.BLE_AUDIO_BROADCAST_SINK: + BLE_AUDIO_BROADCAST_SINK_SYSINIT_STAGE: + description: > + Primary sysinit stage for BLE Audio Broadcast Sink. + value: 500 + + BLE_AUDIO_BROADCAST_SINK_LOG_MOD: + description: 'Numeric module ID to use for BLE Audio Broadcast Sink log messages.' + value: 28 + + BLE_AUDIO_BROADCAST_SINK_LOG_LVL: + description: 'Minimum level for the BLE Audio Broadcast Sink log log.' + value: 1 + + BLE_AUDIO_BROADCAST_SINK_MAX: + description: > + Maximum umber of Audio Broadcast Sink instances. + value: 'MYNEWT_VAL_BLE_ISO_MAX_BIGS' + +syscfg.defs.BLE_AUDIO_SCAN_DELEGATOR: + BLE_AUDIO_SCAN_DELEGATOR_SYSINIT_STAGE: + description: > + Primary sysinit stage for BLE Audio Scan Delegator. + value: 499 + + BLE_AUDIO_SCAN_DELEGATOR_LOG_MOD: + description: 'Numeric module ID to use for BLE Audio Scan Delegator log messages.' + value: 29 + + BLE_AUDIO_SCAN_DELEGATOR_LOG_LVL: + description: 'Minimum level for the BLE Audio Scan Delegator log log.' + value: 1 + + BLE_AUDIO_SCAN_DELEGATOR_RECEIVE_STATE_MAX: + description: > + Maximum number of Receive State instances. + value: MYNEWT_VAL(BLE_SVC_AUDIO_BASS_RECEIVE_STATE_MAX) + + BLE_AUDIO_SCAN_DELEGATOR_SUBGROUP_MAX: + description: > + Maximum number of Subgroups per Receive State. + value: MYNEWT_VAL(BLE_SVC_AUDIO_BASS_SUB_NUM_MAX) + + BLE_AUDIO_SCAN_DELEGATOR_STANDALONE: + description: > + This option enables the BLE Audio Scan Delegator as standalone device. + value: 1 + restrictions: + - '(BLE_AUDIO_BROADCAST_SINK == 0) if 1' + +# syscfg.logs section +syscfg.logs.BLE_AUDIO_BROADCAST_SINK: + BLE_AUDIO_BROADCAST_SINK_LOG: + module: MYNEWT_VAL(BLE_AUDIO_BROADCAST_SINK_LOG_MOD) + level: MYNEWT_VAL(BLE_AUDIO_BROADCAST_SINK_LOG_LVL) + +syscfg.logs.BLE_AUDIO_SCAN_DELEGATOR: + BLE_AUDIO_SCAN_DELEGATOR_LOG: + module: MYNEWT_VAL(BLE_AUDIO_SCAN_DELEGATOR_LOG_MOD) + level: MYNEWT_VAL(BLE_AUDIO_SCAN_DELEGATOR_LOG_LVL) + +# syscfg.vals section +syscfg.vals.BLE_AUDIO_BROADCAST_SINK: + BLE_AUDIO_SCAN_DELEGATOR: 1 + BLE_AUDIO_SCAN_DELEGATOR_STANDALONE: 0 + BLE_AUDIO_MAX_CODEC_RECORDS: 2 diff --git a/nimble/host/audio/targets/btshell_native/pkg.yml b/nimble/host/audio/targets/btshell_native/pkg.yml new file mode 100644 index 0000000000..7c129c62ff --- /dev/null +++ b/nimble/host/audio/targets/btshell_native/pkg.yml @@ -0,0 +1,27 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +pkg.name: audio/targets/btshell_native +pkg.type: target +pkg.description: Target for native btshell application with LE Audio + functionality enabled +pkg.author: "Apache Mynewt " +pkg.homepage: "http://mynewt.apache.org/" +pkg.deps: + - nimble/host/audio diff --git a/nimble/host/audio/targets/btshell_native/syscfg.yml b/nimble/host/audio/targets/btshell_native/syscfg.yml new file mode 100644 index 0000000000..cf2d410487 --- /dev/null +++ b/nimble/host/audio/targets/btshell_native/syscfg.yml @@ -0,0 +1,78 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +syscfg.vals: + CONSOLE_IMPLEMENTATION: full + LOG_IMPLEMENTATION: full + STATS_IMPLEMENTATION: full + + # Enable the shell task. + SHELL_TASK: 1 + + # Set log level to info (disable debug logging). + LOG_LEVEL: 1 + + # Disable security manager (pairing and bonding). + BLE_SM_LEGACY: 0 + BLE_SM_SC: 1 + + # Default task settings + OS_MAIN_STACK_SIZE: 512 + + # SMP is not supported in this app, so disable smp-over-shell. + SHELL_MGMT: 0 + + # Whether to save data to sys/config, or just keep it in RAM. + BLE_STORE_CONFIG_PERSIST: 0 + + # Enable Extended Advertising + BLE_EXT_ADV: 1 + BLE_EXT_ADV_MAX_SIZE: 261 + + BLE_MULTI_ADV_INSTANCES: 1 + + # Enable Periodic Advertising + BLE_PERIODIC_ADV: 1 + BLE_PERIODIC_ADV_SYNC_TRANSFER: 1 + BLE_PERIODIC_ADV_SYNC_BIGINFO_REPORTS: 1 + + BLE_SOCK_USE_TCP: 0 + BLE_SOCK_USE_LINUX_BLUE: 1 + BLE_SOCK_LINUX_DEV: 1 + BLE_TRANSPORT_HS: native + BLE_TRANSPORT_LL: socket + + BLE_VERSION: 54 + BLE_ISO_BROADCAST_SINK: 1 + BLE_ISO_BROADCAST_SOURCE: 1 + BLE_ISO_MAX_BIGS: 1 + BLE_ISO_MAX_BISES: 2 + + BLE_AUDIO: 1 + BLE_AUDIO_BROADCAST_SINK: 1 + BLE_AUDIO_SCAN_DELEGATOR: 1 + + CONSOLE_UART: 1 + CONSOLE_UART_BAUD: 1000000 + CONSOLE_STICKY_PROMPT: 1 + CONSOLE_UART_TX_BUF_SIZE: 256 + STATS_CLI: 1 + STATS_NAMES: 1 + + MSYS_1_BLOCK_COUNT: 100 diff --git a/nimble/host/audio/targets/btshell_native/target.yml b/nimble/host/audio/targets/btshell_native/target.yml new file mode 100644 index 0000000000..30b7d5b744 --- /dev/null +++ b/nimble/host/audio/targets/btshell_native/target.yml @@ -0,0 +1,22 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +target.app: "@apache-mynewt-nimble/apps/btshell" +target.bsp: "@apache-mynewt-core/hw/bsp/native" +target.build_profile: debug diff --git a/nimble/transport/dialog_cmac/cmac_driver/pkg.yml b/nimble/host/audio/test/pkg.yml similarity index 70% rename from nimble/transport/dialog_cmac/cmac_driver/pkg.yml rename to nimble/host/audio/test/pkg.yml index 5b4a212914..5020e9fa45 100644 --- a/nimble/transport/dialog_cmac/cmac_driver/pkg.yml +++ b/nimble/host/audio/test/pkg.yml @@ -17,23 +17,22 @@ # under the License. # -pkg.name: nimble/transport/dialog_cmac/cmac_driver -pkg.description: Driver for Dialog CMAC IPC +pkg.name: nimble/host/audio/test +pkg.type: unittest +pkg.description: "BLE Audio unit tests." pkg.author: "Apache Mynewt " pkg.homepage: "http://mynewt.apache.org/" pkg.keywords: - - dialog - - da1469x - - cmac -pkg.req_apis.CMAC_DEBUG_DIAG_ENABLE: - - dialog_cmac_diag +pkg.deps: + - "@apache-mynewt-core/test/testutil" + - nimble/host/audio -pkg.ign_files.BLE_CONTROLLER: - - cmac_host.c +pkg.deps.SELFTEST: + - "@apache-mynewt-core/sys/console/stub" + - "@apache-mynewt-core/sys/log/full" + - "@apache-mynewt-core/sys/stats/stub" + - nimble/drivers/native -pkg.post_link_cmds.BLE_CONTROLLER: - scripts/create_cmac_bin.sh: 100 - -pkg.pre_link_cmds.BLE_HOST: - scripts/build_libcmac.sh: 100 +pkg.apis: + - ble_driver diff --git a/nimble/transport/da1469x/cmac_driver/include/cmac_driver/cmac_host.h b/nimble/host/audio/test/src/ble_audio_test.c similarity index 71% rename from nimble/transport/da1469x/cmac_driver/include/cmac_driver/cmac_host.h rename to nimble/host/audio/test/src/ble_audio_test.c index f623a48a99..91e4a91449 100644 --- a/nimble/transport/da1469x/cmac_driver/include/cmac_driver/cmac_host.h +++ b/nimble/host/audio/test/src/ble_audio_test.c @@ -17,21 +17,24 @@ * under the License. */ -#ifndef __CMAC_HOST_H_ -#define __CMAC_HOST_H_ +#include "sysinit/sysinit.h" +#include "testutil/testutil.h" -#ifdef __cplusplus -extern "C" { -#endif +TEST_SUITE_DECL(ble_audio_base_parse_test_suite); +TEST_CASE_DECL(ble_audio_listener_register_test); -typedef int (* cmac_mbox_read_cb)(const uint8_t *, uint16_t len); +TEST_SUITE(ble_audio_test) +{ + ble_audio_base_parse_test_suite(); + ble_audio_listener_register_test(); +} -void cmac_host_init(void); -void cmac_mbox_write(const uint8_t *buf, size_t len); -void cmac_mbox_set_read_cb(cmac_mbox_read_cb cb); +int +main(int argc, char **argv) +{ + sysinit(); -#ifdef __cplusplus -} -#endif + ble_audio_test(); -#endif /* __CMAC_HOST_H_ */ + return tu_any_failed; +} diff --git a/nimble/host/audio/test/src/testcases/ble_audio_base_parse_test.c b/nimble/host/audio/test/src/testcases/ble_audio_base_parse_test.c new file mode 100644 index 0000000000..3231b8539b --- /dev/null +++ b/nimble/host/audio/test/src/testcases/ble_audio_base_parse_test.c @@ -0,0 +1,361 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "testutil/testutil.h" + +#include "host/ble_hs.h" +#include "audio/ble_audio.h" + +/** + * BAP_v1.0.1 Table 3.16 + * BASE structure for the logical BASE structure example + */ +static const uint8_t example_base[] = { + 0x1e, 0x00, 0x00, /* Presentation_Delay: 40 ms */ + 0x02, /* Num_Subgroups: 2 Subgroups */ + 0x02, /* Num_BIS[0]: 2 BIS in Subgroup[0] */ + 0x06, 0x00, 0x00, 0x00, 0x00, /* Codec_ID[0]: LC3 */ + 0x0a, /* Codec_Specific_Configuration_Length[0] */ + 0x02, 0x01, 0x08, /* LTV 1: Sampling_Frequency: 48000 Hz */ + 0x02, 0x02, 0x02, /* LTV 2: Frame_Duration: 10 ms */ + 0x03, 0x04, 0x64, 0x00, /* LTV 3: Octets_Per_Codec_Frame: 100 octets */ + 0x09, /* Metadata_Length[0] */ + 0x03, 0x02, 0x04, 0x00, /* LTV 1: Streaming_Audio_Contexts: Media */ + 0x04, 0x04, 0x73, 0x70, 0x61, /* LTV 2: Language: Spanish */ + 0x01, /* BIS_index[0[0]] */ + 0x06, /* Codec_Specific_Configuration_Length[0[0]] */ + 0x05, 0x03, 0x01, 0x00, 0x00, 0x00, /* LTV 1 = Audio_Channel_Allocation: FL */ + 0x02, /* BIS_index[0[1]] */ + 0x06, /* Codec_Specific_Configuration_Length[0[1]] */ + 0x05, 0x03, 0x02, 0x00, 0x00, 0x00, /* LTV 1 = Audio_Channel_Allocation: FR */ + 0x02, /* Num_BIS[1]: 2 BIS in Subgroup[0] */ + 0x06, 0x00, 0x00, 0x00, 0x00, /* Codec_ID[1]: LC3 */ + 0x0a, /* Codec_Specific_Configuration_Length[1] */ + 0x02, 0x01, 0x08, /* LTV 1: Sampling_Frequency: 48000 Hz */ + 0x02, 0x02, 0x02, /* LTV 2: Frame_Duration: 10 ms */ + 0x03, 0x04, 0x64, 0x00, /* LTV 3: Octets_Per_Codec_Frame: 100 octets */ + 0x09, /* Metadata_Length[1] */ + 0x03, 0x02, 0x04, 0x00, /* LTV 1: Streaming_Audio_Contexts: Media */ + 0x04, 0x04, 0x65, 0x6e, 0x67, /* LTV 2: Language: English */ + 0x03, /* BIS_index[1[0]] */ + 0x06, /* Codec_Specific_Configuration_Length[1[0]] */ + 0x05, 0x03, 0x01, 0x00, 0x00, 0x00, /* LTV 1 = Audio_Channel_Allocation: FL */ + 0x04, /* BIS_index[1[1]] */ + 0x06, /* Codec_Specific_Configuration_Length[1[1]] */ + 0x05, 0x03, 0x02, 0x00, 0x00, 0x00, /* LTV 1 = Audio_Channel_Allocation: FR */ +}; + +TEST_CASE_SELF(ble_audio_base_parse_test) +{ + struct ble_audio_base_subgroup subgroup; + struct ble_audio_base_group group; + struct ble_audio_base_bis bis; + struct ble_audio_base_iter subgroup_iter; + struct ble_audio_base_iter bis_iter; + int rc; + + rc = ble_audio_base_parse(example_base, (uint8_t)sizeof(example_base), + &group, &subgroup_iter); + TEST_ASSERT(rc == 0); + + TEST_ASSERT(group.presentation_delay == 30); + TEST_ASSERT(group.num_subgroups == 2); + + rc = ble_audio_base_subgroup_iter(&subgroup_iter, &subgroup, &bis_iter); + TEST_ASSERT(rc == 0); + + TEST_ASSERT(subgroup.codec_id.format == 0x06); + TEST_ASSERT(subgroup.codec_id.company_id == 0x0000); + TEST_ASSERT(subgroup.codec_id.vendor_specific == 0x0000); + TEST_ASSERT(subgroup.codec_spec_config_len == 10); + TEST_ASSERT(subgroup.codec_spec_config != NULL); + TEST_ASSERT(subgroup.metadata_len == 9); + TEST_ASSERT(subgroup.num_bis == 2); + + rc = ble_audio_base_bis_iter(&bis_iter, &bis); + TEST_ASSERT(rc == 0); + + TEST_ASSERT(bis.index == 0x01); + TEST_ASSERT(bis.codec_spec_config_len == 6); + TEST_ASSERT(bis.codec_spec_config != NULL); + + rc = ble_audio_base_bis_iter(&bis_iter, &bis); + TEST_ASSERT(rc == 0); + + TEST_ASSERT(bis.index == 0x02); + TEST_ASSERT(bis.codec_spec_config_len == 6); + TEST_ASSERT(bis.codec_spec_config != NULL); + + rc = ble_audio_base_bis_iter(&bis_iter, &bis); + TEST_ASSERT(rc == BLE_HS_ENOENT); + + rc = ble_audio_base_subgroup_iter(&subgroup_iter, &subgroup, &bis_iter); + TEST_ASSERT(rc == 0); + + TEST_ASSERT(subgroup.codec_id.format == 0x06); + TEST_ASSERT(subgroup.codec_id.company_id == 0x0000); + TEST_ASSERT(subgroup.codec_id.vendor_specific == 0x0000); + TEST_ASSERT(subgroup.codec_spec_config_len == 10); + TEST_ASSERT(subgroup.codec_spec_config != NULL); + TEST_ASSERT(subgroup.metadata_len == 9); + TEST_ASSERT(subgroup.num_bis == 2); + + rc = ble_audio_base_bis_iter(&bis_iter, &bis); + TEST_ASSERT(rc == 0); + + TEST_ASSERT(bis.index == 0x03); + TEST_ASSERT(bis.codec_spec_config_len == 6); + TEST_ASSERT(bis.codec_spec_config != NULL); + + rc = ble_audio_base_bis_iter(&bis_iter, &bis); + TEST_ASSERT(rc == 0); + + TEST_ASSERT(bis.index == 0x04); + TEST_ASSERT(bis.codec_spec_config_len == 6); + TEST_ASSERT(bis.codec_spec_config != NULL); + + rc = ble_audio_base_bis_iter(&bis_iter, &bis); + TEST_ASSERT(rc == BLE_HS_ENOENT); + + rc = ble_audio_base_subgroup_iter(&subgroup_iter, &subgroup, &bis_iter); + TEST_ASSERT(rc == BLE_HS_ENOENT); +} + +TEST_CASE_SELF(ble_audio_base_parse_test_params) +{ + struct ble_audio_base_subgroup subgroup; + struct ble_audio_base_group group; + struct ble_audio_base_bis bis; + struct ble_audio_base_iter subgroup_iter; + struct ble_audio_base_iter bis_iter; + int rc; + + rc = ble_audio_base_parse(NULL, (uint8_t)sizeof(example_base), &group, &subgroup_iter); + TEST_ASSERT(rc == BLE_HS_EINVAL); + + rc = ble_audio_base_parse(NULL, (uint8_t)sizeof(example_base), NULL, &subgroup_iter); + TEST_ASSERT(rc == BLE_HS_EINVAL); + + rc = ble_audio_base_parse(example_base, (uint8_t)sizeof(example_base), &group, NULL); + TEST_ASSERT(rc == 0); + + rc = ble_audio_base_parse(example_base, (uint8_t)sizeof(example_base), &group, &subgroup_iter); + TEST_ASSERT(rc == 0); + + rc = ble_audio_base_subgroup_iter(NULL, &subgroup, &bis_iter); + TEST_ASSERT(rc == BLE_HS_EINVAL); + + rc = ble_audio_base_subgroup_iter(&subgroup_iter, NULL, &bis_iter); + TEST_ASSERT(rc == BLE_HS_EINVAL); + + rc = ble_audio_base_subgroup_iter(&subgroup_iter, &subgroup, NULL); + TEST_ASSERT(rc == 0); + + rc = ble_audio_base_bis_iter(NULL, &bis); + TEST_ASSERT(rc == BLE_HS_EINVAL); + + rc = ble_audio_base_bis_iter(&bis_iter, NULL); + TEST_ASSERT(rc == BLE_HS_EINVAL); +} + +TEST_CASE_SELF(ble_audio_base_parse_test_data_length) +{ + struct ble_audio_base_subgroup subgroup; + struct ble_audio_base_group group; + struct ble_audio_base_bis bis; + struct ble_audio_base_iter subgroup_iter; + struct ble_audio_base_iter bis_iter; + int rc; + + /* Incomplete: empty */ + rc = ble_audio_base_parse(example_base, 0, &group, &subgroup_iter); + TEST_ASSERT(rc == BLE_HS_EMSGSIZE); + + /* Truncated: Presentation_Delay Parameter */ + rc = ble_audio_base_parse(example_base, 2, &group, &subgroup_iter); + TEST_ASSERT(rc == BLE_HS_EMSGSIZE); + + /* Incomplete: no Num_Subgroups[0] Parameter */ + rc = ble_audio_base_parse(example_base, 3, &group, &subgroup_iter); + TEST_ASSERT(rc == BLE_HS_EMSGSIZE); + + /* Incomplete: no Num_BIS[0] Parameter */ + rc = ble_audio_base_parse(example_base, 4, &group, &subgroup_iter); + TEST_ASSERT(rc == 0); + rc = ble_audio_base_subgroup_iter(&subgroup_iter, &subgroup, &bis_iter); + TEST_ASSERT(rc == BLE_HS_EMSGSIZE); + + /* Truncated: Codec_ID[0] Parameter */ + rc = ble_audio_base_parse(example_base, 9, &group, &subgroup_iter); + rc = ble_audio_base_subgroup_iter(&subgroup_iter, &subgroup, &bis_iter); + TEST_ASSERT(rc == BLE_HS_EMSGSIZE); + + /* Incomplete: no Codec_Specific_Configuration_Length[0] Parameter */ + rc = ble_audio_base_parse(example_base, 13, &group, &subgroup_iter); + rc = ble_audio_base_subgroup_iter(&subgroup_iter, &subgroup, &bis_iter); + TEST_ASSERT(rc == BLE_HS_EMSGSIZE); + + /* Truncated: Codec_Specific_Configuration[0] Parameter */ + rc = ble_audio_base_parse(example_base, 14, &group, &subgroup_iter); + rc = ble_audio_base_subgroup_iter(&subgroup_iter, &subgroup, &bis_iter); + TEST_ASSERT(rc == BLE_HS_EMSGSIZE); + + /* Incomplete: no Metadata_Length[0] Parameter */ + rc = ble_audio_base_parse(example_base, 21, &group, &subgroup_iter); + rc = ble_audio_base_subgroup_iter(&subgroup_iter, &subgroup, &bis_iter); + TEST_ASSERT(rc == BLE_HS_EMSGSIZE); + + /* Truncated: Metadata[0] Parameter */ + rc = ble_audio_base_parse(example_base, 30, &group, &subgroup_iter); + rc = ble_audio_base_subgroup_iter(&subgroup_iter, &subgroup, &bis_iter); + TEST_ASSERT(rc == BLE_HS_EMSGSIZE); + + /* Incomplete: no BIS_index[0[0]] Parameter */ + rc = ble_audio_base_parse(example_base, 31, &group, &subgroup_iter); + rc = ble_audio_base_subgroup_iter(&subgroup_iter, &subgroup, &bis_iter); + TEST_ASSERT(rc == 0); + rc = ble_audio_base_bis_iter(&bis_iter, &bis); + TEST_ASSERT(rc == BLE_HS_EMSGSIZE); + + /* Incomplete: no Codec_Specific_Configuration_Length[0[0]] Parameter */ + rc = ble_audio_base_parse(example_base, 32, &group, &subgroup_iter); + rc = ble_audio_base_subgroup_iter(&subgroup_iter, &subgroup, &bis_iter); + rc = ble_audio_base_bis_iter(&bis_iter, &bis); + TEST_ASSERT(rc == BLE_HS_EMSGSIZE); + + /* Truncated: Codec_Specific_Configuration_Length[0[0]] Parameter */ + rc = ble_audio_base_parse(example_base, 38, &group, &subgroup_iter); + rc = ble_audio_base_subgroup_iter(&subgroup_iter, &subgroup, &bis_iter); + rc = ble_audio_base_bis_iter(&bis_iter, &bis); + TEST_ASSERT(rc == BLE_HS_EMSGSIZE); + + /* Incomplete: no BIS_index[0[1]] Parameter */ + rc = ble_audio_base_parse(example_base, 39, &group, &subgroup_iter); + rc = ble_audio_base_subgroup_iter(&subgroup_iter, &subgroup, &bis_iter); + rc = ble_audio_base_bis_iter(&bis_iter, &bis); + TEST_ASSERT(rc == 0); + rc = ble_audio_base_bis_iter(&bis_iter, &bis); + TEST_ASSERT(rc == BLE_HS_EMSGSIZE); + + /* Incomplete: no Codec_Specific_Configuration_Length[0[1]] Parameter */ + rc = ble_audio_base_parse(example_base, 40, &group, &subgroup_iter); + rc = ble_audio_base_subgroup_iter(&subgroup_iter, &subgroup, &bis_iter); + rc = ble_audio_base_bis_iter(&bis_iter, &bis); + rc = ble_audio_base_bis_iter(&bis_iter, &bis); + TEST_ASSERT(rc == BLE_HS_EMSGSIZE); + + /* Truncated: Codec_Specific_Configuration_Length[0[1]] Parameter */ + rc = ble_audio_base_parse(example_base, 46, &group, &subgroup_iter); + rc = ble_audio_base_subgroup_iter(&subgroup_iter, &subgroup, &bis_iter); + rc = ble_audio_base_bis_iter(&bis_iter, &bis); + TEST_ASSERT(rc == 0); + rc = ble_audio_base_bis_iter(&bis_iter, &bis); + TEST_ASSERT(rc == BLE_HS_EMSGSIZE); + + /* Incomplete: no Num_BIS[1] Parameter */ + rc = ble_audio_base_parse(example_base, 47, &group, &subgroup_iter); + rc = ble_audio_base_subgroup_iter(&subgroup_iter, &subgroup, &bis_iter); + TEST_ASSERT(rc == 0); + rc = ble_audio_base_subgroup_iter(&subgroup_iter, &subgroup, &bis_iter); + TEST_ASSERT(rc == BLE_HS_EMSGSIZE); + + /* Truncated: Codec_ID[1] Parameter */ + rc = ble_audio_base_parse(example_base, 52, &group, &subgroup_iter); + rc = ble_audio_base_subgroup_iter(&subgroup_iter, &subgroup, &bis_iter); + rc = ble_audio_base_subgroup_iter(&subgroup_iter, &subgroup, &bis_iter); + TEST_ASSERT(rc == BLE_HS_EMSGSIZE); + + /* Incomplete: no Codec_Specific_Configuration_Length[1] Parameter */ + rc = ble_audio_base_parse(example_base, 53, &group, &subgroup_iter); + rc = ble_audio_base_subgroup_iter(&subgroup_iter, &subgroup, &bis_iter); + rc = ble_audio_base_subgroup_iter(&subgroup_iter, &subgroup, &bis_iter); + TEST_ASSERT(rc == BLE_HS_EMSGSIZE); + + /* Truncated: Codec_Specific_Configuration[1] Parameter */ + rc = ble_audio_base_parse(example_base, 63, &group, &subgroup_iter); + rc = ble_audio_base_subgroup_iter(&subgroup_iter, &subgroup, &bis_iter); + rc = ble_audio_base_subgroup_iter(&subgroup_iter, &subgroup, &bis_iter); + TEST_ASSERT(rc == BLE_HS_EMSGSIZE); + + /* Incomplete: no Metadata_Length[1] Parameter */ + rc = ble_audio_base_parse(example_base, 64, &group, &subgroup_iter); + rc = ble_audio_base_subgroup_iter(&subgroup_iter, &subgroup, &bis_iter); + rc = ble_audio_base_subgroup_iter(&subgroup_iter, &subgroup, &bis_iter); + TEST_ASSERT(rc == BLE_HS_EMSGSIZE); + + /* Truncated: Metadata[1] Parameter */ + rc = ble_audio_base_parse(example_base, 73, &group, &subgroup_iter); + rc = ble_audio_base_subgroup_iter(&subgroup_iter, &subgroup, &bis_iter); + rc = ble_audio_base_subgroup_iter(&subgroup_iter, &subgroup, &bis_iter); + TEST_ASSERT(rc == BLE_HS_EMSGSIZE); + + /* Incomplete: no BIS_index[1[0]] Parameter */ + rc = ble_audio_base_parse(example_base, 74, &group, &subgroup_iter); + rc = ble_audio_base_subgroup_iter(&subgroup_iter, &subgroup, &bis_iter); + rc = ble_audio_base_subgroup_iter(&subgroup_iter, &subgroup, &bis_iter); + TEST_ASSERT(rc == 0); + rc = ble_audio_base_bis_iter(&bis_iter, &bis); + TEST_ASSERT(rc == BLE_HS_EMSGSIZE); + + /* Incomplete: no Codec_Specific_Configuration_Length[1[0]] Parameter */ + rc = ble_audio_base_parse(example_base, 75, &group, &subgroup_iter); + rc = ble_audio_base_subgroup_iter(&subgroup_iter, &subgroup, &bis_iter); + rc = ble_audio_base_subgroup_iter(&subgroup_iter, &subgroup, &bis_iter); + rc = ble_audio_base_bis_iter(&bis_iter, &bis); + TEST_ASSERT(rc == BLE_HS_EMSGSIZE); + + /* Truncated: Codec_Specific_Configuration_Length[1[0]] Parameter */ + rc = ble_audio_base_parse(example_base, 81, &group, &subgroup_iter); + rc = ble_audio_base_subgroup_iter(&subgroup_iter, &subgroup, &bis_iter); + rc = ble_audio_base_subgroup_iter(&subgroup_iter, &subgroup, &bis_iter); + rc = ble_audio_base_bis_iter(&bis_iter, &bis); + TEST_ASSERT(rc == BLE_HS_EMSGSIZE); + + /* Incomplete: no BIS_index[1[1]] Parameter */ + rc = ble_audio_base_parse(example_base, 82, &group, &subgroup_iter); + rc = ble_audio_base_subgroup_iter(&subgroup_iter, &subgroup, &bis_iter); + rc = ble_audio_base_subgroup_iter(&subgroup_iter, &subgroup, &bis_iter); + rc = ble_audio_base_bis_iter(&bis_iter, &bis); + TEST_ASSERT(rc == 0); + rc = ble_audio_base_bis_iter(&bis_iter, &bis); + TEST_ASSERT(rc == BLE_HS_EMSGSIZE); + + /* Incomplete: no Codec_Specific_Configuration_Length[1[1]] Parameter */ + rc = ble_audio_base_parse(example_base, 83, &group, &subgroup_iter); + rc = ble_audio_base_subgroup_iter(&subgroup_iter, &subgroup, &bis_iter); + rc = ble_audio_base_subgroup_iter(&subgroup_iter, &subgroup, &bis_iter); + rc = ble_audio_base_bis_iter(&bis_iter, &bis); + rc = ble_audio_base_bis_iter(&bis_iter, &bis); + TEST_ASSERT(rc == BLE_HS_EMSGSIZE); + + /* Truncated: Codec_Specific_Configuration_Length[0[1]] Parameter */ + rc = ble_audio_base_parse(example_base, 89, &group, &subgroup_iter); + rc = ble_audio_base_subgroup_iter(&subgroup_iter, &subgroup, &bis_iter); + rc = ble_audio_base_subgroup_iter(&subgroup_iter, &subgroup, &bis_iter); + rc = ble_audio_base_bis_iter(&bis_iter, &bis); + rc = ble_audio_base_bis_iter(&bis_iter, &bis); + TEST_ASSERT(rc == BLE_HS_EMSGSIZE); +} + +TEST_SUITE(ble_audio_base_parse_test_suite) +{ + ble_audio_base_parse_test(); + ble_audio_base_parse_test_params(); + ble_audio_base_parse_test_data_length(); +} diff --git a/nimble/host/audio/test/src/testcases/ble_audio_listener_register_test.c b/nimble/host/audio/test/src/testcases/ble_audio_listener_register_test.c new file mode 100644 index 0000000000..363632ecba --- /dev/null +++ b/nimble/host/audio/test/src/testcases/ble_audio_listener_register_test.c @@ -0,0 +1,59 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "testutil/testutil.h" + +#include "host/ble_hs.h" +#include "audio/ble_audio.h" + +static struct ble_audio_event_listener event_listener; + +static int +event_handler(struct ble_audio_event *event, void *arg) +{ + return 0; +} + +TEST_CASE_SELF(ble_audio_listener_register_test) +{ + int rc; + + rc = ble_audio_event_listener_register(&event_listener, event_handler, + NULL); + TEST_ASSERT(rc == 0); + + rc = ble_audio_event_listener_register(&event_listener, event_handler, + NULL); + TEST_ASSERT(rc != 0); + + rc = ble_audio_event_listener_unregister(&event_listener); + TEST_ASSERT(rc == 0); + + rc = ble_audio_event_listener_register(NULL, event_handler, NULL); + TEST_ASSERT(rc != 0); + + rc = ble_audio_event_listener_register(&event_listener, NULL, NULL); + TEST_ASSERT(rc != 0); + + rc = ble_audio_event_listener_unregister(NULL); + TEST_ASSERT(rc != 0); + + rc = ble_audio_event_listener_unregister(&event_listener); + TEST_ASSERT(rc != 0); +} diff --git a/nimble/host/audio/test/syscfg.yml b/nimble/host/audio/test/syscfg.yml new file mode 100644 index 0000000000..7fad93f3fe --- /dev/null +++ b/nimble/host/audio/test/syscfg.yml @@ -0,0 +1,31 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +syscfg.defs: + +syscfg.vals: + # Prevent priority conflict with controller task. + MCU_TIMER_POLLER_PRIO: 1 + MCU_UART_POLLER_PRIO: 2 + NATIVE_SOCKETS_PRIO: 3 + + BLE_VERSION: 54 + BLE_HS_DEBUG: 1 + + BLE_EXT_ADV: 1 diff --git a/nimble/host/include/host/ble_att.h b/nimble/host/include/host/ble_att.h index 391a992aeb..8323c9d764 100644 --- a/nimble/host/include/host/ble_att.h +++ b/nimble/host/include/host/ble_att.h @@ -32,75 +32,247 @@ extern "C" { #endif +/** Chained memory buffer. */ struct os_mbuf; +/** + * @defgroup ble_att_uuids Attribute Protocol (ATT) UUIDs + * @{ + */ +/** UUID for a primary service. */ #define BLE_ATT_UUID_PRIMARY_SERVICE 0x2800 + +/** UUID for a secondary service. */ #define BLE_ATT_UUID_SECONDARY_SERVICE 0x2801 + +/** UUID for an include definition. */ #define BLE_ATT_UUID_INCLUDE 0x2802 + +/** UUID for a characteristic. */ #define BLE_ATT_UUID_CHARACTERISTIC 0x2803 +/** @} */ + +/** + * @defgroup ble_att_err_codes Attribute Protocol (ATT) Error Codes + * @{ + */ + +/** The attribute handle given was not valid on this server */ #define BLE_ATT_ERR_INVALID_HANDLE 0x01 + +/** The attribute cannot be read. */ #define BLE_ATT_ERR_READ_NOT_PERMITTED 0x02 + +/** The attribute cannot be written. */ #define BLE_ATT_ERR_WRITE_NOT_PERMITTED 0x03 + +/** The attribute PDU was invalid. */ #define BLE_ATT_ERR_INVALID_PDU 0x04 + +/** The attribute requires authentication before it can be read or written. */ #define BLE_ATT_ERR_INSUFFICIENT_AUTHEN 0x05 + +/** ATT Server does not support the request received from the client. */ #define BLE_ATT_ERR_REQ_NOT_SUPPORTED 0x06 + +/** Offset specified was past the end of the attribute. */ #define BLE_ATT_ERR_INVALID_OFFSET 0x07 + +/** The attribute requires authorization before it can be read or written. */ #define BLE_ATT_ERR_INSUFFICIENT_AUTHOR 0x08 + +/** Too many prepare writes have been queued. */ #define BLE_ATT_ERR_PREPARE_QUEUE_FULL 0x09 + +/** No attribute found within the given attribute handle range. */ #define BLE_ATT_ERR_ATTR_NOT_FOUND 0x0a + +/** The attribute cannot be read using the ATT_READ_BLOB_REQ PDU. */ #define BLE_ATT_ERR_ATTR_NOT_LONG 0x0b + +/** The Encryption Key Size used for encrypting this link is too short. */ #define BLE_ATT_ERR_INSUFFICIENT_KEY_SZ 0x0c + +/** The attribute value length is invalid for the operation. */ #define BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN 0x0d + +/** The attribute request that was requested has encountered an error that was unlikely, + * and therefore could not be completed as requested. */ #define BLE_ATT_ERR_UNLIKELY 0x0e + +/** The attribute requires encryption before it can be read or written */ #define BLE_ATT_ERR_INSUFFICIENT_ENC 0x0f + +/** The attribute type is not a supported grouping attribute as defined by a higher layer specification. */ #define BLE_ATT_ERR_UNSUPPORTED_GROUP 0x10 + +/**Insufficient Resources to complete the request. */ #define BLE_ATT_ERR_INSUFFICIENT_RES 0x11 +/**Requested value is not allowed. */ +#define BLE_ATT_ERR_VALUE_NOT_ALLOWED 0x13 + +/**Write Request Rejected. */ +#define BLE_ATT_ERR_WRITE_REQ_REJECTED 0xFC + +/**Client Characteristic Configuration Descriptor Improperly Configured. */ +#define BLE_ATT_ERR_CCCD_IMPORER_CONF 0xFD + +/**Procedure Already in Progress. */ +#define BLE_ATT_ERR_PROC_IN_PROGRESS 0xFE + +/**Out of Range. */ +#define BLE_ATT_ERR_OUT_OF_RANGE 0xFF + +/** @} */ + +/** + * @defgroup ble_att_op_codes Attribute Protocol (ATT) Operation Codes + * @{ + */ + +/** Error Response. */ #define BLE_ATT_OP_ERROR_RSP 0x01 + +/** MTU Request. */ #define BLE_ATT_OP_MTU_REQ 0x02 + +/** MTU Response. */ #define BLE_ATT_OP_MTU_RSP 0x03 + +/** Find Information Request. */ #define BLE_ATT_OP_FIND_INFO_REQ 0x04 + +/** Find Information Response. */ #define BLE_ATT_OP_FIND_INFO_RSP 0x05 + +/** Find By Type Value Request. */ #define BLE_ATT_OP_FIND_TYPE_VALUE_REQ 0x06 + +/** Find By Type Value Response. */ #define BLE_ATT_OP_FIND_TYPE_VALUE_RSP 0x07 + +/** Read By Type Request. */ #define BLE_ATT_OP_READ_TYPE_REQ 0x08 + +/** Read By Type Response. */ #define BLE_ATT_OP_READ_TYPE_RSP 0x09 + +/** Read Request. */ #define BLE_ATT_OP_READ_REQ 0x0a + +/** Read Response. */ #define BLE_ATT_OP_READ_RSP 0x0b + +/** Read Blob Request. */ #define BLE_ATT_OP_READ_BLOB_REQ 0x0c + +/** Read Blob Response. */ #define BLE_ATT_OP_READ_BLOB_RSP 0x0d + +/** Read Multiple Request. */ #define BLE_ATT_OP_READ_MULT_REQ 0x0e + +/** Read Multiple Response. */ #define BLE_ATT_OP_READ_MULT_RSP 0x0f + +/** Read By Group Type Request. */ #define BLE_ATT_OP_READ_GROUP_TYPE_REQ 0x10 + +/** Read By Group Type Response. */ #define BLE_ATT_OP_READ_GROUP_TYPE_RSP 0x11 + +/** Write Request. */ #define BLE_ATT_OP_WRITE_REQ 0x12 + +/** Write Response. */ #define BLE_ATT_OP_WRITE_RSP 0x13 + +/** Prepare Write Request. */ #define BLE_ATT_OP_PREP_WRITE_REQ 0x16 + +/** Prepare Write Response. */ #define BLE_ATT_OP_PREP_WRITE_RSP 0x17 + +/** Execute Write Request. */ #define BLE_ATT_OP_EXEC_WRITE_REQ 0x18 + +/** Execute Write Response. */ #define BLE_ATT_OP_EXEC_WRITE_RSP 0x19 + +/** Notify Request. */ #define BLE_ATT_OP_NOTIFY_REQ 0x1b + +/** Indicate Request. */ #define BLE_ATT_OP_INDICATE_REQ 0x1d + +/** Indicate Response. */ #define BLE_ATT_OP_INDICATE_RSP 0x1e + +/** Read Multiple Variable Lenght Request */ +#define BLE_ATT_OP_READ_MULT_VAR_REQ 0x20 + +/** Read Multiple Variable Lenght Response */ +#define BLE_ATT_OP_READ_MULT_VAR_RSP 0x21 + +/** Notify Multiple Request */ +#define BLE_ATT_OP_NOTIFY_MULTI_REQ 0x23 +/** Write Command. */ #define BLE_ATT_OP_WRITE_CMD 0x52 +/** @} */ + +/** Maximum length of an Attribute Protocol (ATT) attribute. */ #define BLE_ATT_ATTR_MAX_LEN 512 +/** + * @defgroup ble_att_flags Attribute Protocol (ATT) Flags + * @{ + */ + +/** Read permission flag. */ #define BLE_ATT_F_READ 0x01 + +/** Write permission flag. */ #define BLE_ATT_F_WRITE 0x02 + +/** Read encrypted permission flag. */ #define BLE_ATT_F_READ_ENC 0x04 + +/** Read authenticated permission flag. */ #define BLE_ATT_F_READ_AUTHEN 0x08 + +/** Read authorized permission flag. */ #define BLE_ATT_F_READ_AUTHOR 0x10 + +/** Write encrypted permission flag. */ #define BLE_ATT_F_WRITE_ENC 0x20 + +/** Write authenticated permission flag. */ #define BLE_ATT_F_WRITE_AUTHEN 0x40 + +/** Write authorized permission flag. */ #define BLE_ATT_F_WRITE_AUTHOR 0x80 +/** Read and write permission flag. */ #define HA_FLAG_PERM_RW (BLE_ATT_F_READ | BLE_ATT_F_WRITE) +/** @} */ + +/** + * @defgroup ble_att_access_op_codes Attribute Protocol (ATT) Access Operation Codes + * @{ + */ + +/** Access operation: Read. */ #define BLE_ATT_ACCESS_OP_READ 1 + +/** Access operation: Write. */ #define BLE_ATT_ACCESS_OP_WRITE 2 +/** @} */ + /** Default ATT MTU. Also the minimum. */ #define BLE_ATT_MTU_DFLT 23 diff --git a/nimble/host/include/host/ble_cs.h b/nimble/host/include/host/ble_cs.h new file mode 100644 index 0000000000..3abbd11e65 --- /dev/null +++ b/nimble/host/include/host/ble_cs.h @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +/* All Channel Sounding APIs are experimental and subject to change at any time */ + +#ifndef H_BLE_CS_ +#define H_BLE_CS_ +#include "syscfg/syscfg.h" + +#define BLE_CS_EVENT_CS_PROCEDURE_COMPLETE (0) + +struct ble_cs_event { + uint8_t type; + union + { + struct + { + uint16_t conn_handle; + uint8_t status; + } procedure_complete; + }; + +}; + +typedef int ble_cs_event_fn(struct ble_cs_event *event, void *arg); + +struct ble_cs_initiator_procedure_start_params { + uint16_t conn_handle; + ble_cs_event_fn *cb; + void *cb_arg; +}; + +struct ble_cs_reflector_setup_params { + ble_cs_event_fn *cb; + void *cb_arg; +}; + +int ble_cs_initiator_procedure_start(const struct ble_cs_initiator_procedure_start_params *params); +int ble_cs_initiator_procedure_terminate(uint16_t conn_handle); +int ble_cs_reflector_setup(struct ble_cs_reflector_setup_params *params); +#endif diff --git a/nimble/host/include/host/ble_dtm.h b/nimble/host/include/host/ble_dtm.h new file mode 100644 index 0000000000..cd01a23b70 --- /dev/null +++ b/nimble/host/include/host/ble_dtm.h @@ -0,0 +1,126 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_BLE_DTM_ +#define H_BLE_DTM_ + +#include +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @file ble_dtm.h + * + * @brief DTM (Direct Test Mode) + * + * This header file provides the interface and data structures for working with + * the Direct Test Mode (DTM) functionality in a BLE (Bluetooth Low Energy) host. + * DTM allows for testing and validation of the BLE radio performance by enabling + * custom transmission and reception of data packets. + * + * @defgroup bt_host_dtm Bluetooth Host Direct Test Mode + * @ingroup bt_host + * @{ + */ + +/** + * @struct ble_dtm_rx_params + * @brief Parameters for DTM RX test. + * + * This structure represents the parameters for a Direct Test Mode (DTM) receiver test. + */ +struct ble_dtm_rx_params { + /** The channel to use for the RX test. */ + uint8_t channel; + + /** The PHY to use for the RX test. */ + uint8_t phy; + + /** The modulation index to use for the RX test. */ + uint8_t modulation_index; +}; + +/** + * @brief Start a Direct Test Mode (DTM) receiver test. + * + * This function starts a DTM RX test with the provided parameters. + * + * @param params The parameters for the DTM RX test. + * + * @return 0 on success; + * A non-zero value on failure. + */ +int ble_dtm_rx_start(const struct ble_dtm_rx_params *params); + +/** + * @struct ble_dtm_tx_params + * @brief Parameters for DTM TX test. + * + * This structure represents the parameters for a Direct Test Mode (DTM) transmitter test. + */ +struct ble_dtm_tx_params { + /** The channel to use for the TX test. */ + uint8_t channel; + + /** The length of the data for the TX test. */ + uint8_t test_data_len; + + /** The payload to use for the TX test. */ + uint8_t payload; + + /** The PHY to use for the TX test. */ + uint8_t phy; +}; + +/** + * @brief Start a Direct Test Mode (DTM) transmitter test. + * + * This function starts a DTM TX test with the provided parameters. + * + * @param params The parameters for the DTM TX test. + * + * @return 0 on success; + * A non-zero value on failure. + */ +int ble_dtm_tx_start(const struct ble_dtm_tx_params *params); + +/** + * @brief Stops a Direct Test Mode (DTM) test and retrieves the number of transmitted packets. + * + * This function sends a command to the Bluetooth controller to stop the currently running DTM test. + * It retrieves the number of packets transmitted during the test and stores it in the provided `num_packets` variable. + * + * @param num_packets Pointer to a `uint16_t` variable to store the number of transmitted packets. + * If an error occurs, the value will be set to 0. + * + * @return 0 on success; + * A non-zero value on failure. + */ +int ble_dtm_stop(uint16_t *num_packets); + +#ifdef __cplusplus +} +#endif + +/** + * @} + */ + +#endif diff --git a/nimble/host/include/host/ble_eddystone.h b/nimble/host/include/host/ble_eddystone.h index 76b7e2b01e..3b75fdccf9 100644 --- a/nimble/host/include/host/ble_eddystone.h +++ b/nimble/host/include/host/ble_eddystone.h @@ -34,30 +34,79 @@ extern "C" { struct ble_hs_adv_fields; +/** + * @defgroup ble_eddystone Eddystone Constants + * @ingroup bt_host + * @{ + */ + +/** Maximum number of 16-bit UUIDs in Eddystone advertisement data. */ #define BLE_EDDYSTONE_MAX_UUIDS16 3 + +/** Maximum length of Eddystone URL. */ #define BLE_EDDYSTONE_URL_MAX_LEN 17 + +/** Eddystone URL Scheme: "http://www./" prefix. */ #define BLE_EDDYSTONE_URL_SCHEME_HTTP_WWW 0 + +/** Eddystone URL Scheme: "https://www./" prefix. */ #define BLE_EDDYSTONE_URL_SCHEME_HTTPS_WWW 1 + +/** Eddystone URL Scheme: "http://" prefix. */ #define BLE_EDDYSTONE_URL_SCHEME_HTTP 2 + +/** Eddystone URL Scheme: "https://" prefix. */ #define BLE_EDDYSTONE_URL_SCHEME_HTTPS 3 + +/** Eddystone URL Suffix: ".com/". */ #define BLE_EDDYSTONE_URL_SUFFIX_COM_SLASH 0x00 + +/** Eddystone URL Suffix: ".org/". */ #define BLE_EDDYSTONE_URL_SUFFIX_ORG_SLASH 0x01 + +/** Eddystone URL Suffix: ".edu/". */ #define BLE_EDDYSTONE_URL_SUFFIX_EDU_SLASH 0x02 + +/** Eddystone URL Suffix: ".net/". */ #define BLE_EDDYSTONE_URL_SUFFIX_NET_SLASH 0x03 + +/** Eddystone URL Suffix: ".info/". */ #define BLE_EDDYSTONE_URL_SUFFIX_INFO_SLASH 0x04 + +/** Eddystone URL Suffix: ".biz/". */ #define BLE_EDDYSTONE_URL_SUFFIX_BIZ_SLASH 0x05 + +/** Eddystone URL Suffix: ".gov/". */ #define BLE_EDDYSTONE_URL_SUFFIX_GOV_SLASH 0x06 + +/** Eddystone URL Suffix: ".com". */ #define BLE_EDDYSTONE_URL_SUFFIX_COM 0x07 + +/** Eddystone URL Suffix: ".org". */ #define BLE_EDDYSTONE_URL_SUFFIX_ORG 0x08 + +/** Eddystone URL Suffix: ".edu". */ #define BLE_EDDYSTONE_URL_SUFFIX_EDU 0x09 + +/** Eddystone URL Suffix: ".net". */ #define BLE_EDDYSTONE_URL_SUFFIX_NET 0x0a + +/** Eddystone URL Suffix: ".info". */ #define BLE_EDDYSTONE_URL_SUFFIX_INFO 0x0b + +/** Eddystone URL Suffix: ".biz". */ #define BLE_EDDYSTONE_URL_SUFFIX_BIZ 0x0c + +/** Eddystone URL Suffix: ".gov". */ #define BLE_EDDYSTONE_URL_SUFFIX_GOV 0x0d + +/** Eddystone URL Suffix: None. */ #define BLE_EDDYSTONE_URL_SUFFIX_NONE 0xff +/** @} */ + /** * Configures the device to advertise Eddystone UID beacons. * @@ -103,7 +152,7 @@ int ble_eddystone_set_adv_data_uid(struct ble_hs_adv_fields *adv_fields, */ int ble_eddystone_set_adv_data_url(struct ble_hs_adv_fields *adv_fields, uint8_t url_scheme, char *url_body, - uint8_t url_body_len, uint8_t suffix, + uint8_t url_body_len, uint8_t url_suffix, int8_t measured_power); #ifdef __cplusplus diff --git a/nimble/host/include/host/ble_gap.h b/nimble/host/include/host/ble_gap.h index fa7ee562df..9a1ead0049 100644 --- a/nimble/host/include/host/ble_gap.h +++ b/nimble/host/include/host/ble_gap.h @@ -39,12 +39,36 @@ extern "C" { struct hci_le_conn_complete; struct hci_conn_update; +/** + * @defgroup ble_gap_ms_convert Generic Access Profile (GAP) Time Conversion Macros + * @{ + */ + +/** Convert advertising interval from milliseconds to BLE HCI units. */ #define BLE_GAP_ADV_ITVL_MS(t) ((t) * 1000 / BLE_HCI_ADV_ITVL) + +/** Convert scan interval from milliseconds to BLE HCI units. */ #define BLE_GAP_SCAN_ITVL_MS(t) ((t) * 1000 / BLE_HCI_SCAN_ITVL) + +/** Convert scan window from milliseconds to BLE HCI units. */ #define BLE_GAP_SCAN_WIN_MS(t) ((t) * 1000 / BLE_HCI_SCAN_ITVL) + +/** Convert connection interval from milliseconds to BLE HCI units. */ #define BLE_GAP_CONN_ITVL_MS(t) ((t) * 1000 / BLE_HCI_CONN_ITVL) + +/** Convert supervision timeout from milliseconds to BLE HCI units. */ #define BLE_GAP_SUPERVISION_TIMEOUT_MS(t) ((t) / 10) +/** Convert periodic advertising interval from milliseconds to BLE HCI units. */ +#define BLE_GAP_PERIODIC_ITVL_MS(t) ((t) * 1000 / BLE_HCI_PERIODIC_ADV_ITVL) + +/** @} */ + +/** + * @defgroup ble_gap_intervals Generic Access Profile (GAP) Intervals and Durations + * @{ + */ + /** 30 ms. */ #define BLE_GAP_ADV_FAST_INTERVAL1_MIN BLE_GAP_ADV_ITVL_MS(30) @@ -72,7 +96,7 @@ struct hci_conn_update; /** 30 ms; active scanning. */ #define BLE_GAP_SCAN_FAST_WINDOW BLE_GAP_SCAN_WIN_MS(30) -/* 30.72 seconds; active scanning. */ +/** 30.72 seconds; active scanning. */ #define BLE_GAP_SCAN_FAST_PERIOD BLE_GAP_SCAN_ITVL_MS(30.72) /** 1.28 seconds; background scanning. */ @@ -93,50 +117,156 @@ struct hci_conn_update; /** 5 seconds. */ #define BLE_GAP_CONN_PAUSE_PERIPHERAL (5 * 1000) -/* 30 ms. */ +/** 30 ms. */ #define BLE_GAP_INITIAL_CONN_ITVL_MIN BLE_GAP_CONN_ITVL_MS(30) -/* 50 ms. */ +/** 50 ms. */ #define BLE_GAP_INITIAL_CONN_ITVL_MAX BLE_GAP_CONN_ITVL_MS(50) +/** @} */ + /** Default channels mask: all three channels are used. */ #define BLE_GAP_ADV_DFLT_CHANNEL_MAP 0x07 +/** + * @defgroup ble_gap_initial_conn_params Generic Access Profile (GAP) Initial Connection Parameters + * @{ + */ + +/** Initial connection latency. */ #define BLE_GAP_INITIAL_CONN_LATENCY 0 + +/** Initial supervision timeout. */ #define BLE_GAP_INITIAL_SUPERVISION_TIMEOUT 0x0100 + +/** Initial minimum connection event length. */ #define BLE_GAP_INITIAL_CONN_MIN_CE_LEN 0x0000 + +/** Initial maximum connection event length. */ #define BLE_GAP_INITIAL_CONN_MAX_CE_LEN 0x0000 +/** @} */ + +/** + * @defgroup ble_gap_roles Generic Access Profile (GAP) Roles + * @{ + */ + +/** GAP role: Master */ #define BLE_GAP_ROLE_MASTER 0 + +/** GAP role: Slave */ #define BLE_GAP_ROLE_SLAVE 1 +/** @} */ + +/** + * @defgroup ble_gap_events Generic Access Profile (GAP) Events + * @{ + */ + +/** GAP event: Connection established */ #define BLE_GAP_EVENT_CONNECT 0 + +/** GAP event: Connection terminated */ #define BLE_GAP_EVENT_DISCONNECT 1 + +/** GAP event: Reserved for future use */ /* Reserved 2 */ + +/** GAP event: Connection update */ #define BLE_GAP_EVENT_CONN_UPDATE 3 + +/** GAP event: Connection update request */ #define BLE_GAP_EVENT_CONN_UPDATE_REQ 4 + +/** GAP event: L2CAP update request */ #define BLE_GAP_EVENT_L2CAP_UPDATE_REQ 5 + +/** GAP event: Termination failure */ #define BLE_GAP_EVENT_TERM_FAILURE 6 + +/** GAP event: Discovery event */ #define BLE_GAP_EVENT_DISC 7 + +/** GAP event: Discovery complete */ #define BLE_GAP_EVENT_DISC_COMPLETE 8 + +/** GAP event: Advertising complete */ #define BLE_GAP_EVENT_ADV_COMPLETE 9 + +/** GAP event: Encryption change */ #define BLE_GAP_EVENT_ENC_CHANGE 10 + +/** GAP event: Passkey action */ #define BLE_GAP_EVENT_PASSKEY_ACTION 11 + +/** GAP event: Notification received */ #define BLE_GAP_EVENT_NOTIFY_RX 12 + +/** GAP event: Notification transmitted */ #define BLE_GAP_EVENT_NOTIFY_TX 13 + +/** GAP event: Subscription */ #define BLE_GAP_EVENT_SUBSCRIBE 14 + +/** GAP event: MTU event */ #define BLE_GAP_EVENT_MTU 15 + +/** GAP event: Identity resolved */ #define BLE_GAP_EVENT_IDENTITY_RESOLVED 16 + +/** GAP event: Repeat pairing */ #define BLE_GAP_EVENT_REPEAT_PAIRING 17 + +/** GAP event: PHY update complete */ #define BLE_GAP_EVENT_PHY_UPDATE_COMPLETE 18 + +/** GAP event: Extended discovery */ #define BLE_GAP_EVENT_EXT_DISC 19 + +/** GAP event: Periodic synchronization */ #define BLE_GAP_EVENT_PERIODIC_SYNC 20 + +/** GAP event: Periodic report */ #define BLE_GAP_EVENT_PERIODIC_REPORT 21 + +/** GAP event: Periodic synchronization lost */ #define BLE_GAP_EVENT_PERIODIC_SYNC_LOST 22 + +/** GAP event: Scan request received */ #define BLE_GAP_EVENT_SCAN_REQ_RCVD 23 + +/** GAP event: Periodic transfer */ #define BLE_GAP_EVENT_PERIODIC_TRANSFER 24 -/*** Reason codes for the subscribe GAP event. */ +/** GAP event: Pathloss threshold */ +#define BLE_GAP_EVENT_PATHLOSS_THRESHOLD 25 + +/** GAP event: Transmit power */ +#define BLE_GAP_EVENT_TRANSMIT_POWER 26 + +/** GAP event: Pairing complete */ +#define BLE_GAP_EVENT_PAIRING_COMPLETE 27 + +/** GAP event: Pairing complete (deprecated) */ +#define BLE_GAP_EVENT_PARING_COMPLETE BLE_GAP_EVENT_PAIRING_COMPLETE + +/** GAP event: Subrate change */ +#define BLE_GAP_EVENT_SUBRATE_CHANGE 28 + +/** GAP event: Unhandled HCI event */ +#define BLE_GAP_EVENT_UNHANDLED_HCI_EVENT 29 + +/** GAP event: BIG (Broadcast Isochronous Group) information report */ +#define BLE_GAP_EVENT_BIGINFO_REPORT 30 + +/** @} */ + +/** + * @defgroup ble_gap_subscribe_reasons Generic Access Profile (GAP) Subscribe Event Reason Codes + * @{ + */ /** Peer's CCCD subscription state changed due to a descriptor write. */ #define BLE_GAP_SUBSCRIBE_REASON_WRITE 1 @@ -150,9 +280,21 @@ struct hci_conn_update; */ #define BLE_GAP_SUBSCRIBE_REASON_RESTORE 3 +/** @} */ + +/** + * @defgroup ble_gap_repeat_pairing_options Generic Access Profile (GAP) Repeat Pairing Options + * @{ + */ + +/** GAP repeat pairing option: Retry the pairing procedure. */ #define BLE_GAP_REPEAT_PAIRING_RETRY 1 + +/** GAP repeat pairing option: Ignore the pairing procedure. */ #define BLE_GAP_REPEAT_PAIRING_IGNORE 2 +/** @} */ + /** Connection security state */ struct ble_gap_sec_state { /** If connection is encrypted */ @@ -435,22 +577,53 @@ struct ble_gap_disc_desc { ble_addr_t direct_addr; }; +/** + * Represents a repeat pairing operation between two devices. + * + * This structure contains information about a repeat pairing operation between + * two devices. The host can use this information to determine whether it needs + * to initiate a pairing procedure with a remote device again. + */ struct ble_gap_repeat_pairing { /** The handle of the relevant connection. */ uint16_t conn_handle; /** Properties of the existing bond. */ + /** The size of the current encryption key in octets. */ uint8_t cur_key_size; + + /** A flag indicating whether the current connection is authenticated. */ uint8_t cur_authenticated:1; + + /** + * A flag indicating whether the current connection is using secure + * connections. + */ uint8_t cur_sc:1; /** * Properties of the imminent secure link if the pairing procedure is * allowed to continue. */ + + /** The size of the imminent encryption key in octets. */ uint8_t new_key_size; + + /** + * A flag indicating whether the imminent connection will be authenticated. + */ uint8_t new_authenticated:1; + + /** + * A flag indicating whether the imminent connection will use secure + * connections. + */ uint8_t new_sc:1; + + /** + * A flag indicating whether the pairing procedure will result in a new + * bonding, + */ uint8_t new_bonding:1; }; @@ -802,6 +975,8 @@ struct ble_gap_event { struct { /** The handle of the relevant connection. */ uint16_t conn_handle; + /** Peer identity address */ + ble_addr_t peer_id_addr; } identity_resolved; /** @@ -973,19 +1148,202 @@ struct ble_gap_event { uint8_t adv_clk_accuracy; } periodic_transfer; #endif + +#if MYNEWT_VAL(BLE_PERIODIC_ADV_SYNC_BIGINFO_REPORTS) + /** + * Represents a periodic advertising sync transfer received. Valid for + * the following event types: + * o BLE_GAP_EVENT_BIGINFO_REPORT + */ + struct { + /** Synchronization handle */ + uint16_t sync_handle; + + /** Number of present BISes */ + uint8_t bis_cnt; + + /** Number of SubEvents */ + uint8_t nse; + + /** ISO Interval */ + uint16_t iso_interval; + + /** Burst Number */ + uint8_t bn; + + /** Pre-Transmission Offset */ + uint8_t pto; + + /** Immediate Repetition Count */ + uint8_t irc; + + /** Maximum PDU size */ + uint16_t max_pdu; + + /** Maximum SDU size */ + uint16_t max_sdu; + + /** Service Data Unit Interval */ + uint32_t sdu_interval; + + /** BIG PHY */ + uint8_t phy; + + /** Framing of BIS Data PDUs */ + uint8_t framing : 1; + + /** Encryption */ + uint8_t encryption : 1; + } biginfo_report; +#endif + +#if MYNEWT_VAL(BLE_POWER_CONTROL) + /** + * Represents a change in either local transmit power or remote transmit + * power. Valid for the following event types: + * o BLE_GAP_EVENT_PATHLOSS_THRESHOLD + */ + + struct { + /** Connection handle */ + uint16_t conn_handle; + + /** Current Path Loss */ + uint8_t current_path_loss; + + /** Entered Zone */ + uint8_t zone_entered; + } pathloss_threshold; + + /** + * Represents crossing of path loss threshold set via LE Set Path Loss + * Reporting Parameter command. Valid for the following event types: + * o BLE_GAP_EVENT_TRANSMIT_POWER + */ + + struct { + /** BLE_ERR_SUCCESS on success or error code on failure */ + uint8_t status; + + /** Connection Handle */ + uint16_t conn_handle; + + /** Reason indicating why event was sent */ + uint8_t reason; + + /** Advertising PHY */ + uint8_t phy; + + /** Transmit power Level */ + int8_t transmit_power_level; + + /** Transmit Power Level Flag */ + uint8_t transmit_power_level_flag; + + /** Delta indicating change in transmit Power Level */ + int8_t delta; + } transmit_power; +#endif + /** + * Represents a received Pairing Complete message + * + * Valid for the following event types: + * o BLE_GAP_EVENT_PAIRING_COMPLETE + * o BLE_GAP_EVENT_PARING_COMPLETE (deprecated) + */ + struct { + /** + * Indicates the result of the encryption state change attempt; + * o 0: the encrypted state was successfully updated; + * o BLE host error code: the encryption state change attempt + * failed for the specified reason. + */ + int status; + + /** The handle of the relevant connection. */ + uint16_t conn_handle; + } pairing_complete; + +#if MYNEWT_VAL(BLE_CONN_SUBRATING) + /** + * Represents a subrate change event that indicates connection subrate update procedure + * has completed and some parameters have changed Valid for + * the following event types: + * o BLE_GAP_EVENT_SUBRATE_CHANGE + */ + struct { + /** BLE_ERR_SUCCESS on success or error code on failure */ + uint8_t status; + + /** Connection Handle */ + uint16_t conn_handle; + + /** Subrate Factor */ + uint16_t subrate_factor; + + /** Peripheral Latency */ + uint16_t periph_latency; + + /** Continuation Number */ + uint16_t cont_num; + + /** Supervision Timeout */ + uint16_t supervision_tmo; + } subrate_change; +#endif + +#if MYNEWT_VAL(BLE_HS_GAP_UNHANDLED_HCI_EVENT) + /** + * Represents an HCI event received from controller that is not handled + * by the host. The event may be a regular event, LE meta event or + * vendor specific event which is denoted by included flags. + * + * Valid for the following event types: + * o BLE_GAP_EVENT_UNHANDLED_HCI_EVENT + */ + struct { + bool is_le_meta; + bool is_vs; + const void *ev; + uint8_t length; + } unhandled_hci; +#endif }; }; +/** Callback function type for handling BLE GAP events. */ typedef int ble_gap_event_fn(struct ble_gap_event *event, void *arg); +/** Callback function type for iterating through BLE connection handles. */ +typedef int ble_gap_conn_foreach_handle_fn(uint16_t conn_handle, void *arg); + +/** + * @defgroup ble_gap_advertising_modes Generic Access Profile (GAP) Advertising Modes + * @{ + */ + +/** Non-connectable mode for advertising. */ #define BLE_GAP_CONN_MODE_NON 0 + +/** Directed connectable mode for advertising. */ #define BLE_GAP_CONN_MODE_DIR 1 + +/** Undirected connectable mode for advertising. */ #define BLE_GAP_CONN_MODE_UND 2 + +/** Non-discoverable mode for advertising. */ #define BLE_GAP_DISC_MODE_NON 0 + +/** Limited discoverable mode for advertising. */ #define BLE_GAP_DISC_MODE_LTD 1 + +/** General discoverable mode for advertising. */ #define BLE_GAP_DISC_MODE_GEN 2 +/** @} */ + + /** * Searches for a connection with the specified handle. If a matching * connection is found, the supplied connection descriptor is filled @@ -1129,13 +1487,13 @@ int ble_gap_adv_rsp_set_data(const uint8_t *data, int data_len); * fit in an advertisement, * other error code on failure. */ -int ble_gap_adv_set_fields(const struct ble_hs_adv_fields *rsp_fields); +int ble_gap_adv_set_fields(const struct ble_hs_adv_fields *adv_fields); /** * Configures the fields to include in subsequent scan responses. This is a * convenience wrapper for ble_gap_adv_rsp_set_data(). * - * @param adv_fields Specifies the scan response data. + * @param rsp_fields Specifies the scan response data. * * @return 0 on success, * BLE_HS_EBUSY if advertising is in progress, @@ -1160,7 +1518,19 @@ struct ble_gap_ext_adv_params { /** If perform high-duty directed advertising */ unsigned int high_duty_directed:1; - /** If use legacy PDUs for advertising */ + /** If use legacy PDUs for advertising. + * + * Valid combinations of the connectable, scannable, directed, + * high_duty_directed options with the legcy_pdu flag are: + * - IND -> legacy_pdu + connectable + scannable + * - LD_DIR -> legacy_pdu + connectable + directed + * - HD_DIR -> legacy_pdu + connectable + directed + high_duty_directed + * - SCAN -> legacy_pdu + scannable + * - NONCONN -> legacy_pdu + * + * Any other combination of these options combined with the legacy_pdu flag + * are invalid. + */ unsigned int legacy_pdu:1; /** If perform anonymous advertising */ @@ -1212,6 +1582,12 @@ struct ble_gap_ext_adv_params { /** Advertising Set ID */ uint8_t sid; + + /** Primary PHY options */ + uint8_t primary_phy_opt; + + /** Secondary PHY options */ + uint8_t secondary_phy_opt; }; /** @@ -1314,6 +1690,28 @@ int ble_gap_ext_adv_remove(uint8_t instance); * other error code on failure. */ int ble_gap_ext_adv_clear(void); + +/** + * Indicates whether an advertisement procedure is currently in progress on + * the specified Instance + * + * @param instance Instance Id + * + * @return 0 if there is no active advertising procedure for the instance, + * 1 otherwise + * + */ +int ble_gap_ext_adv_active(uint8_t instance); + +/** + * Finds first not configured advertising instance. + * + * @param[out] out_adv_instance Pointer to be filled with found advertising instance + * + * @return 0 if free advertising instance was found, error code otherwise + * + */ +int ble_gap_adv_get_free_instance(uint8_t *out_adv_instance); #endif /* Periodic Advertising */ @@ -1322,19 +1720,43 @@ int ble_gap_ext_adv_clear(void); /** @brief Periodic advertising parameters */ struct ble_gap_periodic_adv_params { /** If include TX power in advertising PDU */ - unsigned int include_tx_power:1; + unsigned int include_tx_power : 1; - /** Minimum advertising interval in 0.625ms units, if 0 stack use sane + /** Minimum advertising interval in 1.25ms units, if 0 stack use sane * defaults */ uint16_t itvl_min; - /** Maximum advertising interval in 0.625ms units, if 0 stack use sane + /** Maximum advertising interval in 1.25ms units, if 0 stack use sane * defaults */ uint16_t itvl_max; }; +/** @brief Periodic advertising enable parameters */ +struct ble_gap_periodic_adv_start_params { +#if MYNEWT_VAL(BLE_VERSION) >= 53 + /** If include adi in aux_sync_ind PDU */ + unsigned int include_adi : 1; +#endif +}; + +/** @brief Periodic advertising sync reporting parameters */ +struct ble_gap_periodic_adv_sync_reporting_params { +#if MYNEWT_VAL(BLE_VERSION) >= 53 + /** If filter duplicates */ + unsigned int filter_duplicates : 1; +#endif +}; + +/** @brief Periodic adv set data parameters */ +struct ble_gap_periodic_adv_set_data_params { +#if MYNEWT_VAL(BLE_VERSION) >= 53 + /** If include adi in aux_sync_ind PDU */ + unsigned int update_did : 1; +#endif +}; + /** @brief Periodic sync parameters */ struct ble_gap_periodic_sync_params { /** The maximum number of periodic advertising events that controller can @@ -1347,7 +1769,13 @@ struct ble_gap_periodic_sync_params { uint16_t sync_timeout; /** If reports should be initially disabled when sync is created */ - unsigned int reports_disabled:1; + unsigned int reports_disabled : 1; + +#if MYNEWT_VAL(BLE_VERSION) >= 53 + /** If duplicate filtering should be should be initially enabled when sync is + created */ + unsigned int filter_duplicates : 1; +#endif }; /** @@ -1369,10 +1797,15 @@ int ble_gap_periodic_adv_configure(uint8_t instance, * Start periodic advertising for specified advertising instance. * * @param instance Instance ID + * @param params Additional arguments specifying the particulars + * of periodic advertising. * * @return 0 on success, error code on failure. */ -int ble_gap_periodic_adv_start(uint8_t instance); +int +ble_gap_periodic_adv_start(uint8_t instance, + const struct ble_gap_periodic_adv_start_params *params); + /** * Stop periodic advertising for specified advertising instance. @@ -1389,13 +1822,20 @@ int ble_gap_periodic_adv_stop(uint8_t instance); * * @param instance Instance ID * @param data Chain containing the periodic advertising data. + * @param params Additional arguments specifying the particulars + of periodic advertising data. * * @return 0 on success or error code on failure. */ -int ble_gap_periodic_adv_set_data(uint8_t instance, struct os_mbuf *data); +int ble_gap_periodic_adv_set_data(uint8_t instance, + struct os_mbuf *data, + const struct ble_gap_periodic_adv_set_data_params *params); /** - * Performs the Synchronization procedure with periodic advertiser. + * Schedule the Synchronization procedure with periodic advertiser. + * Procedure is performed as soon as Extended Discovery procedure is started. + * If Extended Discovery is already active when issuing this procedure, + * it will be performed immediately. It is up to application to start Extended Discovery. * * @param addr Peer address to synchronize with. If NULL than * peers from periodic list are used. @@ -1436,10 +1876,14 @@ int ble_gap_periodic_adv_sync_terminate(uint16_t sync_handle); * * @param sync_handle Handle identifying synchronization. * @param enable If reports should be enabled. + * @param params Additional arguments specifying the particulars + * of periodic reports. * * @return 0 on success; nonzero on failure. */ -int ble_gap_periodic_adv_sync_reporting(uint16_t sync_handle, bool enable); +int ble_gap_periodic_adv_sync_reporting(uint16_t sync_handle, + bool enable, + const struct ble_gap_periodic_adv_sync_reporting_params *params); /** * Initialize sync transfer procedure for specified handles. @@ -1471,6 +1915,17 @@ int ble_gap_periodic_adv_sync_set_info(uint8_t instance, uint16_t conn_handle, uint16_t service_data); +/** + * Set the default periodic sync transfer params. + * + * + * @param conn_handle Handle identifying connection. + * @param params Default Parameters for periodic sync transfer. + * + * @return 0 on success; nonzero on failure. + */ +int periodic_adv_set_default_sync_params(const struct ble_gap_periodic_sync_params *params); + /** * Enables or disables sync transfer reception on specified connection. * When sync transfer arrives, BLE_GAP_EVENT_PERIODIC_TRANSFER is sent to the user. @@ -1663,7 +2118,7 @@ int ble_gap_disc_active(void); * On expiration, the procedure ends and a * BLE_GAP_EVENT_DISC_COMPLETE event is * reported. Units are milliseconds. - * @param conn_params Additional arguments specifying the particulars + * @param params Additional arguments specifying the particulars * of the connect procedure. Specify null for * default values. * @param cb The callback to associate with this connect @@ -1790,6 +2245,15 @@ int ble_gap_terminate(uint16_t conn_handle, uint8_t hci_reason); */ int ble_gap_wl_set(const ble_addr_t *addrs, uint8_t white_list_count); +/** + * Retrieves the size of whitelist supported by controller + * + * @param size On success, this holds the size of controller accept list + * + * @return 0 on success; nonzero on failure + */ +int ble_gap_wl_read_size(uint8_t *size); + /** * Initiates a connection parameter update procedure. * @@ -1815,17 +2279,57 @@ int ble_gap_update_params(uint16_t conn_handle, * Configure LE Data Length in controller (OGF = 0x08, OCF = 0x0022). * * @param conn_handle Connection handle. - * @param tx_octets The preferred value of payload octets that the Controller - * should use for a new connection (Range - * 0x001B-0x00FB). - * @param tx_time The preferred maximum number of microseconds that the local Controller - * should use to transmit a single link layer packet - * (Range 0x0148-0x4290). + * @param tx_octets The preferred value of payload octets that the + * Controller should use for a new connection + * (Range 0x001B-0x00FB). + * @param tx_time The preferred maximum number of microseconds that + * the local Controller should use to transmit a single + * link layer packet (Range 0x0148-0x4290). * * @return 0 on success, * other error code on failure. */ -int ble_gap_set_data_len(uint16_t conn_handle, uint16_t tx_octets, uint16_t tx_time); +int ble_gap_set_data_len(uint16_t conn_handle, uint16_t tx_octets, + uint16_t tx_time); + +/** + * Read LE Suggested Default Data Length in controller + * (OGF = 0x08, OCF = 0x0024). + * + * @param out_sugg_max_tx_octets The Host's suggested value for the + * Controller's maximum transmitted number of + * payload octets in LL Data PDUs to be used + * for new connections. (Range 0x001B-0x00FB). + * @param out_sugg_max_tx_time The Host's suggested value for the + * Controller's maximum packet transmission + * time for packets containing LL Data PDUs to + * be used for new connections. + * (Range 0x0148-0x4290). + * + * @return 0 on success, + * other error code on failure. + */ +int ble_gap_read_sugg_def_data_len(uint16_t *out_sugg_max_tx_octets, + uint16_t *out_sugg_max_tx_time); + +/** + * Configure LE Suggested Default Data Length in controller + * (OGF = 0x08, OCF = 0x0024). + * + * @param sugg_max_tx_octets The Host's suggested value for the Controller's + * maximum transmitted number of payload octets in + * LL Data PDUs to be used for new connections. + * (Range 0x001B-0x00FB). + * @param sugg_max_tx_time The Host's suggested value for the Controller's + * maximum packet transmission time for packets + * containing LL Data PDUs to be used for new + * connections. (Range 0x0148-0x4290). + * + * @return 0 on success, + * other error code on failure. + */ +int ble_gap_write_sugg_def_data_len(uint16_t sugg_max_tx_octets, + uint16_t sugg_max_tx_time); /** * Initiates the GAP security procedure. @@ -1870,7 +2374,7 @@ int ble_gap_pair_initiate(uint16_t conn_handle); * start encryption. * @param key_size Encryption key size * @param ltk Long Term Key to be used for encryption. - * @param udiv Encryption Diversifier for LTK + * @param ediv Encryption Diversifier for LTK * @param rand_val Random Value for EDIV and LTK * @param auth If LTK provided is authenticated. * @@ -1942,9 +2446,20 @@ int ble_gap_unpair_oldest_peer(void); */ int ble_gap_unpair_oldest_except(const ble_addr_t *peer_addr); +/** + * @defgroup ble_gap_privacy_modes Generic Access Profile (GAP) Privacy Modes + * @{ + */ + +/** Network privacy mode. */ #define BLE_GAP_PRIVATE_MODE_NETWORK 0 + +/** Device privacy mode. */ #define BLE_GAP_PRIVATE_MODE_DEVICE 1 +/** @} */ + + /** * Set privacy mode for specified peer device * @@ -1958,9 +2473,22 @@ int ble_gap_unpair_oldest_except(const ble_addr_t *peer_addr); */ int ble_gap_set_priv_mode(const ble_addr_t *peer_addr, uint8_t priv_mode); +/** + * @defgroup ble_gap_physical_layers Generic Access Profile (GAP) Physical Layers + * @{ + */ + +/** Physical layer: 1M PHY. */ #define BLE_GAP_LE_PHY_1M 1 + +/** Physical layer: 2M PHY. */ #define BLE_GAP_LE_PHY_2M 2 + +/** Physical layer: Coded PHY. */ #define BLE_GAP_LE_PHY_CODED 3 + +/** @} */ + /** * Read PHYs used for specified connection. * @@ -1980,20 +2508,35 @@ int ble_gap_set_priv_mode(const ble_addr_t *peer_addr, uint8_t priv_mode); */ int ble_gap_read_le_phy(uint16_t conn_handle, uint8_t *tx_phy, uint8_t *rx_phy); +/** + * @defgroup ble_gap_phy_masks Generic Access Profile (GAP) PHY Masks + * @{ + */ + +/** Bitmask for 1M PHY. */ #define BLE_GAP_LE_PHY_1M_MASK 0x01 + +/** Bitmask for 2M PHY. */ #define BLE_GAP_LE_PHY_2M_MASK 0x02 + +/** Bitmask for Coded PHY. */ #define BLE_GAP_LE_PHY_CODED_MASK 0x04 + +/** Bitmask for any PHY. */ #define BLE_GAP_LE_PHY_ANY_MASK 0x0F + +/** @} */ + /** * Set preferred default PHYs to be used for connections. * - * @params tx_phys_mask Preferred TX PHY. Can be mask of following + * @param tx_phys_mask Preferred TX PHY. Can be mask of following * constants: * - BLE_GAP_LE_PHY_1M_MASK * - BLE_GAP_LE_PHY_2M_MASK * - BLE_GAP_LE_PHY_CODED_MASK * - BLE_GAP_LE_PHY_ANY_MASK - * @params rx_phys_mask Preferred RX PHY. Can be mask of following + * @param rx_phys_mask Preferred RX PHY. Can be mask of following * constants: * - BLE_GAP_LE_PHY_1M_MASK * - BLE_GAP_LE_PHY_2M_MASK @@ -2005,20 +2548,33 @@ int ble_gap_read_le_phy(uint16_t conn_handle, uint8_t *tx_phy, uint8_t *rx_phy); int ble_gap_set_prefered_default_le_phy(uint8_t tx_phys_mask, uint8_t rx_phys_mask); +/** + * @defgroup ble_gap_coded_phy_schemes Generic Access Profile (GAP) Coded PHY Schemes + * @{ + */ + +/** Coded PHY: any coding scheme. */ #define BLE_GAP_LE_PHY_CODED_ANY 0 + +/** Coded PHY: S2 coding scheme. */ #define BLE_GAP_LE_PHY_CODED_S2 1 + +/** Coded PHY: S8 coding scheme. */ #define BLE_GAP_LE_PHY_CODED_S8 2 + +/** @} */ + /** * Set preferred PHYs to be used for connection. * * @param conn_handle Connection handle - * @params tx_phys_mask Preferred TX PHY. Can be mask of following + * @param tx_phys_mask Preferred TX PHY. Can be mask of following * constants: * - BLE_GAP_LE_PHY_1M_MASK * - BLE_GAP_LE_PHY_2M_MASK * - BLE_GAP_LE_PHY_CODED_MASK * - BLE_GAP_LE_PHY_ANY_MASK - * @params rx_phys_mask Preferred RX PHY. Can be mask of following + * @param rx_phys_mask Preferred RX PHY. Can be mask of following * constants: * - BLE_GAP_LE_PHY_1M_MASK * - BLE_GAP_LE_PHY_2M_MASK @@ -2034,14 +2590,58 @@ int ble_gap_set_prefered_default_le_phy(uint8_t tx_phys_mask, int ble_gap_set_prefered_le_phy(uint16_t conn_handle, uint8_t tx_phys_mask, uint8_t rx_phys_mask, uint16_t phy_opts); +#if MYNEWT_VAL(BLE_CONN_SUBRATING) +/** + * Set default subrate + * + * @param subrate_min Min subrate factor allowed in request by a peripheral + * @param subrate_max Max subrate factor allowed in request by a peripheral + * @param max_latency Max peripheral latency allowed in units of + * subrated conn interval. + * + * @param cont_num Min number of underlying conn event to remain active + * after a packet containing PDU with non-zero length field + * is sent or received in request by a peripheral. + * + * @param supervision_timeout Max supervision timeout allowed in request by a peripheral + */ +int ble_gap_set_default_subrate(uint16_t subrate_min, uint16_t subrate_max, uint16_t max_latency, + uint16_t cont_num, uint16_t supervision_timeout); + +/** + * Subrate Request + * + * @param conn_handle Connection Handle of the ACL. + * @param subrate_min Min subrate factor to be applied + * @param subrate_max Max subrate factor to be applied + * @param max_latency Max peripheral latency allowed in units of + * subrated conn interval. + * + * @param cont_num Min number of underlying conn event to remain active + * after a packet containing PDU with non-zero length field + * is sent or received in request by a peripheral. + * + * @param supervision_timeout Max supervision timeout allowed for this connection + */ + +int +ble_gap_subrate_req(uint16_t conn_handle, uint16_t subrate_min, uint16_t subrate_max, + uint16_t max_latency, uint16_t cont_num, + uint16_t supervision_timeout); +#endif /** * Event listener structure * * This should be used as an opaque structure and not modified manually. */ struct ble_gap_event_listener { + /** The function to call when a GAP event occurs. */ ble_gap_event_fn *fn; + + /** An optional argument to pass to the event handler function. */ void *arg; + + /** Singly-linked list entry. */ SLIST_ENTRY(ble_gap_event_listener) link; }; @@ -2073,6 +2673,101 @@ int ble_gap_event_listener_register(struct ble_gap_event_listener *listener, */ int ble_gap_event_listener_unregister(struct ble_gap_event_listener *listener); +/** + * Calls function defined by the user for every connection that is currently established + * + * @param cb Callback function + * @param arg Callback argument + */ +void ble_gap_conn_foreach_handle(ble_gap_conn_foreach_handle_fn *cb, void *arg); + +/** + * Looks for the connection with specified address. + * + * @param addr Address to look for + * @param out_conn_handle Pointer to the variable in which conn_handle will be saved if found + * + * @return 0 on success + * BLE_HS_ENOTCONN if connection with specified address was not found + */ +int ble_gap_conn_find_handle_by_addr(const ble_addr_t *addr, uint16_t *out_conn_handle); + +#if MYNEWT_VAL(BLE_POWER_CONTROL) +/** + * Enable Set Path Loss Reporting. + * + * @param conn_handle Connection handle + * @params enable 1: Enable + * 0: Disable + * + * @return 0 on success; nonzero on failure. + */ + +int ble_gap_set_path_loss_reporting_enable(uint16_t conn_handle, uint8_t enable); + +/** + * Enable Reporting of Transmit Power + * + * @param conn_handle Connection handle + * @params local_enable 1: Enable local transmit power reports + * 0: Disable local transmit power reports + * + * @params remote_enable 1: Enable remote transmit power reports + * 0: Disable remote transmit power reports + * + * @return 0 on success; nonzero on failure. + */ +int ble_gap_set_transmit_power_reporting_enable(uint16_t conn_handle, + uint8_t local_enable, + uint8_t remote_enable); + +/** + * LE Enhanced Read Transmit Power Level + * + * @param conn_handle Connection handle + * @params phy Advertising Phy + * + * @params status 0 on success; nonzero on failure. + * @params conn_handle Connection handle + * @params phy Advertising Phy + * + * @params curr_tx_power_level Current trasnmit Power Level + * + * @params mx_tx_power_level Maximum transmit power level + * + * @return 0 on success; nonzero on failure. + */ +int ble_gap_enh_read_transmit_power_level(uint16_t conn_handle, uint8_t phy, + uint8_t *out_status, uint8_t *out_phy, + uint8_t *out_curr_tx_power_level, + uint8_t *out_max_tx_power_level); + +/** + * Read Remote Transmit Power Level + * + * @param conn_handle Connection handle + * @params phy Advertising Phy + * + * @return 0 on success; nonzero on failure. + */ +int ble_gap_read_remote_transmit_power_level(uint16_t conn_handle, uint8_t phy); + +/** + * Set Path Loss Reproting Param + * + * @param conn_handle Connection handle + * @params high_threshold High Threshold value for path loss + * @params high_hysteresis Hysteresis value for high threshold + * @params low_threshold Low Threshold value for path loss + * @params low_hysteresis Hysteresis value for low threshold + * @params min_time_spent Minimum time controller observes the path loss + * + * @return 0 on success; nonzero on failure. + */ +int ble_gap_set_path_loss_reporting_param(uint16_t conn_handle, uint8_t high_threshold, + uint8_t high_hysteresis, uint8_t low_threshold, + uint8_t low_hysteresis, uint16_t min_time_spent); +#endif #ifdef __cplusplus } #endif diff --git a/nimble/host/include/host/ble_gatt.h b/nimble/host/include/host/ble_gatt.h index b06344fc2e..aebfc7ef3d 100644 --- a/nimble/host/include/host/ble_gatt.h +++ b/nimble/host/include/host/ble_gatt.h @@ -38,80 +38,243 @@ struct ble_hs_conn; struct ble_att_error_rsp; struct ble_hs_cfg; +/** + * @defgroup ble_gatt_register_op_codes Generic Attribute Profile (GATT) Registration Operation Codes + * @{ + */ + +/** GATT Service registration. */ #define BLE_GATT_REGISTER_OP_SVC 1 + +/** GATT Characteristic registration. */ #define BLE_GATT_REGISTER_OP_CHR 2 + +/** GATT Descriptor registration. */ #define BLE_GATT_REGISTER_OP_DSC 3 +/** @} */ + +/** + * @defgroup ble_gatt_uuid Generic Attribute Profile (GATT) Service and Descriptor UUIDs + * @{ + */ + +/** GATT service 16-bit UUID. */ #define BLE_GATT_SVC_UUID16 0x1801 + +/** GATT Client Characteristic Configuration descriptor 16-bit UUID. */ #define BLE_GATT_DSC_CLT_CFG_UUID16 0x2902 +/** @} */ + +/** + * @defgroup ble_gatt_chr_properties Generic Attribute Profile (GATT) Characteristic Properties + * @{ + */ + +/** Characteristic property: Broadcast. */ #define BLE_GATT_CHR_PROP_BROADCAST 0x01 + +/** Characteristic property: Read. */ #define BLE_GATT_CHR_PROP_READ 0x02 + +/** Characteristic property: Write Without Response. */ #define BLE_GATT_CHR_PROP_WRITE_NO_RSP 0x04 + +/** Characteristic property: Write. */ #define BLE_GATT_CHR_PROP_WRITE 0x08 + +/** Characteristic property: Notify. */ #define BLE_GATT_CHR_PROP_NOTIFY 0x10 + +/** Characteristic property: Indicate. */ #define BLE_GATT_CHR_PROP_INDICATE 0x20 + +/** Characteristic property: Authenticated Signed Write. */ #define BLE_GATT_CHR_PROP_AUTH_SIGN_WRITE 0x40 + +/** Characteristic property: Extended Properties. */ #define BLE_GATT_CHR_PROP_EXTENDED 0x80 +/** @} */ + +/** @defgroup ble_gatt_access_op_codes Generic Attribute Profile (GATT) Access Operation Codes + * @{ + */ + +/** GATT attribute access operation: Read characteristic. */ #define BLE_GATT_ACCESS_OP_READ_CHR 0 + +/** GATT attribute access operation: Write characteristic. */ #define BLE_GATT_ACCESS_OP_WRITE_CHR 1 + +/** GATT attribute access operation: Read descriptor. */ #define BLE_GATT_ACCESS_OP_READ_DSC 2 + +/** GATT attribute access operation: Write descriptor. */ #define BLE_GATT_ACCESS_OP_WRITE_DSC 3 +/** @} */ + +/** + * @defgroup ble_gatt_chr_flags Generic Attribute Profile (GATT) Characteristic Flags + * @{ + */ + +/** GATT Characteristic Flag: Broadcast property. */ #define BLE_GATT_CHR_F_BROADCAST 0x0001 + +/** GATT Characteristic Flag: Read property. */ #define BLE_GATT_CHR_F_READ 0x0002 + +/** GATT Characteristic Flag: Write without Response property. */ #define BLE_GATT_CHR_F_WRITE_NO_RSP 0x0004 + +/** GATT Characteristic Flag: Write property. */ #define BLE_GATT_CHR_F_WRITE 0x0008 + +/** GATT Characteristic Flag: Notify property. */ #define BLE_GATT_CHR_F_NOTIFY 0x0010 + +/** GATT Characteristic Flag: Indicate property. */ #define BLE_GATT_CHR_F_INDICATE 0x0020 + +/** GATT Characteristic Flag: Authenticated Signed Writes property. */ #define BLE_GATT_CHR_F_AUTH_SIGN_WRITE 0x0040 + +/** GATT Characteristic Flag: Reliable Writes property. */ #define BLE_GATT_CHR_F_RELIABLE_WRITE 0x0080 + +/** GATT Characteristic Flag: Auxiliary Writes permission. */ #define BLE_GATT_CHR_F_AUX_WRITE 0x0100 + +/** GATT Characteristic Flag: Read Encrypted permission. */ #define BLE_GATT_CHR_F_READ_ENC 0x0200 + +/** GATT Characteristic Flag: Read Authenticated permission. */ #define BLE_GATT_CHR_F_READ_AUTHEN 0x0400 + +/** GATT Characteristic Flag: Read Authorized permission. */ #define BLE_GATT_CHR_F_READ_AUTHOR 0x0800 + +/** GATT Characteristic Flag: Write Encrypted permission. */ #define BLE_GATT_CHR_F_WRITE_ENC 0x1000 + +/** GATT Characteristic Flag: Write Authenticated permission. */ #define BLE_GATT_CHR_F_WRITE_AUTHEN 0x2000 + +/** GATT Characteristic Flag: Write Authorized permission. */ #define BLE_GATT_CHR_F_WRITE_AUTHOR 0x4000 + +/** @} */ + +/** + * @defgroup ble_gatt_service_types Generic Attribute Profile (GATT) Service Types + * @{ + */ + +/** GATT Service Type: End of Services. */ #define BLE_GATT_SVC_TYPE_END 0 + +/** GATT Service Type: Primary Service. */ #define BLE_GATT_SVC_TYPE_PRIMARY 1 + +/** GATT Service Type: Secondary Service. */ #define BLE_GATT_SVC_TYPE_SECONDARY 2 +/** @} */ + +/** + * @defgroup ble_gatts_clt_cfg Client Characteristic Configuration Descriptor (CCCD) Flags Types + * @{ + */ + +/** GATT Client Charactaristic Configuration Flag: Notify. */ +#define BLE_GATT_CCCD_NOTIFY 0x01 + +/** GATT Client Charactaristic Configuration Flag: Indicate. */ +#define BLE_GATT_CCCD_INDICATE 0x02 + +/** @} */ + /*** @client. */ +/** Represents a GATT error. */ struct ble_gatt_error { + /** The GATT status code indicating the type of error. */ uint16_t status; + + /** The attribute handle associated with the error. */ uint16_t att_handle; }; +/** Represents a GATT Service. */ struct ble_gatt_svc { + /** The start handle of the GATT service. */ uint16_t start_handle; + + /** The end handle of the GATT service. */ uint16_t end_handle; + + /** The UUID of the GATT service. */ ble_uuid_any_t uuid; }; + +/** Represents a GATT attribute. */ struct ble_gatt_attr { + /** The handle of the GATT attribute. */ uint16_t handle; + + /** The offset of the data within the attribute. */ uint16_t offset; + + /** Pointer to the data buffer represented by an os_mbuf. */ struct os_mbuf *om; }; + +/** Represents a GATT characteristic. */ struct ble_gatt_chr { + /** The handle of the GATT characteristic definition. */ uint16_t def_handle; + + /** The handle of the GATT characteristic value. */ uint16_t val_handle; + + /** The properties of the GATT characteristic. */ uint8_t properties; + + /** The UUID of the GATT characteristic. */ ble_uuid_any_t uuid; }; + +/** Represents a GATT descriptor. */ struct ble_gatt_dsc { + /** The handle of the GATT descriptor. */ uint16_t handle; + + /** The UUID of the GATT descriptor. */ ble_uuid_any_t uuid; }; + +/** Represents a handle-value tuple for multiple handle notifications. */ +struct ble_gatt_notif { + /** The handle of the GATT characteristic */ + uint16_t handle; + + /** The buffer with GATT characteristic value */ + struct os_mbuf *value; +}; + +/** Function prototype for the GATT MTU exchange callback. */ typedef int ble_gatt_mtu_fn(uint16_t conn_handle, const struct ble_gatt_error *error, uint16_t mtu, void *arg); + +/** Function prototype for the GATT service discovery callback. */ typedef int ble_gatt_disc_svc_fn(uint16_t conn_handle, const struct ble_gatt_error *error, const struct ble_gatt_svc *service, @@ -127,6 +290,17 @@ typedef int ble_gatt_attr_fn(uint16_t conn_handle, struct ble_gatt_attr *attr, void *arg); +/** + * The host will free the attribute mbuf automatically after the callback is + * executed. The application can take ownership of the mbuf and prevent it + * from being freed by assigning NULL to attr->om. + */ +typedef int ble_gatt_attr_mult_fn(uint16_t conn_handle, + const struct ble_gatt_error *error, + struct ble_gatt_attr *attrs, + uint8_t num_attrs, + void *arg); + /** * The host will free the attribute mbufs automatically after the callback is * executed. The application can take ownership of the mbufs and prevent them @@ -137,10 +311,12 @@ typedef int ble_gatt_reliable_attr_fn(uint16_t conn_handle, struct ble_gatt_attr *attrs, uint8_t num_attrs, void *arg); +/** Function prototype for the GATT characteristic callback. */ typedef int ble_gatt_chr_fn(uint16_t conn_handle, const struct ble_gatt_error *error, const struct ble_gatt_chr *chr, void *arg); +/** Function prototype for the GATT descriptor callback. */ typedef int ble_gatt_dsc_fn(uint16_t conn_handle, const struct ble_gatt_error *error, uint16_t chr_val_handle, @@ -171,6 +347,8 @@ int ble_gattc_exchange_mtu(uint16_t conn_handle, * updates; null for no callback. * @param cb_arg The optional argument to pass to the callback * function. + * + * @return 0 on success; nonzero on failure. */ int ble_gattc_disc_all_svcs(uint16_t conn_handle, ble_gatt_disc_svc_fn *cb, void *cb_arg); @@ -180,7 +358,7 @@ int ble_gattc_disc_all_svcs(uint16_t conn_handle, * * @param conn_handle The connection over which to execute the * procedure. - * @param service_uuid128 The 128-bit UUID of the service to discover. + * @param uuid The 128-bit UUID of the service to discover. * @param cb The function to call to report procedure status * updates; null for no callback. * @param cb_arg The optional argument to pass to the callback @@ -240,7 +418,7 @@ int ble_gattc_disc_all_chrs(uint16_t conn_handle, uint16_t start_handle, * the service definition handle). * @param end_handle The handle to end the search at (generally the * last handle in the service). - * @param chr_uuid128 The 128-bit UUID of the characteristic to + * @param uuid The 128-bit UUID of the characteristic to * discover. * @param cb The function to call to report procedure status * updates; null for no callback. @@ -258,9 +436,9 @@ int ble_gattc_disc_chrs_by_uuid(uint16_t conn_handle, uint16_t start_handle, * * @param conn_handle The connection over which to execute the * procedure. - * @param chr_val_handle The handle of the characteristic value + * @param start_handle The handle of the characteristic value * attribute. - * @param chr_end_handle The last handle in the characteristic + * @param end_handle The last handle in the characteristic * definition. * @param cb The function to call to report procedure status * updates; null for no callback. @@ -298,6 +476,8 @@ int ble_gattc_read(uint16_t conn_handle, uint16_t attr_handle, * handle of the service definition). * @param end_handle The last handle to search (generally the * last handle in the service definition). + * @param uuid The 128-bit UUID of the characteristic to + * read. * @param cb The function to call to report procedure status * updates; null for no callback. * @param cb_arg The optional argument to pass to the callback @@ -315,6 +495,8 @@ int ble_gattc_read_by_uuid(uint16_t conn_handle, uint16_t start_handle, * @param conn_handle The connection over which to execute the * procedure. * @param handle The handle of the characteristic value to read. + * @param offset The offset within the characteristic value to + * start reading. * @param cb The function to call to report procedure status * updates; null for no callback. * @param cb_arg The optional argument to pass to the callback @@ -343,6 +525,23 @@ int ble_gattc_read_mult(uint16_t conn_handle, const uint16_t *handles, uint8_t num_handles, ble_gatt_attr_fn *cb, void *cb_arg); +/** + * Initiates GATT procedure: Read Multiple Variable Length Characteristic Values. + * + * @param conn_handle The connection over which to execute the + * procedure. + * @param handles An array of 16-bit attribute handles to read. + * @param num_handles The number of entries in the "handles" array. + * @param cb The function to call to report procedure status + * updates; null for no callback. + * @param cb_arg The optional argument to pass to the callback + * function. + * + * @return 0 on success; nonzero on failure. + */ +int ble_gattc_read_mult_var(uint16_t conn_handle, const uint16_t *handles, + uint8_t num_handles, ble_gatt_attr_mult_fn *cb, + void *cb_arg); /** * Initiates GATT procedure: Write Without Response. This function consumes * the supplied mbuf regardless of the outcome. @@ -351,7 +550,7 @@ int ble_gattc_read_mult(uint16_t conn_handle, const uint16_t *handles, * procedure. * @param attr_handle The handle of the characteristic value to write * to. - * @param txom The value to write to the characteristic. + * @param om The value to write to the characteristic. * * @return 0 on success; nonzero on failure. */ @@ -366,8 +565,8 @@ int ble_gattc_write_no_rsp(uint16_t conn_handle, uint16_t attr_handle, * procedure. * @param attr_handle The handle of the characteristic value to write * to. - * @param value The value to write to the characteristic. - * @param value_len The number of bytes to write. + * @param data The value to write to the characteristic. + * @param data_len The number of bytes to write. * * @return 0 on success; nonzero on failure. */ @@ -382,7 +581,7 @@ int ble_gattc_write_no_rsp_flat(uint16_t conn_handle, uint16_t attr_handle, * procedure. * @param attr_handle The handle of the characteristic value to write * to. - * @param txom The value to write to the characteristic. + * @param om The value to write to the characteristic. * @param cb The function to call to report procedure status * updates; null for no callback. * @param cb_arg The optional argument to pass to the callback @@ -401,8 +600,8 @@ int ble_gattc_write(uint16_t conn_handle, uint16_t attr_handle, * procedure. * @param attr_handle The handle of the characteristic value to write * to. - * @param value The value to write to the characteristic. - * @param value_len The number of bytes to write. + * @param data The value to write to the characteristic. + * @param data_len The number of bytes to write. * @param cb The function to call to report procedure status * updates; null for no callback. * @param cb_arg The optional argument to pass to the callback @@ -422,7 +621,8 @@ int ble_gattc_write_flat(uint16_t conn_handle, uint16_t attr_handle, * procedure. * @param attr_handle The handle of the characteristic value to write * to. - * @param txom The value to write to the characteristic. + * @param offset The offset at which to begin writing the value. + * @param om The value to write to the characteristic. * @param cb The function to call to report procedure status * updates; null for no callback. * @param cb_arg The optional argument to pass to the callback @@ -452,6 +652,8 @@ int ble_gattc_write_long(uint16_t conn_handle, uint16_t attr_handle, * updates; null for no callback. * @param cb_arg The optional argument to pass to the callback * function. + * + * @return 0 on success; nonzero on failure. */ int ble_gattc_write_reliable(uint16_t conn_handle, struct ble_gatt_attr *attrs, @@ -464,9 +666,50 @@ int ble_gattc_write_reliable(uint16_t conn_handle, * * @param conn_handle The connection over which to execute the * procedure. - * @param chr_val_handle The attribute handle to indicate in the + * @param att_handle The attribute handle to indicate in the + * outgoing notification. + * @param om The value to write to the characteristic. + * + * @return 0 on success; nonzero on failure. + */ +int ble_gatts_notify_custom(uint16_t conn_handle, uint16_t att_handle, + struct os_mbuf *om); + +/** + * Sends a "free-form" multiple handle variable length characteristic + * notification. This function consumes supplied mbufs regardless of the + * outcome. Notifications are sent in order of supplied entries. + * Function tries to send minimum amount of PDUs. If PDU can't contain all + * of the characteristic values, multiple notifications are sent. If only one + * handle-value pair fits into PDU, or only one characteristic remains in the + * list, regular characteristic notification is sent. + * + * If GATT client doesn't support receiving multiple handle notifications, + * this will use GATT notification for each characteristic, separately. + * + * If value of characteristic is not specified it will be read from local + * GATT database. + * + * @param conn_handle The connection over which to execute the + * procedure. + * @param chr_count Number of characteristics to notify about. + * @param tuples Handle-value pairs in form of `ble_gatt_notif` + * structures. + * + * @return 0 on success; nonzero on failure. + */ +int ble_gatts_notify_multiple_custom(uint16_t conn_handle, + size_t chr_count, + struct ble_gatt_notif *tuples); + +/** + * @deprecated Should not be used. Use ble_gatts_notify_custom instead. + * + * @param conn_handle The connection over which to execute the + * procedure. + * @param att_handle The attribute handle to indicate in the * outgoing notification. - * @param txom The value to write to the characteristic. + * @param om The value to write to the characteristic. * * @return 0 on success; nonzero on failure. */ @@ -485,8 +728,47 @@ int ble_gattc_notify_custom(uint16_t conn_handle, uint16_t att_handle, * * @return 0 on success; nonzero on failure. */ +int ble_gatts_notify(uint16_t conn_handle, uint16_t chr_val_handle); + +/** + * @deprecated Should not be used. Use ble_gatts_notify instead. + * + * @param conn_handle The connection over which to execute the + * procedure. + * @param chr_val_handle The value attribute handle of the + * characteristic to include in the outgoing + * notification. + * + * @return 0 on success; nonzero on failure. + */ int ble_gattc_notify(uint16_t conn_handle, uint16_t chr_val_handle); +/** + * Sends a multiple handle variable length characteristic notification. The + * content of the message is read from the specified characteristics. + * Notifications are sent in order of supplied handles. Function tries to + * send minimum amount of PDUs. If PDU can't contain all of the + * characteristic values, multiple notifications are sent. If only one + * handle-value pair fits into PDU, or only one characteristic remains in the + * list, regular characteristic notification is sent. + * + * If GATT client doesn't support receiving multiple handle notifications, + * this will use GATT notification for each characteristic, separately. + * + * @param conn_handle The connection over which to execute the + * procedure. + * @param num_handles The number of entries in the "chr_val_handles" + * array. + * @param chr_val_handles Array of attribute handles of the + * characteristics to include in the outgoing + * notification. + * + * @return 0 on success; nonzero on failure. + */ +int ble_gatts_notify_multiple(uint16_t conn_handle, + size_t num_handles, + const uint16_t *chr_val_handles); + /** * Sends a "free-form" characteristic indication. The provided mbuf contains * the indication payload. This function consumes the supplied mbuf regardless @@ -501,6 +783,21 @@ int ble_gattc_notify(uint16_t conn_handle, uint16_t chr_val_handle); * * @return 0 on success; nonzero on failure. */ +int ble_gatts_indicate_custom(uint16_t conn_handle, uint16_t chr_val_handle, + struct os_mbuf *txom); + +/** + * @deprecated Should not be used. Use ble_gatts_indicate_custom instead. + * + * @param conn_handle The connection over which to execute the + * procedure. + * @param chr_val_handle The value attribute handle of the + * characteristic to include in the outgoing + * indication. + * @param txom The data to include in the indication. + * + * @return 0 on success; nonzero on failure. + */ int ble_gattc_indicate_custom(uint16_t conn_handle, uint16_t chr_val_handle, struct os_mbuf *txom); @@ -516,18 +813,33 @@ int ble_gattc_indicate_custom(uint16_t conn_handle, uint16_t chr_val_handle, * * @return 0 on success; nonzero on failure. */ +int ble_gatts_indicate(uint16_t conn_handle, uint16_t chr_val_handle); + +/** + * @deprecated Should not be used. Use ble_gatts_indicate instead. + * @copydoc ble_gatts_indicate + */ int ble_gattc_indicate(uint16_t conn_handle, uint16_t chr_val_handle); +/** + * Initialize the BLE GATT client + * + * @return 0 on success; nonzero on failure. + */ int ble_gattc_init(void); /*** @server. */ struct ble_gatt_access_ctxt; + +/** Type definition for GATT access callback function. */ typedef int ble_gatt_access_fn(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg); +/** Type definition for GATT characteristic flags. */ typedef uint16_t ble_gatt_chr_flags; +/** Represents the definition of a GATT characteristic. */ struct ble_gatt_chr_def { /** * Pointer to characteristic UUID; use BLE_UUIDxx_DECLARE macros to declare @@ -564,6 +876,7 @@ struct ble_gatt_chr_def { uint16_t *val_handle; }; +/** Represents the definition of a GATT service. */ struct ble_gatt_svc_def { /** * One of the following: @@ -593,6 +906,7 @@ struct ble_gatt_svc_def { const struct ble_gatt_chr_def *characteristics; }; +/** Represents the definition of a GATT descriptor. */ struct ble_gatt_dsc_def { /** * Pointer to descriptor UUID; use BLE_UUIDxx_DECLARE macros to declare @@ -659,6 +973,12 @@ struct ble_gatt_access_ctxt { */ const struct ble_gatt_dsc_def *dsc; }; + + /** + * An offset in case of BLE_ATT_OP_READ_BLOB_REQ. + * If the value is greater than zero it's an indication of a long attribute read. + */ + uint16_t offset; }; /** @@ -738,6 +1058,7 @@ struct ble_gatt_register_ctxt { }; }; +/** Type definition for GATT registration callback function. */ typedef void ble_gatt_register_fn(struct ble_gatt_register_ctxt *ctxt, void *arg); @@ -834,7 +1155,7 @@ int ble_gatts_find_chr(const ble_uuid_t *svc_uuid, const ble_uuid_t *chr_uuid, * @param svc_uuid The UUID of the grandparent service. * @param chr_uuid The UUID of the parent characteristic. * @param dsc_uuid The UUID of the descriptor ro look up. - * @param out_handle On success, populated with the handle + * @param out_dsc_handle On success, populated with the handle * of the descriptor attribute. Pass null if * you don't need this value. * @@ -846,6 +1167,7 @@ int ble_gatts_find_chr(const ble_uuid_t *svc_uuid, const ble_uuid_t *chr_uuid, int ble_gatts_find_dsc(const ble_uuid_t *svc_uuid, const ble_uuid_t *chr_uuid, const ble_uuid_t *dsc_uuid, uint16_t *out_dsc_handle); +/** Type definition for GATT service iteration callback function. */ typedef void (*ble_gatt_svc_foreach_fn)(const struct ble_gatt_svc_def *svc, uint16_t handle, uint16_t end_group_handle, @@ -885,6 +1207,44 @@ int ble_gatts_reset(void); */ int ble_gatts_start(void); +/** + * Gets Client Supported Features for specified connection. + * + * @param conn_handle Connection handle identifying the connection for + * which Client Supported Features should be saved + * @param out_supported_feat Client supported features to be returned. + * @param len The size of the Client Supported Features + * characteristic in octets. + * + * @return 0 on success; + * BLE_HS_ENOTCONN if no matching connection + * was found + * BLE_HS_EINVAL if supplied buffer is empty or + * if any Client Supported Feature was + * attempted to be disabled. + * A BLE host core return code on unexpected error. + * + */ +int ble_gatts_peer_cl_sup_feat_get(uint16_t conn_handle, uint8_t *out_supported_feat, uint8_t len); + +/** + * Reads configuration values from Client Characteristic Configuration + * Descriptor for specified characteristic. + * + * @param conn_handle Connection handle identifying the connection + * to which CCC instance is related. + * @param chr_val_handle The value handle of characteristic. + * @param cccd_value Configuration value of CCC. + * + * @return 0 on success; + * BLE_HS_ENOTCONN if no matching connection + * was found + * BLE_HS_ENOENT if descriptor could not be found. + * + */ +int ble_gatts_read_cccd(uint16_t conn_handle, uint16_t chr_val_handle, + uint8_t *cccd_value); + #ifdef __cplusplus } #endif @@ -893,4 +1253,4 @@ int ble_gatts_start(void); * @} */ -#endif +#endif /* H_BLE_GATT_ */ diff --git a/nimble/host/include/host/ble_hs.h b/nimble/host/include/host/ble_hs.h index 6c2acfd4d5..5079648fad 100644 --- a/nimble/host/include/host/ble_hs.h +++ b/nimble/host/include/host/ble_hs.h @@ -43,12 +43,14 @@ #include "host/ble_sm.h" #include "host/ble_store.h" #include "host/ble_uuid.h" +#include "host/ble_iso.h" #include "nimble/nimble_npl.h" #ifdef __cplusplus extern "C" { #endif +/** Represents an infinite value for timeouts or durations. */ #define BLE_HS_FOREVER INT32_MAX /** Connection handle not present */ @@ -64,36 +66,97 @@ extern "C" { * @{ */ +/** Operation failed and should be retried later. */ #define BLE_HS_EAGAIN 1 + +/** Operation already in progress. */ #define BLE_HS_EALREADY 2 + +/** Invalid parameter. */ #define BLE_HS_EINVAL 3 + +/** Message too long. */ #define BLE_HS_EMSGSIZE 4 + +/** No such entry. */ #define BLE_HS_ENOENT 5 + +/** Out of memory. */ #define BLE_HS_ENOMEM 6 + +/** Not connected. */ #define BLE_HS_ENOTCONN 7 + +/** Not supported. */ #define BLE_HS_ENOTSUP 8 + +/** Application error. */ #define BLE_HS_EAPP 9 + +/** Bad data. */ #define BLE_HS_EBADDATA 10 + +/** Operating System error. */ #define BLE_HS_EOS 11 + +/** Controller error. */ #define BLE_HS_ECONTROLLER 12 + +/** Operation timed out. */ #define BLE_HS_ETIMEOUT 13 + +/** Operation completed. */ #define BLE_HS_EDONE 14 + +/** Resource busy. */ #define BLE_HS_EBUSY 15 + +/** Operation rejected. */ #define BLE_HS_EREJECT 16 + +/** Unknown error. */ #define BLE_HS_EUNKNOWN 17 + +/** Role error. */ #define BLE_HS_EROLE 18 + +/** HCI operation timed out. */ #define BLE_HS_ETIMEOUT_HCI 19 + +/** Out of memory to handle an event. */ #define BLE_HS_ENOMEM_EVT 20 + +/** No valid address. */ #define BLE_HS_ENOADDR 21 + +/** Not synchronized with the controller. */ #define BLE_HS_ENOTSYNCED 22 + +/** Authentication error. */ #define BLE_HS_EAUTHEN 23 + +/** Authorization error. */ #define BLE_HS_EAUTHOR 24 + +/** Encryption error. */ #define BLE_HS_EENCRYPT 25 + +/** Invalid encryption key size. */ #define BLE_HS_EENCRYPT_KEY_SZ 26 + +/** Storage capacity exceeded. */ #define BLE_HS_ESTORE_CAP 27 + +/** Storage operation failed. */ #define BLE_HS_ESTORE_FAIL 28 + +/** Operation was preempted. */ #define BLE_HS_EPREEMPTED 29 + +/** Operation disabled. */ #define BLE_HS_EDISABLED 30 + +/** Operation stalled. */ #define BLE_HS_ESTALLED 31 /** Error base for ATT errors */ @@ -165,6 +228,25 @@ extern "C" { /** KeyboardDisplay Only IO capability */ #define BLE_HS_IO_KEYBOARD_DISPLAY 0x04 +/** + * @} + */ + +/** + * @brief LE key distribution + * @defgroup bt_host_key_dist LE key distribution + * + * @{ + */ + +/** Distibute LTK */ +#define BLE_HS_KEY_DIST_ENC_KEY 0x01 + +/** Distribute IRK */ +#define BLE_HS_KEY_DIST_ID_KEY 0x02 + +/** CSRK distibution and LinkKey are not supported */ + /** * @} */ @@ -257,6 +339,9 @@ struct ble_hs_cfg { */ ble_hs_sync_fn *sync_cb; + /** Callback to handle generation of security keys */ + ble_store_gen_key_fn *store_gen_key_cb; + /* XXX: These need to go away. Instead, the nimble host package should * require the host-store API (not yet implemented).. */ @@ -283,6 +368,7 @@ struct ble_hs_cfg { void *store_status_arg; }; +/** Configuration structure for the NimBLE Host stack. */ extern struct ble_hs_cfg ble_hs_cfg; /** diff --git a/nimble/host/include/host/ble_hs_adv.h b/nimble/host/include/host/ble_hs_adv.h index e3b6ea7098..b498f67542 100644 --- a/nimble/host/include/host/ble_hs_adv.h +++ b/nimble/host/include/host/ble_hs_adv.h @@ -20,6 +20,13 @@ #ifndef H_BLE_HS_ADV_ #define H_BLE_HS_ADV_ +/** + * @brief Bluetooth Host Advertising API + * @defgroup bt_adv Bluetooth Host Advertising API + * @ingroup bt_host + * @{ + */ + #include #include "host/ble_uuid.h" @@ -27,115 +34,254 @@ extern "C" { #endif +/** Max Advertising Data Size. */ #define BLE_HS_ADV_MAX_SZ BLE_HCI_MAX_ADV_DATA_LEN /** Max field payload size (account for 2-byte header). */ #define BLE_HS_ADV_MAX_FIELD_SZ (BLE_HS_ADV_MAX_SZ - 2) +/** Represents advertising data packet in BLE advertisement or scan response. */ struct ble_hs_adv_field { + /** Length of the advertising data (type and value). */ uint8_t length; + + /** Type of the advertising data field. */ uint8_t type; + + /** Value of the advertising data field. */ uint8_t value[0]; }; +/** Function pointer typedef for parsing an advertising data field. */ typedef int (* ble_hs_adv_parse_func_t) (const struct ble_hs_adv_field *, void *); +/** Advertising Data Fields. */ struct ble_hs_adv_fields { - /*** 0x01 - Flags. */ + /** 0x01 - Flags. */ uint8_t flags; - /*** 0x02,0x03 - 16-bit service class UUIDs. */ + /** 0x02,0x03 - 16-bit service class UUIDs. */ const ble_uuid16_t *uuids16; + + /** Number of 16-bit UUIDs. */ uint8_t num_uuids16; + + /** Indicates if the list of 16-bit UUIDs is complete. */ unsigned uuids16_is_complete:1; - /*** 0x04,0x05 - 32-bit service class UUIDs. */ + + /** 0x04,0x05 - 32-bit service class UUIDs. */ const ble_uuid32_t *uuids32; + + /** Number of 32-bit UUIDs. */ uint8_t num_uuids32; + + /** Indicates if the list of 32-bit UUIDs is complete. */ unsigned uuids32_is_complete:1; - /*** 0x06,0x07 - 128-bit service class UUIDs. */ + + /** 0x06,0x07 - 128-bit service class UUIDs. */ const ble_uuid128_t *uuids128; + + /** Number of 128-bit UUIDs. */ uint8_t num_uuids128; + + /** Indicates if the list of 128-bit UUIDs is complete. */ unsigned uuids128_is_complete:1; - /*** 0x08,0x09 - Local name. */ + + /** 0x08,0x09 - Local name. */ const uint8_t *name; + + /** Length of the local name. */ uint8_t name_len; + + /** Indicates if the list of local names if complete. */ unsigned name_is_complete:1; - /*** 0x0a - Tx power level. */ + + /** 0x0a - Tx power level. */ int8_t tx_pwr_lvl; + + /** Indicates if Tx power level is present. */ unsigned tx_pwr_lvl_is_present:1; - /*** 0x0d - Slave connection interval range. */ + + /** 0x12 - Slave connection interval range. */ const uint8_t *slave_itvl_range; - /*** 0x16 - Service data - 16-bit UUID. */ + /** 0x16 - Service data - 16-bit UUID. */ const uint8_t *svc_data_uuid16; + + /** Length of the service data with 16-bit UUID. */ uint8_t svc_data_uuid16_len; - /*** 0x17 - Public target address. */ + + /** 0x17 - Public target address. */ const uint8_t *public_tgt_addr; + + /** Number of public target addresses. */ uint8_t num_public_tgt_addrs; - /*** 0x19 - Appearance. */ + /** 0x19 - Appearance. */ uint16_t appearance; + + /** Indicates if Appearance is present. */ unsigned appearance_is_present:1; - /*** 0x1a - Advertising interval. */ + + /** 0x1a - Advertising interval. */ uint16_t adv_itvl; + + /** Indicates if advertising interval is present. */ unsigned adv_itvl_is_present:1; - /*** 0x20 - Service data - 32-bit UUID. */ + + /** 0x20 - Service data - 32-bit UUID. */ const uint8_t *svc_data_uuid32; + + /** Length of the service data with 32-bit UUID. */ uint8_t svc_data_uuid32_len; - /*** 0x21 - Service data - 128-bit UUID. */ + + /** 0x21 - Service data - 128-bit UUID. */ const uint8_t *svc_data_uuid128; + + /** Length of service data with 128-bit UUID. */ uint8_t svc_data_uuid128_len; - /*** 0x24 - URI. */ + + /** 0x24 - URI. */ const uint8_t *uri; + + /** Length of the URI. */ uint8_t uri_len; - /*** 0xff - Manufacturer specific data. */ + + /** 0xff - Manufacturer specific data. */ const uint8_t *mfg_data; + + /** Length of manufacturer specific data. */ uint8_t mfg_data_len; + + /** 0x30 - Broadcast name. */ + const uint8_t *broadcast_name; + + /** Length of the Broadcast name. */ + uint8_t broadcast_name_len; }; +/** + * @defgroup ble_hs_adv_types BLE Advertising Common Data Types + * @{ + */ + +/** Common Data Type: Flags. */ #define BLE_HS_ADV_TYPE_FLAGS 0x01 + +/** Common Data Type: Incomplete List of 16-bit Service Class UUIDs. */ #define BLE_HS_ADV_TYPE_INCOMP_UUIDS16 0x02 + +/** Common Data Type: Complete List of 16-bit Service Class UUIDs. */ #define BLE_HS_ADV_TYPE_COMP_UUIDS16 0x03 + +/** Common Data Type: Incomplete List of 32-bit Service Class UUIDs. */ #define BLE_HS_ADV_TYPE_INCOMP_UUIDS32 0x04 + +/** Common Data Type: Complete List of 32-bit Service Class UUIDs. */ #define BLE_HS_ADV_TYPE_COMP_UUIDS32 0x05 + +/** Common Data Type: Incomplete List of 128-bit Service Class UUIDs. */ #define BLE_HS_ADV_TYPE_INCOMP_UUIDS128 0x06 + +/** Common Data Type: Complete List of 128-bit Service Class UUIDs. */ #define BLE_HS_ADV_TYPE_COMP_UUIDS128 0x07 + +/** Common Data Type: Shortened Local Name. */ #define BLE_HS_ADV_TYPE_INCOMP_NAME 0x08 + +/** Common Data Type: Complete Local Name. */ #define BLE_HS_ADV_TYPE_COMP_NAME 0x09 + +/** Common Data Type: Tx Power Level. */ #define BLE_HS_ADV_TYPE_TX_PWR_LVL 0x0a + +/** Common Data Type: Peripheral Connection Interval Range. */ #define BLE_HS_ADV_TYPE_SLAVE_ITVL_RANGE 0x12 + +/** Common Data Type: List of 16-bit Service Solicitation UUIDs. */ #define BLE_HS_ADV_TYPE_SOL_UUIDS16 0x14 + +/** Common Data Type: List of 128-bit Service Solicitation UUIDs. */ #define BLE_HS_ADV_TYPE_SOL_UUIDS128 0x15 + +/** Common Data Type: Service Data - 16-bit UUID. */ #define BLE_HS_ADV_TYPE_SVC_DATA_UUID16 0x16 + +/** Common Data Type: Public Target Address. */ #define BLE_HS_ADV_TYPE_PUBLIC_TGT_ADDR 0x17 + +/** Common Data Type: Random Target Address. */ #define BLE_HS_ADV_TYPE_RANDOM_TGT_ADDR 0x18 + +/** Common Data Type: Appearance. */ #define BLE_HS_ADV_TYPE_APPEARANCE 0x19 + +/** Common Data Type: Advertising Interval. */ #define BLE_HS_ADV_TYPE_ADV_ITVL 0x1a + +/** Common Data Type: Service Data - 32-bit UUID. */ #define BLE_HS_ADV_TYPE_SVC_DATA_UUID32 0x20 + +/** Common Data Type: Service Data - 128-bit UUID. */ #define BLE_HS_ADV_TYPE_SVC_DATA_UUID128 0x21 + +/** Common Data Type: URI. */ #define BLE_HS_ADV_TYPE_URI 0x24 + +/** Common Data Type: PB-ADV. */ #define BLE_HS_ADV_TYPE_MESH_PROV 0x29 + +/** Common Data Type: Mesh Message. */ #define BLE_HS_ADV_TYPE_MESH_MESSAGE 0x2a + +/** Common Data Type: Mesh Beacon. */ #define BLE_HS_ADV_TYPE_MESH_BEACON 0x2b + +/** Common Data Type: Broadcast Name. */ +#define BLE_HS_ADV_TYPE_BROADCAST_NAME 0x30 + +/** Common Data Type: Manufacturer Specific Data. */ #define BLE_HS_ADV_TYPE_MFG_DATA 0xff +/** + * @} + */ + +/** + * @defgroup ble_hs_adv_flags BLE Advertising Flags + * @{ + */ +/** Length of BLE Advertising Flags field. */ #define BLE_HS_ADV_FLAGS_LEN 1 + +/** Limited Discoverable Mode Flag. */ #define BLE_HS_ADV_F_DISC_LTD 0x01 + +/** General Discoverable Mode Flag. */ #define BLE_HS_ADV_F_DISC_GEN 0x02 + +/** BR/EDR Not Supported Flag. */ #define BLE_HS_ADV_F_BREDR_UNSUP 0x04 +/** @} */ + +/** + * @defgroup ble_hs_adv_misc BLE Advertising Miscellaneous + * @{ + */ +/** Length of BLE advertising transmit power level field. */ #define BLE_HS_ADV_TX_PWR_LVL_LEN 1 /** @@ -144,29 +290,83 @@ struct ble_hs_adv_fields { */ #define BLE_HS_ADV_TX_PWR_LVL_AUTO (-128) +/** Length of the Peripheral Connection Interval Range field. */ #define BLE_HS_ADV_SLAVE_ITVL_RANGE_LEN 4 +/** Minimum length of the Service Data - 16-bit UUID field. */ #define BLE_HS_ADV_SVC_DATA_UUID16_MIN_LEN 2 +/** Length of a Public Target Address entry. */ #define BLE_HS_ADV_PUBLIC_TGT_ADDR_ENTRY_LEN 6 +/** Length of the Appearance field. */ #define BLE_HS_ADV_APPEARANCE_LEN 2 +/** Length of the Advertising Interval field. */ #define BLE_HS_ADV_ADV_ITVL_LEN 2 +/** Minimum length of the Service Data - 32-bit UUID field. */ #define BLE_HS_ADV_SVC_DATA_UUID32_MIN_LEN 4 +/** Minimum length of the Service Data - 128-bit UUID field. */ #define BLE_HS_ADV_SVC_DATA_UUID128_MIN_LEN 16 +/** + * @} + */ + +/** + * Set the advertising data fields in an os_mbuf. + * + * @param adv_fields Pointer to the advertising data structure. + * @param om Pointer to the memory buffer that will be written with + * advertising data. + * + * @return 0 on success; non-zero on failure. + */ int ble_hs_adv_set_fields_mbuf(const struct ble_hs_adv_fields *adv_fields, struct os_mbuf *om); +/** + * Set the advertising data fields in a destination buffer. + * + * @param adv_fields Pointer to the advertising data structure. + * @param dst Pointer to the destination buffer that will be written + * with advertising data. + * @param dst_len Pointer to the variable that will hold the length of + * the data written. + * @param max_len Maximum length of the destination buffer. + * + * @return 0 on success; nonzero on failure. + */ int ble_hs_adv_set_fields(const struct ble_hs_adv_fields *adv_fields, uint8_t *dst, uint8_t *dst_len, uint8_t max_len); +/** + * Parse the advertising data fields from a source buffer. + * + * @param adv_fields Pointer to the advertising data fields structure + * to populate. + * @param src Pointer to the source buffer containing the data + * to parse. + * @param src_len Length of the source buffer. + * + * @return 0 on success; nonzero on failure. + */ int ble_hs_adv_parse_fields(struct ble_hs_adv_fields *adv_fields, const uint8_t *src, uint8_t src_len); +/** + * Parse the advertising data using the provided parsing function. + * + * @param data Pointer to the advertising data buffer to parse. + * @param length Length of the advertising data buffer. + * @param func Pointer to the parsing function to apply to each + * field. + * @param user_data User-defined data to pass to the parsing function. + * + * @return 0 on success; nonzero on failure. + */ int ble_hs_adv_parse(const uint8_t *data, uint8_t length, ble_hs_adv_parse_func_t func, void *user_data); @@ -174,4 +374,8 @@ int ble_hs_adv_parse(const uint8_t *data, uint8_t length, } #endif +/** + * @} + */ + #endif diff --git a/nimble/host/include/host/ble_hs_hci.h b/nimble/host/include/host/ble_hs_hci.h index e10b8e62a5..237712080a 100644 --- a/nimble/host/include/host/ble_hs_hci.h +++ b/nimble/host/include/host/ble_hs_hci.h @@ -87,6 +87,39 @@ int ble_hs_hci_read_chan_map(uint16_t conn_handle, uint8_t *out_chan_map); */ int ble_hs_hci_set_chan_class(const uint8_t *chan_map); +/** + * Reads random data into buffer from controller. + * This allows to use BLE controller as a source of true random data. + * + * @param dst Destination buffer. + * @param len Destination buffer length. + * + * @return 0 on success; + * A BLE host HCI return code if the controller + * rejected the request; + * A BLE host core return code on unexpected + * error. + */ +int ble_hs_hci_rand(void *dst, int len); + +#if MYNEWT_VAL(BLE_HCI_VS) +/** + * Send an arbitrary HCI command to the controller. + * + * The command has to be a vendor-specific command, i.e. OGF=0x3f is always + * assumed. + * + * @param ocf OCF for vendor-specific HCI command + * @param cmdbuf command buffer + * @param cmdlen length of command buffer + * @param rspbuf response buffer + * @param rsplen length of response buffer + * @return 0 on success, error code on failure + */ +int ble_hs_hci_send_vs_cmd(uint16_t ocf, const void *cmdbuf, uint8_t cmdlen, + void *rspbuf, uint8_t rsplen); +#endif + #ifdef __cplusplus } #endif diff --git a/nimble/host/include/host/ble_hs_log.h b/nimble/host/include/host/ble_hs_log.h index 7b90eaf9f0..1514a2ba5c 100644 --- a/nimble/host/include/host/ble_hs_log.h +++ b/nimble/host/include/host/ble_hs_log.h @@ -20,34 +20,88 @@ #ifndef H_BLE_HS_LOG_ #define H_BLE_HS_LOG_ -#include "modlog/modlog.h" -#include "log/log.h" +/** + * @file ble_hs_log.h + * + * @brief Bluetooth Host Log + * + * This header file defines macros and functions used for logging messages + * within the BLE Host Stack. + * + * @defgroup bt_host_log Bluetooth Host Log + * @ingroup bt_host + * @{ + */ -/* Only include the logcfg header if this version of newt can generate it. */ -#if MYNEWT_VAL(NEWT_FEATURE_LOGCFG) -#include "logcfg/logcfg.h" +#ifndef BLE_NPL_LOG_MODULE +/** Defines the logging module for NimBLE Porting Layer (NPL). */ +#define BLE_NPL_LOG_MODULE BLE_HS_LOG #endif +#include + #ifdef __cplusplus extern "C" { #endif struct os_mbuf; +/** + * @brief Macro for logging messages at a specified log level. + * + * The BLE_HS_LOG macro allows logging messages with different severity levels, + * such as DEBUG, INFO, WARN, ERROR or CRITICAL. + * + * @param lvl The log level of the message. + * @param ... The format string and additional arguments for the log message. + */ #define BLE_HS_LOG(lvl, ...) \ - BLE_HS_LOG_ ## lvl(__VA_ARGS__) + BLE_NPL_LOG(lvl, __VA_ARGS__) +/** + * @brief Macro for logging a Bluetooth address at a specified log level. + * + * The BLE_HS_LOG_ADDR macro allows logging Bluetooth addresses in the format + * "XX:XX:XX:XX:XX:XX" at different severity levels, such as DEBUG, INFO, WARN, ERROR or CRITICAL. + * + * @param lvl The log level of the message. + * @param addr The Bluetooth address to be logged. + */ #define BLE_HS_LOG_ADDR(lvl, addr) \ - BLE_HS_LOG_ ## lvl("%02x:%02x:%02x:%02x:%02x:%02x", \ - (addr)[5], (addr)[4], (addr)[3], \ - (addr)[2], (addr)[1], (addr)[0]) + BLE_NPL_LOG(lvl, "%02x:%02x:%02x:%02x:%02x:%02x", \ + (addr)[5], (addr)[4], (addr)[3], \ + (addr)[2], (addr)[1], (addr)[0]) +/** + * @brief Logs the content of an `os_mbuf` structure. + * + * This function iterates over each byte in the provided `os_mbuf` and logs its + * value in hexadecimal format using the `BLE_HS_LOG` macro with the log level + * set to DEBUG. + * + * @param om The `os_mbuf` to log. + */ void ble_hs_log_mbuf(const struct os_mbuf *om); + +/** + * @brief Logs the content of a flat buffer. + * + * This function iterates over each byte in the provided buffer and logs its + * value in hexadecimal format using the `BLE_HS_LOG` macro with the log level + * set to DEBUG. + * + * @param data Pointer to the buffer to log. + * @param len Length of the buffer. + */ void ble_hs_log_flat_buf(const void *data, int len); #ifdef __cplusplus } #endif -#endif +/** + * @} + */ + +#endif /* H_BLE_HS_LOG_*/ diff --git a/nimble/host/include/host/ble_hs_stop.h b/nimble/host/include/host/ble_hs_stop.h index d16c9c27bc..8b3ebd3fb4 100644 --- a/nimble/host/include/host/ble_hs_stop.h +++ b/nimble/host/include/host/ble_hs_stop.h @@ -20,6 +20,13 @@ #ifndef H_BLE_HS_STOP_ #define H_BLE_HS_STOP_ +/** + * @brief Bluetooth Host Stop API + * @defgroup bt_hs_stop Bluetooth Host Stop + * @ingroup bt_host + * @{ + */ + /** @typedef ble_hs_stop_fn * @brief Callback function; reports the result of a host stop procedure. * @@ -38,8 +45,13 @@ typedef void ble_hs_stop_fn(int status, void *arg); * This should be used as an opaque structure and not modified manually. */ struct ble_hs_stop_listener { + /** The callback function to be called when the stop procedure completes. */ ble_hs_stop_fn *fn; + + /** An optional argument to be passed to the callback function. */ void *arg; + + /** Singly-linked list entry. */ SLIST_ENTRY(ble_hs_stop_listener) link; }; @@ -64,7 +76,11 @@ struct ble_hs_stop_listener { * BLE_HS_EALREADY: Host already stopped; the * provided callback does *not* get called. */ -int ble_hs_stop(struct ble_hs_stop_listener *listener, +int ble_hs_stop(struct ble_hs_stop_listener *listener, ble_hs_stop_fn *fn, void *arg); +/** +* @} +*/ + #endif diff --git a/nimble/host/include/host/ble_iso.h b/nimble/host/include/host/ble_iso.h new file mode 100644 index 0000000000..ad1d0ed9a8 --- /dev/null +++ b/nimble/host/include/host/ble_iso.h @@ -0,0 +1,509 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_BLE_ISO_ +#define H_BLE_ISO_ + +/** + * @file ble_iso.h + * + * @brief Bluetooth ISO + * @defgroup bt_iso Bluetooth ISO + * @ingroup bt_host + * @{ + */ + +#include +#include "nimble/hci_common.h" +#include "syscfg/syscfg.h" + +/** + * @defgroup ble_iso_events ISO Events + * @{ + */ + +/** ISO event: BIG Create Completed */ +#define BLE_ISO_EVENT_BIG_CREATE_COMPLETE 0 + +/** ISO event: BIG Terminate Completed */ +#define BLE_ISO_EVENT_BIG_TERMINATE_COMPLETE 1 + +/** ISO event: BIG Sync Established */ +#define BLE_ISO_EVENT_BIG_SYNC_ESTABLISHED 2 + +/** ISO event: BIG Sync Terminated */ +#define BLE_ISO_EVENT_BIG_SYNC_TERMINATED 3 + +/** ISO event: ISO Data received */ +#define BLE_ISO_EVENT_ISO_RX 4 + +/** @} */ + +/** @brief Broadcast Isochronous Group (BIG) description */ +struct ble_iso_big_desc { + /** + * The identifier of the BIG. Assigned by the Host when a new BIG is + * created. + */ + uint8_t big_handle; + + /** + * The maximum time in microseconds for transmission of PDUs of all BISes in + * a BIG event. + */ + uint32_t big_sync_delay; + + /** + * The actual transport latency of transmitting payloads of all BISes in the + * BIG in microseconds. + */ + uint32_t transport_latency_big; + + /** The number of subevents per BIS in each BIG event. */ + uint8_t nse; + + /** + * The Burst Number (BN) specifies the number of new payloads in each BIS + * event. + */ + uint8_t bn; + + /** + * The Pre-Transmission Offset (PTO) specifies the offset of groups that + * carry data associated with the future BIS events. + */ + uint8_t pto; + + /** + * The Immediate Repetition Count (IRC) specifies the number of groups that + * carry the data associated with the current BIS event. + */ + uint8_t irc; + + /** + * The maximum number of data octets (excluding the MIC, if any) that can be + * carried in each BIS Data PDU in the BIG. + */ + uint16_t max_pdu; + + /** The time between two adjacent BIG anchor points in units of 1.25 ms. */ + uint16_t iso_interval; + + /** The total number of BISes in the BIG. */ + uint8_t num_bis; + + /** The connection handles of all the BIS in the BIG. */ + uint16_t conn_handle[MYNEWT_VAL(BLE_ISO_MAX_BISES)]; +}; + +/** @brief Received ISO Data status possible values */ +enum ble_iso_rx_data_status { + /** The complete SDU was received correctly. */ + BLE_ISO_DATA_STATUS_VALID = BLE_HCI_ISO_PKT_STATUS_VALID, + + /** May contain errors or part of the SDU may be missing. */ + BLE_ISO_DATA_STATUS_ERROR = BLE_HCI_ISO_PKT_STATUS_INVALID, + + /** Part(s) of the SDU were not received correctly */ + BLE_ISO_DATA_STATUS_LOST = BLE_HCI_ISO_PKT_STATUS_LOST, +}; + +/** @brief Received ISO data info structure */ +struct ble_iso_rx_data_info { + /** ISO Data timestamp. Valid if @ref ble_iso_rx_data_info.ts_valid is set */ + uint32_t ts; + + /** Packet sequence number */ + uint16_t seq_num; + + /** SDU length */ + uint16_t sdu_len : 12; + + /** ISO Data status. See @ref ble_iso_rx_data_status */ + uint16_t status : 2; + + /** Timestamp is valid */ + uint16_t ts_valid : 1; +}; + +/** + * Represents a ISO-related event. When such an event occurs, the host + * notifies the application by passing an instance of this structure to an + * application-specified callback. + */ +struct ble_iso_event { + /** + * Indicates the type of ISO event that occurred. This is one of the + * BLE_ISO_EVENT codes. + */ + uint8_t type; + + /** + * A discriminated union containing additional details concerning the ISO + * event. The 'type' field indicates which member of the union is valid. + */ + union { + /** + * Represents a completion of BIG creation. Valid for the following + * event types: + * o BLE_ISO_EVENT_BIG_CREATE_COMPLETE + */ + struct { + struct ble_iso_big_desc desc; + uint8_t status; + uint8_t phy; + } big_created; + + /** + * Represents a completion of BIG termination. Valid for the following + * event types: + * o BLE_ISO_EVENT_BIG_TERMINATE_COMPLETE + * o BLE_ISO_EVENT_BIG_SYNC_TERMINATED + */ + struct { + uint16_t big_handle; + uint8_t reason; + } big_terminated; + + /** + * Represents a completion of BIG synchronization. Valid for the following + * event types: + * o BLE_ISO_EVENT_BIG_SYNC_ESTABLISHED + */ + struct { + struct ble_iso_big_desc desc; + uint8_t status; + } big_sync_established; + + /** + * Represents a reception of ISO Data. Valid for the following + * event types: + * o BLE_ISO_EVENT_ISO_RX + */ + struct { + uint16_t conn_handle; + const struct ble_iso_rx_data_info *info; + struct os_mbuf *om; + } iso_rx; + }; +}; + +/** Function prototype for isochronous event callback. */ +typedef int ble_iso_event_fn(struct ble_iso_event *event, void *arg); + +/** Broadcast Isochronous Group (BIG) parameters */ +struct ble_iso_big_params { + /** + * The time interval of the periodic SDUs in microseconds. The value shall + * be between 0x0000FF and 0x0FFFFF. + */ + uint32_t sdu_interval; + + /** + * The maximum size of an SDU in octets. The value shall be between 0x0001 + * and 0x0FFF. + */ + uint16_t max_sdu; + + /** + * The maximum transport latency in milliseconds. The value shall be between + * 0x0005 and 0x0FA0. + */ + uint16_t max_transport_latency; + + /** + * The Retransmission Number (RTN) parameter contains the number of times + * every PDU should be retransmitted, irrespective of which BIG events the + * retransmissions occur in. The value shall be between 0x00 and 0x1E. + */ + uint8_t rtn; + + /** + * The PHY parameter is a bit field that indicates the PHY used for + * transmission of PDUs of BISes in the BIG. The value shall be one of the + * following: + * o BLE_HCI_LE_PHY_1M_PREF_MASK + * o BLE_HCI_LE_PHY_2M_PREF_MASK + * o BLE_HCI_LE_PHY_CODED_PREF_MASK + */ + uint8_t phy; + + /** + * Indicates the preferred method of arranging subevents of multiple BISes. + * The value shall be one of the following: + * o 0x00 - Sequential + * o 0x01 - Interleaved + */ + uint8_t packing; + + /** + * Indicates whether the BIG carries framed or unframed data. The value + * shall be one of the following: + * o 0x00 - Unframed + * o 0x01 - Framed + */ + uint8_t framing; + + /** + * Indicates whether the BIG is encrypted or not. The value shall be one of + * the following: + * o 0x00 - Unencrypted + * o 0x01 - Encrypted + */ + uint8_t encryption; + + /** + * The 128-bit code used to derive the session key that is used to encrypt + * and decrypt BIS payloads. + */ + const char *broadcast_code; +}; + +/** Create BIG parameters */ +struct ble_iso_create_big_params { + /** The associated periodic advertising train of the BIG. */ + uint8_t adv_handle; + + /** The total number of BISes in the BIG. */ + uint8_t bis_cnt; + + /** Callback function for reporting the status of the procedure. */ + ble_iso_event_fn *cb; + + /** + * An optional user-defined argument to be passed to the callback function. + */ + void *cb_arg; +}; + +/** + * Initiates the creation of Broadcast Isochronous Group (BIG). It configures + * the BIG parameters based on the provided input and triggers the corresponding + * HCI command. + * + * @param create_params A pointer to the structure holding the + * parameters specific to creating the BIG. + * These parameters define the general settings + * and include a callback function for handling + * creation events. + * @param big_params A pointer to the structure holding detailed + * parameters specific to the configuration of + * the BIG. These parameters include settings + * such as SDU interval, maximum SDU size, + * transport latency, etc. + * @param[out] big_handle BIG instance handle + * + * @return 0 on success; + * an error code on failure. + * + * @note The actual BIG creation result will be reported through the callback + * function specified in @p create_params. + */ +int ble_iso_create_big(const struct ble_iso_create_big_params *create_params, + const struct ble_iso_big_params *big_params, + uint8_t *big_handle); + +/** + * Terminates an existing Broadcast Isochronous Group (BIG). + * + * @param big_handle The identifier of the BIG to be terminated. + * + * @return 0 on success; + * an error code on failure. + */ +int ble_iso_terminate_big(uint8_t big_handle); + +/** @brief BIS parameters for @ref ble_iso_big_sync_create */ +struct ble_iso_bis_params { + /** BIS index */ + uint8_t bis_index; +}; + +/** @brief BIG Sync parameters for @ref ble_iso_big_sync_create */ +struct ble_iso_big_sync_create_params { + /** Periodic advertising train sync handle */ + uint16_t sync_handle; + + /** Null-terminated broadcast code for encrypted BIG or + * NULL if the BIG is unencrypted + */ + const char *broadcast_code; + + /** Maximum Subevents to be used to receive data payloads in each BIS event */ + uint8_t mse; + + /** The maximum permitted time between successful receptions of BIS PDUs */ + uint16_t sync_timeout; + + /** The callback to associate with this sync procedure. + * Sync establishment and termination are reported through this callback. + */ + ble_iso_event_fn *cb; + + /** The optional argument to pass to the callback function */ + void *cb_arg; + + /** Number of a BISes */ + uint8_t bis_cnt; + + /** BIS parameters */ + struct ble_iso_bis_params *bis_params; +}; + +/** + * @brief Synchronize to Broadcast Isochronous Group (BIG) + * + * This function is used to synchronize to a BIG described in the periodic + * advertising train specified by the @p param->pa_sync_handle parameter. + * + * @param[in] params BIG synchronization parameters + * @param[out] big_handle BIG instance handle + * + * @return 0 on success; + * A non-zero value on failure. + */ +int ble_iso_big_sync_create(const struct ble_iso_big_sync_create_params *params, + uint8_t *big_handle); + +/** + * @brief Terminate Broadcast Isochronous Group (BIG) sync + * + * This function is used to stop synchronizing or cancel the process of + * synchronizing to the BIG identified by the @p big_handle parameter. + * The command also terminates the reception of BISes in the BIG. + * + * @param[in] big_handle BIG handle + * + * @return 0 on success; + * A non-zero value on failure. + */ +int ble_iso_big_sync_terminate(uint8_t big_handle); + +/** @brief ISO Data direction */ +enum ble_iso_data_dir { + BLE_ISO_DATA_DIR_TX, + BLE_ISO_DATA_DIR_RX, +}; + +/** @brief ISO Codec ID */ +struct ble_iso_codec_id { + /** Coding Format */ + uint8_t format; + + /** Company ID */ + uint16_t company_id; + + /** Vendor Specific Codec ID */ + uint16_t vendor_specific; +}; + +/** @brief Setup ISO Data Path parameters */ +struct ble_iso_data_path_setup_params { + /** Connection handle of the CIS or BIS */ + uint16_t conn_handle; + + /** Data path direction */ + enum ble_iso_data_dir data_path_dir; + + /** Data path ID. 0x00 for HCI */ + uint8_t data_path_id; + + /** Controller delay */ + uint32_t ctrl_delay; + + /** Codec ID */ + struct ble_iso_codec_id codec_id; + + /** Codec Configuration Length */ + uint8_t codec_config_len; + + /** Codec Configuration */ + const uint8_t *codec_config; + + /** + * The ISO Data callback. Must be set if @p data_path_id is HCI. + * Received ISO data is reported through this callback. + */ + ble_iso_event_fn *cb; + + /** The optional argument to pass to the callback function */ + void *cb_arg; +}; + +/** + * @brief Setup ISO Data Path + * + * This function is used to identify and create the isochronous data path + * between the Host and the Controller for a CIS, CIS configuration, or BIS + * identified by the @p param->conn_handle parameter. + * + * @param[in] param BIG synchronization parameters + * + * @return 0 on success; + * A non-zero value on failure. + */ +int ble_iso_data_path_setup(const struct ble_iso_data_path_setup_params *param); + +/** @brief @brief Remove ISO Data Path parameters */ +struct ble_iso_data_path_remove_params { + /** Connection handle of the CIS or BIS */ + uint16_t conn_handle; + + /** Data path direction */ + enum ble_iso_data_dir data_path_dir; +}; + +/** + * @brief Remove ISO Data Path + * + * This function is used to remove the input and/or output data path(s) + * associated with a CIS, CIS configuration, or BIS identified by the + * @p param->conn_handle parameter. + * + * @param[in] param BIG synchronization parameters + * + * @return 0 on success; + * A non-zero value on failure. + */ +int ble_iso_data_path_remove(const struct ble_iso_data_path_remove_params *param); + +/** + * Initiates the transmission of isochronous data. + * + * @param conn_handle The connection over which to execute the procedure. + * @param data A pointer to the data to be transmitted. + * @param data_len Number of the data octets to be transmitted. + * + * @return 0 on success; + * an error code on failure. + */ +int ble_iso_tx(uint16_t conn_handle, void *data, uint16_t data_len); + +/** + * Initializes memory for ISO. + * + * @return 0 on success + */ +int ble_iso_init(void); + +/** + * @} + */ + +#endif /* H_BLE_ISO_ */ diff --git a/nimble/host/include/host/ble_l2cap.h b/nimble/host/include/host/ble_l2cap.h index 5c5383b261..32bd41bc8d 100644 --- a/nimble/host/include/host/ble_l2cap.h +++ b/nimble/host/include/host/ble_l2cap.h @@ -17,6 +17,20 @@ * under the License. */ +/** + * @file ble_l2cap.h + * + * @brief L2CAP (Logical Link Control and Adaptation Protocol) API + * + * This header file provides the public API for interacting with the L2CAP layer of the BLE + * (Bluetooth Low Energy) stack. L2CAP is responsible for managing logical channels between + * two connected BLE devices. + * + * @defgroup bt_host_l2cap Bluetooth Host Logical Link Control and Adaptation Protocol + * @ingroup bt_host + * @{ + */ + #ifndef H_BLE_L2CAP_ #define H_BLE_L2CAP_ @@ -25,89 +39,317 @@ extern "C" { #endif +/** + * @brief L2CAP Signaling Connection Parameters Update Request. + * + * This structure represents a request to update the L2CAP connection parameters. + */ struct ble_l2cap_sig_update_req; + +/** + * @brief BLE Host Connection structure. + * + * This structure represents a connection between the BLE host and a remote device. + */ struct ble_hs_conn; +/** + * @defgroup ble_l2cap_channel_ids Channel Identifiers + * @{ + */ +/** Attribute Protocol (ATT) CID. */ #define BLE_L2CAP_CID_ATT 4 + +/** L2CAP LE Signaling CID. */ #define BLE_L2CAP_CID_SIG 5 + +/** Security Manager (SM) CID. */ #define BLE_L2CAP_CID_SM 6 +/** Start range for connection oriented channel CID. */ +#define BLE_L2CAP_COC_CID_START 0x0040 + +/** End range for connection oriented channel CID. */ +#define BLE_L2CAP_COC_CID_END 0x007F + +/** @} */ + +/** + * @defgroup ble_l2cap_signaling_op_codes Signaling Commands Operation Codes + * @{ + */ + +/** Reject */ #define BLE_L2CAP_SIG_OP_REJECT 0x01 + +/** Connect Request */ #define BLE_L2CAP_SIG_OP_CONNECT_REQ 0x02 + +/** Connect Response */ #define BLE_L2CAP_SIG_OP_CONNECT_RSP 0x03 + +/** Configuration Request */ #define BLE_L2CAP_SIG_OP_CONFIG_REQ 0x04 + +/** Configuration Response */ #define BLE_L2CAP_SIG_OP_CONFIG_RSP 0x05 + +/** Disconnect Request */ #define BLE_L2CAP_SIG_OP_DISCONN_REQ 0x06 + +/** Disconnect Response */ #define BLE_L2CAP_SIG_OP_DISCONN_RSP 0x07 + +/** Echo Request */ #define BLE_L2CAP_SIG_OP_ECHO_REQ 0x08 + +/** Echo Response */ #define BLE_L2CAP_SIG_OP_ECHO_RSP 0x09 + +/** Information Request */ #define BLE_L2CAP_SIG_OP_INFO_REQ 0x0a + +/** Information Response */ #define BLE_L2CAP_SIG_OP_INFO_RSP 0x0b + +/** Create Channel Request */ #define BLE_L2CAP_SIG_OP_CREATE_CHAN_REQ 0x0c + +/** Create Channel Response */ #define BLE_L2CAP_SIG_OP_CREATE_CHAN_RSP 0x0d + +/** Move Channel Request */ #define BLE_L2CAP_SIG_OP_MOVE_CHAN_REQ 0x0e + +/** Move Channel Response */ #define BLE_L2CAP_SIG_OP_MOVE_CHAN_RSP 0x0f + +/** Move Channel Confirmation Request */ #define BLE_L2CAP_SIG_OP_MOVE_CHAN_CONF_REQ 0x10 + +/** Move Channel Confirmation Response */ #define BLE_L2CAP_SIG_OP_MOVE_CHAN_CONF_RSP 0x11 + +/** Update Request */ #define BLE_L2CAP_SIG_OP_UPDATE_REQ 0x12 + +/** Update Response */ #define BLE_L2CAP_SIG_OP_UPDATE_RSP 0x13 + +/** LE Credit Based Connection Request */ #define BLE_L2CAP_SIG_OP_LE_CREDIT_CONNECT_REQ 0x14 + +/** LE Credit Based Connection Response */ #define BLE_L2CAP_SIG_OP_LE_CREDIT_CONNECT_RSP 0x15 + +/** Credit Based Flow Control Credit */ #define BLE_L2CAP_SIG_OP_FLOW_CTRL_CREDIT 0x16 + +/** Credit Based Connection Request */ #define BLE_L2CAP_SIG_OP_CREDIT_CONNECT_REQ 0x17 + +/** Credit Based Connection Response */ #define BLE_L2CAP_SIG_OP_CREDIT_CONNECT_RSP 0x18 + +/** Credit Based Reconfiguration Request */ #define BLE_L2CAP_SIG_OP_CREDIT_RECONFIG_REQ 0x19 + +/** Credit Based Reconfiguration Response */ #define BLE_L2CAP_SIG_OP_CREDIT_RECONFIG_RSP 0x1A + +/** Signaling Command Maximum Value */ #define BLE_L2CAP_SIG_OP_MAX 0x1B +/** @} */ + +/** + * @defgroup ble_l2cap_signaling_err_codes Signaling Commands Error Codes + * @{ + */ + +/** Command Not Understood */ #define BLE_L2CAP_SIG_ERR_CMD_NOT_UNDERSTOOD 0x0000 + +/** Maximum Transmission Unit (MTU) Exceeded */ #define BLE_L2CAP_SIG_ERR_MTU_EXCEEDED 0x0001 + +/** Invalid CID */ #define BLE_L2CAP_SIG_ERR_INVALID_CID 0x0002 +/** @} */ + +/** + * @defgroup ble_l2cap_coc_err_codes Connection-Oriented Channels (CoC) Error Codes + * @{ + */ + +/** Connection Success */ #define BLE_L2CAP_COC_ERR_CONNECTION_SUCCESS 0x0000 + +/** Unknown LE Protocol/Service Multiplexer (PSM) */ #define BLE_L2CAP_COC_ERR_UNKNOWN_LE_PSM 0x0002 + +/** No Resources */ #define BLE_L2CAP_COC_ERR_NO_RESOURCES 0x0004 + +/** Insufficient Authentication */ #define BLE_L2CAP_COC_ERR_INSUFFICIENT_AUTHEN 0x0005 + +/** Insufficient Authorization */ #define BLE_L2CAP_COC_ERR_INSUFFICIENT_AUTHOR 0x0006 + +/** Insufficient Key Size */ #define BLE_L2CAP_COC_ERR_INSUFFICIENT_KEY_SZ 0x0007 + +/** Insufficient Encryption */ #define BLE_L2CAP_COC_ERR_INSUFFICIENT_ENC 0x0008 + +/** Invalid Source CID */ #define BLE_L2CAP_COC_ERR_INVALID_SOURCE_CID 0x0009 + +/** Source CID Already Used */ #define BLE_L2CAP_COC_ERR_SOURCE_CID_ALREADY_USED 0x000A + +/** Unacceptable Parameters */ #define BLE_L2CAP_COC_ERR_UNACCEPTABLE_PARAMETERS 0x000B + +/** Invalid Parameters */ #define BLE_L2CAP_COC_ERR_INVALID_PARAMETERS 0x000C +/** @} */ + +/** + * @defgroup ble_l2cap_reconfig_err_codes Channel Reconfiguration Error Codes + * @{ + */ + +/** Reconfiguration Succeeded */ #define BLE_L2CAP_ERR_RECONFIG_SUCCEED 0x0000 + +/** Reduction of Maximum Transmission Unit (MTU) Not Allowed */ #define BLE_L2CAP_ERR_RECONFIG_REDUCTION_MTU_NOT_ALLOWED 0x0001 + +/** Reduction of Maximum Packet Size (MPS) Not Allowed */ #define BLE_L2CAP_ERR_RECONFIG_REDUCTION_MPS_NOT_ALLOWED 0x0002 + +/** Invalid Destination CID */ #define BLE_L2CAP_ERR_RECONFIG_INVALID_DCID 0x0003 -#define BLE_L2CAP_ERR_RECONFIG_UNACCAPTED_PARAM 0x0004 +/** Unaccepted Parameters */ +#define BLE_L2CAP_ERR_RECONFIG_UNACCEPTED_PARAM 0x0004 + +/** @} */ + +/** + * @defgroup ble_l2cap_coc_event_types Connection-Oriented Channel (CoC) Event Types + * @{ + */ + +/** CoC Connected */ #define BLE_L2CAP_EVENT_COC_CONNECTED 0 + +/** CoC Disconnected */ #define BLE_L2CAP_EVENT_COC_DISCONNECTED 1 + +/** CoC Accept */ #define BLE_L2CAP_EVENT_COC_ACCEPT 2 + +/** CoC Data Received */ #define BLE_L2CAP_EVENT_COC_DATA_RECEIVED 3 + +/** CoC Transmission Unstalled */ #define BLE_L2CAP_EVENT_COC_TX_UNSTALLED 4 + +/** CoC Reconfiguration Completed */ #define BLE_L2CAP_EVENT_COC_RECONFIG_COMPLETED 5 + +/** CoC Peer Reconfigured */ #define BLE_L2CAP_EVENT_COC_PEER_RECONFIGURED 6 +/** @} */ + + +/** + * @brief Function signature for L2CAP signaling update event callback. + * + * This function is used to handle signaling update events in the L2CAP layer, + * such as changes in connection parameters. + * + * @param conn_handle The connection handle associated with the signaling update event. + * @param status The status of the signaling update event. + * @param arg A pointer to additional arguments passed to the callback function. + */ typedef void ble_l2cap_sig_update_fn(uint16_t conn_handle, int status, void *arg); +/** + * @brief Represents the signaling update in L2CAP. + * + * This structure holds the parameters required for initiating a signaling update in the L2CAP layer. + * It defines the connection interval, slave latency, and supervision timeout multiplier for the update. + */ struct ble_l2cap_sig_update_params { + /** + * The minimum desired connection interval in increments of 1.25 ms. + * This value defines the lower bound for the connection interval range. + */ uint16_t itvl_min; + + /** + * The maximum desired connection interval in increments of 1.25 ms. + * This value defines the upper bound for the connection interval range. + */ uint16_t itvl_max; + + /** + * The desired number of connection events that a slave device can skip. + * It specifies the maximum allowed latency between consecutive connection events. + */ uint16_t slave_latency; + + /** + * The desired supervision timeout multiplier. + * The supervision timeout defines the time limit for detecting the loss of a connection. + * This value is multiplied by the connection interval to determine the supervision timeout duration. + */ uint16_t timeout_multiplier; }; +/** + * @brief Initiate an L2CAP connection update procedure. + * + * This function initiates an L2CAP connection update procedure for the specified connection handle. + * The update procedure is used to modify the connection parameters, such as interval, latency, and timeout. + * + * @param conn_handle The connection handle of the L2CAP connection. + * + * @param params A pointer to a structure containing the desired update parameters. + * This includes the new connection interval, slave latency, and + * supervision timeout multiplier. + * + * @param cb The callback function to be called when the update request completes. + * The function signature for the callback is defined by `ble_l2cap_sig_update_fn`. + * + * @param cb_arg An optional argument to be passed to the callback function. + * + * @return 0 on success; + * A non-zero value on failure. + */ int ble_l2cap_sig_update(uint16_t conn_handle, struct ble_l2cap_sig_update_params *params, ble_l2cap_sig_update_fn *cb, void *cb_arg); +/** + * @brief Structure representing a L2CAP channel. + * + * It is used to maintain the state and track the properties of an L2CAP channel + * during its lifecycle. + */ struct ble_l2cap_chan; /** - * Represents a L2CAP-related event. + * @brief Represents a L2CAP-related event. + * * When such an event occurs, the host notifies the application by passing an * instance of this structure to an application-specified callback. */ @@ -234,55 +476,161 @@ struct ble_l2cap_event { }; }; +/** + * @brief Represents information about an L2CAP channel. + * + * This structure is typically used to retrieve or provide information about an existing L2CAP channel. + */ struct ble_l2cap_chan_info { + /** Source Channel Identifier. */ uint16_t scid; + + /** Destination Channel Identifier. */ uint16_t dcid; + + /** Local L2CAP Maximum Transmission Unit. */ uint16_t our_l2cap_mtu; + + /** Peer L2CAP Maximum Transmission Unit. */ uint16_t peer_l2cap_mtu; + + /** Protocol/Service Multiplexer of the channel. */ uint16_t psm; + + /** Local CoC Maximum Transmission Unit. */ uint16_t our_coc_mtu; + + /** Peer CoC Maximum Transmission Unit. */ uint16_t peer_coc_mtu; }; +/** + * @brief Function pointer type for handling L2CAP events. + * + * @param event A pointer to the L2CAP event structure. + * @param arg A pointer to additional arguments passed to the callback function. + * + * @return Integer value representing the status or result of the event handling. + */ typedef int ble_l2cap_event_fn(struct ble_l2cap_event *event, void *arg); -typedef void ble_l2cap_ping_fn(uint16_t conn_handle, uint32_t rtt_ms, - struct os_mbuf *om); - +/** + * @brief Get the connection handle associated with an L2CAP channel. + * + * This function retrieves the connection handle associated with the specified L2CAP channel. + * + * @param chan A pointer to the L2CAP channel structure. + * + * @return The connection handle associated with the L2CAP channel on success; + * A Bluetooth Host Error Code on failure: + * BLE_HS_CONN_HANDLE_NONE: if the provided channel pointer is NULL. + */ uint16_t ble_l2cap_get_conn_handle(struct ble_l2cap_chan *chan); + +/** + * @brief Create an L2CAP server. + * + * This function creates an L2CAP server with the specified Protocol/Service Multiplexer (PSM) and Maximum + * Transmission Unit (MTU) size. The server is used to accept incoming L2CAP connections from remote clients. + * When a connection request is received, the provided callback function will be invoked with the corresponding + * event information. + * + * @param psm The Protocol/Service Multiplexer (PSM) for the server. + * @param mtu The Maximum Transmission Unit (MTU) size for the server. + * @param cb Pointer to the callback function to be invoked when a connection request is received. + * @param cb_arg An optional argument to be passed to the callback function. + * + * @return 0 on success; + * A non-zero value on failure. + */ int ble_l2cap_create_server(uint16_t psm, uint16_t mtu, ble_l2cap_event_fn *cb, void *cb_arg); +/** + * @brief Initiate an L2CAP connection. + * + * This function initiates an L2CAP connection to a remote device with the specified connection handle, + * Protocol/Service Multiplexer (PSM), Maximum Transmission Unit (MTU) size, and receive SDU buffer. + * When the connection is established or if there is an error during the connection process, the provided + * callback function will be invoked with the corresponding event information. + * + * @param conn_handle The connection handle for the remote device. + * @param psm The Protocol/Service Multiplexer (PSM) for the connection. + * @param mtu The Maximum Transmission Unit (MTU) size for the connection. + * @param sdu_rx Pointer to the receive Service Data Unit (SDU) buffer. + * @param cb Pointer to the callback function to be invoked when the connection is established. + * @param cb_arg An optional argument to be passed to the callback function. + * + * @return 0 on success; + * A non-zero value on failure. + */ int ble_l2cap_connect(uint16_t conn_handle, uint16_t psm, uint16_t mtu, struct os_mbuf *sdu_rx, ble_l2cap_event_fn *cb, void *cb_arg); + +/** + * @brief Disconnect an L2CAP channel. + * + * This function disconnects the specified L2CAP connection oriented channel by sending a disconnect signal. + * + * @param chan Pointer to the L2CAP channel structure representing the channel to disconnect. + * + * @return 0 on success; + * A non-zero value on failure. + */ int ble_l2cap_disconnect(struct ble_l2cap_chan *chan); + +/** + * @brief Send an SDU (Service Data Unit) over an L2CAP channel. + * + * This function sends an SDU over the specified L2CAP channel. The SDU is encapsulated + * in L2CAP frames and transmitted to the remote device. + * + * @param chan Pointer to the L2CAP channel structure representing the channel to send the SDU on. + * @param sdu_tx Pointer to the os_mbuf structure containing the SDU (Service Data Unit) to send. + * + * @return 0 on success; + * BLE_HS_ESTALLED: if there was not enough credits available to send whole SDU. + * The application needs to wait for the event 'BLE_L2CAP_EVENT_COC_TX_UNSTALLED' + * before being able to transmit more data; + * Another non-zero value on failure. + */ int ble_l2cap_send(struct ble_l2cap_chan *chan, struct os_mbuf *sdu_tx); + +/** + * @brief Check if the L2CAP channel is ready to receive an SDU. + * + * This function checks if the specified L2CAP channel is ready to receive an SDU (Service Data Unit). + * It can be used to determine if the channel is in a state where it can accept incoming data. + * + * @param chan Pointer to the L2CAP channel structure to check. + * @param sdu_rx Pointer to the os_mbuf structure to receive the incoming SDU. + * + * @return 0 if the channel is ready to receive an SDU; + * A non-zero value on failure. + */ int ble_l2cap_recv_ready(struct ble_l2cap_chan *chan, struct os_mbuf *sdu_rx); -int ble_l2cap_get_chan_info(struct ble_l2cap_chan *chan, struct ble_l2cap_chan_info *chan_info); /** - * Send an ECHO_REQ packet over the L2CAP signalling channel for the given - * connection - * - * @param conn_handle Connection handle - * @param cb Function called once the corresponding ECHO_RSP is - * received. May be NULL. - * @param data User payload appended to the ECHO_REQ packet, may be - * NULL - * @param data_len Length of @p data in bytes. Set to 0 to omit any user - * payload - * - * @return 0 on success - * BLE_HS_EBADDATA if given payload is invalid - * BLE_HS_ENOMEM if request packet cannot be allocated - * BLE_HS_ENOTCONN if not connected + * @brief Get information about an L2CAP channel. + * + * This function retrieves information about the specified L2CAP channel and populates + * the provided `ble_l2cap_chan_info` structure with the channel's details. + * + * @param chan Pointer to the L2CAP channel structure to retrieve information from. + * @param chan_info Pointer to the `ble_l2cap_chan_info` structure to populate with channel information. + * + * @return 0 on success; + * A non-zero value on failure. */ -int ble_l2cap_ping(uint16_t conn_handle, ble_l2cap_ping_fn cb, - const void *data, uint16_t data_len); +int ble_l2cap_get_chan_info(struct ble_l2cap_chan *chan, struct ble_l2cap_chan_info *chan_info); #ifdef __cplusplus } #endif +/** + * @} + */ + #endif diff --git a/nimble/host/include/host/ble_sm.h b/nimble/host/include/host/ble_sm.h index ceebb85643..503e1310a4 100644 --- a/nimble/host/include/host/ble_sm.h +++ b/nimble/host/include/host/ble_sm.h @@ -20,73 +20,229 @@ #ifndef H_BLE_SM_ #define H_BLE_SM_ +/** + * @brief Bluetooth Security Manager (SM) + * @defgroup bt_sm Bluetooth Security Manager (SM) + * @ingroup bt_host + * @{ + */ + #include #include "syscfg/syscfg.h" +#include +#include "nimble/ble.h" #ifdef __cplusplus extern "C" { #endif +/** + * @defgroup ble_sm_err Security Manager (SM) Error Codes + * @{ + */ + +/** SM Error Code: Success */ +#define BLE_SM_ERR_SUCCESS 0x00 + +/** SM Error Code: Passkey entry failed */ #define BLE_SM_ERR_PASSKEY 0x01 + +/** SM Error Code: Out Of Band (OOB) not available */ #define BLE_SM_ERR_OOB 0x02 + +/** SM Error Code: Authentication Requirements */ #define BLE_SM_ERR_AUTHREQ 0x03 + +/** SM Error Code: Confirm Value failed */ #define BLE_SM_ERR_CONFIRM_MISMATCH 0x04 + +/** SM Error Code: Pairing Not Supported */ #define BLE_SM_ERR_PAIR_NOT_SUPP 0x05 + +/** SM Error Code: Encryption Key Size */ #define BLE_SM_ERR_ENC_KEY_SZ 0x06 + +/** SM Error Code: Command Not Supported */ #define BLE_SM_ERR_CMD_NOT_SUPP 0x07 + +/** SM Error Code: Unspecified Reason */ #define BLE_SM_ERR_UNSPECIFIED 0x08 + +/** SM Error Code: Repeated Attempts */ #define BLE_SM_ERR_REPEATED 0x09 + +/** SM Error Code: Invalid Parameters */ #define BLE_SM_ERR_INVAL 0x0a + +/** SM Error Code: DHKey Check failed */ #define BLE_SM_ERR_DHKEY 0x0b + +/** SM Error Code: Numeric Comparison failed */ #define BLE_SM_ERR_NUMCMP 0x0c + +/** SM Error Code: Pairing in progress */ #define BLE_SM_ERR_ALREADY 0x0d + +/** SM Error Code: Cross-transport Key Derivation/Generation not allowed */ #define BLE_SM_ERR_CROSS_TRANS 0x0e -#define BLE_SM_ERR_MAX_PLUS_1 0x0f +/** SM Error Code: Key Rejected */ +#define BLE_SM_ERR_KEY_REJ 0x0f + +/** SM Error Code: Out Of Boundary Code Value */ +#define BLE_SM_ERR_MAX_PLUS_1 0x10 + +/** @} */ + +/** + * @defgroup ble_sm_pair_alg Security Manager (SM) Pairing Algorithms + * @{ + */ + +/** SM Pairing Algorithm: Just Works */ #define BLE_SM_PAIR_ALG_JW 0 + +/** SM Pairing Algorithm: Passkey Entry */ #define BLE_SM_PAIR_ALG_PASSKEY 1 + +/** SM Pairing Algorithm: Out Of Band */ #define BLE_SM_PAIR_ALG_OOB 2 + +/** SM Pairing Algorithm: Numeric Comparison */ #define BLE_SM_PAIR_ALG_NUMCMP 3 +/** @} */ + +/** + * @defgroup ble_sm_pair_key_dist Security Manager (SM) Key Distribution Flags + * @{ + */ + +/** SM Key Distribution: Distribute Long Term Key (LTK) */ #define BLE_SM_PAIR_KEY_DIST_ENC 0x01 + +/** SM Key Distribution: Distribute Identity Resolving Key (IRK) */ #define BLE_SM_PAIR_KEY_DIST_ID 0x02 + +/** SM Key Distribution: Distribute Connection Signature Resolving Key (CSRK) */ #define BLE_SM_PAIR_KEY_DIST_SIGN 0x04 + +/** SM Key Distribution: Derive the Link Key from the LTK */ #define BLE_SM_PAIR_KEY_DIST_LINK 0x08 + +/** SM Key Distribution: Reserved For Future Use */ #define BLE_SM_PAIR_KEY_DIST_RESERVED 0xf0 +/** @} */ + +/** + * @defgroup ble_sm_io_cap Security Manager (SM) Input/Output Capabilities + * @{ + */ + +/** SM IO Capabilities: Display Only */ #define BLE_SM_IO_CAP_DISP_ONLY 0x00 + +/** SM IO Capabilities: Display Yes No */ #define BLE_SM_IO_CAP_DISP_YES_NO 0x01 + +/** SM IO Capabilities: Keyboard Only */ #define BLE_SM_IO_CAP_KEYBOARD_ONLY 0x02 + +/** SM IO Capabilities: No Input No Output */ #define BLE_SM_IO_CAP_NO_IO 0x03 + +/** SM IO Capabilities: Keyboard Display */ #define BLE_SM_IO_CAP_KEYBOARD_DISP 0x04 + +/** SM IO Capabilities: Reserved For Future Use */ #define BLE_SM_IO_CAP_RESERVED 0x05 +/** @} */ + +/** + * @defgroup ble_sm_pair_oob Security Manager (SM) Out Of Band Data (OOB) Flags + * @{ + */ + +/** SM OOB: Out Of Band Data Not Available */ #define BLE_SM_PAIR_OOB_NO 0x00 + +/** SM OOB: Out Of Band Data Available */ #define BLE_SM_PAIR_OOB_YES 0x01 + +/** SM OOB: Reserved For Future Use */ #define BLE_SM_PAIR_OOB_RESERVED 0x02 +/** @} */ + +/** + * @defgroup ble_sm_authreq Security Manager (SM) Authentication Requirements Flags + * @{ + */ + +/** SM Authentication Requirement: Bonding */ #define BLE_SM_PAIR_AUTHREQ_BOND 0x01 + +/** SM Authentication Requirement: MITM protection */ #define BLE_SM_PAIR_AUTHREQ_MITM 0x04 + +/** SM Authentication Requirement: Secure Connections */ #define BLE_SM_PAIR_AUTHREQ_SC 0x08 + +/** SM Authentication Requirement: Keypress notifications */ #define BLE_SM_PAIR_AUTHREQ_KEYPRESS 0x10 + +/** SM Authentication Requirement: Reserved For Future Use */ #define BLE_SM_PAIR_AUTHREQ_RESERVED 0xe2 +/** @} */ + +/** + * @defgroup ble_sm_pair_key_sz Security Manager (SM) Key Sizes + * @{ + */ + +/** SM Key Size: Minimum supported encryption key size in octets */ #define BLE_SM_PAIR_KEY_SZ_MIN 7 + +/** SM Key Size: Maximum supported encryption key size in octets */ #define BLE_SM_PAIR_KEY_SZ_MAX 16 -/* +/** @} */ + +/** + * @defgroup ble_sm_ioact Security Manager (SM) Key Generation Action + * @{ * The security manager asks the application to perform a key generation * action. The application passes the passkey back to SM via * ble_sm_inject_io(). */ + +/** SM IO Action: None (Just Works pairing) */ #define BLE_SM_IOACT_NONE 0 + +/** SM IO Action: Out Of Band (OOB) */ #define BLE_SM_IOACT_OOB 1 + +/** SM IO Action: Input (Passkey Entry) */ #define BLE_SM_IOACT_INPUT 2 + +/** SM IO Action: Passkey Display */ #define BLE_SM_IOACT_DISP 3 + +/** SM IO Action: Numeric Comparison */ #define BLE_SM_IOACT_NUMCMP 4 + +/** SM IO Action: Out Of Band (OOB) Secure Connections */ #define BLE_SM_IOACT_OOB_SC 5 + +/** SM IO Action: Out Of Boundary Code Value */ #define BLE_SM_IOACT_MAX_PLUS_ONE 6 +/** @} */ + +/** Represents Out Of Band (OOB) data used in Secure Connections pairing */ struct ble_sm_sc_oob_data { /** Random Number. */ uint8_t r[16]; @@ -95,24 +251,100 @@ struct ble_sm_sc_oob_data { uint8_t c[16]; }; +/** Represents Input/Output data for Security Manager used during pairing process */ struct ble_sm_io { + /** Pairing action, indicating the type of pairing method. Can be one of the + * following: + * o BLE_SM_IOACT_NONE + * o BLE_SM_IOACT_OOB + * o BLE_SM_IOACT_INPUT + * o BLE_SM_IOACT_DISP + * o BLE_SM_IOACT_NUMCMP + * o BLE_SM_IOACT_OOB_SC + */ uint8_t action; + + /** Union holding different types of pairing data. The valid field is inferred + * from the action field. */ union { + /** Passkey value between 000000 and 999999. + * Valid for the following actions: + * o BLE_SM_IOACT_INPUT + * o BLE_SM_IOACT_DISP + */ uint32_t passkey; + + /** Temporary Key random value used in Legacy Pairing. + * Valid for the following actions: + * o BLE_SM_IOACT_OOB + */ uint8_t oob[16]; + + /** Numeric Comparison acceptance indicator. + * Valid for the following actions: + * o BLE_SM_IOACT_NUMCMP + */ uint8_t numcmp_accept; + + /** Out Of Band (OOB) data used in Secure Connections. + * Valid for the following actions: + * o BLE_SM_IOACT_OOB_SC + */ struct { - struct ble_sm_sc_oob_data *local; + /** Remote Secure Connections Out Of Band (OOB) data */ struct ble_sm_sc_oob_data *remote; + /** Local Secure Connections Out Of Band (OOB) data */ + struct ble_sm_sc_oob_data *local; } oob_sc_data; }; }; +/** + * Generates Out of Band (OOB) data used during the authentication process. + * The data consists of 128-bit Random Number and 128-bit Confirm Value. + * + * @param oob_data A pointer to the structure where the generated + * OOB data will be stored. + * + * @return 0 on success; + * Non-zero on failure. + */ int ble_sm_sc_oob_generate_data(struct ble_sm_sc_oob_data *oob_data); +#if MYNEWT_VAL(BLE_SM_CSIS_SIRK) +/** + * Resolves CSIS RSI to check if advertising device is part of the same Coordinated Set, + * as the device with specified SIRK + * + * @param rsi RSI value from Advertising Data + * @param sirk SIRK + * @param ltk_peer_addr If SIRK is in plaintext form this should be set to NULL, + * otherwise peer address should be passed here to get + * LTK and decrypt SIRK + * + * @return 0 if RSI was resolved succesfully; nonzero on failure. + */ +int ble_sm_csis_resolve_rsi(const uint8_t *rsi, const uint8_t *sirk, + const ble_addr_t *ltk_peer_addr); +#endif + #if NIMBLE_BLE_SM +/** + * @brief Passes the IO data from an application to the Security Manager during the pairing + * process. + * + * It should be used after a pairing method has been established for given connection + * and once the appropriate key generation information (e.g. passkey) has been obtained. + * + * @param conn_handle The connection handle of the relevant connection. + * @param pkey A pointer to the structure where IO data is stored. + * + * @return 0 on success; + * Non-zero on failure. + */ int ble_sm_inject_io(uint16_t conn_handle, struct ble_sm_io *pkey); #else +/** This macro replaces the function to return BLE_HS_ENOTSUP when SM is disabled. */ #define ble_sm_inject_io(conn_handle, pkey) \ ((void)(conn_handle), BLE_HS_ENOTSUP) #endif @@ -121,4 +353,8 @@ int ble_sm_inject_io(uint16_t conn_handle, struct ble_sm_io *pkey); } #endif -#endif +/** + * @} + */ + +#endif /* H_BLE_SM_ */ diff --git a/nimble/host/include/host/ble_store.h b/nimble/host/include/host/ble_store.h index 30a5666cfe..83b1c4f15f 100644 --- a/nimble/host/include/host/ble_store.h +++ b/nimble/host/include/host/ble_store.h @@ -20,6 +20,13 @@ #ifndef H_BLE_STORE_ #define H_BLE_STORE_ +/** + * @brief Bluetooth Store API + * @defgroup bt_store Bluetooth Store + * @ingroup bt_host + * @{ + */ + #include #include "nimble/ble.h" @@ -27,16 +34,35 @@ extern "C" { #endif +/** + * @defgroup bt_store_obj_types Bluetooth Store Object Types + * @ingroup bt_host + * @{ + */ +/** Object type: Our security material. */ #define BLE_STORE_OBJ_TYPE_OUR_SEC 1 + +/** Object type: Peer security material. */ #define BLE_STORE_OBJ_TYPE_PEER_SEC 2 + +/** Object type: Client Characteristic Configuration Descriptor. */ #define BLE_STORE_OBJ_TYPE_CCCD 3 +/** @} */ + +/** + * @defgroup bt_store_event_types Bluetooth Store Event Types + * @ingroup bt_host + * @{ + */ /** Failed to persist record; insufficient storage capacity. */ #define BLE_STORE_EVENT_OVERFLOW 1 /** About to execute a procedure that may fail due to overflow. */ #define BLE_STORE_EVENT_FULL 2 +/** @} */ + /** * Used as a key for lookups of security material. This struct corresponds to * the following store object types: @@ -50,14 +76,6 @@ struct ble_store_key_sec { */ ble_addr_t peer_addr; - /** Key by ediv; ediv_rand_present=0 means don't key off ediv. */ - uint16_t ediv; - - /** Key by rand_num; ediv_rand_present=0 means don't key off rand_num. */ - uint64_t rand_num; - - unsigned ediv_rand_present:1; - /** Number of results to skip; 0 means retrieve the first match. */ uint8_t idx; }; @@ -69,21 +87,33 @@ struct ble_store_key_sec { * o BLE_STORE_OBJ_TYPE_PEER_SEC */ struct ble_store_value_sec { + /** Peer address for which the security material is stored. */ ble_addr_t peer_addr; + /** Encryption key size. */ uint8_t key_size; + /** Encrypted Diversifier used for encryption key generation. */ uint16_t ediv; + /** Random number used for encryption key generation. */ uint64_t rand_num; + /** Long Term Key. */ uint8_t ltk[16]; + /** Flag indicating whether Long Term Key is present. */ uint8_t ltk_present:1; + /** Identity Resolving Key. */ uint8_t irk[16]; + /** Flag indicating whether Identity Resolving Key is present. */ uint8_t irk_present:1; + /** Connection Signature Resolving Key. */ uint8_t csrk[16]; + /** Flag indicating if Connection Signature Resolving Key is present. */ uint8_t csrk_present:1; + /** Flag indicating whether the connection is authenticated. */ unsigned authenticated:1; + /** Flag indicating Secure Connections support. */ uint8_t sc:1; }; @@ -114,9 +144,13 @@ struct ble_store_key_cccd { * This struct corresponds to the BLE_STORE_OBJ_TYPE_CCCD store object type. */ struct ble_store_value_cccd { + /** The peer address associated with the stored CCCD. */ ble_addr_t peer_addr; + /** The handle of the characteristic value. */ uint16_t chr_val_handle; + /** Flags associated with the CCCD. */ uint16_t flags; + /** Flag indicating whether the value has changed. */ unsigned value_changed:1; }; @@ -125,7 +159,9 @@ struct ble_store_value_cccd { * object type code to indicate which field is valid. */ union ble_store_key { + /** Key for security material store lookups. */ struct ble_store_key_sec sec; + /** Key for Client Characteristic Configuration Descriptor store lookups. */ struct ble_store_key_cccd cccd; }; @@ -134,10 +170,13 @@ union ble_store_key { * code to indicate which field is valid. */ union ble_store_value { + /** Stored security material. */ struct ble_store_value_sec sec; + /** Stored Client Characteristic Configuration Descriptor. */ struct ble_store_value_cccd cccd; }; +/** Represents an event associated with the BLE Store. */ struct ble_store_status_event { /** * The type of event being reported; one of the BLE_STORE_EVENT_TYPE_[...] @@ -178,6 +217,48 @@ struct ble_store_status_event { }; }; +/** Generate LTK, EDIT and Rand. */ +#define BLE_STORE_GEN_KEY_LTK 0x01 +/** Generate IRK. */ +#define BLE_STORE_GEN_KEY_IRK 0x02 +/** Generate CSRK. */ +#define BLE_STORE_GEN_KEY_CSRK 0x03 + +/** Represents a storage for generated key. */ +struct ble_store_gen_key { + union { + /** Long Term Key (LTK) for peripheral role. */ + uint8_t ltk_periph[16]; + /** Identity Resolving Key (IRK). */ + uint8_t irk[16]; + /** Connection Signature Resolving Key (CSRK). */ + uint8_t csrk[16]; + }; + /** Encrypted Diversifier (EDIV). */ + uint16_t ediv; + /** Random Number for key generation. */ + uint64_t rand; +}; + +/** + * Generates key required by security module. + * This can be used to use custom routines to generate keys instead of simply + * randomizing them. + * + * \p conn_handle is set to \p BLE_HS_CONN_HANDLE_NONE if key is not requested + * for a specific connection (e.g. an IRK). + * + * @param key Key that shall be generated. + * @param gen_key Storage for generated key. + * @param conn_handle Connection handle for which keys are generated. + * + * @return 0 if keys were generated successfully + * Other nonzero on error. + */ +typedef int ble_store_gen_key_fn(uint8_t key, + struct ble_store_gen_key *gen_key, + uint16_t conn_handle); + /** * Searches the store for an object matching the specified criteria. If a * match is found, it is read from the store and the dst parameter is populated @@ -245,59 +326,432 @@ typedef int ble_store_delete_fn(int obj_type, const union ble_store_key *key); typedef int ble_store_status_fn(struct ble_store_status_event *event, void *arg); +/** + * Reads data from a storage. + * + * @param obj_type The type of the object to read. + * @param key Pointer to the key used for the lookup. + * @param val Pointer to store the retrieved data. + * + * @return 0 if the read operation is successful; + * Non-zero on error. + */ int ble_store_read(int obj_type, const union ble_store_key *key, union ble_store_value *val); + +/** + * Writes data to a storage. + * + * @param obj_type The type of the object to write. + * @param val Pointer to the data to be written. + * + * @return 0 if the write operation is successful; + * Non-zero on error. + */ int ble_store_write(int obj_type, const union ble_store_value *val); + +/** + * Deletes data from a storage. + * + * @param obj_type The type of the object to delete. + * @param key Pointer to the key used for the lookup. + * + * @return 0 if the deletion operation is successful; + * Non-zero on error. + */ int ble_store_delete(int obj_type, const union ble_store_key *key); + +/** + * @brief Handles a storage overflow event. + * + * This function is called when a storage overflow event occurs. It constructs + * an event structure and passes it to the general storage status handler using + * the `ble_store_status` function. + * + * @param obj_type The type of the object for which the overflow + * occurred. + * @param value Pointer to the value associated with the + * overflow. + * + * @return 0 if the event is successfully handled; + * Non-zero on error. + */ int ble_store_overflow_event(int obj_type, const union ble_store_value *value); + +/** + * @brief Handles a storage full event. + * + * This function is called when a storage full event occurs, typically during + * a write operation. It constructs an event structure and passes it to the + * general storage status handler using the `ble_store_status` function. + * + * @param obj_type The type of the object that may fail to be + * written. + * @param conn_handle The connection handle associated with the write + * operation. + * + * @return 0 if the event is successfully handled; + * Non-zero on error. + */ int ble_store_full_event(int obj_type, uint16_t conn_handle); +/** + * @brief Reads our security material from a storage. + * + * This function reads our security material from a storage, using the provided + * key and populates the `ble_store_value_sec` structure with the retrieved data. + * + * @param key_sec The key identifying the security material to + * read. + * @param value_sec A pointer to a `ble_store_value_sec` structure + * where the retrieved security material will + * be stored. + * + * @return 0 if the security material was successfully read + * from a storage; + * Non-zero on error. + */ int ble_store_read_our_sec(const struct ble_store_key_sec *key_sec, struct ble_store_value_sec *value_sec); + +/** + * @brief Writes our security material to a storage. + * + * This function writes our security material to a storage, using the provided + * `ble_store_value_sec` structure. + * + * @param value_sec A pointer to a `ble_store_value_sec` structure + * containing the security material to be + * stored. + * + * @return 0 if the security material was successfully + * written to a storage; + * Non-zero on error. + */ int ble_store_write_our_sec(const struct ble_store_value_sec *value_sec); + +/** + * @brief Deletes our security material from a storage. + * + * This function deletes our security material from a storage, identified by the + * provided `ble_store_key_sec`. + * + * @param key_sec A pointer to a `ble_store_key_sec` structure + * that specifies the security material to be + * deleted. + * + * @return 0 if the security material was successfully + * deleted from a storage; + * Non-zero on error. + */ int ble_store_delete_our_sec(const struct ble_store_key_sec *key_sec); + +/** + * @brief Reads peer security material from a storage. + * + * This function reads peer security material from a storage, identified by the + * provided `ble_store_key_sec`. The retrieved security material is stored in + * the `ble_store_value_sec` structure. + * + * @param key_sec A pointer to a `ble_store_key_sec` structure + * that specifies the peer's security material + * to be retrieved. + * @param value_sec A pointer to a `ble_store_value_sec` structure + * where the retrieved security material will + * be stored. + * + * @return 0 if the security material was successfully + * retrieved; + * Non-zero on error. + */ int ble_store_read_peer_sec(const struct ble_store_key_sec *key_sec, struct ble_store_value_sec *value_sec); + +/** + * @brief Writes peer security material to a storage. + * + * This function writes the provided peer security material, specified by a + * `ble_store_value_sec` structure, to a storage. Additionally, if the provided + * peer IRK is present and the peer address is not `BLE_ADDR_ANY`, it is also + * written to the controller's key cache. + * + * @param value_sec A pointer to a `ble_store_value_sec` structure + * containing the peer's security material + * to be written. + * + * @return 0 if the peer's security material was + * successfully written to a storage and + * the peer IRK was added to the controller key + * cache if present; + * Non-zero on error. + */ int ble_store_write_peer_sec(const struct ble_store_value_sec *value_sec); + +/** + * @brief Deletes peer security material from a storage. + * + * This function deletes the peer security material associated with the provided + * key from a storage. + * + * @param key_sec A pointer to a `ble_store_key_sec` structure + * identifying the security material to be + * deleted. + * + * @return 0 if the peer's security material was + * successfully deleted from a storage; + * Non-zero on error. + */ int ble_store_delete_peer_sec(const struct ble_store_key_sec *key_sec); + +/** + * @brief Reads a Client Characteristic Configuration Descriptor (CCCD) from + * a storage. + * + * This function reads a CCCD from a storage based on the provided key and + * stores the retrieved value in the specified output structure. + * + * @param key A pointer to a `ble_store_key_cccd` structure + * representing the key to identify the CCCD to + * be read. + * @param out_value A pointer to a `ble_store_value_cccd` structure + * to store the CCCD value read from a storage. + * + * @return 0 if the CCCD was successfully read and stored + * in the `out_value` structure; + * Non-zero on error. + */ int ble_store_read_cccd(const struct ble_store_key_cccd *key, struct ble_store_value_cccd *out_value); + +/** + * @brief Writes a Client Characteristic Configuration Descriptor (CCCD) to + * a storage. + * + * This function writes a CCCD to a storage based on the provided value. + * + * @param value A pointer to a `ble_store_value_cccd` structure + * representing the CCCD value to be written to + * a storage. + * + * @return 0 if the CCCD was successfully written to + * a storage; + * Non-zero on error. + */ int ble_store_write_cccd(const struct ble_store_value_cccd *value); + +/** + * @brief Deletes a Client Characteristic Configuration Descriptor (CCCD) from + * a storage. + * + * This function deletes a CCCD from a storage based on the provided key. + * + * @param key A pointer to a `ble_store_key_cccd` structure + * identifying the CCCD to be deleted from + * a storage. + * + * @return 0 if the CCCD was successfully deleted from + * a storage; + * Non-zero on error. + */ int ble_store_delete_cccd(const struct ble_store_key_cccd *key); + +/** + * @brief Generates a storage key for a security material entry from its value. + * + * This function generates a storage key for a security material entry based on + * the provided security material value. + * + * @param out_key A pointer to a `ble_store_key_sec` structure + * where the generated key will be stored. + * @param value A pointer to a `ble_store_value_sec` structure + * containing the security material value from + * which the key will be generated. + */ void ble_store_key_from_value_sec(struct ble_store_key_sec *out_key, const struct ble_store_value_sec *value); + +/** + * @brief Generates a storage key for a CCCD entry from its value. + * + * This function generates a storage key for a Client Characteristic + * Configuration Descriptor (CCCD) entry based on the provided CCCD value. + * + * @param out_key A pointer to a `ble_store_key_cccd` structure + * where the generated key will be stored. + * @param value A pointer to a `ble_store_value_cccd` structure + * containing the CCCD value from which the key + * will be generated. + */ void ble_store_key_from_value_cccd(struct ble_store_key_cccd *out_key, const struct ble_store_value_cccd *value); + +/** + * @brief Generates a storage key from a value based on the object type. + * + * This function generates a storage key from a value based on the provided + * object type. + * + * @param obj_type The type of object for which the key is + * generated. + * @param out_key A pointer to a `ble_store_key` union where + * the generated key will be stored. + * @param value A pointer to a `ble_store_value` union + * containing the value from which the key will + * be generated. + */ void ble_store_key_from_value(int obj_type, union ble_store_key *out_key, const union ble_store_value *value); + +/** + * @brief Function signature for the storage iterator callback. + * + * This function signature represents a callback function used for iterating + * over stored objects in a store. + * + * @param obj_type The type of object being iterated. + * @param val A pointer to the stored value of the object. + * @param cookie A user-defined pointer for additional data. + * + * @return 0 to continue iterating; + * Non-zero value to stop the iteration. + */ typedef int ble_store_iterator_fn(int obj_type, union ble_store_value *val, void *cookie); + +/** + * @brief Iterates over stored objects of a specific type in a store. + * + * This function allows you to iterate over stored objects of a specific type in + * the store and invoke a user-defined callback function for each object. + * + * @param obj_type The type of objects to iterate over. + * @param callback A pointer to the user-defined callback function + * that will be invoked for each stored object. + * @param cookie A user-defined pointer for additional data to + * pass to the callback function. + * + * @return 0 on success; + * Non-zero on error. + */ int ble_store_iterate(int obj_type, ble_store_iterator_fn *callback, void *cookie); + +/** + * @brief Clears all stored objects from a store. + * + * This function removes all stored objects from a store, effectively clearing + * the storage. + * + * @return 0 on success; + * Non-zero on error. + */ int ble_store_clear(void); -/*** Utility functions. */ +/** + * @defgroup ble_store_util Bluetooth Store Utility Functions + * @{ + */ +/** + * Retrieves the set of peer addresses for which a bond has been established. + * + * @param out_peer_id_addrs The set of bonded peer addresses. + * @param out_num_peers The number of bonds that have been established. + * @param max_peers The capacity of the destination buffer. + * + * @return 0 on success; + * BLE_HS_ENOMEM if the destination buffer is too + * small; + * Other non-zero on error. + */ int ble_store_util_bonded_peers(ble_addr_t *out_peer_id_addrs, int *out_num_peers, int max_peers); + +/** + * Deletes all entries from a store that match the specified key. + * + * @param type The type of store entry to delete. + * @param key Entries matching this key get deleted. + * + * @return 0 on success; + * Non-zero on error. + */ int ble_store_util_delete_all(int type, const union ble_store_key *key); + +/** + * Deletes all entries from a store that are attached to the specified peer + * address. This function deletes security entries and CCCD records. + * + * @param peer_id_addr Entries with this peer address get deleted. + * + * @return 0 on success; + * Non-zero on error. + */ int ble_store_util_delete_peer(const ble_addr_t *peer_id_addr); + +/** + * @brief Deletes the oldest peer from a store. + * + * This function deletes the oldest bonded peer from the storage. If there are + * no bonded peers in the storage, the function returns success. + * + * @return 0 on success; + * Non-zero on error. + */ int ble_store_util_delete_oldest_peer(void); + +/** + * @brief Counts the number of stored objects of a given type. + * + * This function counts the number of stored objects of a specific type in + * a store and returns the count in the `out_count` parameter. + * + * @param type The type of the objects to count. + * @param out_count The count of stored objects. + * + * @return 0 on success; + * Non-zero on error. + */ int ble_store_util_count(int type, int *out_count); + +/** + * @brief Round-robin status callback for handling store status events. + * + * This function handles store status events, particularly in cases where there + * is insufficient storage capacity for new records. + * It attempts to resolve overflow issues by deleting the oldest bond and + * proceeds with the persist operation. + * + * @note This behavior may not be suitable for production use as it may lead to + * removal of important bonds by less relevant peers. It is more useful for + * demonstration purposes and sample applications. + * + * @param event A pointer to the store status event. + * @param arg A pointer to additional user-defined arguments. + * + * @return 0 on success; + * Non-zero on error. + */ int ble_store_util_status_rr(struct ble_store_status_event *event, void *arg); +/** @} */ + #ifdef __cplusplus } #endif +/** + * @} + */ + #endif diff --git a/nimble/host/include/host/ble_uuid.h b/nimble/host/include/host/ble_uuid.h index d3576c5950..16ba4157fa 100644 --- a/nimble/host/include/host/ble_uuid.h +++ b/nimble/host/include/host/ble_uuid.h @@ -56,63 +56,161 @@ typedef struct { /** 16-bit UUID */ typedef struct { + /** Generic UUID structure */ ble_uuid_t u; + + /** 16-bit UUID value */ uint16_t value; } ble_uuid16_t; /** 32-bit UUID */ typedef struct { + /** Generic UUID structure */ ble_uuid_t u; + + /** 32-bit UUID value */ uint32_t value; } ble_uuid32_t; /** 128-bit UUID */ typedef struct { + /** Generic UUID structure */ ble_uuid_t u; + + /** 128-bit UUID value */ uint8_t value[16]; } ble_uuid128_t; /** Universal UUID type, to be used for any-UUID static allocation */ typedef union { + /** Generic UUID structure */ ble_uuid_t u; + + /** 16-bit UUID structure */ ble_uuid16_t u16; + + /** 32-bit UUID structure */ ble_uuid32_t u32; + + /** 128-bit UUID structure */ ble_uuid128_t u128; } ble_uuid_any_t; +/** + * @brief Macro for initializing a 16-bit UUID. + * + * This macro initializes a 16-bit UUID with the provided value. + * + * @param uuid16 The value of the 16-bit UUID. + * + * @return The initialized 16-bit UUID structure. + */ #define BLE_UUID16_INIT(uuid16) \ { \ - .u.type = BLE_UUID_TYPE_16, \ + .u = { \ + .type = BLE_UUID_TYPE_16, \ + }, \ .value = (uuid16), \ } +/** + * @brief Macro for initializing a 32-bit UUID. + * + * This macro initializes a 32-bit UUID with the provided value. + * + * @param uuid32 The value of the 32-bit UUID. + * + * @return The initialized 32-bit UUID structure. + */ #define BLE_UUID32_INIT(uuid32) \ { \ - .u.type = BLE_UUID_TYPE_32, \ + .u = { \ + .type = BLE_UUID_TYPE_32, \ + }, \ .value = (uuid32), \ } -#define BLE_UUID128_INIT(uuid128...) \ +/** + * @brief Macro for initializing a 128-bit UUID. + * + * This macro initializes a 128-bit UUID with the provided value. + * + * @param ... A sequence of values in little-endian order representing + * the 128-bit UUID. + * + * @return The initialized 128-bit UUID structure. + */ +#define BLE_UUID128_INIT(uuid128 ...) \ { \ - .u.type = BLE_UUID_TYPE_128, \ + .u = { \ + .type = BLE_UUID_TYPE_128, \ + }, \ .value = { uuid128 }, \ } +/** + * @brief Macro for declaring a pointer to a 16-bit UUID structure initialized + * with a specific 16-bit UUID value. + * + * @param uuid16 The 16-bit UUID value to initialize the structure with. + * + * @return Pointer to a `ble_uuid_t` structure. + */ #define BLE_UUID16_DECLARE(uuid16) \ ((ble_uuid_t *) (&(ble_uuid16_t) BLE_UUID16_INIT(uuid16))) +/** + * @brief Macro for declaring a pointer to a 32-bit UUID structure initialized + * with a specific 32-bit UUID value. + * + * @param uuid32 The 32-bit UUID value to initialize the structure with. + * + * @return Pointer to a `ble_uuid_t` structure. + */ #define BLE_UUID32_DECLARE(uuid32) \ ((ble_uuid_t *) (&(ble_uuid32_t) BLE_UUID32_INIT(uuid32))) +/** + * @brief Macro for declaring a pointer to a 128-bit UUID structure initialized + * with specific 128-bit UUID values. + * + * @param uuid128 The 128-bit UUID value to initialize the structure with. + * + * @return Pointer to a `ble_uuid_t` structure. + */ #define BLE_UUID128_DECLARE(uuid128...) \ ((ble_uuid_t *) (&(ble_uuid128_t) BLE_UUID128_INIT(uuid128))) +/** + * @brief Macro for casting a pointer to a `ble_uuid_t` structure to a pointer + * to 16-bit UUID structure. + * + * @param u Pointer to a `ble_uuid_t` structure. + * + * @return Pointer to a `ble_uuid16_t` structure. + */ #define BLE_UUID16(u) \ ((ble_uuid16_t *) (u)) +/** + * @brief Macro for casting a pointer to a `ble_uuid_t` structure to a pointer + * to 32-bit UUID structure. + * + * @param u Pointer to a `ble_uuid_t` structure. + * + * @return Pointer to a `ble_uuid32_t` structure. + */ #define BLE_UUID32(u) \ ((ble_uuid32_t *) (u)) +/** + * @brief Macro for casting a pointer to a `ble_uuid_t` structure to a pointer + * to 128-bit UUID structure. + * + * @param u Pointer to a `ble_uuid_t` structure. + * + * @return Pointer to a `ble_uuid128_t` structure. + */ #define BLE_UUID128(u) \ ((ble_uuid128_t *) (u)) @@ -127,8 +225,8 @@ typedef union { * @param buf The source buffer to parse. * @param len The size of the buffer, in bytes. * - * @return 0 on success, BLE_HS_EINVAL if the source buffer does not contain - * a valid UUID. + * @return 0 on success; + * BLE_HS_EINVAL if the source buffer does not contain a valid UUID. */ int ble_uuid_init_from_buf(ble_uuid_any_t *uuid, const void *buf, size_t len); @@ -137,7 +235,8 @@ int ble_uuid_init_from_buf(ble_uuid_any_t *uuid, const void *buf, size_t len); * @param uuid1 The first UUID to compare. * @param uuid2 The second UUID to compare. * - * @return 0 if the two UUIDs are equal, nonzero if the UUIDs differ. + * @return 0 if the two UUIDs are equal; + * nonzero if the UUIDs differ. */ int ble_uuid_cmp(const ble_uuid_t *uuid1, const ble_uuid_t *uuid2); @@ -162,6 +261,25 @@ void ble_uuid_copy(ble_uuid_any_t *dst, const ble_uuid_t *src); */ char *ble_uuid_to_str(const ble_uuid_t *uuid, char *dst); +/** + * @brief Converts the specified UUID string to ble_uuid_any_t representation. + * If the UUID is recognised as Bluetooth SIG UUID, it will provide its + * 32-bit or 16-bit representation. + * + * Example 128-bit string representations: + * o "12345678-1234-1234-1234-123456789abc" + * o "12345678123412341234123456789abc" + * + * @param uuid Destination UUID. + * @param str The source string UUID. + * + * @return 0 on success, + * BLE_HS_EINVAL if the specified UUID string has wrong size or + * contains disallowed characters. + */ +int +ble_uuid_from_str(ble_uuid_any_t *uuid, const char *str); + /** @brief Converts the specified 16-bit UUID to a uint16_t. * * @param uuid The source UUID to convert. @@ -179,4 +297,4 @@ uint16_t ble_uuid_u16(const ble_uuid_t *uuid); * @} */ -#endif /* _BLE_HOST_UUID_H */ +#endif /* H_BLE_UUID_ */ diff --git a/nimble/host/mesh/include/mesh/access.h b/nimble/host/mesh/include/mesh/access.h index 9f923cb9e4..f552b584c2 100644 --- a/nimble/host/mesh/include/mesh/access.h +++ b/nimble/host/mesh/include/mesh/access.h @@ -10,6 +10,9 @@ #ifndef __BT_MESH_ACCESS_H #define __BT_MESH_ACCESS_H +#include "msg.h" +#include + /** * @brief Bluetooth Mesh Access Layer * @defgroup bt_mesh_access Bluetooth Mesh Access Layer @@ -138,50 +141,33 @@ struct bt_mesh_elem { #define BT_MESH_MODEL_ID_LIGHT_LC_SETUPSRV 0x1310 #define BT_MESH_MODEL_ID_LIGHT_LC_CLI 0x1311 -/** Message sending context. */ -struct bt_mesh_msg_ctx { - /** NetKey Index of the subnet to send the message on. */ - uint16_t net_idx; - - /** AppKey Index to encrypt the message with. */ - uint16_t app_idx; - - /** Remote address. */ - uint16_t addr; - - /** Destination address of a received message. Not used for sending. */ - uint16_t recv_dst; - - /** RSSI of received packet. Not used for sending. */ - int8_t recv_rssi; - - /** Received TTL value. Not used for sending. */ - uint8_t recv_ttl; - - /** Force sending reliably by using segment acknowledgement */ - bool send_rel; - - /** TTL, or BT_MESH_TTL_DEFAULT for default TTL. */ - uint8_t send_ttl; -}; - struct bt_mesh_model_op { /* OpCode encoded using the BT_MESH_MODEL_OP_* macros */ const uint32_t opcode; - /* Minimum required message length */ - const size_t min_len; + /** Message length. If the message has variable length then this value + * indicates minimum message length and should be positive. Handler + * function should verify precise length based on the contents of the + * message. If the message has fixed length then this value should + * be negative. Use BT_MESH_LEN_* macros when defining this value. + */ + const ssize_t len; /* Message handler for the opcode */ - void (*const func)(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf); + int (*const func)(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf); }; #define BT_MESH_MODEL_OP_1(b0) (b0) #define BT_MESH_MODEL_OP_2(b0, b1) (((b0) << 8) | (b1)) #define BT_MESH_MODEL_OP_3(b0, cid) ((((b0) << 16) | 0xc00000) | (cid)) +/** Macro for encoding exact message length for fixed-length messages. */ +#define BT_MESH_LEN_EXACT(len) (-len) +/** Macro for encoding minimum message length for variable-length messages. */ +#define BT_MESH_LEN_MIN(len) (len) + #define BT_MESH_MODEL_OP_END { 0, 0, NULL } #define BT_MESH_MODEL_NO_OPS ((struct bt_mesh_model_op []) \ { BT_MESH_MODEL_OP_END }) @@ -189,55 +175,6 @@ struct bt_mesh_model_op { /** Helper to define an empty model array */ #define BT_MESH_MODEL_NONE ((struct bt_mesh_model []){}) -/** Length of a short Mesh MIC. */ -#define BT_MESH_MIC_SHORT 4 -/** Length of a long Mesh MIC. */ -#define BT_MESH_MIC_LONG 8 - -/** @def BT_MESH_MODEL_OP_LEN - * - * @brief Helper to determine the length of an opcode. - * - * @param _op Opcode. - */ -#define BT_MESH_MODEL_OP_LEN(_op) ((_op) <= 0xff ? 1 : (_op) <= 0xffff ? 2 : 3) - -/** @def BT_MESH_MODEL_BUF_LEN - * - * @brief Helper for model message buffer length. - * - * Returns the length of a Mesh model message buffer, including the opcode - * length and a short MIC. - * - * @param _op Opcode of the message. - * @param _payload_len Length of the model payload. - */ -#define BT_MESH_MODEL_BUF_LEN(_op, _payload_len) \ - (BT_MESH_MODEL_OP_LEN(_op) + (_payload_len) + BT_MESH_MIC_SHORT) - -/** @def BT_MESH_MODEL_BUF_LEN_LONG_MIC - * - * @brief Helper for model message buffer length. - * - * Returns the length of a Mesh model message buffer, including the opcode - * length and a long MIC. - * - * @param _op Opcode of the message. - * @param _payload_len Length of the model payload. - */ -#define BT_MESH_MODEL_BUF_LEN_LONG_MIC(_op, _payload_len) \ - (BT_MESH_MODEL_OP_LEN(_op) + (_payload_len) + BT_MESH_MIC_LONG) - -/** @def BT_MESH_MODEL_BUF_DEFINE - * - * @brief Define a Mesh model message buffer using @ref NET_BUF_SIMPLE. - * - * @param _op Opcode of the message. - * @param _payload_len Length of the model message payload. - */ -#define BT_MESH_MODEL_BUF(_op, _payload_len) \ - NET_BUF_SIMPLE(BT_MESH_MODEL_BUF_LEN(_op, (_payload_len))) - /** @def BT_MESH_MODEL_CB * * @brief Composition data SIG model entry with callback functions. @@ -384,17 +321,17 @@ struct bt_mesh_model_pub { /** The model the context belongs to. Initialized by the stack. */ struct bt_mesh_model *mod; - uint16_t addr; /**< Publish Address. */ - uint16_t key; /**< Publish AppKey Index. */ + uint16_t addr; /**< Publish Address. */ + uint16_t key:12, /**< Publish AppKey Index. */ + cred:1, /**< Friendship Credentials Flag. */ + send_rel:1, /**< Force reliable sending (segment acks) */ + fast_period:1; /**< Use FastPeriodDivisor */ uint8_t ttl; /**< Publish Time to Live. */ uint8_t retransmit; /**< Retransmit Count & Interval Steps. */ uint8_t period; /**< Publish Period. */ uint8_t period_div:4, /**< Divisor for the Period. */ - cred:1, /**< Friendship Credentials Flag. */ - send_rel:1, - fast_period:1,/**< Use FastPeriodDivisor */ - count:3; /**< Retransmissions left. */ + count:4; uint32_t period_start; /**< Start of the current period. */ @@ -436,7 +373,7 @@ struct bt_mesh_model_pub { int (*update)(struct bt_mesh_model *mod); /** Publish Period Timer. Only for stack-internal use. */ - struct k_delayed_work timer; + struct k_work_delayable timer; }; /** Model callback functions. */ @@ -495,14 +432,19 @@ struct bt_mesh_model_cb { void (*const reset)(struct bt_mesh_model *model); }; +/** Vendor model ID */ +struct bt_mesh_mod_id_vnd { + /** Vendor's company ID */ + uint16_t company; + /** Model ID */ + uint16_t id; +}; + /** Abstraction that describes a Mesh Model instance */ struct bt_mesh_model { union { const uint16_t id; - struct { - uint16_t company; - uint16_t id; - } vnd; + const struct bt_mesh_mod_id_vnd vnd; }; /* Internal information, mainly for persistent storage */ @@ -525,11 +467,10 @@ struct bt_mesh_model { const struct bt_mesh_model_cb * const cb; #if MYNEWT_VAL(BLE_MESH_MODEL_EXTENSIONS) - /* Pointer to the next model in a model extension tree. */ + /* Pointer to the next model in a model extension list. */ struct bt_mesh_model *next; - /* Pointer to the first model this model extends. */ - struct bt_mesh_model *extends; #endif + /* Model-specific user data */ void *user_data; }; @@ -539,8 +480,6 @@ struct bt_mesh_send_cb { void (*end)(int err, void *cb_data); }; -void bt_mesh_model_msg_init(struct os_mbuf *msg, uint32_t opcode); - /** Special TTL value to request using configured default TTL */ #define BT_MESH_TTL_DEFAULT 0xff @@ -625,41 +564,49 @@ static inline bool bt_mesh_model_in_primary(const struct bt_mesh_model *mod) /** @brief Immediately store the model's user data in persistent storage. * - * @param mod Mesh model. - * @param vnd This is a vendor model. - * @param name Name/key of the settings item. - * @param data Model data to store, or NULL to delete any model data. + * @param mod Mesh model. + * @param vnd This is a vendor model. + * @param name Name/key of the settings item. Only + * @ref SETTINGS_MAX_DIR_DEPTH bytes will be used at most. + * @param data Model data to store, or NULL to delete any model data. * @param data_len Length of the model data. * * @return 0 on success, or (negative) error code on failure. */ int bt_mesh_model_data_store(struct bt_mesh_model *mod, bool vnd, - const char *name, const void *data, size_t data_len); + const char *name, const void *data, + size_t data_len); /** @brief Let a model extend another. * * Mesh models may be extended to reuse their functionality, forming a more * complex model. A Mesh model may extend any number of models, in any element. * The extensions may also be nested, ie a model that extends another may itself - * be extended. Extensions may not be cyclical, and a model can only be extended - * by one other model. + * be extended. * - * A set of models that extend each other form a model extension tree. + * A set of models that extend each other form a model extension list. * - * All models in an extension tree share one subscription list per element. The + * All models in an extension list share one subscription list per element. The * access layer will utilize the combined subscription list of all models in an - * extension tree and element, giving the models extended subscription list + * extension list and element, giving the models extended subscription list * capacity. * - * @param[in] mod Mesh model. - * @param[in] base_mod The model being extended. + * @param extending_mod Mesh model that is extending the base model. + * @param base_mod The model being extended. * * @retval 0 Successfully extended the base_mod model. - * @retval -EALREADY The base_mod model is already extended. */ -int bt_mesh_model_extend(struct bt_mesh_model *mod, +int bt_mesh_model_extend(struct bt_mesh_model *extending_mod, struct bt_mesh_model *base_mod); +/** @brief Check if model is extended by another model. + * + * @param model The model to check. + * + * @retval true If model is extended by another model, otherwise false + */ +bool bt_mesh_model_is_extended(struct bt_mesh_model *model); + /** Node Composition */ struct bt_mesh_comp { uint16_t cid; diff --git a/nimble/host/mesh/include/mesh/cdb.h b/nimble/host/mesh/include/mesh/cdb.h index 440390cd62..fa691eb642 100644 --- a/nimble/host/mesh/include/mesh/cdb.h +++ b/nimble/host/mesh/include/mesh/cdb.h @@ -22,7 +22,6 @@ enum { BT_MESH_CDB_NODE_CONFIGURED, - BT_MESH_CDB_NODE_BLACKLISTED, BT_MESH_CDB_NODE_FLAG_COUNT }; @@ -263,4 +262,4 @@ struct bt_mesh_cdb_app_key *bt_mesh_cdb_app_key_get(uint16_t app_idx); */ void bt_mesh_cdb_app_key_store(const struct bt_mesh_cdb_app_key *key); -#endif /* ZEPHYR_INCLUDE_BLUETOOTH_MESH_CDB_H_ */ \ No newline at end of file +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_MESH_CDB_H_ */ diff --git a/nimble/host/mesh/include/mesh/cfg.h b/nimble/host/mesh/include/mesh/cfg.h index 6fd69266ea..422ef3e661 100644 --- a/nimble/host/mesh/include/mesh/cfg.h +++ b/nimble/host/mesh/include/mesh/cfg.h @@ -488,4 +488,4 @@ ssize_t bt_mesh_app_keys_get(uint16_t net_idx, uint16_t app_idxs[], size_t max, * @} */ -#endif /* _BT_MESH_CFG_H_ */ \ No newline at end of file +#endif /* _BT_MESH_CFG_H_ */ diff --git a/nimble/host/mesh/include/mesh/cfg_cli.h b/nimble/host/mesh/include/mesh/cfg_cli.h index 368bdfc344..86716f3162 100644 --- a/nimble/host/mesh/include/mesh/cfg_cli.h +++ b/nimble/host/mesh/include/mesh/cfg_cli.h @@ -24,11 +24,7 @@ extern "C" { /** Mesh Configuration Client Model Context */ struct bt_mesh_cfg_cli { struct bt_mesh_model *model; - - struct k_sem op_sync; - uint32_t op_pending; - void *op_param; - uint16_t op_addr; + struct bt_mesh_msg_ack_ctx ack_ctx; }; extern const struct bt_mesh_model_op bt_mesh_cfg_cli_op[]; @@ -41,10 +37,16 @@ extern const struct bt_mesh_model_cb bt_mesh_cfg_cli_cb; int bt_mesh_cfg_node_reset(uint16_t net_idx, uint16_t addr, bool *status); int bt_mesh_cfg_comp_data_get(uint16_t net_idx, uint16_t addr, uint8_t page, - uint8_t *status, struct os_mbuf *comp); + uint8_t *rsp, struct os_mbuf *comp); int bt_mesh_cfg_beacon_get(uint16_t net_idx, uint16_t addr, uint8_t *status); +int bt_mesh_cfg_krp_get(uint16_t net_idx, uint16_t addr, uint16_t key_net_idx, + uint8_t *status, uint8_t *phase); + +int bt_mesh_cfg_krp_set(uint16_t net_idx, uint16_t addr, uint16_t key_net_idx, + uint8_t transition, uint8_t *status, uint8_t *phase); + int bt_mesh_cfg_beacon_set(uint16_t net_idx, uint16_t addr, uint8_t val, uint8_t *status); int bt_mesh_cfg_ttl_get(uint16_t net_idx, uint16_t addr, uint8_t *ttl); @@ -157,7 +159,8 @@ int bt_mesh_cfg_mod_app_get_vnd(uint16_t net_idx, uint16_t addr, uint16_t elem_a #define BT_MESH_PUB_PERIOD_10MIN(steps) (((steps) & BIT_MASK(6)) | (3 << 6)) struct bt_mesh_cfg_mod_pub { - uint16_t addr; + uint16_t addr; + const uint8_t *uuid; uint16_t app_idx; bool cred_flag; uint8_t ttl; @@ -266,9 +269,72 @@ int bt_mesh_cfg_hb_pub_set(uint16_t net_idx, uint16_t addr, int bt_mesh_cfg_hb_pub_get(uint16_t net_idx, uint16_t addr, struct bt_mesh_cfg_hb_pub *pub, uint8_t *status); +int bt_mesh_cfg_mod_sub_del_all(uint16_t net_idx, uint16_t addr, + uint16_t elem_addr, uint16_t mod_id, + uint8_t *status); + +int bt_mesh_cfg_mod_sub_del_all_vnd(uint16_t net_idx, uint16_t addr, + uint16_t elem_addr, uint16_t mod_id, + uint16_t cid, uint8_t *status); + +int bt_mesh_cfg_net_key_update(uint16_t net_idx, uint16_t addr, + uint16_t key_net_idx, const uint8_t net_key[16], + uint8_t *status); + +int bt_mesh_cfg_app_key_update(uint16_t net_idx, uint16_t addr, + uint16_t key_net_idx, uint16_t key_app_idx, + const uint8_t app_key[16], uint8_t *status); + +int bt_mesh_cfg_node_identity_set(uint16_t net_idx, uint16_t addr, + uint16_t key_net_idx, uint8_t new_identity, + uint8_t *status, uint8_t *identity); + +int bt_mesh_cfg_node_identity_get(uint16_t net_idx, uint16_t addr, + uint16_t key_net_idx, uint8_t *status, + uint8_t *identity); + +int bt_mesh_cfg_lpn_timeout_get(uint16_t net_idx, uint16_t addr, + uint16_t unicast_addr, int32_t *polltimeout); + int32_t bt_mesh_cfg_cli_timeout_get(void); void bt_mesh_cfg_cli_timeout_set(int32_t timeout); +struct bt_mesh_comp_p0 { + /** Company ID */ + uint16_t cid; + /** Product ID */ + uint16_t pid; + /** Version ID */ + uint16_t vid; + /** Replay protection list size */ + uint16_t crpl; + /** Supported features, see @ref BT_MESH_FEAT_SUPPORTED. */ + uint16_t feat; + + struct os_mbuf *_buf; +}; + +struct bt_mesh_comp_p0_elem { + /** Element location */ + uint16_t loc; + /** The number of SIG models in this element */ + size_t nsig; + /** The number of vendor models in this element */ + size_t nvnd; + + uint8_t *_buf; +}; + +int bt_mesh_comp_p0_get(struct bt_mesh_comp_p0 *comp, + struct os_mbuf *buf); + +struct bt_mesh_comp_p0_elem *bt_mesh_comp_p0_elem_pull(const struct bt_mesh_comp_p0 *comp, + struct bt_mesh_comp_p0_elem *elem); + +uint16_t bt_mesh_comp_p0_elem_mod(struct bt_mesh_comp_p0_elem *elem, int idx); + +struct bt_mesh_mod_id_vnd bt_mesh_comp_p0_elem_mod_vnd(struct bt_mesh_comp_p0_elem *elem, int idx); + #ifdef __cplusplus } #endif diff --git a/nimble/host/mesh/include/mesh/glue.h b/nimble/host/mesh/include/mesh/glue.h index 8c9166c259..de36e6fbb6 100644 --- a/nimble/host/mesh/include/mesh/glue.h +++ b/nimble/host/mesh/include/mesh/glue.h @@ -24,8 +24,6 @@ #include #include "syscfg/syscfg.h" -#include "logcfg/logcfg.h" -#include "modlog/modlog.h" #include "nimble/nimble_npl.h" #include "os/os_mbuf.h" @@ -51,6 +49,19 @@ extern "C" { #endif +#define SETTINGS_MAX_DIR_DEPTH 8 /* max depth of settings tree */ + +/** Key size used in Bluetooth's ECC domain. */ +#define BT_ECC_KEY_SIZE 32 + /** Length of a Bluetooth ECC public key coordinate. */ +#define BT_PUB_KEY_COORD_LEN (BT_ECC_KEY_SIZE) + /** Length of a Bluetooth ECC public key. */ +#define BT_PUB_KEY_LEN (2 * (BT_PUB_KEY_COORD_LEN)) + /** Length of a Bluetooth ECC private key. */ +#define BT_PRIV_KEY_LEN (BT_ECC_KEY_SIZE) + /** Length of a Bluetooth Diffie-Hellman key. */ +#define BT_DH_KEY_LEN (BT_ECC_KEY_SIZE) + /** @brief Helper to declare elements of bt_data arrays * * This macro is mainly for creating an array of struct bt_data @@ -144,6 +155,10 @@ extern "C" { #define ASSERT_NOT_CHAIN(om) (void)(om) #endif +#define CHECKIF(expr) \ + __ASSERT_NO_MSG(!(expr)); \ + if (0) + #define __packed __attribute__((__packed__)) #define MSEC_PER_SEC (1000) @@ -165,19 +180,10 @@ extern "C" { #define BT_GAP_ADV_SLOW_INT_MIN 0x0640 /* 1 s */ #define BT_GAP_ADV_SLOW_INT_MAX 0x0780 /* 1.2 s */ -#ifndef MESH_LOG_MODULE -#define MESH_LOG_MODULE BLE_MESH_LOG -#endif - -#define CAT(a, ...) PRIMITIVE_CAT(a, __VA_ARGS__) -#define PRIMITIVE_CAT(a, ...) a ## __VA_ARGS__ - -#define BLE_MESH_LOG(lvl, ...) CAT(MESH_LOG_MODULE, CAT(_, lvl))(__VA_ARGS__) - -#define BT_DBG(fmt, ...) BLE_MESH_LOG(DEBUG, "%s: " fmt "\n", __func__, ## __VA_ARGS__); -#define BT_INFO(fmt, ...) BLE_MESH_LOG(INFO, "%s: " fmt "\n", __func__, ## __VA_ARGS__); -#define BT_WARN(fmt, ...) BLE_MESH_LOG(WARN, "%s: " fmt "\n", __func__, ## __VA_ARGS__); -#define BT_ERR(fmt, ...) BLE_MESH_LOG(ERROR, "%s: " fmt "\n", __func__, ## __VA_ARGS__); +#define BT_DBG(fmt, ...) BLE_NPL_LOG(DEBUG, "%s: " fmt "\n", __func__, ## __VA_ARGS__); +#define BT_INFO(fmt, ...) BLE_NPL_LOG(INFO, "%s: " fmt "\n", __func__, ## __VA_ARGS__); +#define BT_WARN(fmt, ...) BLE_NPL_LOG(WARN, "%s: " fmt "\n", __func__, ## __VA_ARGS__); +#define BT_ERR(fmt, ...) BLE_NPL_LOG(ERROR, "%s: " fmt "\n", __func__, ## __VA_ARGS__); #define BT_GATT_ERR(_att_err) (-(_att_err)) typedef ble_addr_t bt_addr_le_t; @@ -241,11 +247,18 @@ static inline void net_buf_simple_reset(struct os_mbuf *om) net_buf_simple_init(om, 0); } +struct bt_le_ext_adv_start_param { + uint16_t timeout; + + uint8_t num_events; +}; + void net_buf_put(struct ble_npl_eventq *fifo, struct os_mbuf *buf); void * net_buf_ref(struct os_mbuf *om); void net_buf_unref(struct os_mbuf *om); uint16_t net_buf_simple_pull_le16(struct os_mbuf *om); uint16_t net_buf_simple_pull_be16(struct os_mbuf *om); +uint32_t net_buf_simple_pull_le24(struct os_mbuf *om); uint32_t net_buf_simple_pull_be32(struct os_mbuf *om); uint32_t net_buf_simple_pull_le32(struct os_mbuf *om); uint8_t net_buf_simple_pull_u8(struct os_mbuf *om); @@ -284,8 +297,14 @@ void net_buf_reserve(struct os_mbuf *om, size_t reserve); #define BT_GATT_CCC_NOTIFY BLE_GATT_CHR_PROP_NOTIFY +#ifndef MIN #define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#endif + +#ifndef MAX #define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#endif + /** Description of different data types that can be encoded into * advertising data. Used to form arrays that are passed to the * bt_le_adv_start() function. @@ -305,15 +324,84 @@ struct bt_pub_key_cb { * * @param key The local public key, or NULL in case of no key. */ - void (*func)(const uint8_t key[64]); + void (*func)(const uint8_t key[BT_PUB_KEY_LEN]); struct bt_pub_key_cb *_next; }; -typedef void (*bt_dh_key_cb_t)(const uint8_t key[32]); -int bt_dh_key_gen(const uint8_t remote_pk[64], bt_dh_key_cb_t cb); +/** LE Advertising Parameters. */ +struct bt_le_adv_param { + /** + * @brief Local identity. + * + * @note When extended advertising @kconfig{CONFIG_BT_EXT_ADV} is not + * enabled or not supported by the controller it is not possible + * to scan and advertise simultaneously using two different + * random addresses. + */ + uint8_t id; + + /** + * @brief Advertising Set Identifier, valid range 0x00 - 0x0f. + * + * @note Requires @ref BT_LE_ADV_OPT_EXT_ADV + **/ + uint8_t sid; + + /** + * @brief Secondary channel maximum skip count. + * + * Maximum advertising events the advertiser can skip before it must + * send advertising data on the secondary advertising channel. + * + * @note Requires @ref BT_LE_ADV_OPT_EXT_ADV + */ + uint8_t secondary_max_skip; + + /** Bit-field of advertising options */ + uint32_t options; + + /** Minimum Advertising Interval (N * 0.625 milliseconds) + * Minimum Advertising Interval shall be less than or equal to the + * Maximum Advertising Interval. The Minimum Advertising Interval and + * Maximum Advertising Interval should not be the same value (as stated + * in Bluetooth Core Spec 5.2, section 7.8.5) + * Range: 0x0020 to 0x4000 + */ + uint32_t interval_min; + + /** Maximum Advertising Interval (N * 0.625 milliseconds) + * Minimum Advertising Interval shall be less than or equal to the + * Maximum Advertising Interval. The Minimum Advertising Interval and + * Maximum Advertising Interval should not be the same value (as stated + * in Bluetooth Core Spec 5.2, section 7.8.5) + * Range: 0x0020 to 0x4000 + */ + uint32_t interval_max; + + /** + * @brief Directed advertising to peer + * + * When this parameter is set the advertiser will send directed + * advertising to the remote device. + * + * The advertising type will either be high duty cycle, or low duty + * cycle if the BT_LE_ADV_OPT_DIR_MODE_LOW_DUTY option is enabled. + * When using @ref BT_LE_ADV_OPT_EXT_ADV then only low duty cycle is + * allowed. + * + * In case of connectable high duty cycle if the connection could not + * be established within the timeout the connected() callback will be + * called with the status set to @ref BT_HCI_ERR_ADV_TIMEOUT. + */ + const bt_addr_le_t *peer; +}; + +typedef void (*bt_dh_key_cb_t)(const uint8_t key[BT_DH_KEY_LEN]); +int bt_dh_key_gen(const uint8_t remote_pk[BT_PUB_KEY_LEN], bt_dh_key_cb_t cb); int bt_pub_key_gen(struct bt_pub_key_cb *new_cb); uint8_t *bt_pub_key_get(void); +void bt_conn_get_info(struct ble_hs_conn *conn, struct ble_gap_conn_desc *desc); int bt_rand(void *buf, size_t len); const char * bt_hex(const void *buf, size_t len); int bt_encrypt_be(const uint8_t *key, const uint8_t *plaintext, uint8_t *enc_data); @@ -327,24 +415,28 @@ void bt_mesh_register_gatt(void); int bt_le_adv_start(const struct ble_gap_adv_params *param, const struct bt_data *ad, size_t ad_len, const struct bt_data *sd, size_t sd_len); -int bt_le_adv_stop(bool proxy); -struct k_delayed_work { +int bt_le_adv_stop(); + +struct k_work_delayable { struct ble_npl_callout work; }; void k_work_init(struct ble_npl_callout *work, ble_npl_event_fn handler); -void k_delayed_work_init(struct k_delayed_work *w, ble_npl_event_fn *f); -void k_delayed_work_cancel(struct k_delayed_work *w); -bool k_delayed_work_pending(struct k_delayed_work *w); -void k_delayed_work_submit(struct k_delayed_work *w, uint32_t ms); +void k_work_init_delayable(struct k_work_delayable *w, ble_npl_event_fn *f); +void k_work_cancel_delayable(struct k_work_delayable *w); +bool k_work_delayable_is_pending(struct k_work_delayable *w); +void k_work_reschedule(struct k_work_delayable *w, uint32_t ms); int64_t k_uptime_get(void); uint32_t k_uptime_get_32(void); +int64_t k_uptime_delta(int64_t *reftime); void k_sleep(int32_t duration); void k_work_submit(struct ble_npl_callout *w); void k_work_add_arg(struct ble_npl_callout *w, void *arg); -void k_delayed_work_add_arg(struct k_delayed_work *w, void *arg); -uint32_t k_delayed_work_remaining_get(struct k_delayed_work *w); +void k_work_add_arg_delayable(struct k_work_delayable *w, void *arg); +ble_npl_time_t k_work_delayable_remaining_get(struct k_work_delayable *w); +void k_work_schedule(struct k_work_delayable *w, uint32_t ms); +uint32_t k_ticks_to_ms_floor32(ble_npl_time_t ticks); static inline void net_buf_simple_save(struct os_mbuf *buf, struct net_buf_simple_state *state) @@ -353,6 +445,8 @@ static inline void net_buf_simple_save(struct os_mbuf *buf, state->len = buf->om_len; } +void net_buf_simple_clone(const struct os_mbuf *original, struct os_mbuf *clone); + static inline void net_buf_simple_restore(struct os_mbuf *buf, struct net_buf_simple_state *state) { @@ -405,13 +499,15 @@ static inline unsigned int find_msb_set(uint32_t op) #define CONFIG_BT_MESH_PROVISIONER BLE_MESH_PROVISIONER #define CONFIG_BT_MESH_PROV_DEVICE BLE_MESH_PROV_DEVICE #define CONFIG_BT_MESH_CDB BLE_MESH_CDB +#define CONFIG_BT_MESH_DEBUG_CFG BLE_MESH_DEBUG_CFG +#define CONFIG_BT_MESH_DEBUG_ADV BLE_MESH_DEBUG_ADV /* Above flags are used with IS_ENABLED macro */ #define IS_ENABLED(config) MYNEWT_VAL(config) #define CONFIG_BT_MESH_LPN_GROUPS MYNEWT_VAL(BLE_MESH_LPN_GROUPS) #define CONFIG_BT_MESH_ADV_BUF_COUNT MYNEWT_VAL(BLE_MESH_ADV_BUF_COUNT) -#define CONFIG_BT_MESH_SEG_BUFS MYNEWT_VAL(BLE_MESH_SEG_BUFS ) +#define CONFIG_BT_MESH_SEG_BUFS MYNEWT_VAL(BLE_MESH_SEG_BUFS) #define CONFIG_BT_MESH_FRIEND_QUEUE_SIZE MYNEWT_VAL(BLE_MESH_FRIEND_QUEUE_SIZE) #define CONFIG_BT_MESH_FRIEND_RECV_WIN MYNEWT_VAL(BLE_MESH_FRIEND_RECV_WIN) #define CONFIG_BT_MESH_LPN_POLL_TIMEOUT MYNEWT_VAL(BLE_MESH_LPN_POLL_TIMEOUT) @@ -424,6 +520,7 @@ static inline unsigned int find_msb_set(uint32_t op) #define CONFIG_BT_MESH_APP_KEY_COUNT MYNEWT_VAL(BLE_MESH_APP_KEY_COUNT) #define CONFIG_BT_MESH_SUBNET_COUNT MYNEWT_VAL(BLE_MESH_SUBNET_COUNT) #define CONFIG_BT_MESH_STORE_TIMEOUT MYNEWT_VAL(BLE_MESH_STORE_TIMEOUT) +#define CONFIG_BT_MESH_IV_UPDATE_SEQ_LIMIT MYNEWT_VAL(BLE_MESH_IV_UPDATE_SEQ_LIMIT) #define CONFIG_BT_MESH_IVU_DIVIDER MYNEWT_VAL(BLE_MESH_IVU_DIVIDER) #define CONFIG_BT_DEVICE_NAME MYNEWT_VAL(BLE_MESH_DEVICE_NAME) #define CONFIG_BT_RX_SEG_MAX MYNEWT_VAL(BLE_MESH_RX_SEG_MAX) @@ -431,6 +528,7 @@ static inline unsigned int find_msb_set(uint32_t op) #define CONFIG_BT_MESH_RX_SEG_MAX MYNEWT_VAL(BLE_MESH_RX_SEG_MAX) #define CONFIG_BT_MESH_RX_SEG_MSG_COUNT MYNEWT_VAL(BLE_MESH_RX_SEG_MSG_COUNT) #define CONFIG_BT_MESH_LABEL_COUNT MYNEWT_VAL(BLE_MESH_LABEL_COUNT) +#define CONFIG_BT_MESH_MODEL_VND_MSG_CID_FORCE MYNEWT_VAL(BLE_MESH_MODEL_VND_MSG_CID_FORCE) #define CONFIG_BT_MESH_NODE_COUNT MYNEWT_VAL(BLE_MESH_CDB_NODE_COUNT) #define CONFIG_BT_GATT_PROXY_ENABLED MYNEWT_VAL(BLE_MESH_GATT_PROXY_ENABLED) #define CONFIG_BT_MESH_DEFAULT_TTL MYNEWT_VAL(BLE_MESH_DEFAULT_TTL) @@ -443,6 +541,7 @@ static inline unsigned int find_msb_set(uint32_t op) #define CONFIG_BT_MESH_RELAY MYNEWT_VAL(BLE_MESH_RELAY) #define CONFIG_BT_MESH_RELAY_RETRANSMIT_COUNT MYNEWT_VAL(BLE_MESH_RELAY_RETRANSMIT_COUNT) #define CONFIG_BT_MESH_GATT_PROXY_ENABLED MYNEWT_VAL(BLE_MESH_GATT_PROXY_ENABLED) +#define CONFIG_BT_MESH_PROXY_MSG_LEN MYNEWT_VAL(BLE_MESH_PROXY_MSG_LEN) #define printk console_printf @@ -471,6 +570,10 @@ static inline void k_sem_give(struct k_sem *sem) ble_npl_sem_release(sem); } +static inline void k_sem_reset(struct k_sem *sem) +{ + ble_npl_sem_init(sem, 0); +} /* Helpers to access the storage array, since we don't have access to its * type at this point anymore. */ @@ -525,7 +628,7 @@ settings_load(void) #endif /* MYNEWT_VAL(MYNEWT_VAL_BLE_MESH_SETTINGS) */ -#define BUILD_ASSERT(cond) _Static_assert(cond, "") +#define BUILD_ASSERT(cond, msg) _Static_assert(cond, msg) /* Memory slabs/blocks */ diff --git a/nimble/host/mesh/include/mesh/health_cli.h b/nimble/host/mesh/include/mesh/health_cli.h index e9efe4b1f9..cb14ee6bcd 100644 --- a/nimble/host/mesh/include/mesh/health_cli.h +++ b/nimble/host/mesh/include/mesh/health_cli.h @@ -29,9 +29,7 @@ struct bt_mesh_health_cli { uint8_t test_id, uint16_t cid, uint8_t *faults, size_t fault_count); - struct k_sem op_sync; - uint32_t op_pending; - void *op_param; + struct bt_mesh_msg_ack_ctx ack_ctx; }; extern const struct bt_mesh_model_op bt_mesh_health_cli_op[]; diff --git a/nimble/host/mesh/include/mesh/health_srv.h b/nimble/host/mesh/include/mesh/health_srv.h index ad79e368da..980e757486 100644 --- a/nimble/host/mesh/include/mesh/health_srv.h +++ b/nimble/host/mesh/include/mesh/health_srv.h @@ -65,7 +65,7 @@ struct bt_mesh_health_srv { const struct bt_mesh_health_srv_cb *cb; /* Attention Timer state */ - struct k_delayed_work attn_timer; + struct k_work_delayable attn_timer; }; int bt_mesh_fault_update(struct bt_mesh_elem *elem); diff --git a/nimble/host/mesh/include/mesh/heartbeat.h b/nimble/host/mesh/include/mesh/heartbeat.h index b9990f6fdc..2e4986094d 100644 --- a/nimble/host/mesh/include/mesh/heartbeat.h +++ b/nimble/host/mesh/include/mesh/heartbeat.h @@ -120,4 +120,4 @@ extern struct bt_mesh_hb_cb hb_cb; * @} */ -#endif /* _BLUETOOTH_MESH_HEARTBEAT_H_ */ \ No newline at end of file +#endif /* _BLUETOOTH_MESH_HEARTBEAT_H_ */ diff --git a/nimble/host/mesh/include/mesh/main.h b/nimble/host/mesh/include/mesh/main.h index 2bcb05c830..6e9d2e629d 100644 --- a/nimble/host/mesh/include/mesh/main.h +++ b/nimble/host/mesh/include/mesh/main.h @@ -101,6 +101,23 @@ struct bt_mesh_prov { /** Out of Band information field. */ bt_mesh_prov_oob_info_t oob_info; + /** Pointer to Public Key in big-endian for OOB public key type support. + * + * Remember to enable @option{CONFIG_BT_MESH_PROV_OOB_PUBLIC_KEY} + * when initializing this parameter. + * + * Must be used together with @ref bt_mesh_prov::private_key_be. + */ + const uint8_t *public_key_be; + /** Pointer to Private Key in big-endian for OOB public key type support. + * + * Remember to enable @option{CONFIG_BT_MESH_PROV_OOB_PUBLIC_KEY} + * when initializing this parameter. + * + * Must be used together with @ref bt_mesh_prov::public_key_be. + */ + const uint8_t *private_key_be; + /** Static OOB value */ const uint8_t *static_val; /** Static OOB value length */ @@ -270,11 +287,11 @@ int bt_mesh_input_number(uint32_t num); /** @brief Provide Device public key. * - * @param public_key Device public key. + * @param public_key Device public key in big-endian. * * @return Zero on success or (negative) error code otherwise. */ -int bt_mesh_prov_remote_pub_key_set(const uint8_t public_key[64]); +int bt_mesh_prov_remote_pub_key_set(const uint8_t public_key[BT_PUB_KEY_LEN]); /** @brief Use Input OOB authentication. * @@ -548,6 +565,19 @@ void bt_mesh_lpn_set_cb(void (*cb)(uint16_t friend_addr, bool established)); */ int bt_mesh_friend_terminate(uint16_t lpn_addr); +/** @brief Store pending RPL entry(ies) in the persistent storage. + * + * This API allows the user to store pending RPL entry(ies) in the persistent + * storage without waiting for the timeout. + * + * @note When flash is used as the persistent storage, calling this API too + * frequently may wear it out. + * + * @param addr Address of the node which RPL entry needs to be stored or + * @ref BT_MESH_ADDR_ALL_NODES to store all pending RPL entries. + */ +void bt_mesh_rpl_pending_store(uint16_t addr); + #ifdef __cplusplus } #endif diff --git a/nimble/host/mesh/include/mesh/mesh.h b/nimble/host/mesh/include/mesh/mesh.h index 83390ec4ce..c644d0bb0b 100644 --- a/nimble/host/mesh/include/mesh/mesh.h +++ b/nimble/host/mesh/include/mesh/mesh.h @@ -15,6 +15,7 @@ #include "os/os_mbuf.h" #include "glue.h" +#include "msg.h" #include "access.h" #include "main.h" #include "cfg.h" diff --git a/nimble/host/mesh/include/mesh/msg.h b/nimble/host/mesh/include/mesh/msg.h new file mode 100644 index 0000000000..e327545b12 --- /dev/null +++ b/nimble/host/mesh/include/mesh/msg.h @@ -0,0 +1,225 @@ +/** @file + * @brief Bluetooth Mesh Message APIs. + */ + +/* + * Copyright (c) 2021 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_BLUETOOTH_MESH_MSG_H_ +#define ZEPHYR_INCLUDE_BLUETOOTH_MESH_MSG_H_ + +/** + * @brief Bluetooth Mesh Message API + * @defgroup bt_mesh_msg Bluetooth Mesh Message API + * @ingroup bt_mesh + * @{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** Length of a short Mesh MIC. */ +#define BT_MESH_MIC_SHORT 4 +/** Length of a long Mesh MIC. */ +#define BT_MESH_MIC_LONG 8 + +/** @def BT_MESH_MODEL_OP_LEN + * + * @brief Helper to determine the length of an opcode. + * + * @param _op Opcode. + */ +#define BT_MESH_MODEL_OP_LEN(_op) ((_op) <= 0xff ? 1 : (_op) <= 0xffff ? 2 : 3) + + +/** @def BT_MESH_MODEL_BUF_LEN + * + * @brief Helper for model message buffer length. + * + * Returns the length of a Mesh model message buffer, including the opcode + * length and a short MIC. + * + * @param _op Opcode of the message. + * @param _payload_len Length of the model payload. + */ +#define BT_MESH_MODEL_BUF_LEN(_op, _payload_len) \ + (BT_MESH_MODEL_OP_LEN(_op) + (_payload_len) + BT_MESH_MIC_SHORT) + + +/** @def BT_MESH_MODEL_BUF_LEN_LONG_MIC + * + * @brief Helper for model message buffer length. + * + * Returns the length of a Mesh model message buffer, including the opcode + * length and a long MIC. + * + * @param _op Opcode of the message. + * @param _payload_len Length of the model payload. + */ +#define BT_MESH_MODEL_BUF_LEN_LONG_MIC(_op, _payload_len) \ + (BT_MESH_MODEL_OP_LEN(_op) + (_payload_len) + BT_MESH_MIC_LONG) + + +/** @def BT_MESH_MODEL_BUF_DEFINE + * + * @brief Define a Mesh model message buffer using @ref NET_BUF_SIMPLE_DEFINE. + * + * @param _buf Buffer name. + * @param _op Opcode of the message. + * @param _payload_len Length of the model message payload. + */ +#define BT_MESH_MODEL_BUF(_op, _payload_len) \ + NET_BUF_SIMPLE(BT_MESH_MODEL_BUF_LEN(_op, (_payload_len))) + + +/** Message sending context. */ +struct bt_mesh_msg_ctx { + /** NetKey Index of the subnet to send the message on. */ + uint16_t net_idx; + + /** AppKey Index to encrypt the message with. */ + uint16_t app_idx; + + /** Remote address. */ + uint16_t addr; + + /** Destination address of a received message. Not used for sending. */ + uint16_t recv_dst; + + /** RSSI of received packet. Not used for sending. */ + int8_t recv_rssi; + + /** Received TTL value. Not used for sending. */ + uint8_t recv_ttl; + + /** Force sending reliably by using segment acknowledgment */ + bool send_rel; + + /** TTL, or BT_MESH_TTL_DEFAULT for default TTL. */ + uint8_t send_ttl; +}; + +/** @brief Initialize a model message. + * + * Clears the message buffer contents, and encodes the given opcode. + * The message buffer will be ready for filling in payload data. + * + * @param msg Message buffer. + * @param opcode Opcode to encode. + */ +void bt_mesh_model_msg_init(struct os_mbuf *msg, uint32_t opcode); + +/** + * Acknowledged message context for tracking the status of model messages pending a response. + */ +struct bt_mesh_msg_ack_ctx { + struct k_sem sem; /**< Sync semaphore. */ + uint32_t op; /**< Opcode we're waiting for. */ + uint16_t dst; /**< Address of the node that should respond. */ + void *user_data; /**< User specific parameter. */ +}; + +/** @brief Initialize an acknowledged message context. + * + * Initializes semaphore used for synchronization between @ref bt_mesh_msg_ack_ctx_wait and + * @ref bt_mesh_msg_ack_ctx_rx calls. Call this function before using @ref bt_mesh_msg_ack_ctx. + * + * @param ack Acknowledged message context to initialize. + */ +static inline void bt_mesh_msg_ack_ctx_init(struct bt_mesh_msg_ack_ctx *ack) +{ + k_sem_init(&ack->sem, 0, 1); +} + +/** @brief Reset the synchronization semaphore in an acknowledged message context. + * + * This function aborts call to @ref bt_mesh_msg_ack_ctx_wait. + * + * @param ack Acknowledged message context to be reset. + */ +static inline void bt_mesh_msg_ack_ctx_reset(struct bt_mesh_msg_ack_ctx *ack) +{ + k_sem_reset(&ack->sem); +} + +/** @brief Clear parameters of an acknowledged message context. + * + * This function clears the opcode, remote address and user data set + * by @ref bt_mesh_msg_ack_ctx_prepare. + * + * @param ack Acknowledged message context to be cleared. + */ +void bt_mesh_msg_ack_ctx_clear(struct bt_mesh_msg_ack_ctx *ack); + +/** @brief Prepare an acknowledged message context for the incoming message to wait. + * + * This function sets the opcode, remote address of the incoming message and stores the user data. + * Use this function before calling @ref bt_mesh_msg_ack_ctx_wait. + * + * @param ack Acknowledged message context to prepare. + * @param op The message OpCode. + * @param dst Destination address of the message. + * @param user_data User data for the acknowledged message context. + * + * @return 0 on success, or (negative) error code on failure. + */ +int bt_mesh_msg_ack_ctx_prepare(struct bt_mesh_msg_ack_ctx *ack, + uint32_t op, uint16_t dst, void *user_data); +/** @brief Check if the acknowledged message context is initialized with an opcode. + * + * @param ack Acknowledged message context. + * + * @return true if the acknowledged message context is initialized with an opcode, + * false otherwise. + */ +static inline bool bt_mesh_msg_ack_ctx_busy(struct bt_mesh_msg_ack_ctx *ack) +{ + return (ack->op != 0); +} + +/** @brief Wait for a message acknowledge. + * + * This function blocks execution until @ref bt_mesh_msg_ack_ctx_rx is called or by timeout. + * + * @param ack Acknowledged message context of the message to wait for. + * @param timeout Wait timeout. + * + * @return 0 on success, or (negative) error code on failure. + */ +int bt_mesh_msg_ack_ctx_wait(struct bt_mesh_msg_ack_ctx *ack, int32_t timeout); + +/** @brief Mark a message as acknowledged. + * + * This function unblocks call to @ref bt_mesh_msg_ack_ctx_wait. + * + * @param ack Context of a message to be acknowledged. + */ +static inline void bt_mesh_msg_ack_ctx_rx(struct bt_mesh_msg_ack_ctx *ack) +{ + k_sem_give(&ack->sem); +} + +/** @brief Check if an opcode and address of a message matches the expected one. + * + * @param ack Acknowledged message context to be checked. + * @param op OpCode of the incoming message. + * @param addr Source address of the incoming message. + * @param user_data If not NULL, returns a user data stored in the acknowledged message context + * by @ref bt_mesh_msg_ack_ctx_prepare. + * + * @return true if the incoming message matches the expected one, false otherwise. + */ +bool bt_mesh_msg_ack_ctx_match(const struct bt_mesh_msg_ack_ctx *ack, + uint32_t op, uint16_t addr, void **user_data); + +#ifdef __cplusplus +} +#endif +/** + * @} + */ +#endif /* ZEPHYR_INCLUDE_BLUETOOTH_MESH_MSG_H_ */ diff --git a/nimble/host/mesh/src/access.c b/nimble/host/mesh/src/access.c index d23a656551..40395fe445 100644 --- a/nimble/host/mesh/src/access.c +++ b/nimble/host/mesh/src/access.c @@ -7,9 +7,12 @@ */ #include "syscfg/syscfg.h" -#define MESH_LOG_MODULE BLE_MESH_ACCESS_LOG + +#define BLE_NPL_LOG_MODULE BLE_MESH_ACCESS_LOG +#include #include +#include #include #include "mesh/mesh.h" @@ -21,12 +24,33 @@ #include "transport.h" #include "access.h" #include "foundation.h" +#include "settings.h" #if MYNEWT_VAL(BLE_MESH_SHELL_MODELS) #include "mesh/model_cli.h" #endif +/* bt_mesh_model.flags */ +enum { + BT_MESH_MOD_BIND_PENDING = BIT(0), + BT_MESH_MOD_SUB_PENDING = BIT(1), + BT_MESH_MOD_PUB_PENDING = BIT(2), + BT_MESH_MOD_EXTENDED = BIT(3), +}; + +/* Model publication information for persistent storage. */ +struct mod_pub_val { + uint16_t addr; + uint16_t key; + uint8_t ttl; + uint8_t retransmit; + uint8_t period; + uint8_t period_div:4, + cred:1; +}; + static const struct bt_mesh_comp *dev_comp; static uint16_t dev_primary_addr; +static void (*msg_cb)(uint32_t opcode, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf); void bt_mesh_model_foreach(void (*func)(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, @@ -127,7 +151,7 @@ static void publish_sent(int err, void *user_data) if (delay) { BT_DBG("Publishing next time in %dms", (int) delay); - k_delayed_work_submit(&mod->pub->timer, delay); + k_work_schedule(&mod->pub->timer, delay); } } @@ -138,6 +162,7 @@ static void publish_start(uint16_t duration, int err, void *user_data) if (err) { BT_ERR("Failed to publish: err %d", err); + publish_sent(err, user_data); return; } @@ -152,7 +177,7 @@ static const struct bt_mesh_send_cb pub_sent_cb = { .end = publish_sent, }; -static int publish_retransmit(struct bt_mesh_model *mod) +static int publish_transmit(struct bt_mesh_model *mod) { struct os_mbuf *sdu = NET_BUF_SIMPLE(BT_MESH_TX_SDU_MAX); struct bt_mesh_model_pub *pub = mod->pub; @@ -171,67 +196,68 @@ static int publish_retransmit(struct bt_mesh_model *mod) net_buf_simple_init(sdu, 0); net_buf_simple_add_mem(sdu, pub->msg->om_data, pub->msg->om_len); - pub->count--; - err = bt_mesh_trans_send(&tx, sdu, &pub_sent_cb, mod); os_mbuf_free_chain(sdu); return err; } -static void publish_retransmit_end(int err, struct bt_mesh_model_pub *pub) +static int pub_period_start(struct bt_mesh_model_pub *pub) { - /* Cancel all retransmits for this publish attempt */ - pub->count = 0U; - /* Make sure the publish timer gets reset */ - publish_sent(err, pub->mod); + int err; + + pub->count = BT_MESH_PUB_TRANSMIT_COUNT(pub->retransmit); + + if (!pub->update) { + return 0; + } + + err = pub->update(pub->mod); + if (err) { + /* Skip this publish attempt. */ + BT_DBG("Update failed, skipping publish (err: %d)", err); + pub->count = 0; + pub->period_start = k_uptime_get_32(); + publish_sent(err, pub->mod); + return err; + } + + return 0; } static void mod_publish(struct ble_npl_event *work) { struct bt_mesh_model_pub *pub = ble_npl_event_get_arg(work); - int32_t period_ms; int err; - BT_DBG(""); + if (pub->addr == BT_MESH_ADDR_UNASSIGNED || + atomic_test_bit(bt_mesh.flags, BT_MESH_SUSPENDED)) { + /* Publication is no longer active, but the cancellation of the + * delayed work failed. Abandon recurring timer. + */ + return; + } - period_ms = bt_mesh_model_pub_period_get(pub->mod); - BT_DBG("period %u ms", (unsigned) period_ms); + BT_DBG(""); if (pub->count) { - err = publish_retransmit(pub->mod); + pub->count--; + } else { + /* First publication in this period */ + err = pub_period_start(pub); if (err) { - BT_ERR("Failed to retransmit (err %d)", err); - - pub->count = 0; - - /* Continue with normal publication */ - if (period_ms) { - k_delayed_work_submit(&pub->timer, period_ms); - } + return; } - - return; - } - - if (!period_ms) { - return; } - __ASSERT_NO_MSG(pub->update != NULL); - - err = pub->update(pub->mod); + err = publish_transmit(pub->mod); if (err) { - /* Cancel this publish attempt. */ - BT_DBG("Update failed, skipping publish (err: %d)", err); - pub->period_start = k_uptime_get_32(); - publish_retransmit_end(err, pub); - return; - } + BT_ERR("Failed to publish (err %d)", err); + if (pub->count == BT_MESH_PUB_TRANSMIT_COUNT(pub->retransmit)) { + pub->period_start = k_uptime_get_32(); + } - err = bt_mesh_model_publish(pub->mod); - if (err) { - BT_ERR("Publishing failed (err %d)", err); + publish_sent(err, pub->mod); } } @@ -268,6 +294,30 @@ struct bt_mesh_model *bt_mesh_model_get(bool vnd, uint8_t elem_idx, uint8_t mod_ } } +#if defined(CONFIG_BT_MESH_MODEL_VND_MSG_CID_FORCE) +static int bt_mesh_vnd_mod_msg_cid_check(struct bt_mesh_model *mod) +{ + uint16_t cid; + const struct bt_mesh_model_op *op; + + for (op = mod->op; op->func; op++) { + cid = (uint16_t)(op->opcode & 0xffff); + + if (cid == mod->vnd.company) { + continue; + } + + BT_ERR("Invalid vendor model(company:0x%04x" + " id:0x%04x) message opcode 0x%08x", + mod->vnd.company, mod->vnd.id, op->opcode); + + return -EINVAL; + } + + return 0; +} +#endif + static void mod_init(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, bool vnd, bool primary, void *user_data) { @@ -280,8 +330,8 @@ static void mod_init(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, if (mod->pub) { mod->pub->mod = mod; - k_delayed_work_init(&mod->pub->timer, mod_publish); - k_delayed_work_add_arg(&mod->pub->timer, mod->pub); + k_work_init_delayable(&mod->pub->timer, mod_publish); + k_work_add_arg_delayable(&mod->pub->timer, mod->pub); } for (i = 0; i < ARRAY_SIZE(mod->keys); i++) { @@ -291,6 +341,13 @@ static void mod_init(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, mod->elem_idx = elem - dev_comp->elem; if (vnd) { mod->mod_idx = mod - elem->vnd_models; + + if (CONFIG_BT_MESH_MODEL_VND_MSG_CID_FORCE) { + *err = bt_mesh_vnd_mod_msg_cid_check(mod); + if (*err) { + return; + } + } } else { mod->mod_idx = mod - elem->models; } @@ -305,7 +362,7 @@ int bt_mesh_comp_register(const struct bt_mesh_comp *comp) int err; /* There must be at least one element */ - if (!comp->elem_count) { + if (!comp || !comp->elem_count) { return -EINVAL; } @@ -366,8 +423,7 @@ struct find_group_visitor_ctx { uint16_t addr; }; -static enum bt_mesh_walk find_group_mod_visitor(struct bt_mesh_model *mod, - uint32_t depth, void *user_data) +static enum bt_mesh_walk find_group_mod_visitor(struct bt_mesh_model *mod, void *user_data) { struct find_group_visitor_ctx *ctx = user_data; @@ -392,8 +448,7 @@ uint16_t *bt_mesh_model_find_group(struct bt_mesh_model **mod, uint16_t addr) .addr = addr, }; - bt_mesh_model_tree_walk(bt_mesh_model_root(*mod), - find_group_mod_visitor, &ctx); + bt_mesh_model_extensions_walk(*mod, find_group_mod_visitor, &ctx); *mod = ctx.mod; return ctx.entry; @@ -431,24 +486,67 @@ struct bt_mesh_elem *bt_mesh_elem_find(uint16_t addr) { uint16_t index; + if (!BT_MESH_ADDR_IS_UNICAST(addr)) { + return NULL; + } + + index = addr - dev_comp->elem[0].addr; + if (index >= dev_comp->elem_count) { + return NULL; + } + + return &dev_comp->elem[index]; +} + +bool bt_mesh_has_addr(uint16_t addr) +{ + uint16_t index; + if (BT_MESH_ADDR_IS_UNICAST(addr)) { - index = (addr - dev_comp->elem[0].addr); - if (index < dev_comp->elem_count) { - return &dev_comp->elem[index]; - } else { - return NULL; - } + return bt_mesh_elem_find(addr) != NULL; + } + + if (MYNEWT_VAL(BLE_MESH_ACCESS_LAYER_MSG) && msg_cb) { + return true; } for (index = 0; index < dev_comp->elem_count; index++) { struct bt_mesh_elem *elem = &dev_comp->elem[index]; if (bt_mesh_elem_find_group(elem, addr)) { - return elem; + return true; } } - return NULL; + return false; +} + +#if MYNEWT_VAL(BLE_MESH_ACCESS_LAYER_MSG) +void bt_mesh_msg_cb_set(void (*cb)(uint32_t opcode, struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf)) +{ + msg_cb = cb; +} +#endif + +int bt_mesh_msg_send(struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf, uint16_t src_addr, + const struct bt_mesh_send_cb *cb, void *cb_data) +{ + struct bt_mesh_net_tx tx = { + .ctx = ctx, + .src = src_addr, + }; + + BT_DBG("net_idx 0x%04x app_idx 0x%04x dst 0x%04x", tx.ctx->net_idx, + tx.ctx->app_idx, tx.ctx->addr); + BT_DBG("len %u: %s", buf->om_len, bt_hex(buf->om_data, buf->om_len)); + + if (!bt_mesh_is_provisioned()) { + BT_ERR("Local node is not yet provisioned"); + return -EAGAIN; + } + + return bt_mesh_trans_send(&tx, buf, cb, cb_data); } uint8_t bt_mesh_elem_count(void) @@ -456,7 +554,7 @@ uint8_t bt_mesh_elem_count(void) return dev_comp->elem_count; } -static bool model_has_key(struct bt_mesh_model *mod, uint16_t key) +bool bt_mesh_model_has_key(struct bt_mesh_model *mod, uint16_t key) { int i; @@ -486,15 +584,37 @@ static bool model_has_dst(struct bt_mesh_model *mod, uint16_t dst) return mod->elem_idx == 0; } -static const struct bt_mesh_model_op *find_op(struct bt_mesh_model *models, - uint8_t model_count, uint32_t opcode, - struct bt_mesh_model **model) +static const struct bt_mesh_model_op *find_op(struct bt_mesh_elem *elem, + uint32_t opcode, struct bt_mesh_model **model) { uint8_t i; + uint8_t count; + /* This value shall not be used in shipping end products. */ + uint32_t cid = UINT32_MAX; + struct bt_mesh_model *models; + + /* SIG models cannot contain 3-byte (vendor) OpCodes, and + * vendor models cannot contain SIG (1- or 2-byte) OpCodes, so + * we only need to do the lookup in one of the model lists. + */ + if (BT_MESH_MODEL_OP_LEN(opcode) < 3) { + models = elem->models; + count = elem->model_count; + } else { + models = elem->vnd_models; + count = elem->vnd_model_count; - for (i = 0; i < model_count; i++) { + cid = (uint16_t)(opcode & 0xffff); + } + + for (i = 0U; i < count; i++) { const struct bt_mesh_model_op *op; + if (CONFIG_BT_MESH_MODEL_VND_MSG_CID_FORCE && + cid != UINT32_MAX && + cid != models[i].vnd.company) { + continue; + } *model = &models[i]; for (op = (*model)->op; op->func; op++) { @@ -548,10 +668,9 @@ static int get_opcode(struct os_mbuf *buf, uint32_t *opcode) void bt_mesh_model_recv(struct bt_mesh_net_rx *rx, struct os_mbuf *buf) { - struct bt_mesh_model *models, *model; + struct bt_mesh_model *model; const struct bt_mesh_model_op *op; uint32_t opcode; - uint8_t count; int i; BT_DBG("app_idx 0x%04x src 0x%04x dst 0x%04x", rx->ctx.app_idx, @@ -566,28 +685,16 @@ void bt_mesh_model_recv(struct bt_mesh_net_rx *rx, struct os_mbuf *buf) BT_DBG("OpCode 0x%08x", (unsigned) opcode); for (i = 0; i < dev_comp->elem_count; i++) { - struct bt_mesh_elem *elem = &dev_comp->elem[i]; struct net_buf_simple_state state; - /* SIG models cannot contain 3-byte (vendor) OpCodes, and - * vendor models cannot contain SIG (1- or 2-byte) OpCodes, so - * we only need to do the lookup in one of the model lists. - */ - if (BT_MESH_MODEL_OP_LEN(opcode) < 3) { - models = elem->models; - count = elem->model_count; - } else { - models = elem->vnd_models; - count = elem->vnd_model_count; - } + op = find_op(&dev_comp->elem[i], opcode, &model); - op = find_op(models, count, opcode, &model); if (!op) { BT_DBG("No OpCode 0x%08x for elem %d", opcode, i); continue; } - if (!model_has_key(model, rx->ctx.app_idx)) { + if (!bt_mesh_model_has_key(model, rx->ctx.app_idx)) { continue; } @@ -595,9 +702,13 @@ void bt_mesh_model_recv(struct bt_mesh_net_rx *rx, struct os_mbuf *buf) continue; } - if (buf->om_len < op->min_len) { + if ((op->len >= 0) && (buf->om_len < (size_t)op->len)) { BT_ERR("Too short message for OpCode 0x%08x", opcode); continue; + } else if ((op->len < 0) && (buf->om_len != (size_t)(-op->len))) { + BT_ERR("Invalid message size for OpCode 0x%08x", + opcode); + continue; } /* The callback will likely parse the buffer, so @@ -605,139 +716,64 @@ void bt_mesh_model_recv(struct bt_mesh_net_rx *rx, struct os_mbuf *buf) * receive the message. */ net_buf_simple_save(buf, &state); - op->func(model, &rx->ctx, buf); + (void)op->func(model, &rx->ctx, buf); net_buf_simple_restore(buf, &state); } -} - -void bt_mesh_model_msg_init(struct os_mbuf *msg, uint32_t opcode) -{ - net_buf_simple_init(msg, 0); - switch (BT_MESH_MODEL_OP_LEN(opcode)) { - case 1: - net_buf_simple_add_u8(msg, opcode); - break; - case 2: - net_buf_simple_add_be16(msg, opcode); - break; - case 3: - net_buf_simple_add_u8(msg, ((opcode >> 16) & 0xff)); - /* Using LE for the CID since the model layer is defined as - * little-endian in the mesh spec and using BT_MESH_MODEL_OP_3 - * will declare the opcode in this way. - */ - net_buf_simple_add_le16(msg, opcode & 0xffff); - break; - default: - BT_WARN("Unknown opcode format"); - break; - } -} - -static int model_send(struct bt_mesh_model *model, - struct bt_mesh_net_tx *tx, bool implicit_bind, - struct os_mbuf *msg, - const struct bt_mesh_send_cb *cb, void *cb_data) -{ - BT_DBG("net_idx 0x%04x app_idx 0x%04x dst 0x%04x", tx->ctx->net_idx, - tx->ctx->app_idx, tx->ctx->addr); - BT_DBG("len %u: %s", msg->om_len, bt_hex(msg->om_data, msg->om_len)); - - if (!bt_mesh_is_provisioned()) { - BT_ERR("Local node is not yet provisioned"); - return -EAGAIN; - } - - if (net_buf_simple_tailroom(msg) < 4) { - BT_ERR("Not enough tailroom for TransMIC"); - return -EINVAL; + if (MYNEWT_VAL(BLE_MESH_ACCESS_LAYER_MSG) && msg_cb) { + msg_cb(opcode, &rx->ctx, buf); } - - if (msg->om_len > BT_MESH_TX_SDU_MAX - 4) { - BT_ERR("Too big message"); - return -EMSGSIZE; - } - - if (!implicit_bind && !model_has_key(model, tx->ctx->app_idx)) { - BT_ERR("Model not bound to AppKey 0x%04x", tx->ctx->app_idx); - return -EINVAL; - } - - return bt_mesh_trans_send(tx, msg, cb, cb_data); } -int bt_mesh_model_send(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, +int bt_mesh_model_send(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *msg, const struct bt_mesh_send_cb *cb, void *cb_data) { - struct bt_mesh_net_tx tx = { - .ctx = ctx, - .src = bt_mesh_model_elem(model)->addr, - }; + if (!bt_mesh_model_has_key(model, ctx->app_idx)) { + BT_ERR("Model not bound to AppKey 0x%04x", ctx->app_idx); + return -EINVAL; + } - return model_send(model, &tx, false, msg, cb, cb_data); + return bt_mesh_msg_send(ctx, msg, bt_mesh_model_elem(model)->addr, cb, cb_data); } int bt_mesh_model_publish(struct bt_mesh_model *model) { - int err; - struct os_mbuf *sdu = NET_BUF_SIMPLE(BT_MESH_TX_SDU_MAX); struct bt_mesh_model_pub *pub = model->pub; if (!pub) { - err = -ENOTSUP; - goto done; + return -ENOTSUP; } - struct bt_mesh_msg_ctx ctx = { - .addr = pub->addr, - .send_ttl = pub->ttl, - .send_rel = pub->send_rel, - .app_idx = pub->key, - }; - struct bt_mesh_net_tx tx = { - .ctx = &ctx, - .src = bt_mesh_model_elem(model)->addr, - }; - BT_DBG(""); if (pub->addr == BT_MESH_ADDR_UNASSIGNED) { - err = -EADDRNOTAVAIL; - goto done; + return -EADDRNOTAVAIL; } - if (pub->msg->om_len + 4 > BT_MESH_TX_SDU_MAX) { + if (!pub->msg || !pub->msg->om_len) { + BT_ERR("No publication message"); + return -EINVAL; + } + + if (pub->msg->om_len + BT_MESH_MIC_SHORT > BT_MESH_TX_SDU_MAX) { BT_ERR("Message does not fit maximum SDU size"); - err = -EMSGSIZE; - goto done; + return -EMSGSIZE; } if (pub->count) { BT_WARN("Clearing publish retransmit timer"); - k_delayed_work_cancel(&pub->timer); } - net_buf_simple_init(sdu, 0); - net_buf_simple_add_mem(sdu, pub->msg->om_data, pub->msg->om_len); - - tx.friend_cred = pub->cred; - - pub->count = BT_MESH_PUB_TRANSMIT_COUNT(pub->retransmit); + /* Account for initial transmission */ + pub->count = BT_MESH_PUB_TRANSMIT_COUNT(pub->retransmit) + 1; BT_DBG("Publish Retransmit Count %u Interval %ums", pub->count, BT_MESH_PUB_TRANSMIT_INT(pub->retransmit)); - err = model_send(model, &tx, true, sdu, &pub_sent_cb, model); - if (err) { - publish_retransmit_end(err, pub); - } + k_work_reschedule(&pub->timer, K_NO_WAIT); -done: - os_mbuf_free_chain(sdu); - return err; + return 0; } struct bt_mesh_model *bt_mesh_model_find_vnd(const struct bt_mesh_elem *elem, @@ -774,76 +810,506 @@ const struct bt_mesh_comp *bt_mesh_comp_get(void) return dev_comp; } -struct bt_mesh_model *bt_mesh_model_root(struct bt_mesh_model *mod) +void bt_mesh_model_extensions_walk(struct bt_mesh_model *model, + enum bt_mesh_walk (*cb)(struct bt_mesh_model *mod, + void *user_data), + void *user_data) { -#ifdef CONFIG_BT_MESH_MODEL_EXTENSIONS - while (mod->next) { - mod = mod->next; +#ifndef CONFIG_BT_MESH_MODEL_EXTENSIONS + (void)cb(model, user_data); + return; +#else + struct bt_mesh_model *it; + + if (cb(model, user_data) == BT_MESH_WALK_STOP || !model->next) { + return; + } + /* List is circular. Step through all models until we reach the start: */ + for (it = model->next; it != model; it = it->next) { + if (cb(it, user_data) == BT_MESH_WALK_STOP) { + return; + } } #endif - return mod; } -void bt_mesh_model_tree_walk(struct bt_mesh_model *root, - enum bt_mesh_walk (*cb)(struct bt_mesh_model *mod, - uint32_t depth, - void *user_data), - void *user_data) +#if MYNEWT_VAL(BLE_MESH_MODEL_EXTENSIONS) +int bt_mesh_model_extend(struct bt_mesh_model *extending_mod, struct bt_mesh_model *base_mod) { - struct bt_mesh_model *m = root; - int depth = 0; - /* 'skip' is set to true when we ascend from child to parent node. - * In that case, we want to skip calling the callback on the parent - * node and we don't want to descend onto a child node as those - * nodes have already been visited. - */ - bool skip = false; + struct bt_mesh_model *a = extending_mod; + struct bt_mesh_model *b = base_mod; + struct bt_mesh_model *a_next = a->next; + struct bt_mesh_model *b_next = b->next; + struct bt_mesh_model *it; + + base_mod->flags |= BT_MESH_MOD_EXTENDED; + + if (a == b) { + return 0; + } + + /* Check if a's list contains b */ + for (it = a; (it != NULL) && (it->next != a); it = it->next) { + if (it == b) { + return 0; + } + } + + /* Merge lists */ + if (a_next) { + b->next = a_next; + } else { + b->next = a; + } + + if (b_next) { + a->next = b_next; + } else { + a->next = b; + } + + return 0; +} +#endif - do { - if (!skip && - cb(m, (uint32_t)depth, user_data) == BT_MESH_WALK_STOP) { +bool bt_mesh_model_is_extended(struct bt_mesh_model *model) +{ + return model->flags & BT_MESH_MOD_EXTENDED; +} + +#if MYNEWT_VAL(BLE_MESH_SETTINGS) +static int mod_set_bind(struct bt_mesh_model *mod, char *val) +{ + int len, err, i; + + /* Start with empty array regardless of cleared or set value */ + for (i = 0; i < ARRAY_SIZE(mod->keys); i++) { + mod->keys[i] = BT_MESH_KEY_UNUSED; + } + + if (!val) { + BT_DBG("Cleared bindings for model"); + return 0; + } + + len = sizeof(mod->keys); + err = settings_bytes_from_str(val, mod->keys, &len); + if (err) { + BT_ERR("Failed to decode value %s (err %d)", val, err); + return -EINVAL; + } + + BT_DBG("Decoded %u bound keys for model", len / sizeof(mod->keys[0])); + return 0; +} + +static int mod_set_sub(struct bt_mesh_model *mod, char *val) +{ + int len, err; + + /* Start with empty array regardless of cleared or set value */ + memset(mod->groups, 0, sizeof(mod->groups)); + + if (!val) { + BT_DBG("Cleared subscriptions for model"); + return 0; + } + + len = sizeof(mod->groups); + err = settings_bytes_from_str(val, mod->groups, &len); + if (err) { + BT_ERR("Failed to decode value %s (err %d)", val, err); + return -EINVAL; + } + + BT_DBG("Decoded %u subscribed group addresses for model", + len / sizeof(mod->groups[0])); + return 0; +} + +static int mod_set_pub(struct bt_mesh_model *mod, char *val) +{ + struct mod_pub_val pub; + int len, err; + + if (!mod->pub) { + BT_WARN("Model has no publication context!"); + return -EINVAL; + } + + if (!val) { + mod->pub->addr = BT_MESH_ADDR_UNASSIGNED; + mod->pub->key = 0; + mod->pub->cred = 0; + mod->pub->ttl = 0; + mod->pub->period = 0; + mod->pub->retransmit = 0; + mod->pub->period_div = pub.period_div; + mod->pub->count = 0; + + BT_DBG("Cleared publication for model"); + return 0; + } + + len = sizeof(pub); + err = settings_bytes_from_str(val, &pub, &len); + if (err) { + BT_ERR("Failed to decode value %s (err %d)", val, err); + return -EINVAL; + } + + if (len != sizeof(pub)) { + BT_ERR("Invalid length for model publication"); + return -EINVAL; + } + + mod->pub->addr = pub.addr; + mod->pub->key = pub.key; + mod->pub->cred = pub.cred; + mod->pub->ttl = pub.ttl; + mod->pub->period = pub.period; + mod->pub->retransmit = pub.retransmit; + mod->pub->period_div = pub.period_div; + mod->pub->count = 0; + + BT_DBG("Restored model publication, dst 0x%04x app_idx 0x%03x", + pub.addr, pub.key); + + return 0; +} + +static int mod_data_set(struct bt_mesh_model *mod, + char *name, char *len_rd) +{ + char *next; + + settings_name_next(name, &next); + + if (mod->cb && mod->cb->settings_set) { + return mod->cb->settings_set(mod, next, len_rd); + } + + return 0; +} + +static int mod_set(bool vnd, int argc, char **argv, char *val) +{ + struct bt_mesh_model *mod; + uint8_t elem_idx, mod_idx; + uint16_t mod_key; + + if (argc < 2) { + BT_ERR("Too small argc (%d)", argc); + return -ENOENT; + } + + mod_key = strtol(argv[0], NULL, 16); + elem_idx = mod_key >> 8; + mod_idx = mod_key; + + BT_DBG("Decoded mod_key 0x%04x as elem_idx %u mod_idx %u", + mod_key, elem_idx, mod_idx); + + mod = bt_mesh_model_get(vnd, elem_idx, mod_idx); + if (!mod) { + BT_ERR("Failed to get model for elem_idx %u mod_idx %u", + elem_idx, mod_idx); + return -ENOENT; + } + + if (!strcmp(argv[1], "bind")) { + return mod_set_bind(mod, val); + } + + if (!strcmp(argv[1], "sub")) { + return mod_set_sub(mod, val); + } + + if (!strcmp(argv[1], "pub")) { + return mod_set_pub(mod, val); + } + + if (!strcmp(argv[1], "data")) { + return mod_data_set(mod, argv[1], val); + } + + BT_WARN("Unknown module key %s", argv[1]); + return -ENOENT; +} + +static int sig_mod_set(int argc, char **argv, char *val) +{ + return mod_set(false, argc, argv, val); +} + +static int vnd_mod_set(int argc, char **argv, char *val) +{ + return mod_set(true, argc, argv, val); +} + +static void encode_mod_path(struct bt_mesh_model *mod, bool vnd, + const char *key, char *path, size_t path_len) +{ + uint16_t mod_key = (((uint16_t)mod->elem_idx << 8) | mod->mod_idx); + + if (vnd) { + snprintk(path, path_len, "bt_mesh/v/%x/%s", mod_key, key); + } else { + snprintk(path, path_len, "bt_mesh/s/%x/%s", mod_key, key); + } +} + +static void store_pending_mod_bind(struct bt_mesh_model *mod, bool vnd) +{ + uint16_t keys[CONFIG_BT_MESH_MODEL_KEY_COUNT]; + char buf[BT_SETTINGS_SIZE(sizeof(keys))]; + char path[20]; + int i, count, err; + char *val; + + for (i = 0, count = 0; i < ARRAY_SIZE(mod->keys); i++) { + if (mod->keys[i] != BT_MESH_KEY_UNUSED) { + keys[count++] = mod->keys[i]; + BT_DBG("model key 0x%04x", mod->keys[i]); + } + } + + if (count) { + val = settings_str_from_bytes(keys, count * sizeof(keys[0]), + buf, sizeof(buf)); + if (!val) { + BT_ERR("Unable to encode model bindings as value"); return; } -#if MYNEWT_VAL(BLE_MESH_MODEL_EXTENSIONS) - if (!skip && m->extends) { - m = m->extends; - depth++; - } else if (m->flags & BT_MESH_MOD_NEXT_IS_PARENT) { - m = m->next; - depth--; - skip = true; - } else { - m = m->next; - skip = false; + } else { + val = NULL; + } + + encode_mod_path(mod, vnd, "bind", path, sizeof(path)); + + BT_DBG("Saving %s as %s", path, val ? val : "(null)"); + err = settings_save_one(path, val); + if (err) { + BT_ERR("Failed to store bind"); + } else { + BT_DBG("Stored bind"); + } +} + +static void store_pending_mod_sub(struct bt_mesh_model *mod, bool vnd) +{ + uint16_t groups[CONFIG_BT_MESH_MODEL_GROUP_COUNT]; + char buf[BT_SETTINGS_SIZE(sizeof(groups))]; + char path[20]; + int i, count, err; + char *val; + + for (i = 0, count = 0; i < CONFIG_BT_MESH_MODEL_GROUP_COUNT; i++) { + if (mod->groups[i] != BT_MESH_ADDR_UNASSIGNED) { + groups[count++] = mod->groups[i]; + } + } + + if (count) { + val = settings_str_from_bytes(groups, count * sizeof(groups[0]), + buf, sizeof(buf)); + if (!val) { + BT_ERR("Unable to encode model subscription as value"); + return; } -#endif - } while (m && depth > 0); + } else { + val = NULL; + } + + encode_mod_path(mod, vnd, "sub", path, sizeof(path)); + + BT_DBG("Saving %s as %s", path, val ? val : "(null)"); + err = settings_save_one(path, val); + if (err) { + BT_ERR("Failed to store sub"); + } else { + BT_DBG("Stored sub"); + } } -#if MYNEWT_VAL(BLE_MESH_MODEL_EXTENSIONS) -int bt_mesh_model_extend(struct bt_mesh_model *mod, - struct bt_mesh_model *base_mod) -{ - /* Form a cyclical LCRS tree: - * The extends-pointer points to the first child, and the next-pointer - * points to the next sibling. The last sibling is marked by the - * BT_MESH_MOD_NEXT_IS_PARENT flag, and its next-pointer points back to - * the parent. This way, the whole tree is accessible from any node. - * - * We add children (extend them) by inserting them as the first child. - */ - if (base_mod->next) { - return -EALREADY; +static void store_pending_mod_pub(struct bt_mesh_model *mod, bool vnd) +{ + char buf[BT_SETTINGS_SIZE(sizeof(struct mod_pub_val))]; + struct mod_pub_val pub; + char path[20]; + char *val; + int err; + + if (!mod->pub || mod->pub->addr == BT_MESH_ADDR_UNASSIGNED) { + val = NULL; + } else { + pub.addr = mod->pub->addr; + pub.key = mod->pub->key; + pub.ttl = mod->pub->ttl; + pub.retransmit = mod->pub->retransmit; + pub.period = mod->pub->period; + pub.period_div = mod->pub->period_div; + pub.cred = mod->pub->cred; + + val = settings_str_from_bytes(&pub, sizeof(pub), buf, sizeof(buf)); + if (!val) { + BT_ERR("Unable to encode model publication as value"); + return; + } } - if (mod->extends) { - base_mod->next = mod->extends; + encode_mod_path(mod, vnd, "pub", path, sizeof(path)); + + BT_DBG("Saving %s as %s", path, val ? val : "(null)"); + err = settings_save_one(path, val); + if (err) { + BT_ERR("Failed to store pub"); } else { - base_mod->next = mod; - base_mod->flags |= BT_MESH_MOD_NEXT_IS_PARENT; + BT_DBG("Stored pub"); } +} - mod->extends = base_mod; - return 0; +static void store_pending_mod(struct bt_mesh_model *mod, + struct bt_mesh_elem *elem, bool vnd, + bool primary, void *user_data) +{ + if (!mod->flags) { + return; + } + + if (mod->flags & BT_MESH_MOD_BIND_PENDING) { + mod->flags &= ~BT_MESH_MOD_BIND_PENDING; + store_pending_mod_bind(mod, vnd); + } + + if (mod->flags & BT_MESH_MOD_SUB_PENDING) { + mod->flags &= ~BT_MESH_MOD_SUB_PENDING; + store_pending_mod_sub(mod, vnd); + } + + if (mod->flags & BT_MESH_MOD_PUB_PENDING) { + mod->flags &= ~BT_MESH_MOD_PUB_PENDING; + store_pending_mod_pub(mod, vnd); + } +} + +void bt_mesh_model_pending_store(void) +{ + bt_mesh_model_foreach(store_pending_mod, NULL); +} + +void bt_mesh_model_bind_store(struct bt_mesh_model *mod) +{ + mod->flags |= BT_MESH_MOD_BIND_PENDING; + bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_MOD_PENDING); } + +void bt_mesh_model_sub_store(struct bt_mesh_model *mod) +{ + mod->flags |= BT_MESH_MOD_SUB_PENDING; + bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_MOD_PENDING); +} + +void bt_mesh_model_pub_store(struct bt_mesh_model *mod) +{ + mod->flags |= BT_MESH_MOD_PUB_PENDING; + bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_MOD_PENDING); +} + +int bt_mesh_model_data_store(struct bt_mesh_model *mod, bool vnd, + const char *name, const void *data, + size_t data_len) +{ + char path[30]; + char buf[BT_SETTINGS_SIZE(sizeof(struct mod_pub_val))]; + char *val; + int err; + + encode_mod_path(mod, vnd, "data", path, sizeof(path)); + if (name) { + strcat(path, "/"); + strncat(path, name, SETTINGS_MAX_DIR_DEPTH); + } + + if (data_len) { + val = settings_str_from_bytes(data, data_len, buf, sizeof(buf)); + if (!val) { + BT_ERR("Unable to encode model publication as value"); + return -EINVAL; + } + err = settings_save_one(path, val); + } else { + err = settings_save_one(path, NULL); + } + + if (err) { + BT_ERR("Failed to store %s value", path); + } else { + BT_DBG("Stored %s value", path); + } + return err; +} +#endif + +static void commit_mod(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, + bool vnd, bool primary, void *user_data) +{ + if (mod->pub && mod->pub->update && + mod->pub->addr != BT_MESH_ADDR_UNASSIGNED) { + int32_t ms = bt_mesh_model_pub_period_get(mod); + + if (ms > 0) { + BT_DBG("Starting publish timer (period %u ms)", ms); + k_work_schedule(&mod->pub->timer, K_MSEC(ms)); + } + } + + if (!IS_ENABLED(CONFIG_BT_MESH_LOW_POWER)) { + return; + } + + for (int i = 0; i < ARRAY_SIZE(mod->groups); i++) { + if (mod->groups[i] != BT_MESH_ADDR_UNASSIGNED) { + bt_mesh_lpn_group_add(mod->groups[i]); + } + } +} + +void bt_mesh_model_settings_commit(void) +{ + bt_mesh_model_foreach(commit_mod, NULL); +} + +#if MYNEWT_VAL(BLE_MESH_SETTINGS) +static struct conf_handler bt_mesh_sig_mod_conf_handler = { + .ch_name = "bt_mesh", + .ch_get = NULL, + .ch_set = sig_mod_set, + .ch_commit = NULL, + .ch_export = NULL, +}; + +static struct conf_handler bt_mesh_vnd_mod_conf_handler = { + .ch_name = "bt_mesh", + .ch_get = NULL, + .ch_set = vnd_mod_set, + .ch_commit = NULL, + .ch_export = NULL, +}; #endif + +void bt_mesh_access_init(void) +{ + #if MYNEWT_VAL(BLE_MESH_SETTINGS) + int rc; + + rc = conf_register(&bt_mesh_sig_mod_conf_handler); + + SYSINIT_PANIC_ASSERT_MSG(rc == 0, + "Failed to register bt_mesh_access conf"); + rc = conf_register(&bt_mesh_vnd_mod_conf_handler); + + SYSINIT_PANIC_ASSERT_MSG(rc == 0, + "Failed to register bt_mesh_access conf"); + #endif +} diff --git a/nimble/host/mesh/src/access.h b/nimble/host/mesh/src/access.h index affba538f2..217f4abe0f 100644 --- a/nimble/host/mesh/src/access.h +++ b/nimble/host/mesh/src/access.h @@ -11,14 +11,6 @@ #include "mesh/mesh.h" -/* bt_mesh_model.flags */ -enum { - BT_MESH_MOD_BIND_PENDING = BIT(0), - BT_MESH_MOD_SUB_PENDING = BIT(1), - BT_MESH_MOD_PUB_PENDING = BIT(2), - BT_MESH_MOD_NEXT_IS_PARENT = BIT(3), -}; - /* Tree walk return codes */ enum bt_mesh_walk { BT_MESH_WALK_STOP, @@ -29,15 +21,16 @@ void bt_mesh_elem_register(struct bt_mesh_elem *elem, uint8_t count); uint8_t bt_mesh_elem_count(void); -/* Find local element based on unicast or group address */ +/* Find local element based on unicast address */ struct bt_mesh_elem *bt_mesh_elem_find(uint16_t addr); -struct bt_mesh_model *bt_mesh_model_root(struct bt_mesh_model *mod); -void bt_mesh_model_tree_walk(struct bt_mesh_model *root, - enum bt_mesh_walk (*cb)(struct bt_mesh_model *mod, - uint32_t depth, - void *user_data), - void *user_data); +bool bt_mesh_has_addr(uint16_t addr); +bool bt_mesh_model_has_key(struct bt_mesh_model *mod, uint16_t key); + +void bt_mesh_model_extensions_walk(struct bt_mesh_model *root, + enum bt_mesh_walk (*cb)(struct bt_mesh_model *mod, + void *user_data), + void *user_data); uint16_t *bt_mesh_model_find_group(struct bt_mesh_model **mod, uint16_t addr); @@ -61,4 +54,35 @@ struct bt_mesh_model *bt_mesh_model_get(bool vnd, uint8_t elem_idx, uint8_t mod_ void bt_mesh_model_recv(struct bt_mesh_net_rx *rx, struct os_mbuf *buf); int bt_mesh_comp_register(const struct bt_mesh_comp *comp); + +void bt_mesh_model_pending_store(void); +void bt_mesh_model_bind_store(struct bt_mesh_model *mod); +void bt_mesh_model_sub_store(struct bt_mesh_model *mod); +void bt_mesh_model_pub_store(struct bt_mesh_model *mod); +void bt_mesh_model_settings_commit(void); + +/** @brief Register a callback function hook for mesh model messages. + * + * Register a callback function to act as a hook for recieving mesh model layer messages + * directly to the application without having instantiated the relevant models. + * + * @param cb A pointer to the callback function. + */ +void bt_mesh_msg_cb_set(void (*cb)(uint32_t opcode, struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf)); + +/** @brief Send a mesh model message. + * + * Send a mesh model layer message out into the mesh network without having instantiated + * the relevant mesh models. + * + * @param ctx The Bluetooth mesh message context. + * @param buf The message payload. + * + * @return 0 on success or negative error code on failure. + */ +int bt_mesh_msg_send(struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf, uint16_t src_addr, + const struct bt_mesh_send_cb *cb, void *cb_data); + +void bt_mesh_access_init(void); #endif diff --git a/nimble/host/mesh/src/adv.c b/nimble/host/mesh/src/adv.c index 7e0e1927fa..b2c54ae928 100644 --- a/nimble/host/mesh/src/adv.c +++ b/nimble/host/mesh/src/adv.c @@ -8,12 +8,12 @@ */ #include "syscfg/syscfg.h" -#define MESH_LOG_MODULE BLE_MESH_ADV_LOG +#define BLE_NPL_LOG_MODULE BLE_MESH_ADV_LOG +#include #include "mesh/mesh.h" #include "host/ble_hs_adv.h" #include "host/ble_gap.h" -#include "nimble/hci_common.h" #include "mesh/porting.h" #include "adv.h" @@ -23,41 +23,26 @@ #include "prov.h" #include "proxy.h" -/* Convert from ms to 0.625ms units */ -#define ADV_SCAN_UNIT(_ms) ((_ms) * 8 / 5) - /* Window and Interval are equal for continuous scanning */ -#define MESH_SCAN_INTERVAL_MS 30 -#define MESH_SCAN_WINDOW_MS 30 -#define MESH_SCAN_INTERVAL ADV_SCAN_UNIT(MESH_SCAN_INTERVAL_MS) -#define MESH_SCAN_WINDOW ADV_SCAN_UNIT(MESH_SCAN_WINDOW_MS) - -/* Pre-5.0 controllers enforce a minimum interval of 100ms - * whereas 5.0+ controllers can go down to 20ms. - */ -#define ADV_INT_DEFAULT_MS 100 -#define ADV_INT_FAST_MS 20 +#define MESH_SCAN_INTERVAL BT_MESH_ADV_SCAN_UNIT(BT_MESH_SCAN_INTERVAL_MS) +#define MESH_SCAN_WINDOW BT_MESH_ADV_SCAN_UNIT(BT_MESH_SCAN_WINDOW_MS) -static int32_t adv_int_min = ADV_INT_DEFAULT_MS; +const uint8_t bt_mesh_adv_type[BT_MESH_ADV_TYPES] = { + [BT_MESH_ADV_PROV] = BT_DATA_MESH_PROV, + [BT_MESH_ADV_DATA] = BT_DATA_MESH_MESSAGE, + [BT_MESH_ADV_BEACON] = BT_DATA_MESH_BEACON, + [BT_MESH_ADV_URI] = BT_DATA_URI, +}; -/* TinyCrypt PRNG consumes a lot of stack space, so we need to have - * an increased call stack whenever it's used. - */ -#if MYNEWT -OS_TASK_STACK_DEFINE(g_blemesh_stack, MYNEWT_VAL(BLE_MESH_ADV_STACK_SIZE)); -struct os_task adv_task; -#endif - -static struct ble_npl_eventq adv_queue; extern uint8_t g_mesh_addr_type; -static int adv_initialized = false; - -static os_membuf_t adv_buf_mem[OS_MEMPOOL_SIZE( - MYNEWT_VAL(BLE_MESH_ADV_BUF_COUNT), - BT_MESH_ADV_DATA_SIZE + BT_MESH_MBUF_HEADER_SIZE)]; struct os_mbuf_pool adv_os_mbuf_pool; -static struct os_mempool adv_buf_mempool; +struct ble_npl_eventq bt_mesh_adv_queue; + +os_membuf_t adv_buf_mem[OS_MEMPOOL_SIZE( + MYNEWT_VAL(BLE_MESH_ADV_BUF_COUNT), + BT_MESH_ADV_DATA_SIZE + BT_MESH_MBUF_HEADER_SIZE)]; +struct os_mempool adv_buf_mempool; static struct bt_mesh_adv adv_pool[CONFIG_BT_MESH_ADV_BUF_COUNT]; @@ -66,143 +51,6 @@ static struct bt_mesh_adv *adv_alloc(int id) return &adv_pool[id]; } -static inline void adv_send_start(uint16_t duration, int err, - const struct bt_mesh_send_cb *cb, - void *cb_data) -{ - if (cb && cb->start) { - cb->start(duration, err, cb_data); - } -} - -static inline void adv_send_end(int err, const struct bt_mesh_send_cb *cb, - void *cb_data) -{ - if (cb && cb->end) { - cb->end(err, cb_data); - } -} - -static inline void adv_send(struct os_mbuf *buf) -{ - static const uint8_t adv_type[] = { - [BT_MESH_ADV_PROV] = BLE_HS_ADV_TYPE_MESH_PROV, - [BT_MESH_ADV_DATA] = BLE_HS_ADV_TYPE_MESH_MESSAGE, - [BT_MESH_ADV_BEACON] = BLE_HS_ADV_TYPE_MESH_BEACON, - [BT_MESH_ADV_URI] = BLE_HS_ADV_TYPE_URI, -} ; - - const struct bt_mesh_send_cb *cb = BT_MESH_ADV(buf)->cb; - void *cb_data = BT_MESH_ADV(buf)->cb_data; - struct ble_gap_adv_params param = { 0 }; - uint16_t duration, adv_int; - struct bt_data ad; - int err; - - adv_int = max(adv_int_min, - BT_MESH_TRANSMIT_INT(BT_MESH_ADV(buf)->xmit)); -#if MYNEWT_VAL(BLE_CONTROLLER) - duration = ((BT_MESH_TRANSMIT_COUNT(BT_MESH_ADV(buf)->xmit) + 1) * - (adv_int + 10)); -#else - duration = (MESH_SCAN_WINDOW_MS + - ((BT_MESH_TRANSMIT_COUNT(BT_MESH_ADV(buf)->xmit) + 1) * - (adv_int + 10))); -#endif - - BT_DBG("type %u om_len %u: %s", BT_MESH_ADV(buf)->type, - buf->om_len, bt_hex(buf->om_data, buf->om_len)); - BT_DBG("count %u interval %ums duration %ums", - BT_MESH_TRANSMIT_COUNT(BT_MESH_ADV(buf)->xmit) + 1, adv_int, - duration); - - ad.type = adv_type[BT_MESH_ADV(buf)->type]; - ad.data_len = buf->om_len; - ad.data = buf->om_data; - - param.itvl_min = ADV_SCAN_UNIT(adv_int); - param.itvl_max = param.itvl_min; - param.conn_mode = BLE_GAP_CONN_MODE_NON; - - err = bt_le_adv_start(¶m, &ad, 1, NULL, 0); - net_buf_unref(buf); - adv_send_start(duration, err, cb, cb_data); - if (err) { - BT_ERR("Advertising failed: err %d", err); - return; - } - - BT_DBG("Advertising started. Sleeping %u ms", duration); - - k_sleep(K_MSEC(duration)); - - err = bt_le_adv_stop(false); - adv_send_end(err, cb, cb_data); - if (err) { - BT_ERR("Stopping advertising failed: err %d", err); - return; - } - - BT_DBG("Advertising stopped"); -} - -void -mesh_adv_thread(void *args) -{ - static struct ble_npl_event *ev; - struct os_mbuf *buf; -#if (MYNEWT_VAL(BLE_MESH_PROXY)) - int32_t timeout; -#endif - - BT_DBG("started"); - - while (1) { -#if (MYNEWT_VAL(BLE_MESH_PROXY)) - ev = ble_npl_eventq_get(&adv_queue, 0); - while (!ev) { - timeout = bt_mesh_proxy_adv_start(); - BT_DBG("Proxy Advertising up to %d ms", (int) timeout); - - // FIXME: should we redefine K_SECONDS macro instead in glue? - if (timeout != K_FOREVER) { - timeout = ble_npl_time_ms_to_ticks32(timeout); - } - - ev = ble_npl_eventq_get(&adv_queue, timeout); - bt_mesh_proxy_adv_stop(); - } -#else - ev = ble_npl_eventq_get(&adv_queue, BLE_NPL_TIME_FOREVER); -#endif - - if (!ev || !ble_npl_event_get_arg(ev)) { - continue; - } - - buf = ble_npl_event_get_arg(ev); - - /* busy == 0 means this was canceled */ - if (BT_MESH_ADV(buf)->busy) { - BT_MESH_ADV(buf)->busy = 0; - adv_send(buf); - } else { - net_buf_unref(buf); - } - - /* os_sched(NULL); */ - } -} - -void bt_mesh_adv_update(void) -{ - static struct ble_npl_event ev = { }; - - BT_DBG(""); - - ble_npl_eventq_put(&adv_queue, &ev); -} - struct os_mbuf *bt_mesh_adv_create_from_pool(struct os_mbuf_pool *pool, bt_mesh_adv_alloc_t get_id, enum bt_mesh_adv_type type, @@ -252,7 +100,8 @@ void bt_mesh_adv_send(struct os_mbuf *buf, const struct bt_mesh_send_cb *cb, BT_MESH_ADV(buf)->cb_data = cb_data; BT_MESH_ADV(buf)->busy = 1; - net_buf_put(&adv_queue, net_buf_ref(buf)); + net_buf_put(&bt_mesh_adv_queue, net_buf_ref(buf)); + bt_mesh_adv_buf_ready(); } static void bt_mesh_scan_cb(const bt_addr_le_t *addr, int8_t rssi, @@ -306,42 +155,6 @@ static void bt_mesh_scan_cb(const bt_addr_le_t *addr, int8_t rssi, } } -void bt_mesh_adv_init(void) -{ - int rc; - - /* Advertising should only be initialized once. Calling - * os_task init the second time will result in an assert. */ - if (adv_initialized) { - return; - } - - rc = os_mempool_init(&adv_buf_mempool, MYNEWT_VAL(BLE_MESH_ADV_BUF_COUNT), - BT_MESH_ADV_DATA_SIZE + BT_MESH_MBUF_HEADER_SIZE, - adv_buf_mem, "adv_buf_pool"); - assert(rc == 0); - - rc = os_mbuf_pool_init(&adv_os_mbuf_pool, &adv_buf_mempool, - BT_MESH_ADV_DATA_SIZE + BT_MESH_MBUF_HEADER_SIZE, - MYNEWT_VAL(BLE_MESH_ADV_BUF_COUNT)); - assert(rc == 0); - - ble_npl_eventq_init(&adv_queue); - -#if MYNEWT - os_task_init(&adv_task, "mesh_adv", mesh_adv_thread, NULL, - MYNEWT_VAL(BLE_MESH_ADV_TASK_PRIO), OS_WAIT_FOREVER, - g_blemesh_stack, MYNEWT_VAL(BLE_MESH_ADV_STACK_SIZE)); -#endif - - /* For BT5 controllers we can have fast advertising interval */ - if (ble_hs_hci_get_hci_version() >= BLE_HCI_VER_BCS_5_0) { - adv_int_min = ADV_INT_FAST_MS; - } - - adv_initialized = true; -} - int ble_adv_gap_mesh_cb(struct ble_gap_event *event, void *arg) { diff --git a/nimble/host/mesh/src/adv.h b/nimble/host/mesh/src/adv.h index 6dd2c8107c..aa83a47b86 100644 --- a/nimble/host/mesh/src/adv.h +++ b/nimble/host/mesh/src/adv.h @@ -14,6 +14,10 @@ #define BT_MESH_ADV(om) (*(struct bt_mesh_adv **) OS_MBUF_USRHDR(om)) +#define BT_MESH_ADV_SCAN_UNIT(_ms) ((_ms) * 8 / 5) +#define BT_MESH_SCAN_INTERVAL_MS 30 +#define BT_MESH_SCAN_WINDOW_MS 30 + #define BT_MESH_ADV_DATA_SIZE 31 /* The user data is a pointer (4 bytes) to struct bt_mesh_adv */ @@ -23,17 +27,35 @@ BT_MESH_ADV_USER_DATA_SIZE +\ sizeof(struct os_mbuf)) +/* We declare it as extern here to share it between 'adv' and 'adv_legacy' */ +extern struct os_mbuf_pool adv_os_mbuf_pool; +extern struct ble_npl_eventq bt_mesh_adv_queue; +extern struct os_mempool adv_buf_mempool; +extern os_membuf_t adv_buf_mem[]; + enum bt_mesh_adv_type { BT_MESH_ADV_PROV, BT_MESH_ADV_DATA, BT_MESH_ADV_BEACON, BT_MESH_ADV_URI, + + BT_MESH_ADV_TYPES, }; typedef void (*bt_mesh_adv_func_t)(struct os_mbuf *buf, uint16_t duration, int err, void *user_data); + +static inline void adv_send_start(uint16_t duration, int err, + const struct bt_mesh_send_cb *cb, + void *cb_data) +{ + if (cb && cb->start) { + cb->start(duration, err, cb_data); + } +} + struct bt_mesh_adv { /** Fragments associated with this buffer. */ struct os_mbuf *frags; @@ -42,7 +64,9 @@ struct bt_mesh_adv { void *cb_data; uint8_t type:2, - busy:1; + started:1, + busy:1; + uint8_t xmit; uint8_t flags; @@ -72,6 +96,36 @@ void bt_mesh_adv_init(void); int bt_mesh_scan_enable(void); int bt_mesh_scan_disable(void); +int bt_mesh_adv_enable(void); +void bt_mesh_adv_buf_ready(void); + +int bt_mesh_adv_start(const struct ble_gap_adv_params *param, int32_t duration, + const struct bt_data *ad, size_t ad_len, + const struct bt_data *sd, size_t sd_len); + +static inline void bt_mesh_adv_send_start(uint16_t duration, int err, + struct bt_mesh_adv *adv) +{ + if (!adv->started) { + adv->started = 1; + + if (adv->cb && adv->cb->start) { + adv->cb->start(duration, err, adv->cb_data); + } + + if (err) { + adv->cb = NULL; + } + } +} + +static inline void bt_mesh_adv_send_end( + int err, struct bt_mesh_adv const *adv) +{ + if (adv->started && adv->cb && adv->cb->end) { + adv->cb->end(err, adv->cb_data); + } +} int ble_adv_gap_mesh_cb(struct ble_gap_event *event, void *arg); #endif diff --git a/nimble/host/mesh/src/adv_ext.c b/nimble/host/mesh/src/adv_ext.c new file mode 100644 index 0000000000..c5689e5652 --- /dev/null +++ b/nimble/host/mesh/src/adv_ext.c @@ -0,0 +1,345 @@ +/* Bluetooth Mesh */ + +/* + * Copyright (c) 2018 Nordic Semiconductor ASA + * Copyright (c) 2017 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define BLE_NPL_LOG_MODULE BLE_MESH_ADV_LOG +#include + +#include "adv.h" +#include "net.h" +#include "proxy.h" +#include "pb_gatt_srv.h" +#include "syscfg/syscfg.h" +#include "host/ble_gap.h" + +#if MYNEWT_VAL(BLE_MESH_ADV_EXT) +/* Convert from ms to 0.625ms units */ +#define ADV_INT_FAST_MS 20 +#define BT_ID_DEFAULT 0 + +static struct ble_gap_ext_adv_params adv_param = { + .itvl_min = BT_MESH_ADV_SCAN_UNIT(ADV_INT_FAST_MS), + .itvl_max = BT_MESH_ADV_SCAN_UNIT(ADV_INT_FAST_MS), +}; + +bool ext_adv_configured = false; + +enum { + /** Controller is currently advertising */ + ADV_FLAG_ACTIVE, + /** Currently performing proxy advertising */ + ADV_FLAG_PROXY, + /** The send-call has been scheduled. */ + ADV_FLAG_SCHEDULED, + /** Custom adv params have been set, we need to update the parameters on + * the next send. + */ + ADV_FLAG_UPDATE_PARAMS, + + /* Number of adv flags. */ + ADV_FLAGS_NUM +}; + +static struct { + ATOMIC_DEFINE(flags, ADV_FLAGS_NUM); + struct bt_le_ext_adv *instance; + struct os_mbuf *buf; + int64_t timestamp; + struct k_work_delayable work; +} adv; + + +static void schedule_send(void) +{ + int64_t timestamp = adv.timestamp; + int64_t delta; + + if (atomic_test_and_clear_bit(adv.flags, ADV_FLAG_PROXY)) { + ble_gap_ext_adv_stop(BT_ID_DEFAULT); + atomic_clear_bit(adv.flags, ADV_FLAG_ACTIVE); + } + + if (atomic_test_bit(adv.flags, ADV_FLAG_ACTIVE) || + atomic_test_and_set_bit(adv.flags, ADV_FLAG_SCHEDULED)) { + return; + } + + /* The controller will send the next advertisement immediately. + * Introduce a delay here to avoid sending the next mesh packet closer + * to the previous packet than what's permitted by the specification. + */ + delta = k_uptime_delta(×tamp); + k_work_reschedule(&adv.work, K_MSEC(ADV_INT_FAST_MS - delta)); +} + +static int +ble_mesh_ext_adv_event_handler(struct ble_gap_event *event, void *arg) +{ + int64_t duration; + + switch (event->type) { + case BLE_GAP_EVENT_CONNECT: + if (atomic_test_and_clear_bit(adv.flags, ADV_FLAG_PROXY)) { + atomic_clear_bit(adv.flags, ADV_FLAG_ACTIVE); + schedule_send(); + } + break; + case BLE_GAP_EVENT_ADV_COMPLETE: + /* Calling k_uptime_delta on a timestamp moves it to the current time. + * This is essential here, as schedule_send() uses the end of the event + * as a reference to avoid sending the next advertisement too soon. + */ + duration = k_uptime_delta(&adv.timestamp); + + BT_DBG("Advertising stopped after %u ms", (uint32_t)duration); + + atomic_clear_bit(adv.flags, ADV_FLAG_ACTIVE); + + if (!atomic_test_and_clear_bit(adv.flags, ADV_FLAG_PROXY)) { + net_buf_unref(adv.buf); + } + + schedule_send(); + break; + default: + return 0; + } + return 0; +} + +static int adv_start(const struct ble_gap_ext_adv_params *param, + uint32_t timeout, + const struct bt_data *ad, size_t ad_len, + const struct bt_data *sd, size_t sd_len) +{ + int err; + struct os_mbuf *ad_data; + struct os_mbuf *sd_data; + + ad_data = os_msys_get_pkthdr(BLE_HS_ADV_MAX_SZ, 0); + assert(ad_data); + sd_data = os_msys_get_pkthdr(BLE_HS_ADV_MAX_SZ, 0); + assert(sd_data); + if (!adv.instance) { + BT_ERR("Mesh advertiser not enabled"); + err = -ENODEV; + goto error; + } + + if (atomic_test_and_set_bit(adv.flags, ADV_FLAG_ACTIVE)) { + BT_ERR("Advertiser is busy"); + err = -EBUSY; + goto error; + } + + if (atomic_test_bit(adv.flags, ADV_FLAG_UPDATE_PARAMS)) { + err = ble_gap_ext_adv_configure(BT_ID_DEFAULT, param, NULL, + ble_mesh_ext_adv_event_handler, NULL); + if (err) { + BT_ERR("Failed updating adv params: %d", err); + atomic_clear_bit(adv.flags, ADV_FLAG_ACTIVE); + goto error; + } + + atomic_set_bit_to(adv.flags, ADV_FLAG_UPDATE_PARAMS, + param != &adv_param); + } + + assert(ad_data); + err = os_mbuf_append(ad_data, ad, ad_len); + if (err) { + goto error; + } + + err = ble_gap_ext_adv_set_data(BT_ID_DEFAULT, ad_data); + if (err) { + BT_ERR("Failed setting adv data: %d", err); + atomic_clear_bit(adv.flags, ADV_FLAG_ACTIVE); + goto error; + } + + err = os_mbuf_append(sd_data, sd, sd_len); + if (err) { + goto error; + } + err = ble_gap_ext_adv_rsp_set_data(BT_ID_DEFAULT, sd_data); + if (err) { + BT_ERR("Failed setting scan response data: %d", err); + atomic_clear_bit(adv.flags, ADV_FLAG_ACTIVE); + goto error; + } + + adv.timestamp = k_uptime_get(); + + err = ble_gap_ext_adv_start(BT_ID_DEFAULT, timeout, 0); + if (err) { + BT_ERR("Advertising failed: err %d", err); + atomic_clear_bit(adv.flags, ADV_FLAG_ACTIVE); + } + +error: + if (ad_data) { + os_mbuf_free_chain(ad_data); + } + + if (sd_data) { + os_mbuf_free_chain(sd_data); + } + return err; +} + +static int buf_send(struct os_mbuf *buf) +{ + static const uint8_t bt_mesh_adv_type[] = { + [BT_MESH_ADV_PROV] = BLE_HS_ADV_TYPE_MESH_PROV, + [BT_MESH_ADV_DATA] = BLE_HS_ADV_TYPE_MESH_MESSAGE, + [BT_MESH_ADV_BEACON] = BLE_HS_ADV_TYPE_MESH_BEACON, + [BT_MESH_ADV_URI] = BLE_HS_ADV_TYPE_URI, + }; + + struct bt_le_ext_adv_start_param start = { + .num_events = + BT_MESH_TRANSMIT_COUNT(BT_MESH_ADV(buf)->xmit) + 1, + }; + uint16_t duration, adv_int; + struct bt_data ad; + int err; + + adv_int = MAX(ADV_INT_FAST_MS, + BT_MESH_TRANSMIT_INT(BT_MESH_ADV(buf)->xmit)); + /* Upper boundary estimate: */ + duration = start.num_events * (adv_int + 10); + + BT_DBG("type %u len %u: %s", BT_MESH_ADV(buf)->type, + buf->om_len, bt_hex(buf->om_data, buf->om_len)); + BT_DBG("count %u interval %ums duration %ums", + BT_MESH_TRANSMIT_COUNT(BT_MESH_ADV(buf)->xmit) + 1, adv_int, + duration); + + ad.type = bt_mesh_adv_type[BT_MESH_ADV(buf)->type]; + ad.data_len = buf->om_len; + ad.data = buf->om_data; + + /* Only update advertising parameters if they're different */ + if (adv_param.itvl_min != BT_MESH_ADV_SCAN_UNIT(adv_int)) { + adv_param.itvl_min = BT_MESH_ADV_SCAN_UNIT(adv_int); + adv_param.itvl_max = adv_param.itvl_min; + atomic_set_bit(adv.flags, ADV_FLAG_UPDATE_PARAMS); + } + + err = adv_start(&adv_param, duration, &ad, 1, NULL, 0); + if (!err) { + adv.buf = net_buf_ref(buf); + } + + bt_mesh_adv_send_start(duration, err, BT_MESH_ADV(buf)); + + return err; +} + +static void send_pending_adv(struct ble_npl_event *work) +{ + struct os_mbuf *buf; + int err; + + atomic_clear_bit(adv.flags, ADV_FLAG_SCHEDULED); + + while ((buf = net_buf_get(&bt_mesh_adv_queue, K_NO_WAIT))) { + /* busy == 0 means this was canceled */ + if (!BT_MESH_ADV(buf)->busy) { + net_buf_unref(buf); + continue; + } + + BT_MESH_ADV(buf)->busy = 0U; + err = buf_send(buf); + + net_buf_unref(buf); + + if (!err) { + return; /* Wait for advertising to finish */ + } + } + + if (!MYNEWT_VAL(BLE_MESH_GATT_SERVER)) { + return; + } + + /* No more pending buffers */ + if (bt_mesh_is_provisioned()) { + if (IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY)) { + err = bt_mesh_proxy_adv_start(); + BT_DBG("Proxy Advertising"); + } + } else if (IS_ENABLED(CONFIG_BT_MESH_PB_GATT)) { + err = bt_mesh_pb_gatt_adv_start(); + BT_DBG("PB-GATT Advertising"); + } + + if (!err) { + atomic_set_bit(adv.flags, ADV_FLAG_PROXY); + } +} + +void bt_mesh_adv_update(void) +{ + BT_DBG(""); + + schedule_send(); +} + +void bt_mesh_adv_buf_ready(void) +{ + schedule_send(); +} + +void bt_mesh_adv_init(void) +{ + int rc; + + rc = os_mempool_init(&adv_buf_mempool, MYNEWT_VAL(BLE_MESH_ADV_BUF_COUNT), + BT_MESH_ADV_DATA_SIZE + BT_MESH_MBUF_HEADER_SIZE, + adv_buf_mem, "adv_buf_pool"); + assert(rc == 0); + + rc = os_mbuf_pool_init(&adv_os_mbuf_pool, &adv_buf_mempool, + BT_MESH_ADV_DATA_SIZE + BT_MESH_MBUF_HEADER_SIZE, + MYNEWT_VAL(BLE_MESH_ADV_BUF_COUNT)); + assert(rc == 0); + + ble_npl_eventq_init(&bt_mesh_adv_queue); + + k_work_init_delayable(&adv.work, send_pending_adv); +} + +int bt_mesh_adv_enable(void) +{ + /* No need to initialize extended advertiser instance here */ + return 0; +} + +int bt_mesh_adv_start(const struct ble_gap_adv_params *param, int32_t duration, + const struct bt_data *ad, size_t ad_len, + const struct bt_data *sd, size_t sd_len) +{ + static uint32_t adv_timeout; + struct ble_gap_ext_adv_params params = { + .itvl_min = param->itvl_min, + .itvl_max = param->itvl_max + }; + + /* In NimBLE duration is in ms, not 10ms units */ + adv_timeout = (duration == BLE_HS_FOREVER) ? 0 : duration; + + BT_DBG("Start advertising %d ms", duration); + + atomic_set_bit(adv.flags, ADV_FLAG_UPDATE_PARAMS); + + return adv_start(¶ms, adv_timeout, ad, ad_len, sd, sd_len); +} +#endif diff --git a/nimble/host/mesh/src/adv_legacy.c b/nimble/host/mesh/src/adv_legacy.c new file mode 100644 index 0000000000..6d6a666df5 --- /dev/null +++ b/nimble/host/mesh/src/adv_legacy.c @@ -0,0 +1,245 @@ +/* Bluetooth Mesh */ + +/* + * Copyright (c) 2018 Nordic Semiconductor ASA + * Copyright (c) 2017 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define BLE_NPL_LOG_MODULE BLE_MESH_ADV_LOG +#include + +#include "adv.h" +#include "net.h" +#include "foundation.h" +#include "beacon.h" +#include "prov.h" +#include "proxy.h" +#include "mesh/glue.h" +#include "pb_gatt_srv.h" + +#if MYNEWT_VAL(BLE_MESH_ADV_LEGACY) +/* Convert from ms to 0.625ms units */ +#define ADV_SCAN_UNIT(_ms) ((_ms) * 8 / 5) + +#if (MYNEWT_VAL(BSP_NRF51) && !MYNEWT_VAL(BLE_CONTROLLER)) +#define CONFIG_BT_CTLR_LOW_LAT 1 +#else +#define CONFIG_BT_CTLR_LOW_LAT 0 +#endif + +/* Pre-5.0 controllers enforce a minimum interval of 100ms + * whereas 5.0+ controllers can go down to 20ms. + */ +#define ADV_INT_DEFAULT_MS 100 +#define ADV_INT_FAST_MS 20 + +static int32_t adv_int_min = ADV_INT_DEFAULT_MS; + +static int adv_initialized = false; +/* TinyCrypt PRNG consumes a lot of stack space, so we need to have + * an increased call stack whenever it's used. + */ +#ifdef MYNEWT +OS_TASK_STACK_DEFINE(g_blemesh_stack, MYNEWT_VAL(BLE_MESH_ADV_STACK_SIZE)); +struct os_task adv_task; +#endif + +static int32_t adv_timeout; + +static inline void adv_send(struct os_mbuf *buf) +{ + static const uint8_t adv_type[] = { + [BT_MESH_ADV_PROV] = BLE_HS_ADV_TYPE_MESH_PROV, + [BT_MESH_ADV_DATA] = BLE_HS_ADV_TYPE_MESH_MESSAGE, + [BT_MESH_ADV_BEACON] = BLE_HS_ADV_TYPE_MESH_BEACON, + [BT_MESH_ADV_URI] = BLE_HS_ADV_TYPE_URI, + }; + + struct ble_gap_adv_params param = { 0 }; + uint16_t duration, adv_int; + struct bt_data ad; + int err; + + adv_int = MAX(adv_int_min, + BT_MESH_TRANSMIT_INT(BT_MESH_ADV(buf)->xmit)); +#if MYNEWT_VAL(BLE_CONTROLLER) + duration = ((BT_MESH_TRANSMIT_COUNT(BT_MESH_ADV(buf)->xmit) + 1) * + (adv_int + 10)); +#else + /* Zephyr Bluetooth Low Energy Controller for mesh stack uses + * pre-emptible continuous scanning, allowing advertising events to be + * transmitted without delay when advertising is enabled. No need to + * compensate with scan window duration. + * An advertising event could be delayed by upto one interval when + * advertising is stopped and started in quick succession, hence add + * advertising interval to the total advertising duration. + */ + duration = (adv_int + + ((BT_MESH_TRANSMIT_COUNT(BT_MESH_ADV(buf)->xmit) + 1) * + (adv_int + 10))); + + /* Zephyr Bluetooth Low Energy Controller built for nRF51x SoCs use + * CONFIG_BT_CTLR_LOW_LAT=y, and continuous scanning cannot be + * pre-empted, hence, scanning will block advertising events from + * being transmitted. Increase the advertising duration by the + * amount of scan window duration to compensate for the blocked + * advertising events. + */ + if (CONFIG_BT_CTLR_LOW_LAT) { + duration += BT_MESH_SCAN_WINDOW_MS; + } +#endif + + BT_DBG("type %u om_len %u: %s", BT_MESH_ADV(buf)->type, + buf->om_len, bt_hex(buf->om_data, buf->om_len)); + BT_DBG("count %u interval %ums duration %ums", + BT_MESH_TRANSMIT_COUNT(BT_MESH_ADV(buf)->xmit) + 1, adv_int, + duration); + + ad.type = adv_type[BT_MESH_ADV(buf)->type]; + ad.data_len = buf->om_len; + ad.data = buf->om_data; + + param.itvl_min = ADV_SCAN_UNIT(adv_int); + param.itvl_max = param.itvl_min; + param.conn_mode = BLE_GAP_CONN_MODE_NON; + + int64_t time = k_uptime_get(); + + err = bt_le_adv_start(¶m, &ad, 1, NULL, 0); + + bt_mesh_adv_send_start(duration, err, BT_MESH_ADV(buf)); + if (err) { + BT_ERR("Advertising failed: err %d", err); + return; + } + + BT_DBG("Advertising started. Sleeping %u ms", duration); + + k_sleep(K_MSEC(duration)); + + err = bt_le_adv_stop(); + if (err) { + BT_ERR("Stopping advertising failed: err %d", err); + return; + } + + BT_DBG("Advertising stopped (%u ms)", (uint32_t) k_uptime_delta(&time)); +} + +void +mesh_adv_thread(void *args) +{ + static struct ble_npl_event *ev; + struct os_mbuf *buf; + + BT_DBG("started"); + + while (1) { + if (MYNEWT_VAL(BLE_MESH_GATT_SERVER)) { + ev = ble_npl_eventq_get(&bt_mesh_adv_queue, 0); + while (!ev) { + /* Adv timeout may be set by a call from proxy + * to bt_mesh_adv_start: + */ + adv_timeout = K_FOREVER; + if (bt_mesh_is_provisioned()) { + if (IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY)) { + bt_mesh_proxy_adv_start(); + BT_DBG("Proxy Advertising up to %d ms", (int) adv_timeout); + } + } else if (IS_ENABLED(CONFIG_BT_MESH_PB_GATT)) { + bt_mesh_pb_gatt_adv_start(); + BT_DBG("PB-GATT Advertising up to %d ms", (int) adv_timeout); + } + + ev = ble_npl_eventq_get(&bt_mesh_adv_queue, ble_npl_time_ms_to_ticks32(adv_timeout)); + bt_le_adv_stop(); + } + } else { + ev = ble_npl_eventq_get(&bt_mesh_adv_queue, BLE_NPL_TIME_FOREVER); + } + if (!ev || !ble_npl_event_get_arg(ev)) { + continue; + } + + buf = ble_npl_event_get_arg(ev); + + /* busy == 0 means this was canceled */ + if (BT_MESH_ADV(buf)->busy) { + BT_MESH_ADV(buf)->busy = 0; + adv_send(buf); + } + + net_buf_unref(buf); + + /* os_sched(NULL); */ + } +} + +void bt_mesh_adv_update(void) +{ + static struct ble_npl_event ev = { }; + + BT_DBG(""); + + ble_npl_eventq_put(&bt_mesh_adv_queue, &ev); +} + +void bt_mesh_adv_buf_ready(void) +{ + /* Will be handled automatically */ +} + +void bt_mesh_adv_init(void) +{ + int rc; + + /* Advertising should only be initialized once. Calling + * os_task init the second time will result in an assert. */ + if (adv_initialized) { + return; + } + + rc = os_mempool_init(&adv_buf_mempool, MYNEWT_VAL(BLE_MESH_ADV_BUF_COUNT), + BT_MESH_ADV_DATA_SIZE + BT_MESH_MBUF_HEADER_SIZE, + adv_buf_mem, "adv_buf_pool"); + assert(rc == 0); + + rc = os_mbuf_pool_init(&adv_os_mbuf_pool, &adv_buf_mempool, + BT_MESH_ADV_DATA_SIZE + BT_MESH_MBUF_HEADER_SIZE, + MYNEWT_VAL(BLE_MESH_ADV_BUF_COUNT)); + assert(rc == 0); + + ble_npl_eventq_init(&bt_mesh_adv_queue); + +#ifdef MYNEWT + os_task_init(&adv_task, "mesh_adv", mesh_adv_thread, NULL, + MYNEWT_VAL(BLE_MESH_ADV_TASK_PRIO), OS_WAIT_FOREVER, + g_blemesh_stack, MYNEWT_VAL(BLE_MESH_ADV_STACK_SIZE)); +#endif + + /* For BT5 controllers we can have fast advertising interval */ + if (ble_hs_hci_get_hci_version() >= BLE_HCI_VER_BCS_5_0) { + adv_int_min = ADV_INT_FAST_MS; + } + + adv_initialized = true; +} + +int bt_mesh_adv_enable(void) +{ + /* Dummy function - in legacy adv thread is started on init*/ + return 0; +} + +int bt_mesh_adv_start(const struct ble_gap_adv_params *param, int32_t duration, + const struct bt_data *ad, size_t ad_len, + const struct bt_data *sd, size_t sd_len) +{ + adv_timeout = duration; + return bt_le_adv_start(param, ad, ad_len, sd, sd_len); +} +#endif diff --git a/nimble/host/mesh/src/aes-ccm.c b/nimble/host/mesh/src/aes-ccm.c index ab23c26446..4814438b3c 100644 --- a/nimble/host/mesh/src/aes-ccm.c +++ b/nimble/host/mesh/src/aes-ccm.c @@ -5,8 +5,10 @@ * SPDX-License-Identifier: Apache-2.0 */ +#define BLE_NPL_LOG_MODULE BLE_MESH_LOG +#include + #include "crypto.h" -#define MESH_LOG_MODULE BLE_MESH_LOG static inline void xor16(uint8_t *dst, const uint8_t *a, const uint8_t *b) { diff --git a/nimble/host/mesh/src/app_keys.c b/nimble/host/mesh/src/app_keys.c index 9582bbd045..ab7ab0597f 100644 --- a/nimble/host/mesh/src/app_keys.c +++ b/nimble/host/mesh/src/app_keys.c @@ -5,6 +5,9 @@ * SPDX-License-Identifier: Apache-2.0 */ +#define BLE_NPL_LOG_MODULE BLE_MESH_LOG +#include + #include #include #include "mesh/mesh.h" @@ -21,42 +24,181 @@ #include "access.h" #include "subnet.h" -#define MESH_LOG_MODULE BLE_MESH_LOG -#include "log/log.h" +/* Tracking of what storage changes are pending for App Keys. We track this in + * a separate array here instead of within the respective bt_mesh_app_key + * struct itselve, since once a key gets deleted its struct becomes invalid + * and may be reused for other keys. + */ +struct app_key_update { + uint16_t key_idx:12, /* AppKey Index */ + valid:1, /* 1 if this entry is valid, 0 if not */ + clear:1; /* 1 if key needs clearing, 0 if storing */ +}; + +/* AppKey information for persistent storage. */ +struct app_key_val { + uint16_t net_idx; + bool updated; + uint8_t val[2][16]; +} __packed; + +/** Mesh Application Key. */ +struct app_key { + uint16_t net_idx; + uint16_t app_idx; + bool updated; + struct bt_mesh_app_cred { + uint8_t id; + uint8_t val[16]; + } keys[2]; +}; + +static struct app_key_update app_key_updates[CONFIG_BT_MESH_APP_KEY_COUNT]; -static struct bt_mesh_app_key apps[CONFIG_BT_MESH_APP_KEY_COUNT] = { +static struct app_key apps[CONFIG_BT_MESH_APP_KEY_COUNT] = { [0 ... (CONFIG_BT_MESH_APP_KEY_COUNT - 1)] = { .app_idx = BT_MESH_KEY_UNUSED, .net_idx = BT_MESH_KEY_UNUSED, } }; -static void app_key_evt(struct bt_mesh_app_key *app, enum bt_mesh_key_evt evt) +static struct app_key *app_get(uint16_t app_idx) { + for (int i = 0; i < ARRAY_SIZE(apps); i++) { + if (apps[i].app_idx == app_idx) { + return &apps[i]; + } + } + + return NULL; +} + +static void clear_app_key(uint16_t app_idx) +{ +#if MYNEWT_VAL(BLE_MESH_SETTINGS) + char path[20]; + int err; + + BT_DBG("AppKeyIndex 0x%03x", app_idx); + + snprintk(path, sizeof(path), "bt_mesh/AppKey/%x", app_idx); + err = settings_save_one(path, NULL); + if (err) { + BT_ERR("Failed to clear AppKeyIndex 0x%03x", app_idx); + } else { + BT_DBG("Cleared AppKeyIndex 0x%03x", app_idx); + } +#endif +} + +static void store_app_key(uint16_t app_idx) +{ +#if MYNEWT_VAL(BLE_MESH_SETTINGS) + const struct app_key *app; + struct app_key_val key; + char path[20]; + char buf[BT_SETTINGS_SIZE(sizeof(struct app_key_val))]; + int err; + char *str; + + snprintk(path, sizeof(path), "bt_mesh/AppKey/%x", app_idx); + + app = app_get(app_idx); + if (!app) { + BT_WARN("ApKeyIndex 0x%03x not found", app_idx); + return; + } + + key.net_idx = app->net_idx, + key.updated = app->updated, + + memcpy(key.val[0], app->keys[0].val, 16); + memcpy(key.val[1], app->keys[1].val, 16); + str = settings_str_from_bytes(&key, sizeof(key), buf, sizeof(buf)); + + err = settings_save_one(path, str); + if (err) { + BT_ERR("Failed to store AppKey"); + } else { + BT_DBG("Stored AppKey %s value"); + } +#endif +} + +#if MYNEWT_VAL(BLE_MESH_SETTINGS) +static struct app_key_update *app_key_update_find(uint16_t key_idx, + struct app_key_update **free_slot) + { + struct app_key_update *match; int i; - for (i = 0; i < (sizeof(bt_mesh_app_key_cb_list)/sizeof(void *)); i++) { - if (bt_mesh_app_key_cb_list[i]) { - BT_DBG("app_key_evt %d", i); - bt_mesh_app_key_cb_list[i] (app->app_idx, app->net_idx, evt); + match = NULL; + *free_slot = NULL; + + for (i = 0; i < ARRAY_SIZE(app_key_updates); i++) { + struct app_key_update *update = &app_key_updates[i]; + + if (!update->valid) { + *free_slot = update; + continue; + } + + if (update->key_idx == key_idx) { + match = update; } } + + return match; } +#endif -struct bt_mesh_app_key *app_get(uint16_t app_idx) +static void update_app_key_settings(uint16_t app_idx, bool store) { - for (int i = 0; i < ARRAY_SIZE(apps); i++) { - if (apps[i].app_idx == app_idx) { - return &apps[i]; +#if MYNEWT_VAL(BLE_MESH_SETTINGS) + struct app_key_update *update, *free_slot; + uint8_t clear = store ? 0U : 1U; + + BT_DBG("AppKeyIndex 0x%03x", app_idx); + + update = app_key_update_find(app_idx, &free_slot); + if (update) { + update->clear = clear; + bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_APP_KEYS_PENDING); + return; + } + + if (!free_slot) { + if (store) { + store_app_key(app_idx); + } else { + clear_app_key(app_idx); } + return; } - return NULL; + free_slot->valid = 1U; + free_slot->key_idx = app_idx; + free_slot->clear = clear; + + bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_APP_KEYS_PENDING); +#endif +} + +static void app_key_evt(struct app_key *app, enum bt_mesh_key_evt evt) +{ + int i; + + for (i = 0; i < (sizeof(bt_mesh_app_key_cb_list)/sizeof(void *)); i++) { + if (bt_mesh_app_key_cb_list[i]) { + BT_DBG("app_key_evt %d", i); + bt_mesh_app_key_cb_list[i] (app->app_idx, app->net_idx, evt); + } + } } -static struct bt_mesh_app_key *app_key_alloc(uint16_t app_idx) +static struct app_key *app_key_alloc(uint16_t app_idx) { - struct bt_mesh_app_key *app = NULL; + struct app_key *app = NULL; for (int i = 0; i < ARRAY_SIZE(apps); i++) { /* Check for already existing app_key */ @@ -72,12 +214,12 @@ static struct bt_mesh_app_key *app_key_alloc(uint16_t app_idx) return app; } -static void app_key_del(struct bt_mesh_app_key *app) +static void app_key_del(struct app_key *app) { BT_DBG("AppIdx 0x%03x", app->app_idx); if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_clear_app_key(app->app_idx); + update_app_key_settings(app->app_idx, false); } app_key_evt(app, BT_MESH_KEY_DELETED); @@ -87,7 +229,7 @@ static void app_key_del(struct bt_mesh_app_key *app) (void)memset(app->keys, 0, sizeof(app->keys)); } -static void app_key_revoke(struct bt_mesh_app_key *app) +static void app_key_revoke(struct app_key *app) { if (!app->updated) { return; @@ -98,7 +240,7 @@ static void app_key_revoke(struct bt_mesh_app_key *app) app->updated = false; if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_app_key(app->app_idx); + update_app_key_settings(app->app_idx, true); } app_key_evt(app, BT_MESH_KEY_REVOKED); @@ -112,7 +254,7 @@ static void subnet_evt(struct bt_mesh_subnet *sub, enum bt_mesh_key_evt evt) } for (int i = 0; i < ARRAY_SIZE(apps); i++) { - struct bt_mesh_app_key *app = &apps[i]; + struct app_key *app = &apps[i]; if (app->app_idx == BT_MESH_KEY_UNUSED) { continue; @@ -140,7 +282,7 @@ uint8_t bt_mesh_app_key_add(uint16_t app_idx, uint16_t net_idx, bt_mesh_subnet_cb_list[0] = subnet_evt; } - struct bt_mesh_app_key *app; + struct app_key *app; BT_DBG("net_idx 0x%04x app_idx %04x val %s", net_idx, app_idx, bt_hex(key, 16)); @@ -156,7 +298,7 @@ uint8_t bt_mesh_app_key_add(uint16_t app_idx, uint16_t net_idx, if (app->app_idx == app_idx) { if (app->net_idx != net_idx) { - return STATUS_INVALID_BINDING; + return STATUS_INVALID_NETKEY; } if (memcmp(key, app->keys[0].val, 16)) { @@ -179,7 +321,7 @@ uint8_t bt_mesh_app_key_add(uint16_t app_idx, uint16_t net_idx, if (IS_ENABLED(CONFIG_BT_SETTINGS)) { BT_DBG("Storing AppKey persistently"); - bt_mesh_store_app_key(app->app_idx); + update_app_key_settings(app->app_idx, true); } app_key_evt(app, BT_MESH_KEY_ADDED); @@ -187,22 +329,10 @@ uint8_t bt_mesh_app_key_add(uint16_t app_idx, uint16_t net_idx, return STATUS_SUCCESS; } -struct bt_mesh_app_key *bt_mesh_app_key_get(uint16_t app_idx) -{ - struct bt_mesh_app_key *app; - - app = app_get(app_idx); - if (app) { - return app; - } - - return NULL; -} - uint8_t bt_mesh_app_key_update(uint16_t app_idx, uint16_t net_idx, const uint8_t key[16]) { - struct bt_mesh_app_key *app; + struct app_key *app; struct bt_mesh_subnet *sub; BT_DBG("net_idx 0x%04x app_idx %04x val %s", net_idx, app_idx, @@ -250,7 +380,7 @@ uint8_t bt_mesh_app_key_update(uint16_t app_idx, uint16_t net_idx, if (IS_ENABLED(CONFIG_BT_SETTINGS)) { BT_DBG("Storing AppKey persistently"); - bt_mesh_store_app_key(app->app_idx); + update_app_key_settings(app->app_idx, true); } app_key_evt(app, BT_MESH_KEY_UPDATED); @@ -260,7 +390,7 @@ uint8_t bt_mesh_app_key_update(uint16_t app_idx, uint16_t net_idx, uint8_t bt_mesh_app_key_del(uint16_t app_idx, uint16_t net_idx) { - struct bt_mesh_app_key *app; + struct app_key *app; BT_DBG("AppIdx 0x%03x", app_idx); @@ -288,7 +418,7 @@ uint8_t bt_mesh_app_key_del(uint16_t app_idx, uint16_t net_idx) int bt_mesh_app_key_set(uint16_t app_idx, uint16_t net_idx, const uint8_t old_key[16], const uint8_t new_key[16]) { - struct bt_mesh_app_key *app; + struct app_key *app; app = app_key_alloc(app_idx); if (!app) { @@ -337,7 +467,7 @@ ssize_t bt_mesh_app_keys_get(uint16_t net_idx, uint16_t app_idxs[], size_t max, size_t count = 0; for (int i = 0; i < ARRAY_SIZE(apps); i++) { - struct bt_mesh_app_key *app = &apps[i]; + struct app_key *app = &apps[i]; if (app->app_idx == BT_MESH_KEY_UNUSED) { continue; @@ -364,9 +494,9 @@ ssize_t bt_mesh_app_keys_get(uint16_t net_idx, uint16_t app_idxs[], size_t max, int bt_mesh_keys_resolve(struct bt_mesh_msg_ctx *ctx, struct bt_mesh_subnet **sub, - const uint8_t *app_key[16], uint8_t *aid) + const uint8_t **app_key, uint8_t *aid) { - struct bt_mesh_app_key *app = NULL; + struct app_key *app = NULL; if (BT_MESH_IS_DEV_KEY(ctx->app_idx)) { /* With device keys, the application has to decide which subnet @@ -379,7 +509,7 @@ int bt_mesh_keys_resolve(struct bt_mesh_msg_ctx *ctx, } if (ctx->app_idx == BT_MESH_KEY_DEV_REMOTE && - !bt_mesh_elem_find(ctx->addr)) { + !bt_mesh_has_addr(ctx->addr)) { struct bt_mesh_cdb_node *node; if (!IS_ENABLED(CONFIG_BT_MESH_CDB)) { @@ -462,7 +592,7 @@ uint16_t bt_mesh_app_key_find(bool dev_key, uint8_t aid, } for (i = 0; i < ARRAY_SIZE(apps); i++) { - const struct bt_mesh_app_key *app = &apps[i]; + const struct app_key *app = &apps[i]; const struct bt_mesh_app_cred *cred; if (app->app_idx == BT_MESH_KEY_UNUSED) { @@ -498,10 +628,89 @@ uint16_t bt_mesh_app_key_find(bool dev_key, uint8_t aid, void bt_mesh_app_keys_reset(void) { for (int i = 0; i < ARRAY_SIZE(apps); i++) { - struct bt_mesh_app_key *app = &apps[i]; + struct app_key *app = &apps[i]; if (app->app_idx != BT_MESH_KEY_UNUSED) { app_key_del(app); } } } + +#if MYNEWT_VAL(BLE_MESH_SETTINGS) +static int app_key_set(int argc, char **argv, char *val) +{ + struct app_key_val key; + uint16_t app_idx; + int len_rd, err; + + BT_DBG("argv[0] %s val %s", argv[0], val ? val : "(null)"); + + app_idx = strtol(argv[0], NULL, 16); + len_rd = strtol(argv[1], NULL, 16); + + + if (!len_rd) { + return 0; + } + + err = settings_bytes_from_str(val, &key, &len_rd); + if (err) { + BT_ERR("Failed to decode value %s (err %d)", val, err); + return err; + } + + err = bt_mesh_app_key_set(app_idx, key.net_idx, key.val[0], + key.updated ? key.val[1] : NULL); + if (err) { + BT_ERR("Failed to set \'app-key\'"); + return err; + } + + BT_DBG("AppKeyIndex 0x%03x recovered from storage", app_idx); + + return 0; +} +#endif + +void bt_mesh_app_key_pending_store(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(app_key_updates); i++) { + struct app_key_update *update = &app_key_updates[i]; + + if (!update->valid) { + continue; + } + + if (update->clear) { + clear_app_key(update->key_idx); + } else { + store_app_key(update->key_idx); + } + + update->valid = 0U; + } +} + +#if MYNEWT_VAL(BLE_MESH_SETTINGS) +static struct conf_handler bt_mesh_app_key_conf_handler = { + .ch_name = "bt_mesh", + .ch_get = NULL, + .ch_set = app_key_set, + .ch_commit = NULL, + .ch_export = NULL, +}; +#endif + +void bt_mesh_app_key_init(void) +{ +#if MYNEWT_VAL(BLE_MESH_SETTINGS) + int rc; + + rc = conf_register(&bt_mesh_app_key_conf_handler); + + SYSINIT_PANIC_ASSERT_MSG(rc == 0, + "Failed to register bt_mesh_app_key conf"); +#endif +} diff --git a/nimble/host/mesh/src/app_keys.h b/nimble/host/mesh/src/app_keys.h index d007b785f6..40df664506 100644 --- a/nimble/host/mesh/src/app_keys.h +++ b/nimble/host/mesh/src/app_keys.h @@ -10,28 +10,9 @@ #include "mesh/mesh.h" #include "subnet.h" -/** Mesh Application. */ -struct bt_mesh_app_key { - uint16_t net_idx; - uint16_t app_idx; - bool updated; - struct bt_mesh_app_cred { - uint8_t id; - uint8_t val[16]; - } keys[2]; -}; - /** @brief Reset the app keys module. */ void bt_mesh_app_keys_reset(void); -/** @brief Get the application key with the given AppIdx. - * - * @param app_idx App index. - * - * @return The matching application, or NULL if the application isn't known. - */ -struct bt_mesh_app_key *bt_mesh_app_key_get(uint16_t app_idx); - /** @brief Initialize a new application key with the given parameters. * * @param app_idx AppIndex. @@ -60,7 +41,7 @@ int bt_mesh_app_key_set(uint16_t app_idx, uint16_t net_idx, */ int bt_mesh_keys_resolve(struct bt_mesh_msg_ctx *ctx, struct bt_mesh_subnet **sub, - const uint8_t *app_key[16], uint8_t *aid); + const uint8_t **app_key, uint8_t *aid); /** @brief Iterate through all matching application keys and call @c cb on each. * @@ -78,9 +59,10 @@ uint16_t bt_mesh_app_key_find(bool dev_key, uint8_t aid, const uint8_t key[16], void *cb_data), void *cb_data); -struct bt_mesh_app_key *app_get(uint16_t app_idx); - extern void (*bt_mesh_app_key_cb_list[1]) (uint16_t app_idx, uint16_t net_idx, enum bt_mesh_key_evt evt); -#endif /* _BT_MESH_APP_KEYS_H_ */ \ No newline at end of file +/** @brief Store pending application keys in persistent storage. */ +void bt_mesh_app_key_pending_store(void); +void bt_mesh_app_key_init(void); +#endif /* _BT_MESH_APP_KEYS_H_ */ diff --git a/nimble/host/mesh/src/beacon.c b/nimble/host/mesh/src/beacon.c index 6a5fc5a1cd..e646fc6a31 100644 --- a/nimble/host/mesh/src/beacon.c +++ b/nimble/host/mesh/src/beacon.c @@ -7,7 +7,10 @@ */ #include "syscfg/syscfg.h" -#define MESH_LOG_MODULE BLE_MESH_BEACON_LOG + +#define BLE_NPL_LOG_MODULE BLE_MESH_BEACON_LOG +#include + #include #include @@ -34,7 +37,7 @@ /* 1 transmission, 20ms interval */ #define PROV_XMIT BT_MESH_TRANSMIT(0, 20) -static struct k_delayed_work beacon_timer; +static struct k_work_delayable beacon_timer; static int cache_check(struct bt_mesh_subnet *sub, void *beacon_data) { @@ -228,33 +231,30 @@ static void update_beacon_observation(void) static void beacon_send(struct ble_npl_event *work) { - /* Don't send anything if we have an active provisioning link */ - if (IS_ENABLED(CONFIG_BT_MESH_PB_ADV) && bt_mesh_prov_active()) { - k_delayed_work_submit(&beacon_timer, - K_SECONDS(MYNEWT_VAL(BLE_MESH_UNPROV_BEACON_INT))); - return; - } BT_DBG(""); if (bt_mesh_is_provisioned()) { + if (!bt_mesh_beacon_enabled() && + !atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_INITIATOR)) { + return; + } + update_beacon_observation(); (void)bt_mesh_subnet_find(secure_beacon_send, NULL); - /* Only resubmit if beaconing is still enabled */ - if (bt_mesh_beacon_enabled() || - atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_INITIATOR)) { - k_delayed_work_submit(&beacon_timer, - PROVISIONED_INTERVAL); - } + k_work_schedule(&beacon_timer, PROVISIONED_INTERVAL); return; } if (IS_ENABLED(BLE_MESH_PB_ADV)) { - unprovisioned_beacon_send(); - k_delayed_work_submit(&beacon_timer, - K_SECONDS(MYNEWT_VAL(BLE_MESH_UNPROV_BEACON_INT))); + /* Don't send anything if we have an active provisioning link */ + if (!bt_mesh_prov_active()) { + unprovisioned_beacon_send(); + } + + k_work_schedule(&beacon_timer, K_SECONDS(MYNEWT_VAL(BLE_MESH_UNPROV_BEACON_INT))); } } @@ -426,22 +426,27 @@ static void subnet_evt(struct bt_mesh_subnet *sub, enum bt_mesh_key_evt evt) void bt_mesh_beacon_init(void) { - if (!bt_mesh_subnet_cb_list[1]) { + if (!bt_mesh_subnet_cb_list[1]) { bt_mesh_subnet_cb_list[1] = subnet_evt; } - k_delayed_work_init(&beacon_timer, beacon_send); + k_work_init_delayable(&beacon_timer, beacon_send); } void bt_mesh_beacon_ivu_initiator(bool enable) { atomic_set_bit_to(bt_mesh.flags, BT_MESH_IVU_INITIATOR, enable); - if (enable) { - k_delayed_work_submit(&beacon_timer, K_NO_WAIT); - } else if (!bt_mesh_beacon_enabled()) { - k_delayed_work_cancel(&beacon_timer); - } + /* Fire the beacon handler straight away if it's not already pending - + * in which case we'll fire according to the ongoing periodic sending. + * If beacons are disabled, the handler will exit early. + * + * An alternative solution would be to check whether beacons are enabled + * here, and cancel if not. As the cancel operation may fail, we would + * still have to implement an early exit mechanism, so we might as well + * just use this every time. + */ + k_work_schedule(&beacon_timer, K_NO_WAIT); } static void subnet_beacon_enable(struct bt_mesh_subnet *sub) @@ -454,19 +459,17 @@ static void subnet_beacon_enable(struct bt_mesh_subnet *sub) void bt_mesh_beacon_enable(void) { - if (!bt_mesh_is_provisioned()) { - k_delayed_work_submit(&beacon_timer, K_NO_WAIT); - return; + if (bt_mesh_is_provisioned()) { + bt_mesh_subnet_foreach(subnet_beacon_enable); } - bt_mesh_subnet_foreach(subnet_beacon_enable); - - k_delayed_work_submit(&beacon_timer, K_NO_WAIT); + k_work_reschedule(&beacon_timer, K_NO_WAIT); } void bt_mesh_beacon_disable(void) { if (!atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_INITIATOR)) { - k_delayed_work_cancel(&beacon_timer); + /* If this fails, we'll do an early exit in the work handler. */ + (void)k_work_cancel_delayable(&beacon_timer); } } diff --git a/nimble/host/mesh/src/cdb.c b/nimble/host/mesh/src/cdb.c index 60d47dee26..ed97ce539c 100644 --- a/nimble/host/mesh/src/cdb.c +++ b/nimble/host/mesh/src/cdb.c @@ -4,11 +4,12 @@ * SPDX-License-Identifier: Apache-2.0 */ -#define BT_DBG_ENABLED MYNEWT_VAL(BLE_MESH_DEBUG_CDB) -#define LOG_MODULE_NAME bt_mesh_cdb -#include "log/log.h" +#define BLE_NPL_LOG_MODULE BLE_MESH_LOG +#include -#include "mesh/mesh.h" +#include + +#include "cdb_priv.h" #include "net.h" #include "rpl.h" #include "settings.h" @@ -16,6 +17,58 @@ #include "mesh/glue.h" #if MYNEWT_VAL(BLE_MESH_CDB) +/* Tracking of what storage changes are pending for App and Net Keys. We + * track this in a separate array here instead of within the respective + * bt_mesh_app_key and bt_mesh_subnet structs themselves, since once a key + * gets deleted its struct becomes invalid and may be reused for other keys. + */ +struct key_update { + uint16_t key_idx:12, /* AppKey or NetKey Index */ + valid:1, /* 1 if this entry is valid, 0 if not */ + app_key:1, /* 1 if this is an AppKey, 0 if a NetKey */ + clear:1; /* 1 if key needs clearing, 0 if storing */ +}; + +/* Tracking of what storage changes are pending for node settings. */ +struct node_update { + uint16_t addr; + bool clear; +}; + +/* Node information for persistent storage. */ +struct node_val { + uint16_t net_idx; + uint8_t num_elem; + uint8_t flags; +#define F_NODE_CONFIGURED 0x01 + uint8_t uuid[16]; + uint8_t dev_key[16]; +} __packed; + +/* NetKey storage information */ +struct net_key_val { + uint8_t kr_flag:1, + kr_phase:7; + uint8_t val[2][16]; +} __packed; + +/* AppKey information for persistent storage. */ +struct app_key_val { + uint16_t net_idx; + bool updated; + uint8_t val[2][16]; +} __packed; + +/* IV Index & IV Update information for persistent storage. */ +struct net_val { + uint32_t iv_index; + bool iv_update; +} __packed; + +static struct node_update cdb_node_updates[MYNEWT_VAL(BLE_MESH_CDB_NODE_COUNT)]; +static struct key_update cdb_key_updates[MYNEWT_VAL(BLE_MESH_CDB_SUBNET_COUNT) + + MYNEWT_VAL(BLE_MESH_CDB_APP_KEY_COUNT)]; + struct bt_mesh_cdb bt_mesh_cdb = { .nodes = { [0 ... (CONFIG_BT_MESH_NODE_COUNT - 1)] = { @@ -107,6 +160,544 @@ static uint16_t find_lowest_free_addr(uint8_t num_elem) return addr; } +#if MYNEWT_VAL(BLE_MESH_SETTINGS) +static int cdb_net_set(int argc, char *val) +{ + struct net_val net; + int len, err; + + len = sizeof(net); + err = settings_bytes_from_str(val, &net, &len); + if (err) { + BT_ERR("Failed to set \'cdb_net\'"); + return err; + } + + bt_mesh_cdb.iv_index = net.iv_index; + + if (net.iv_update) { + atomic_set_bit(bt_mesh_cdb.flags, BT_MESH_CDB_IVU_IN_PROGRESS); + } + + atomic_set_bit(bt_mesh_cdb.flags, BT_MESH_CDB_VALID); + + return 0; +} + +static int cdb_node_set(int argc, char *str) +{ + struct bt_mesh_cdb_node *node; + struct node_val val; + uint16_t addr; + int len, err; + + if (argc < 1) { + BT_ERR("Insufficient number of arguments"); + return -ENOENT; + } + + addr = strtol(str, NULL, 16); + len = sizeof(str); + + if (argc < 1) { + BT_DBG("val (null)"); + BT_DBG("Deleting node 0x%04x", addr); + + node = bt_mesh_cdb_node_get(addr); + if (node) { + bt_mesh_cdb_node_del(node, false); + } + + return 0; + } + + err = settings_bytes_from_str(str, &val, &len); + if (err) { + BT_ERR("Failed to decode value %s (err %d)", val, err); + return -EINVAL; + } + + if (len != sizeof(struct node_val)) { + BT_ERR("Invalid length for node_val"); + return -EINVAL; + } + + node = bt_mesh_cdb_node_get(addr); + if (!node) { + node = bt_mesh_cdb_node_alloc(val.uuid, addr, val.num_elem, + val.net_idx); + } + + if (!node) { + BT_ERR("No space for a new node"); + return -ENOMEM; + } + + if (val.flags & F_NODE_CONFIGURED) { + atomic_set_bit(node->flags, BT_MESH_CDB_NODE_CONFIGURED); + } + + memcpy(node->uuid, val.uuid, 16); + memcpy(node->dev_key, val.dev_key, 16); + + BT_DBG("Node 0x%04x recovered from storage", addr); + + return 0; +} + +static int cdb_subnet_set(int argc, char *name) +{ + struct bt_mesh_cdb_subnet *sub; + struct net_key_val key; + uint16_t net_idx; + int len, len_rd, err; + + if (!name) { + BT_ERR("Insufficient number of arguments"); + return -ENOENT; + } + + len_rd = sizeof(sub); + net_idx = strtol(name, NULL, 16); + sub = bt_mesh_cdb_subnet_get(net_idx); + + if (len_rd == 0) { + BT_DBG("val (null)"); + if (!sub) { + BT_ERR("No subnet with NetKeyIndex 0x%03x", net_idx); + return -ENOENT; + } + + BT_DBG("Deleting NetKeyIndex 0x%03x", net_idx); + bt_mesh_cdb_subnet_del(sub, false); + return 0; + } + + len = sizeof(key); + err = settings_bytes_from_str(name, &key, &len); + if (err) { + BT_ERR("Failed to set \'net-key\'"); + return err; + } + + if (sub) { + BT_DBG("Updating existing NetKeyIndex 0x%03x", net_idx); + + sub->kr_phase = key.kr_phase; + memcpy(sub->keys[0].net_key, &key.val[0], 16); + memcpy(sub->keys[1].net_key, &key.val[1], 16); + + return 0; + } + + sub = bt_mesh_cdb_subnet_alloc(net_idx); + if (!sub) { + BT_ERR("No space to allocate a new subnet"); + return -ENOMEM; + } + + sub->kr_phase = key.kr_phase; + memcpy(sub->keys[0].net_key, &key.val[0], 16); + memcpy(sub->keys[1].net_key, &key.val[1], 16); + + BT_DBG("NetKeyIndex 0x%03x recovered from storage", net_idx); + + return 0; +} + +static int cdb_app_key_set(int argc, char *name) +{ + struct bt_mesh_cdb_app_key *app; + struct app_key_val key; + uint16_t app_idx; + int len_rd, err; + + app_idx = strtol(name, NULL, 16); + len_rd = sizeof(key); + + if (len_rd == 0) { + BT_DBG("val (null)"); + BT_DBG("Deleting AppKeyIndex 0x%03x", app_idx); + + app = bt_mesh_cdb_app_key_get(app_idx); + if (app) { + bt_mesh_cdb_app_key_del(app, false); + } + + return 0; + } + + err = settings_bytes_from_str(name, &key, &len_rd); + if (err) { + BT_ERR("Failed to set \'app-key\'"); + return err; + } + + app = bt_mesh_cdb_app_key_get(app_idx); + if (!app) { + app = bt_mesh_cdb_app_key_alloc(key.net_idx, app_idx); + } + + if (!app) { + BT_ERR("No space for a new app key"); + return -ENOMEM; + } + + memcpy(app->keys[0].app_key, key.val[0], 16); + memcpy(app->keys[1].app_key, key.val[1], 16); + + BT_DBG("AppKeyIndex 0x%03x recovered from storage", app_idx); + + return 0; +} + +static int cdb_set(int argc, char **argv, char *name) +{ + int len; + char *next; + + if (argc < 1) { + BT_ERR("Insufficient number of arguments"); + return -ENOENT; + } + + if (!strcmp(name, "Net")) { + return cdb_net_set(1, name); + } + + len = settings_name_next(name, &next); + + if (!next) { + BT_ERR("Insufficient number of arguments"); + return -ENOENT; + } + + if (!strncmp(name, "Node", len)) { + return cdb_node_set(1, next); + } + + if (!strncmp(name, "Subnet", len)) { + return cdb_subnet_set(1, next); + } + + if (!strncmp(name, "AppKey", len)) { + return cdb_app_key_set(1, next); + } + + BT_WARN("Unknown module key %s", name); + return -ENOENT; +} +#endif + +static void store_cdb_node(const struct bt_mesh_cdb_node *node) +{ +#if MYNEWT_VAL(BLE_MESH_SETTINGS) + char buf[BT_SETTINGS_SIZE(sizeof(struct node_val))]; + struct node_val val; + char path[30]; + char *str; + int err; + + val.net_idx = node->net_idx; + val.num_elem = node->num_elem; + val.flags = 0; + + if (atomic_test_bit(node->flags, BT_MESH_CDB_NODE_CONFIGURED)) { + val.flags |= F_NODE_CONFIGURED; + } + + memcpy(val.uuid, node->uuid, 16); + memcpy(val.dev_key, node->dev_key, 16); + + snprintk(path, sizeof(path), "bt_mesh/cdb/Node/%x", node->addr); + + str = settings_str_from_bytes(&val, sizeof(val), buf, sizeof(buf)); + if (!str) { + BT_ERR("Unable to encode Node as value"); + return; + } + + + err = settings_save_one(path, str); + if (err) { + BT_ERR("Failed to store Node %s value", path); + } else { + BT_DBG("Stored Node %s value", path); + } +#endif +} + +static void clear_cdb_node(uint16_t addr) +{ +#if MYNEWT_VAL(BLE_MESH_SETTINGS) + char path[30]; + int err; + + BT_DBG("Node 0x%04x", addr); + + snprintk(path, sizeof(path), "bt_mesh/cdb/Node/%x", addr); + err = settings_save_one(path, NULL); + if (err) { + BT_ERR("Failed to clear Node 0x%04x", addr); + } else { + BT_DBG("Cleared Node 0x%04x", addr); + } +#endif +} + +static void store_cdb_subnet(const struct bt_mesh_cdb_subnet *sub) +{ +#if MYNEWT_VAL(BLE_MESH_SETTINGS) + char buf[BT_SETTINGS_SIZE(sizeof(struct net_key_val))]; + struct net_key_val key; + char path[30]; + int err; + char *str; + + BT_DBG("NetKeyIndex 0x%03x NetKey %s", sub->net_idx, + bt_hex(sub->keys[0].net_key, 16)); + + memcpy(&key.val[0], sub->keys[0].net_key, 16); + memcpy(&key.val[1], sub->keys[1].net_key, 16); + key.kr_flag = 0U; /* Deprecated */ + key.kr_phase = sub->kr_phase; + + snprintk(path, sizeof(path), "bt_mesh/cdb/Subnet/%x", sub->net_idx); + + + str = settings_str_from_bytes(&key, sizeof(key), buf, sizeof(buf)); + if (!str) { + BT_ERR("Unable to encode Subnet as value"); + return; + } + err = settings_save_one(path, str); + if (err) { + BT_ERR("Failed to store Subnet value"); + } else { + BT_DBG("Stored Subnet value"); + } +#endif +} + +static void clear_cdb_subnet(uint16_t net_idx) +{ +#if MYNEWT_VAL(BLE_MESH_SETTINGS) + char path[30]; + int err; + + BT_DBG("NetKeyIndex 0x%03x", net_idx); + + snprintk(path, sizeof(path), "bt_mesh/cdb/Subnet/%x", net_idx); + err = settings_save_one(path, NULL); + if (err) { + BT_ERR("Failed to clear NetKeyIndex 0x%03x", net_idx); + } else { + BT_DBG("Cleared NetKeyIndex 0x%03x", net_idx); + } +#endif +} + +static void store_cdb_app_key(const struct bt_mesh_cdb_app_key *app) +{ +#if MYNEWT_VAL(BLE_MESH_SETTINGS) + char buf[BT_SETTINGS_SIZE(sizeof(struct app_key_val))]; + struct app_key_val key; + char path[30]; + int err; + char *str; + + key.net_idx = app->net_idx; + key.updated = false; + memcpy(key.val[0], app->keys[0].app_key, 16); + memcpy(key.val[1], app->keys[1].app_key, 16); + + snprintk(path, sizeof(path), "bt_mesh/cdb/AppKey/%x", app->app_idx); + + str = settings_str_from_bytes(&key, sizeof(key), buf, sizeof(buf)); + err = settings_save_one(path, str); + if (err) { + BT_ERR("Failed to store AppKey"); + } else { + BT_DBG("Stored AppKey"); + } +#endif +} + +static void clear_cdb_app_key(uint16_t app_idx) +{ +#if MYNEWT_VAL(BLE_MESH_SETTINGS) + char path[30]; + int err; + + snprintk(path, sizeof(path), "bt_mesh/cdb/AppKey/%x", app_idx); + err = settings_save_one(path, NULL); + if (err) { + BT_ERR("Failed to clear AppKeyIndex 0x%03x", app_idx); + } else { + BT_DBG("Cleared AppKeyIndex 0x%03x", app_idx); + } +#endif +} + +static void schedule_cdb_store(int flag) +{ + atomic_set_bit(bt_mesh_cdb.flags, flag); + bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_CDB_PENDING); +} + +static void update_cdb_net_settings(void) +{ + schedule_cdb_store(BT_MESH_CDB_SUBNET_PENDING); +} + +static struct node_update *cdb_node_update_find(uint16_t addr, + struct node_update **free_slot) +{ + struct node_update *match; + int i; + + match = NULL; + *free_slot = NULL; + + for (i = 0; i < ARRAY_SIZE(cdb_node_updates); i++) { + struct node_update *update = &cdb_node_updates[i]; + + if (update->addr == BT_MESH_ADDR_UNASSIGNED) { + *free_slot = update; + continue; + } + + if (update->addr == addr) { + match = update; + } + } + + return match; +} + +static void update_cdb_node_settings(const struct bt_mesh_cdb_node *node, + bool store) +{ + struct node_update *update, *free_slot; + + BT_DBG("Node 0x%04x", node->addr); + + update = cdb_node_update_find(node->addr, &free_slot); + if (update) { + update->clear = !store; + schedule_cdb_store(BT_MESH_CDB_NODES_PENDING); + return; + } + + if (!free_slot) { + if (store) { + store_cdb_node(node); + } else { + clear_cdb_node(node->addr); + } + return; + } + + free_slot->addr = node->addr; + free_slot->clear = !store; + + schedule_cdb_store(BT_MESH_CDB_NODES_PENDING); +} + +static struct key_update *cdb_key_update_find(bool app_key, uint16_t key_idx, + struct key_update **free_slot) +{ + struct key_update *match; + int i; + + match = NULL; + *free_slot = NULL; + + for (i = 0; i < ARRAY_SIZE(cdb_key_updates); i++) { + struct key_update *update = &cdb_key_updates[i]; + + if (!update->valid) { + *free_slot = update; + continue; + } + + if (update->app_key != app_key) { + continue; + } + + if (update->key_idx == key_idx) { + match = update; + } + } + + return match; +} + +static void update_cdb_subnet_settings(const struct bt_mesh_cdb_subnet *sub, + bool store) +{ + struct key_update *update, *free_slot; + uint8_t clear = store ? 0U : 1U; + + BT_DBG("NetKeyIndex 0x%03x", sub->net_idx); + + update = cdb_key_update_find(false, sub->net_idx, &free_slot); + if (update) { + update->clear = clear; + schedule_cdb_store(BT_MESH_CDB_KEYS_PENDING); + return; + } + + if (!free_slot) { + if (store) { + store_cdb_subnet(sub); + } else { + clear_cdb_subnet(sub->net_idx); + } + return; + } + + free_slot->valid = 1U; + free_slot->key_idx = sub->net_idx; + free_slot->app_key = 0U; + free_slot->clear = clear; + + schedule_cdb_store(BT_MESH_CDB_KEYS_PENDING); +} + +static void update_cdb_app_key_settings(const struct bt_mesh_cdb_app_key *key, + bool store) +{ + struct key_update *update, *free_slot; + uint8_t clear = store ? 0U : 1U; + + BT_DBG("AppKeyIndex 0x%03x", key->app_idx); + + update = cdb_key_update_find(true, key->app_idx, &free_slot); + if (update) { + update->clear = clear; + schedule_cdb_store(BT_MESH_CDB_KEYS_PENDING); + return; + } + + if (!free_slot) { + if (store) { + store_cdb_app_key(key); + } else { + clear_cdb_app_key(key->app_idx); + } + + return; + } + + free_slot->valid = 1U; + free_slot->key_idx = key->app_idx; + free_slot->app_key = 1U; + free_slot->clear = clear; + + schedule_cdb_store(BT_MESH_CDB_KEYS_PENDING); +} + int bt_mesh_cdb_create(const uint8_t key[16]) { struct bt_mesh_cdb_subnet *sub; @@ -125,8 +716,8 @@ int bt_mesh_cdb_create(const uint8_t key[16]) bt_mesh_cdb.iv_index = 0; if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_cdb(); - bt_mesh_store_cdb_subnet(sub); + update_cdb_net_settings(); + update_cdb_subnet_settings(sub, true); } return 0; @@ -157,7 +748,7 @@ void bt_mesh_cdb_clear(void) } if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_cdb(); + update_cdb_net_settings(); } } @@ -171,7 +762,7 @@ void bt_mesh_cdb_iv_update(uint32_t iv_index, bool iv_update) iv_update); if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_cdb(); + update_cdb_net_settings(); } } @@ -204,7 +795,7 @@ void bt_mesh_cdb_subnet_del(struct bt_mesh_cdb_subnet *sub, bool store) BT_DBG("NetIdx 0x%03x store %u", sub->net_idx, store); if (IS_ENABLED(CONFIG_BT_SETTINGS) && store) { - bt_mesh_clear_cdb_subnet(sub); + update_cdb_subnet_settings(sub, false); } sub->net_idx = BT_MESH_KEY_UNUSED; @@ -226,8 +817,8 @@ struct bt_mesh_cdb_subnet *bt_mesh_cdb_subnet_get(uint16_t net_idx) void bt_mesh_cdb_subnet_store(const struct bt_mesh_cdb_subnet *sub) { - if (MYNEWT_VAL(BLE_MESH_SETTINGS)) { - bt_mesh_store_cdb_subnet(sub); + if (IS_ENABLED(CONFIG_BT_SETTINGS)) { + update_cdb_subnet_settings(sub, true); } } @@ -283,7 +874,7 @@ void bt_mesh_cdb_node_del(struct bt_mesh_cdb_node *node, bool store) BT_DBG("Node addr 0x%04x store %u", node->addr, store); if (IS_ENABLED(CONFIG_BT_SETTINGS) && store) { - bt_mesh_clear_cdb_node(node); + update_cdb_node_settings(node, false); } node->addr = BT_MESH_ADDR_UNASSIGNED; @@ -308,8 +899,8 @@ struct bt_mesh_cdb_node *bt_mesh_cdb_node_get(uint16_t addr) void bt_mesh_cdb_node_store(const struct bt_mesh_cdb_node *node) { - if (MYNEWT_VAL(BLE_MESH_SETTINGS)) { - bt_mesh_store_cdb_node(node); + if (IS_ENABLED(CONFIG_BT_SETTINGS)) { + update_cdb_node_settings(node, true); } } @@ -356,7 +947,7 @@ void bt_mesh_cdb_app_key_del(struct bt_mesh_cdb_app_key *key, bool store) BT_DBG("AppIdx 0x%03x store %u", key->app_idx, store); if (IS_ENABLED(CONFIG_BT_SETTINGS) && store) { - bt_mesh_clear_cdb_app_key(key); + update_cdb_app_key_settings(key, false); } key->net_idx = BT_MESH_KEY_UNUSED; @@ -381,8 +972,172 @@ struct bt_mesh_cdb_app_key *bt_mesh_cdb_app_key_get(uint16_t app_idx) void bt_mesh_cdb_app_key_store(const struct bt_mesh_cdb_app_key *key) { - if (MYNEWT_VAL(BLE_MESH_SETTINGS)) { - bt_mesh_store_cdb_app_key(key); + if (IS_ENABLED(CONFIG_BT_SETTINGS)) { + update_cdb_app_key_settings(key, true); + } +} + +static void clear_cdb_net(void) +{ +#if MYNEWT_VAL(BLE_MESH_SETTINGS) + char path[30]; + int err; + + snprintk(path, sizeof(path), "bt_mesh/cdb/Net"); + err = settings_save_one(path, NULL); + if (err) { + BT_ERR("Failed to clear Net"); + } else { + BT_DBG("Cleared NetKeyIndex 0x%03x"); + } +#endif +} + +static void store_cdb_pending_net(void) +{ +#if MYNEWT_VAL(BLE_MESH_SETTINGS) + struct net_val net; + int err; + char buf[BT_SETTINGS_SIZE(sizeof(struct net_val))]; + char *str; + + BT_DBG(""); + + net.iv_index = bt_mesh_cdb.iv_index; + net.iv_update = atomic_test_bit(bt_mesh_cdb.flags, + BT_MESH_CDB_IVU_IN_PROGRESS); + + str = settings_str_from_bytes(&net, sizeof(net), buf, sizeof(buf)); + if (!str) { + BT_ERR("Unable to encode Network as value"); + return; + } + err = settings_save_one("bt_mesh/cdb/Net", str); + if (err) { + BT_ERR("Failed to store Network value"); + } else { + BT_DBG("Stored Network value"); + } +#endif +} + +static void store_cdb_pending_nodes(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(cdb_node_updates); ++i) { + struct node_update *update = &cdb_node_updates[i]; + + if (update->addr == BT_MESH_ADDR_UNASSIGNED) { + continue; + } + + BT_DBG("addr: 0x%04x, clear: %d", update->addr, update->clear); + + if (update->clear) { + clear_cdb_node(update->addr); + } else { + struct bt_mesh_cdb_node *node; + + node = bt_mesh_cdb_node_get(update->addr); + if (node) { + store_cdb_node(node); + } else { + BT_WARN("Node 0x%04x not found", update->addr); + } + } + + update->addr = BT_MESH_ADDR_UNASSIGNED; + } +} + +static void store_cdb_pending_keys(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(cdb_key_updates); i++) { + struct key_update *update = &cdb_key_updates[i]; + + if (!update->valid) { + continue; + } + + if (update->clear) { + if (update->app_key) { + clear_cdb_app_key(update->key_idx); + } else { + clear_cdb_subnet(update->key_idx); + } + } else { + if (update->app_key) { + struct bt_mesh_cdb_app_key *key; + + key = bt_mesh_cdb_app_key_get(update->key_idx); + if (key) { + store_cdb_app_key(key); + } else { + BT_WARN("AppKeyIndex 0x%03x not found", + update->key_idx); + } + } else { + struct bt_mesh_cdb_subnet *sub; + + sub = bt_mesh_cdb_subnet_get(update->key_idx); + if (sub) { + store_cdb_subnet(sub); + } else { + BT_WARN("NetKeyIndex 0x%03x not found", + update->key_idx); + } + } + } + + update->valid = 0U; } } + +void bt_mesh_cdb_pending_store(void) +{ + if (atomic_test_and_clear_bit(bt_mesh_cdb.flags, + BT_MESH_CDB_SUBNET_PENDING)) { + if (atomic_test_bit(bt_mesh_cdb.flags, + BT_MESH_CDB_VALID)) { + store_cdb_pending_net(); + } else { + clear_cdb_net(); + } + } + + if (atomic_test_and_clear_bit(bt_mesh_cdb.flags, + BT_MESH_CDB_NODES_PENDING)) { + store_cdb_pending_nodes(); + } + + if (atomic_test_and_clear_bit(bt_mesh_cdb.flags, + BT_MESH_CDB_KEYS_PENDING)) { + store_cdb_pending_keys(); + } +} + +#if MYNEWT_VAL(BLE_MESH_SETTINGS) +static struct conf_handler bt_mesh_cdb_conf_handler = { + .ch_name = "bt_mesh", + .ch_get = NULL, + .ch_set = cdb_set, + .ch_commit = NULL, + .ch_export = NULL, +}; +#endif + +void bt_mesh_cdb_init(void) +{ +#if MYNEWT_VAL(BLE_MESH_SETTINGS) + int rc; + + rc = conf_register(&bt_mesh_cdb_conf_handler); + + SYSINIT_PANIC_ASSERT_MSG(rc == 0, + "Failed to register bt_mesh_net conf"); +#endif +} #endif diff --git a/nimble/host/mesh/src/cdb_priv.h b/nimble/host/mesh/src/cdb_priv.h new file mode 100644 index 0000000000..ff865a56fd --- /dev/null +++ b/nimble/host/mesh/src/cdb_priv.h @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2021 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* ommitted `bt_mesh_cdb_node_store` declaration - every header + * includes mesh/mesh.h, which already has it + * void bt_mesh_cdb_node_store(const struct bt_mesh_cdb_node *node); + */ +void bt_mesh_cdb_pending_store(void); +void bt_mesh_cdb_init(void); diff --git a/nimble/host/mesh/src/cfg.c b/nimble/host/mesh/src/cfg.c index 4e14925506..122ab4dc74 100644 --- a/nimble/host/mesh/src/cfg.c +++ b/nimble/host/mesh/src/cfg.c @@ -4,6 +4,9 @@ * SPDX-License-Identifier: Apache-2.0 */ +#define BLE_NPL_LOG_MODULE BLE_MESH_LOG +#include + #include "mesh/mesh.h" #include "mesh_priv.h" #include "net.h" @@ -15,6 +18,17 @@ #include "cfg.h" #include "mesh/glue.h" +/* Miscellaneous configuration server model states */ +struct cfg_val { + uint8_t net_transmit; + uint8_t relay; + uint8_t relay_retransmit; + uint8_t beacon; + uint8_t gatt_proxy; + uint8_t frnd; + uint8_t default_ttl; +}; + void bt_mesh_beacon_set(bool beacon) { if (atomic_test_bit(bt_mesh.flags, BT_MESH_BEACON) == beacon) { @@ -31,7 +45,7 @@ void bt_mesh_beacon_set(bool beacon) if (IS_ENABLED(CONFIG_BT_SETTINGS) && atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) { - bt_mesh_store_cfg(); + bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_CFG_PENDING); } } @@ -82,7 +96,7 @@ int bt_mesh_gatt_proxy_set(enum bt_mesh_feat_state gatt_proxy) if (IS_ENABLED(CONFIG_BT_SETTINGS) && atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) { - bt_mesh_store_cfg(); + bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_CFG_PENDING); } return 0; @@ -111,7 +125,7 @@ int bt_mesh_default_ttl_set(uint8_t default_ttl) if (IS_ENABLED(CONFIG_BT_SETTINGS) && atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) { - bt_mesh_store_cfg(); + bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_CFG_PENDING); } return 0; @@ -139,7 +153,7 @@ int bt_mesh_friend_set(enum bt_mesh_feat_state friendship) if (IS_ENABLED(CONFIG_BT_SETTINGS) && atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) { - bt_mesh_store_cfg(); + bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_CFG_PENDING); } if (friendship == BT_MESH_FEATURE_DISABLED) { @@ -168,7 +182,7 @@ void bt_mesh_net_transmit_set(uint8_t xmit) if (IS_ENABLED(CONFIG_BT_SETTINGS) && atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) { - bt_mesh_store_cfg(); + bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_CFG_PENDING); } } @@ -199,7 +213,7 @@ int bt_mesh_relay_set(enum bt_mesh_feat_state relay, uint8_t xmit) if (IS_ENABLED(CONFIG_BT_SETTINGS) && atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) { - bt_mesh_store_cfg(); + bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_CFG_PENDING); } return 0; @@ -236,8 +250,115 @@ bool bt_mesh_fixed_group_match(uint16_t addr) } } -void bt_mesh_cfg_init(void) +#if MYNEWT_VAL(BLE_MESH_SETTINGS) +static int cfg_set(int argc, char **argv, char *val) +{ + struct cfg_val cfg; + int len, err; + + BT_DBG("val %s", val ? val : "(null)"); + + if (!val) { + BT_DBG("Cleared configuration state"); + return 0; + } + + len = sizeof(cfg); + err = settings_bytes_from_str(val, &cfg, &len); + if (err) { + BT_ERR("Failed to decode value %s (err %d)", val, err); + return err; + } + + if (len != sizeof(cfg)) { + BT_ERR("Unexpected value length (%d != %zu)", len, + sizeof(cfg)); + return -EINVAL; + } + + bt_mesh_net_transmit_set(cfg.net_transmit); + bt_mesh_relay_set(cfg.relay, cfg.relay_retransmit); + bt_mesh_beacon_set(cfg.beacon); + bt_mesh_gatt_proxy_set(cfg.gatt_proxy); + bt_mesh_friend_set(cfg.frnd); + bt_mesh_default_ttl_set(cfg.default_ttl); + + BT_DBG("Restored configuration state"); + + return 0; +} + +static void clear_cfg(void) { + int err; + + err = settings_save_one("bt_mesh/Cfg", NULL); + if (err) { + BT_ERR("Failed to clear configuration"); + } else { + BT_DBG("Cleared configuration"); + } +} + +static void store_pending_cfg(void) +{ + char buf[BT_SETTINGS_SIZE(sizeof(struct cfg_val))]; + struct cfg_val val; + char *str; + int err; + + val.net_transmit = bt_mesh_net_transmit_get(); + val.relay = bt_mesh_relay_get(); + val.relay_retransmit = bt_mesh_relay_retransmit_get(); + val.beacon = bt_mesh_beacon_enabled(); + val.gatt_proxy = bt_mesh_gatt_proxy_get(); + val.frnd = bt_mesh_friend_get(); + val.default_ttl = bt_mesh_default_ttl_get(); + + str = settings_str_from_bytes(&val, sizeof(val), buf, sizeof(buf)); + if (!str) { + BT_ERR("Unable to encode configuration as value"); + return; + } + + BT_DBG("Saving configuration as value %s", str); + err = settings_save_one("bt_mesh/Cfg", str); + if (err) { + BT_ERR("Failed to store configuration"); + } else { + BT_DBG("Stored configuration"); + } +} + +void bt_mesh_cfg_pending_store(void) +{ + if (atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) { + store_pending_cfg(); + } else { + clear_cfg(); + } +} + +static struct conf_handler bt_mesh_cfg_conf_handler = { + .ch_name = "bt_mesh", + .ch_get = NULL, + .ch_set = cfg_set, + .ch_commit = NULL, + .ch_export = NULL, +}; +#endif + +void bt_mesh_cfg_default_set(void) +{ +#if MYNEWT_VAL(BLE_MESH_SETTINGS) + int rc; + + rc = conf_register(&bt_mesh_cfg_conf_handler); + + SYSINIT_PANIC_ASSERT_MSG(rc == 0, + "Failed to register bt_mesh_settings conf"); +#endif + bt_mesh.default_ttl = CONFIG_BT_MESH_DEFAULT_TTL; bt_mesh.net_xmit = BT_MESH_TRANSMIT(CONFIG_BT_MESH_NETWORK_TRANSMIT_COUNT, @@ -264,4 +385,4 @@ void bt_mesh_cfg_init(void) if (CONFIG_BT_MESH_FRIEND_ENABLED) { atomic_set_bit(bt_mesh.flags, BT_MESH_FRIEND); } -} \ No newline at end of file +} diff --git a/nimble/host/mesh/src/cfg.h b/nimble/host/mesh/src/cfg.h index 6f58acf8b0..4901655f57 100644 --- a/nimble/host/mesh/src/cfg.h +++ b/nimble/host/mesh/src/cfg.h @@ -4,6 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -void bt_mesh_cfg_init(void); +void bt_mesh_cfg_default_set(void); +void bt_mesh_cfg_pending_store(void); -bool bt_mesh_fixed_group_match(uint16_t addr); \ No newline at end of file +bool bt_mesh_fixed_group_match(uint16_t addr); diff --git a/nimble/host/mesh/src/cfg_cli.c b/nimble/host/mesh/src/cfg_cli.c index 2df7d70271..f4a1ad1574 100644 --- a/nimble/host/mesh/src/cfg_cli.c +++ b/nimble/host/mesh/src/cfg_cli.c @@ -7,7 +7,10 @@ */ #include "syscfg/syscfg.h" -#define MESH_LOG_MODULE BLE_MESH_MODEL_LOG + +#define BLE_NPL_LOG_MODULE BLE_MESH_MODEL_LOG +#include + #if MYNEWT_VAL(BLE_MESH_CFG_CLI) #include "mesh/mesh.h" @@ -25,7 +28,7 @@ #define DUMMY_2_BYTE_OP BT_MESH_MODEL_OP_2(0xff, 0xff) struct comp_data { - uint8_t *status; + uint8_t *page; struct os_mbuf *comp; }; @@ -33,14 +36,9 @@ static int32_t msg_timeout = K_SECONDS(5); static struct bt_mesh_cfg_cli *cli; -static inline bool cli_response_check(uint32_t resp_opcode, uint16_t resp_addr) -{ - return cli->op_pending == resp_opcode && cli->op_addr == resp_addr; -} - -static void comp_data_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int comp_data_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { struct comp_data *param; size_t to_copy; @@ -49,24 +47,26 @@ static void comp_data_status(struct bt_mesh_model *model, ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, bt_hex(buf->om_data, buf->om_len)); - if (!cli_response_check(OP_DEV_COMP_DATA_STATUS, ctx->addr)) { - BT_WARN("Unexpected Composition Data Status"); - return; + if (!bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_DEV_COMP_DATA_STATUS, ctx->addr, + (void **)¶m)) { + return -ENOENT; } - param = cli->op_param; - - *(param->status) = net_buf_simple_pull_u8(buf); - to_copy = min(net_buf_simple_tailroom(param->comp), buf->om_len); + if (param->page) { + *(param->page) = net_buf_simple_pull_u8(buf); + } + to_copy = MIN(net_buf_simple_tailroom(param->comp), buf->om_len); net_buf_simple_add_mem(param->comp, buf->om_data, to_copy); - k_sem_give(&cli->op_sync); + bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx); + + return 0; } -static void state_status_u8(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf*buf, - uint32_t expect_status) +static int state_status_u8(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf*buf, + uint32_t expect_status) { uint8_t *status; @@ -74,92 +74,127 @@ static void state_status_u8(struct bt_mesh_model *model, ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, bt_hex(buf->om_data, buf->om_len)); - if (!cli_response_check(expect_status, ctx->addr)) { - BT_WARN("Unexpected Status (0x%08x != 0x%08x)", - (unsigned) cli->op_pending, (unsigned) expect_status); - return; + if (!bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, expect_status, ctx->addr, + (void **)&status)) { + return -ENOENT; } - status = cli->op_param; *status = net_buf_simple_pull_u8(buf); - k_sem_give(&cli->op_sync); + bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx); + + return 0; } -static void beacon_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int beacon_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { - state_status_u8(model, ctx, buf, OP_BEACON_STATUS); + return state_status_u8(model, ctx, buf, OP_BEACON_STATUS); } -static void ttl_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf*buf) +static int ttl_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf*buf) { - state_status_u8(model, ctx, buf, OP_DEFAULT_TTL_STATUS); + return state_status_u8(model, ctx, buf, OP_DEFAULT_TTL_STATUS); } -static void friend_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf*buf) +static int friend_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf*buf) { - state_status_u8(model, ctx, buf, OP_FRIEND_STATUS); + return state_status_u8(model, ctx, buf, OP_FRIEND_STATUS); } -static void gatt_proxy_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf*buf) +static int gatt_proxy_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf*buf) { - state_status_u8(model, ctx, buf, OP_GATT_PROXY_STATUS); + return state_status_u8(model, ctx, buf, OP_GATT_PROXY_STATUS); } -struct relay_param { +static int transmit_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) +{ + return state_status_u8(model, ctx, buf, OP_NET_TRANSMIT_STATUS); +} + + struct krp_param { uint8_t *status; - uint8_t *transmit; + uint16_t net_idx; + uint8_t *phase; }; -static void relay_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf*buf) +static int krp_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { - struct relay_param *param; + struct krp_param *param; + uint16_t net_idx; + uint8_t status, phase; BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, bt_hex(buf->om_data, buf->om_len)); - if (!cli_response_check(OP_RELAY_STATUS, ctx->addr)) { - BT_WARN("Unexpected Relay Status message"); - return; + if (!bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_KRP_STATUS, ctx->addr, (void **)¶m)) { + return -ENOENT; } - param = cli->op_param; - *param->status = net_buf_simple_pull_u8(buf); - *param->transmit = net_buf_simple_pull_u8(buf); + status = net_buf_simple_pull_u8(buf); + net_idx = net_buf_simple_pull_le16(buf) & 0xfff; + phase = net_buf_simple_pull_u8(buf); + + if (param->net_idx != net_idx) { + return -ENOENT; + } - k_sem_give(&cli->op_sync); + if (param->status) { + *param->status = status; + } + + if (param->phase) { + *param->phase = phase; + } + + bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx); + + return 0; } -static void net_transmit_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ +struct relay_param { uint8_t *status; + uint8_t *transmit; +}; + +static int relay_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf*buf) +{ + struct relay_param *param; BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, bt_hex(buf->om_data, buf->om_len)); - if (!cli_response_check(OP_NET_TRANSMIT_STATUS, ctx->addr)) { - BT_WARN("Unexpected Net Transmit Status message"); - return; + if (!bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_RELAY_STATUS, ctx->addr, + (void **)¶m)) { + return -ENOENT; } - status = cli->op_param; - *status = net_buf_simple_pull_u8(buf); + *param->status = net_buf_simple_pull_u8(buf); + *param->transmit = net_buf_simple_pull_u8(buf); + + bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx); - k_sem_give(&cli->op_sync); + return 0; +} + +static int net_transmit_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) +{ + return state_status_u8(model, ctx, buf, OP_NET_TRANSMIT_STATUS); } struct net_key_param { @@ -167,9 +202,9 @@ struct net_key_param { uint16_t net_idx; }; -static void net_key_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int net_key_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { struct net_key_param *param; uint16_t net_idx; @@ -179,25 +214,26 @@ static void net_key_status(struct bt_mesh_model *model, ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, bt_hex(buf->om_data, buf->om_len)); - if (!cli_response_check(OP_NET_KEY_STATUS, ctx->addr)) { - BT_WARN("Unexpected Net Key Status message"); - return; + if (!bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_NET_KEY_STATUS, ctx->addr, + (void **)¶m)) { + return -ENOENT; } status = net_buf_simple_pull_u8(buf); net_idx = net_buf_simple_pull_le16(buf) & 0xfff; - param = cli->op_param; if (param->net_idx != net_idx) { BT_WARN("Net Key Status key index does not match"); - return; + return -ENOENT; } if (param->status) { *param->status = status; } - k_sem_give(&cli->op_sync); + bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx); + + return 0; } struct net_key_list_param { @@ -205,9 +241,9 @@ struct net_key_list_param { size_t *key_cnt; }; -static void net_key_list(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int net_key_list(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { struct net_key_list_param *param; int i; @@ -216,13 +252,11 @@ static void net_key_list(struct bt_mesh_model *model, ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, bt_hex(buf->om_data, buf->om_len)); - if (!cli_response_check(OP_NET_KEY_LIST, ctx->addr)) { - BT_WARN("Unexpected Net Key List message"); - return; + if (!bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_NET_KEY_LIST, ctx->addr, + (void **)¶m)) { + return -ENOENT; } - param = cli->op_param; - for (i = 0; i < *param->key_cnt && buf->om_len >= 3; i += 2) { key_idx_unpack(buf, ¶m->keys[i], ¶m->keys[i + 1]); } @@ -231,29 +265,37 @@ static void net_key_list(struct bt_mesh_model *model, param->keys[i++] = net_buf_simple_pull_le16(buf) & 0xfff; } + if (buf->om_len > 0) { + BT_ERR("The message size for the application opcode is incorrect."); + return -EMSGSIZE; + } + *param->key_cnt = i; - k_sem_give(&cli->op_sync); + bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx); + + return 0; } -static void node_reset_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) +static int node_reset_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { bool *param = NULL; - BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x", - ctx->net_idx, ctx->app_idx, ctx->addr); + BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x", ctx->net_idx, + ctx->app_idx, ctx->addr); - if (!cli_response_check(OP_NODE_RESET_STATUS, ctx->addr)) { - BT_WARN("Unexpected Node Reset Status message"); - return; + if (!bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_NODE_RESET_STATUS, + ctx->addr, (void **)¶m)) { + return -ENOENT; } - param = cli->op_param; - if (param) { *param = true; } - k_sem_give(&cli->op_sync); + bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx); + + return 0; } struct app_key_param { @@ -262,9 +304,9 @@ struct app_key_param { uint16_t app_idx; }; -static void app_key_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf*buf) +static int app_key_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf*buf) { struct app_key_param *param; uint16_t net_idx, app_idx; @@ -274,25 +316,26 @@ static void app_key_status(struct bt_mesh_model *model, ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, bt_hex(buf->om_data, buf->om_len)); - if (!cli_response_check(OP_APP_KEY_STATUS, ctx->addr)) { - BT_WARN("Unexpected App Key Status message"); - return; + if (!bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_APP_KEY_STATUS, ctx->addr, + (void **)¶m)) { + return -ENOENT; } status = net_buf_simple_pull_u8(buf); key_idx_unpack(buf, &net_idx, &app_idx); - param = cli->op_param; if (param->net_idx != net_idx || param->app_idx != app_idx) { BT_WARN("App Key Status key indices did not match"); - return; + return -ENOENT; } if (param->status) { *param->status = status; } - k_sem_give(&cli->op_sync); + bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx); + + return 0; } struct app_key_list_param { @@ -302,9 +345,9 @@ struct app_key_list_param { size_t *key_cnt; }; -static void app_key_list(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int app_key_list(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { struct app_key_list_param *param; uint16_t net_idx; @@ -315,18 +358,17 @@ static void app_key_list(struct bt_mesh_model *model, ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, bt_hex(buf->om_data, buf->om_len)); - if (!cli_response_check(OP_APP_KEY_LIST, ctx->addr)) { - BT_WARN("Unexpected App Key List message"); - return; + if (!bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_APP_KEY_LIST, ctx->addr, + (void **)¶m)) { + return -ENOENT; } status = net_buf_simple_pull_u8(buf); net_idx = net_buf_simple_pull_le16(buf) & 0xfff; - param = cli->op_param; if (param->net_idx != net_idx) { BT_WARN("App Key List Net Key index did not match"); - return; + return -ENOENT; } for (i = 0; i < *param->key_cnt && buf->om_len >= 3; i += 2) { @@ -337,12 +379,19 @@ static void app_key_list(struct bt_mesh_model *model, param->keys[i++] = net_buf_simple_pull_le16(buf) & 0xfff; } + if (buf->om_len > 0U) { + BT_ERR("The message size for the application opcode is incorrect."); + return -EINVAL; + } + *param->key_cnt = i; if (param->status) { *param->status = status; } - k_sem_give(&cli->op_sync); + bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx); + + return 0; } struct mod_app_param { @@ -353,9 +402,9 @@ struct mod_app_param { uint16_t cid; }; -static void mod_app_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf*buf) +static int mod_app_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf*buf) { uint16_t elem_addr, mod_app_idx, mod_id, cid; struct mod_app_param *param; @@ -365,9 +414,14 @@ static void mod_app_status(struct bt_mesh_model *model, ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, bt_hex(buf->om_data, buf->om_len)); - if (!cli_response_check(OP_MOD_APP_STATUS, ctx->addr)) { - BT_WARN("Unexpected Model App Status message"); - return; + if ((buf->om_len != 7U) && (buf->om_len != 9U)) { + BT_ERR("The message size for the application opcode is incorrect."); + return -EMSGSIZE; + } + + if (!bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_MOD_APP_STATUS, ctx->addr, + (void **)¶m)) { + return -ENOENT; } status = net_buf_simple_pull_u8(buf); @@ -382,19 +436,20 @@ static void mod_app_status(struct bt_mesh_model *model, mod_id = net_buf_simple_pull_le16(buf); - param = cli->op_param; if (param->elem_addr != elem_addr || param->mod_app_idx != mod_app_idx || param->mod_id != mod_id || param->cid != cid) { BT_WARN("Model App Status parameters did not match"); - return; + return -ENOENT; } if (param->status) { *param->status = status; } - k_sem_give(&cli->op_sync); + bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx); + + return 0; } struct mod_member_list_param { @@ -406,14 +461,19 @@ struct mod_member_list_param { size_t *member_cnt; }; -static void mod_member_list_handle(struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf, bool vnd) +static int mod_member_list_handle(struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf, bool vnd, + struct mod_member_list_param *param) { - struct mod_member_list_param *param; - uint16_t elem_addr, mod_id, cid; + uint16_t elem_addr, mod_id, cid = 0; uint8_t status; int i; + if ((vnd && buf->om_len < 7U) || (buf->om_len < 5U)) { + BT_ERR("The message size for the application opcode is incorrect."); + return -EMSGSIZE; + } + status = net_buf_simple_pull_u8(buf); elem_addr = net_buf_simple_pull_le16(buf); if (vnd) { @@ -422,16 +482,15 @@ static void mod_member_list_handle(struct bt_mesh_msg_ctx *ctx, mod_id = net_buf_simple_pull_le16(buf); - param = cli->op_param; if (param->elem_addr != elem_addr || param->mod_id != mod_id || (vnd && param->cid != cid)) { BT_WARN("Model Member List parameters did not match"); - return; + return -ENOENT; } - if (buf->om_len % 2) { - BT_WARN("Model Member List invalid length"); - return; + if (buf->om_len % 2U) { + BT_ERR("Model Member List invalid length"); + return -EMSGSIZE; } for (i = 0; i < *param->member_cnt && buf->om_len; i++) { @@ -443,39 +502,45 @@ static void mod_member_list_handle(struct bt_mesh_msg_ctx *ctx, *param->status = status; } - k_sem_give(&cli->op_sync); + bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx); + + return 0; } -static void mod_app_list(struct bt_mesh_model *model, +static int mod_app_list(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { + struct mod_member_list_param *param; + BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, bt_hex(buf->om_data, buf->om_len)); - if (!cli_response_check(OP_SIG_MOD_APP_LIST, ctx->addr)) { - BT_WARN("Unexpected Model App List message"); - return; + if (!bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_SIG_MOD_APP_LIST, ctx->addr, + (void **)¶m)) { + return -ENOENT; } - mod_member_list_handle(ctx, buf, false); + return mod_member_list_handle(ctx, buf, false, param); } -static void mod_app_list_vnd(struct bt_mesh_model *model, +static int mod_app_list_vnd(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { + struct mod_member_list_param *param; + BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, bt_hex(buf->om_data, buf->om_len)); - if (!cli_response_check(OP_VND_MOD_APP_LIST, ctx->addr)) { - BT_WARN("Unexpected Model App List Vendor message"); - return; + if (!bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_VND_MOD_APP_LIST, ctx->addr, + (void **)¶m)) { + return -ENOENT; } - mod_member_list_handle(ctx, buf, true); + return mod_member_list_handle(ctx, buf, true, param); } struct mod_pub_param { @@ -486,7 +551,7 @@ struct mod_pub_param { struct bt_mesh_cfg_mod_pub *pub; }; -static void mod_pub_status(struct bt_mesh_model *model, +static int mod_pub_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf*buf) { @@ -498,16 +563,21 @@ static void mod_pub_status(struct bt_mesh_model *model, ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, bt_hex(buf->om_data, buf->om_len)); - if (!cli_response_check(OP_MOD_PUB_STATUS, ctx->addr)) { + if ((buf->om_len != 12U) && (buf->om_len != 14U)) { + BT_ERR("The message size for the application opcode is incorrect."); + return -EINVAL; + } + + if (!bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_MOD_PUB_STATUS, ctx->addr, + (void **)¶m)) { BT_WARN("Unexpected Model Pub Status message"); - return; + return -ENOENT; } - param = cli->op_param; if (param->cid != CID_NVAL) { if (buf->om_len < 14) { BT_WARN("Unexpected Mod Pub Status with SIG Model"); - return; + return -ENOENT; } cid = sys_get_le16(&buf->om_data[10]); @@ -515,7 +585,7 @@ static void mod_pub_status(struct bt_mesh_model *model, } else { if (buf->om_len > 12) { BT_WARN("Unexpected Mod Pub Status with Vendor Model"); - return; + return -ENOENT; } cid = CID_NVAL; @@ -524,7 +594,7 @@ static void mod_pub_status(struct bt_mesh_model *model, if (mod_id != param->mod_id || cid != param->cid) { BT_WARN("Mod Pub Model ID or Company ID mismatch"); - return; + return -ENOENT; } status = net_buf_simple_pull_u8(buf); @@ -533,7 +603,7 @@ static void mod_pub_status(struct bt_mesh_model *model, if (elem_addr != param->elem_addr) { BT_WARN("Model Pub Status for unexpected element (0x%04x)", elem_addr); - return; + return -ENOENT; } if (param->status) { @@ -550,7 +620,9 @@ static void mod_pub_status(struct bt_mesh_model *model, param->pub->transmit = net_buf_simple_pull_u8(buf); } - k_sem_give(&cli->op_sync); + bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx); + + return 0; } struct mod_sub_param { @@ -562,9 +634,9 @@ struct mod_sub_param { uint16_t cid; }; -static void mod_sub_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf*buf) +static int mod_sub_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf*buf) { uint16_t elem_addr, sub_addr, mod_id, cid; struct mod_sub_param *param; @@ -574,9 +646,14 @@ static void mod_sub_status(struct bt_mesh_model *model, ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, bt_hex(buf->om_data, buf->om_len)); - if (!cli_response_check(OP_MOD_SUB_STATUS, ctx->addr)) { - BT_WARN("Unexpected Model Subscription Status message"); - return; + if ((buf->om_len != 7U) && (buf->om_len != 9U)) { + BT_ERR("The message size for the application opcode is incorrect."); + return -EINVAL; + } + + if (!bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_MOD_SUB_STATUS, ctx->addr, + (void **)¶m)) { + return -ENOENT; } status = net_buf_simple_pull_u8(buf); @@ -591,12 +668,11 @@ static void mod_sub_status(struct bt_mesh_model *model, mod_id = net_buf_simple_pull_le16(buf); - param = cli->op_param; if (param->elem_addr != elem_addr || param->mod_id != mod_id || (param->expect_sub && *param->expect_sub != sub_addr) || param->cid != cid) { BT_WARN("Model Subscription Status parameters did not match"); - return; + return -ENOENT; } if (param->sub_addr) { @@ -607,39 +683,45 @@ static void mod_sub_status(struct bt_mesh_model *model, *param->status = status; } - k_sem_give(&cli->op_sync); + bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx); + + return 0; } -static void mod_sub_list(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int mod_sub_list(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { + struct mod_member_list_param *param; + BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, bt_hex(buf->om_data, buf->om_len)); - if (!cli_response_check(OP_MOD_SUB_LIST, ctx->addr)) { - BT_WARN("Unexpected Model Subscription List message"); - return; + if (!bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_MOD_SUB_LIST, ctx->addr, + (void **)¶m)) { + return -ENOENT; } - mod_member_list_handle(ctx, buf, false); + return mod_member_list_handle(ctx, buf, false, param); } -static void mod_sub_list_vnd(struct bt_mesh_model *model, +static int mod_sub_list_vnd(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { + struct mod_member_list_param *param; + BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, bt_hex(buf->om_data, buf->om_len)); - if (!cli_response_check(OP_MOD_SUB_LIST_VND, ctx->addr)) { - BT_WARN("Unexpected Model Subscription List Vendor message"); - return; + if (!bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_MOD_SUB_LIST_VND, ctx->addr, + (void **)¶m)) { + return -ENOENT; } - mod_member_list_handle(ctx, buf, true); + return mod_member_list_handle(ctx, buf, true,param); } struct hb_sub_param { @@ -647,9 +729,9 @@ struct hb_sub_param { struct bt_mesh_cfg_hb_sub *sub; }; -static void hb_sub_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf*buf) +static int hb_sub_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf*buf) { struct hb_sub_param *param; @@ -657,13 +739,11 @@ static void hb_sub_status(struct bt_mesh_model *model, ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, bt_hex(buf->om_data, buf->om_len)); - if (!cli_response_check(OP_HEARTBEAT_SUB_STATUS, ctx->addr)) { - BT_WARN("Unexpected Heartbeat Subscription Status message"); - return; + if (!bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_HEARTBEAT_SUB_STATUS, ctx->addr, + (void **)¶m)) { + return -ENOENT; } - param = cli->op_param; - *param->status = net_buf_simple_pull_u8(buf); param->sub->src = net_buf_simple_pull_le16(buf); @@ -673,7 +753,9 @@ static void hb_sub_status(struct bt_mesh_model *model, param->sub->min = net_buf_simple_pull_u8(buf); param->sub->max = net_buf_simple_pull_u8(buf); - k_sem_give(&cli->op_sync); + bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx); + + return 0; } struct hb_pub_param { @@ -681,7 +763,7 @@ struct hb_pub_param { struct bt_mesh_cfg_hb_pub *pub; }; -static void hb_pub_status(struct bt_mesh_model *model, +static int hb_pub_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -691,13 +773,11 @@ static void hb_pub_status(struct bt_mesh_model *model, ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, bt_hex(buf->om_data, buf->om_len)); - if (!cli_response_check(OP_HEARTBEAT_PUB_STATUS, ctx->addr)) { - BT_WARN("Unexpected Heartbeat Publication Status message"); - return; + if (!bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_HEARTBEAT_PUB_STATUS, ctx->addr, + (void **)¶m)) { + return -ENOENT; } - param = cli->op_param; - *param->status = net_buf_simple_pull_u8(buf); if (param->pub) { @@ -709,31 +789,118 @@ static void hb_pub_status(struct bt_mesh_model *model, param->pub->net_idx = net_buf_simple_pull_u8(buf); } - k_sem_give(&cli->op_sync); + bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx); + + return 0; +} + +struct node_idt_param { + uint8_t *status; + uint16_t net_idx; + uint8_t *identity; +}; + +static int node_identity_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) +{ + struct node_idt_param *param; + uint16_t net_idx, identity; + uint8_t status; + + BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", + ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, + bt_hex(buf->om_data, buf->om_len)); + + if (!bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_NODE_IDENTITY_STATUS, + ctx->addr, (void **)¶m)) { + return -ENOENT; + } + + status = net_buf_simple_pull_u8(buf); + net_idx = net_buf_simple_pull_le16(buf) & 0xfff; + identity = net_buf_simple_pull_u8(buf); + + if (param && param->status) { + *param->status = status; + } + + if (param->net_idx != net_idx) { + return -ENOENT; + } + + if (param && param->identity) { + *param->identity = identity; + } + + bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx); + + return 0; +} + +struct lpn_timeout_param { + uint16_t unicast_addr; + int32_t *polltimeout; +}; + +static int lpn_timeout_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) +{ + struct lpn_timeout_param *param; + uint16_t unicast_addr; + int32_t polltimeout; + + BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", + ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, + bt_hex(buf->om_data, buf->om_len)); + + if (!bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_LPN_TIMEOUT_STATUS, ctx->addr, + (void **)¶m)) { + return -ENOENT; + } + + unicast_addr = net_buf_simple_pull_le16(buf); + polltimeout = net_buf_simple_pull_le24(buf); + + if (param->unicast_addr != unicast_addr) { + return -ENOENT; + } + + if (param->polltimeout) { + *param->polltimeout = polltimeout; + } + + bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx); + + return 0; } const struct bt_mesh_model_op bt_mesh_cfg_cli_op[] = { - { OP_DEV_COMP_DATA_STATUS, 15, comp_data_status }, - { OP_BEACON_STATUS, 1, beacon_status }, - { OP_DEFAULT_TTL_STATUS, 1, ttl_status }, - { OP_FRIEND_STATUS, 1, friend_status }, - { OP_GATT_PROXY_STATUS, 1, gatt_proxy_status }, - { OP_RELAY_STATUS, 2, relay_status }, - { OP_NET_TRANSMIT_STATUS, 1, net_transmit_status }, - { OP_NET_KEY_STATUS, 3, net_key_status }, - { OP_NET_KEY_LIST, 0, net_key_list }, - { OP_APP_KEY_STATUS, 4, app_key_status }, - { OP_APP_KEY_LIST, 3, app_key_list }, - { OP_MOD_APP_STATUS, 7, mod_app_status }, - { OP_SIG_MOD_APP_LIST, 5, mod_app_list}, - { OP_VND_MOD_APP_LIST, 7, mod_app_list_vnd}, - { OP_MOD_PUB_STATUS, 12, mod_pub_status }, - { OP_MOD_SUB_STATUS, 7, mod_sub_status }, - { OP_MOD_SUB_LIST, 5, mod_sub_list}, - { OP_MOD_SUB_LIST_VND, 7, mod_sub_list_vnd}, - { OP_HEARTBEAT_SUB_STATUS, 9, hb_sub_status }, - { OP_HEARTBEAT_PUB_STATUS, 10, hb_pub_status }, - { OP_NODE_RESET_STATUS, 0, node_reset_status}, + { OP_DEV_COMP_DATA_STATUS, BT_MESH_LEN_MIN(15), comp_data_status }, + { OP_BEACON_STATUS, BT_MESH_LEN_EXACT(1), beacon_status }, + { OP_DEFAULT_TTL_STATUS, BT_MESH_LEN_EXACT(1), ttl_status }, + { OP_FRIEND_STATUS, BT_MESH_LEN_EXACT(1), friend_status }, + { OP_GATT_PROXY_STATUS, BT_MESH_LEN_EXACT(1), gatt_proxy_status }, + { OP_RELAY_STATUS, BT_MESH_LEN_EXACT(2), relay_status }, + { OP_NET_TRANSMIT_STATUS, BT_MESH_LEN_EXACT(1), net_transmit_status }, + { OP_NET_KEY_STATUS, BT_MESH_LEN_EXACT(3), net_key_status }, + { OP_NET_KEY_LIST, BT_MESH_LEN_MIN(0), net_key_list }, + { OP_APP_KEY_STATUS, BT_MESH_LEN_EXACT(4), app_key_status }, + { OP_APP_KEY_LIST, BT_MESH_LEN_MIN(3), app_key_list }, + { OP_MOD_APP_STATUS, BT_MESH_LEN_MIN(7), mod_app_status }, + { OP_SIG_MOD_APP_LIST, BT_MESH_LEN_MIN(5), mod_app_list }, + { OP_VND_MOD_APP_LIST, BT_MESH_LEN_MIN(7), mod_app_list_vnd }, + { OP_MOD_PUB_STATUS, BT_MESH_LEN_MIN(12), mod_pub_status }, + { OP_MOD_SUB_STATUS, BT_MESH_LEN_MIN(7), mod_sub_status }, + { OP_MOD_SUB_LIST, BT_MESH_LEN_MIN(5), mod_sub_list }, + { OP_MOD_SUB_LIST_VND, BT_MESH_LEN_MIN(7), mod_sub_list_vnd }, + { OP_HEARTBEAT_SUB_STATUS, BT_MESH_LEN_EXACT(9), hb_sub_status }, + { OP_HEARTBEAT_PUB_STATUS, BT_MESH_LEN_EXACT(10), hb_pub_status }, + { OP_NODE_RESET_STATUS, BT_MESH_LEN_EXACT(0), node_reset_status }, + { OP_NODE_IDENTITY_STATUS, BT_MESH_LEN_EXACT(4), node_identity_status}, + { OP_LPN_TIMEOUT_STATUS, BT_MESH_LEN_EXACT(5), lpn_timeout_status }, + { OP_NET_TRANSMIT_STATUS, BT_MESH_LEN_EXACT(1), transmit_status}, + { OP_KRP_STATUS, BT_MESH_LEN_EXACT(4), krp_status}, BT_MESH_MODEL_OP_END, }; @@ -760,7 +927,7 @@ static int cfg_cli_init(struct bt_mesh_model *model) */ model->keys[0] = BT_MESH_KEY_DEV_ANY; - k_sem_init(&cli->op_sync, 0, 1); + bt_mesh_msg_ack_ctx_init(&cli->ack_ctx); return 0; } @@ -776,38 +943,11 @@ static int cli_prepare(void *param, uint32_t op, uint16_t addr) return -EINVAL; } - if (cli->op_pending) { - BT_WARN("Another synchronous operation pending"); - return -EBUSY; - } - - cli->op_param = param; - cli->op_pending = op; - cli->op_addr = addr; - - return 0; -} - -static void cli_reset(void) -{ - cli->op_pending = 0; - cli->op_param = NULL; - cli->op_addr = BT_MESH_ADDR_UNASSIGNED; -} - -static int cli_wait(void) -{ - int err; - - err = k_sem_take(&cli->op_sync, msg_timeout); - - cli_reset(); - - return err; + return bt_mesh_msg_ack_ctx_prepare(&cli->ack_ctx, op, addr, param); } int bt_mesh_cfg_comp_data_get(uint16_t net_idx, uint16_t addr, uint8_t page, - uint8_t *status, struct os_mbuf *comp) + uint8_t *rsp, struct os_mbuf *comp) { struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_DEV_COMP_DATA_GET, 1); struct bt_mesh_msg_ctx ctx = { @@ -817,7 +957,7 @@ int bt_mesh_cfg_comp_data_get(uint16_t net_idx, uint16_t addr, uint8_t page, .send_ttl = BT_MESH_TTL_DEFAULT, }; struct comp_data param = { - .status = status, + .page = rsp, .comp = comp, }; int err; @@ -833,11 +973,11 @@ int bt_mesh_cfg_comp_data_get(uint16_t net_idx, uint16_t addr, uint8_t page, err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); goto done; } - err = cli_wait(); + err = bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); done: os_mbuf_free_chain(msg); return err; @@ -865,11 +1005,11 @@ static int get_state_u8(uint16_t net_idx, uint16_t addr, uint32_t op, uint32_t r err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); goto done; } - err = cli_wait(); + err = bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); done: os_mbuf_free_chain(msg); return err; @@ -898,11 +1038,11 @@ static int set_state_u8(uint16_t net_idx, uint16_t addr, uint32_t op, uint32_t r err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); goto done; } - err = cli_wait(); + err = bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); done: os_mbuf_free_chain(msg); return err; @@ -914,6 +1054,75 @@ int bt_mesh_cfg_beacon_get(uint16_t net_idx, uint16_t addr, uint8_t *status) status); } +int bt_mesh_cfg_krp_get(uint16_t net_idx, uint16_t addr, uint16_t key_net_idx, + uint8_t *status, uint8_t *phase) +{ + struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_KRP_GET, 2); + struct bt_mesh_msg_ctx ctx = { + .net_idx = net_idx, + .app_idx = BT_MESH_KEY_DEV_REMOTE, + .addr = addr, + .send_ttl = BT_MESH_TTL_DEFAULT, + }; + struct krp_param param = { + .status = status, + .phase = phase, + }; + int err; + + err = cli_prepare(¶m, OP_KRP_STATUS, addr); + if (err) { + return err; + } + + bt_mesh_model_msg_init(msg, OP_KRP_GET); + net_buf_simple_add_le16(msg, key_net_idx); + + err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); + if (err) { + BT_ERR("model_send() failed (err %d)", err); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); + return err; + } + + return bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); +} + +int bt_mesh_cfg_krp_set(uint16_t net_idx, uint16_t addr, uint16_t key_net_idx, + uint8_t transition, uint8_t *status, uint8_t *phase) +{ + struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_KRP_SET, 3); + struct bt_mesh_msg_ctx ctx = { + .net_idx = net_idx, + .app_idx = BT_MESH_KEY_DEV_REMOTE, + .addr = addr, + .send_ttl = BT_MESH_TTL_DEFAULT, + }; + struct krp_param param = { + .status = status, + .phase = phase, + }; + int err; + + err = cli_prepare(¶m, OP_KRP_STATUS, addr); + if (err) { + return err; + } + + bt_mesh_model_msg_init(msg, OP_KRP_SET); + net_buf_simple_add_le16(msg, key_net_idx); + net_buf_simple_add_u8(msg, transition); + + err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); + if (err) { + BT_ERR("model_send() failed (err %d)", err); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); + return err; + } + + return bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); +} + int bt_mesh_cfg_beacon_set(uint16_t net_idx, uint16_t addr, uint8_t val, uint8_t *status) { return set_state_u8(net_idx, addr, OP_BEACON_SET, OP_BEACON_STATUS, @@ -997,11 +1206,11 @@ int bt_mesh_cfg_relay_get(uint16_t net_idx, uint16_t addr, uint8_t *status, err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); goto done; } - err = cli_wait(); + err = bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); done: os_mbuf_free_chain(msg); return err; @@ -1035,11 +1244,11 @@ int bt_mesh_cfg_relay_set(uint16_t net_idx, uint16_t addr, uint8_t new_relay, err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); goto done; } - err = cli_wait(); + err = bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); done: os_mbuf_free_chain(msg); return err; @@ -1073,21 +1282,62 @@ int bt_mesh_cfg_net_key_add(uint16_t net_idx, uint16_t addr, uint16_t key_net_id err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); goto done; } if (!status) { - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); goto done; } - err = cli_wait(); + err = bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); done: os_mbuf_free_chain(msg); return err; } +int bt_mesh_cfg_net_key_update(uint16_t net_idx, uint16_t addr, + uint16_t key_net_idx, const uint8_t net_key[16], + uint8_t *status) +{ + struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_NET_KEY_UPDATE, 18); + struct bt_mesh_msg_ctx ctx = { + .net_idx = net_idx, + .app_idx = BT_MESH_KEY_DEV_REMOTE, + .addr = addr, + .send_ttl = BT_MESH_TTL_DEFAULT, + }; + struct net_key_param param = { + .status = status, + .net_idx = key_net_idx, + }; + int err; + + err = cli_prepare(¶m, OP_NET_KEY_STATUS, addr); + if (err) { + return err; + } + + bt_mesh_model_msg_init(msg, OP_NET_KEY_UPDATE); + net_buf_simple_add_le16(msg, key_net_idx); + net_buf_simple_add_mem(msg, net_key, 16); + + err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); + if (err) { + BT_ERR("model_send() failed (err %d)", err); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); + return err; + } + + if (!status) { + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); + return 0; + } + + return bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); +} + int bt_mesh_cfg_net_key_get(uint16_t net_idx, uint16_t addr, uint16_t *keys, size_t *key_cnt) { @@ -1114,12 +1364,12 @@ int bt_mesh_cfg_net_key_get(uint16_t net_idx, uint16_t addr, uint16_t *keys, err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); return err; } os_mbuf_free_chain(msg); - return cli_wait(); + return bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); } int bt_mesh_cfg_net_key_del(uint16_t net_idx, uint16_t addr, @@ -1149,16 +1399,16 @@ int bt_mesh_cfg_net_key_del(uint16_t net_idx, uint16_t addr, err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); goto done; } if (!status) { - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); goto done; } - err = cli_wait(); + err = bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); done: os_mbuf_free_chain(msg); return err; @@ -1194,21 +1444,63 @@ int bt_mesh_cfg_app_key_add(uint16_t net_idx, uint16_t addr, uint16_t key_net_id err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); goto done; } if (!status) { - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); goto done; } - err = cli_wait(); + err = bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); done: os_mbuf_free_chain(msg); return err; } +int bt_mesh_cfg_app_key_update(uint16_t net_idx, uint16_t addr, + uint16_t key_net_idx, uint16_t key_app_idx, + const uint8_t app_key[16], uint8_t *status) +{ + struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_APP_KEY_UPDATE, 19); + struct bt_mesh_msg_ctx ctx = { + .net_idx = net_idx, + .app_idx = BT_MESH_KEY_DEV_REMOTE, + .addr = addr, + .send_ttl = BT_MESH_TTL_DEFAULT, + }; + struct app_key_param param = { + .status = status, + .net_idx = key_net_idx, + .app_idx = key_app_idx, + }; + int err; + + err = cli_prepare(¶m, OP_APP_KEY_STATUS, addr); + if (err) { + return err; + } + + bt_mesh_model_msg_init(msg, OP_APP_KEY_UPDATE); + key_idx_pack(msg, key_net_idx, key_app_idx); + net_buf_simple_add_mem(msg, app_key, 16); + + err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); + if (err) { + BT_ERR("model_send() failed (err %d)", err); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); + return err; + } + + if (!status) { + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); + return 0; + } + + return bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); +} + int bt_mesh_cfg_node_reset(uint16_t net_idx, uint16_t addr, bool *status) { struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_NODE_RESET, 0); @@ -1235,16 +1527,16 @@ int bt_mesh_cfg_node_reset(uint16_t net_idx, uint16_t addr, bool *status) err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); goto done; } if (!status) { - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); goto done; } - err = cli_wait(); + err = bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); done: os_mbuf_free_chain(msg); if (err) { @@ -1285,12 +1577,12 @@ int bt_mesh_cfg_app_key_get(uint16_t net_idx, uint16_t addr, uint16_t key_net_id if (err) { BT_ERR("model_send() failed (err %d)", err); os_mbuf_free_chain(msg); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); return err; } os_mbuf_free_chain(msg); - return cli_wait(); + return bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); } int bt_mesh_cfg_app_key_del(uint16_t net_idx, uint16_t addr, @@ -1323,18 +1615,18 @@ int bt_mesh_cfg_app_key_del(uint16_t net_idx, uint16_t addr, if (err) { BT_ERR("model_send() failed (err %d)", err); os_mbuf_free_chain(msg); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); return err; } if (!status) { - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); os_mbuf_free_chain(msg); return 0; } os_mbuf_free_chain(msg); - return cli_wait(); + return bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); } static int mod_app_bind(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, @@ -1375,16 +1667,16 @@ static int mod_app_bind(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); goto done; } if (!status) { - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); goto done; } - err = cli_wait(); + err = bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); done: os_mbuf_free_chain(msg); return err; @@ -1447,12 +1739,12 @@ static int mod_app_unbind(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); goto done; } if (!status) { - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); err = 0; goto done; } @@ -1462,7 +1754,7 @@ static int mod_app_unbind(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, if (err) { return err; } else { - return cli_wait(); + return bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); } } @@ -1529,11 +1821,11 @@ static int mod_member_list_get(uint32_t op, uint32_t expect_op, uint16_t net_idx err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); goto done; } - err = cli_wait(); + err = bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); done: os_mbuf_free_chain(msg); return err; @@ -1557,7 +1849,7 @@ int bt_mesh_cfg_mod_app_get_vnd(uint16_t net_idx, uint16_t addr, uint16_t elem_a } return mod_member_list_get(OP_VND_MOD_APP_GET, OP_VND_MOD_APP_LIST, - net_idx, addr, elem_addr, mod_id, CID_NVAL, + net_idx, addr, elem_addr, mod_id, cid, status, apps, app_cnt); } @@ -1587,7 +1879,10 @@ static int mod_sub(uint32_t op, uint16_t net_idx, uint16_t addr, uint16_t elem_a bt_mesh_model_msg_init(msg, op); net_buf_simple_add_le16(msg, elem_addr); - net_buf_simple_add_le16(msg, sub_addr); + + if (sub_addr != BT_MESH_ADDR_UNASSIGNED) { + net_buf_simple_add_le16(msg, sub_addr); + } if (cid != CID_NVAL) { net_buf_simple_add_le16(msg, cid); @@ -1598,17 +1893,17 @@ static int mod_sub(uint32_t op, uint16_t net_idx, uint16_t addr, uint16_t elem_a err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); goto done; } if (!status) { - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); err = 0; goto done; } - err = cli_wait(); + err = bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); done: os_mbuf_free_chain(msg); return err; @@ -1617,6 +1912,10 @@ static int mod_sub(uint32_t op, uint16_t net_idx, uint16_t addr, uint16_t elem_a int bt_mesh_cfg_mod_sub_add(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, uint16_t sub_addr, uint16_t mod_id, uint8_t *status) { + if (!BT_MESH_ADDR_IS_GROUP(sub_addr)) { + return -EINVAL; + } + return mod_sub(OP_MOD_SUB_ADD, net_idx, addr, elem_addr, sub_addr, mod_id, CID_NVAL, status); } @@ -1625,7 +1924,7 @@ int bt_mesh_cfg_mod_sub_add_vnd(uint16_t net_idx, uint16_t addr, uint16_t elem_a uint16_t sub_addr, uint16_t mod_id, uint16_t cid, uint8_t *status) { - if (cid == CID_NVAL) { + if (!BT_MESH_ADDR_IS_GROUP(sub_addr) || cid == CID_NVAL) { return -EINVAL; } @@ -1636,15 +1935,27 @@ int bt_mesh_cfg_mod_sub_add_vnd(uint16_t net_idx, uint16_t addr, uint16_t elem_a int bt_mesh_cfg_mod_sub_del(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, uint16_t sub_addr, uint16_t mod_id, uint8_t *status) { + if (!BT_MESH_ADDR_IS_GROUP(sub_addr)) { + return -EINVAL; + } + return mod_sub(OP_MOD_SUB_DEL, net_idx, addr, elem_addr, sub_addr, mod_id, CID_NVAL, status); } +int bt_mesh_cfg_mod_sub_del_all(uint16_t net_idx, uint16_t addr, + uint16_t elem_addr, uint16_t mod_id, + uint8_t *status) +{ + return mod_sub(OP_MOD_SUB_DEL_ALL, net_idx, addr, elem_addr, + BT_MESH_ADDR_UNASSIGNED, mod_id, CID_NVAL, status); +} + int bt_mesh_cfg_mod_sub_del_vnd(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, uint16_t sub_addr, uint16_t mod_id, uint16_t cid, uint8_t *status) { - if (cid == CID_NVAL) { + if (!BT_MESH_ADDR_IS_GROUP(sub_addr) || cid == CID_NVAL) { return -EINVAL; } @@ -1652,9 +1963,25 @@ int bt_mesh_cfg_mod_sub_del_vnd(uint16_t net_idx, uint16_t addr, uint16_t elem_a mod_id, cid, status); } +int bt_mesh_cfg_mod_sub_del_all_vnd(uint16_t net_idx, uint16_t addr, + uint16_t elem_addr, uint16_t mod_id, + uint16_t cid, uint8_t *status) +{ + if (cid == CID_NVAL) { + return -EINVAL; + } + + return mod_sub(OP_MOD_SUB_DEL_ALL, net_idx, addr, elem_addr, + BT_MESH_ADDR_UNASSIGNED, mod_id, cid, status); +} + int bt_mesh_cfg_mod_sub_overwrite(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, uint16_t sub_addr, uint16_t mod_id, uint8_t *status) { + if (!BT_MESH_ADDR_IS_GROUP(sub_addr)) { + return -EINVAL; + } + return mod_sub(OP_MOD_SUB_OVERWRITE, net_idx, addr, elem_addr, sub_addr, mod_id, CID_NVAL, status); } @@ -1663,7 +1990,7 @@ int bt_mesh_cfg_mod_sub_overwrite_vnd(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, uint16_t sub_addr, uint16_t mod_id, uint16_t cid, uint8_t *status) { - if (cid == CID_NVAL) { + if (!BT_MESH_ADDR_IS_GROUP(sub_addr) || cid == CID_NVAL) { return -EINVAL; } @@ -1697,7 +2024,7 @@ static int mod_sub_va(uint32_t op, uint16_t net_idx, uint16_t addr, uint16_t ele } BT_DBG("net_idx 0x%04x addr 0x%04x elem_addr 0x%04x label %s", - net_idx, addr, elem_addr, label); + net_idx, addr, elem_addr, bt_hex(label, 16)); BT_DBG("mod_id 0x%04x cid 0x%04x", mod_id, cid); bt_mesh_model_msg_init(msg, op); @@ -1713,16 +2040,16 @@ static int mod_sub_va(uint32_t op, uint16_t net_idx, uint16_t addr, uint16_t ele err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); goto done; } if (!status) { - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); goto done; } - err = cli_wait(); + err = bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); done: os_mbuf_free_chain(msg); return err; @@ -1808,7 +2135,7 @@ int bt_mesh_cfg_mod_sub_get_vnd(uint16_t net_idx, uint16_t addr, uint16_t elem_a } return mod_member_list_get(OP_MOD_SUB_GET_VND, OP_MOD_SUB_LIST_VND, - net_idx, addr, elem_addr, mod_id, CID_NVAL, + net_idx, addr, elem_addr, mod_id, cid, status, subs, sub_cnt); } @@ -1850,16 +2177,16 @@ static int mod_pub_get(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); goto done; } if (!status) { - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); goto done; } - err = cli_wait(); + err = bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); done: os_mbuf_free_chain(msg); return err; @@ -1927,38 +2254,101 @@ static int mod_pub_set(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); goto done; } if (!status) { - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); goto done; } - err = cli_wait(); + err = bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); done: os_mbuf_free_chain(msg); return err; } +static int mod_pub_va_set(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, + uint16_t mod_id, uint16_t cid, + struct bt_mesh_cfg_mod_pub *pub, uint8_t *status) +{ + struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_MOD_PUB_VA_SET, 27); + struct bt_mesh_msg_ctx ctx = { + .net_idx = net_idx, + .app_idx = BT_MESH_KEY_DEV_REMOTE, + .addr = addr, + .send_ttl = BT_MESH_TTL_DEFAULT, + }; + struct mod_pub_param param = { + .mod_id = mod_id, + .cid = cid, + .elem_addr = elem_addr, + .status = status, + .pub = pub, + }; + int err; + + err = cli_prepare(¶m, OP_MOD_PUB_STATUS, addr); + if (err) { + return err; + } + BT_DBG("app_idx 0x%04x", pub->app_idx); + bt_mesh_model_msg_init(msg, OP_MOD_PUB_VA_SET); + + net_buf_simple_add_le16(msg, elem_addr); + net_buf_simple_add_mem(msg, pub->uuid, 16); + net_buf_simple_add_le16(msg, (pub->app_idx | (pub->cred_flag << 12))); + net_buf_simple_add_u8(msg, pub->ttl); + net_buf_simple_add_u8(msg, pub->period); + net_buf_simple_add_u8(msg, pub->transmit); + + if (cid != CID_NVAL) { + net_buf_simple_add_le16(msg, cid); + } + + net_buf_simple_add_le16(msg, mod_id); + + err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); + if (err) { + BT_ERR("model_send() failed (err %d)", err); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); + return err; + } + + if (!status) { + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); + return 0; + } + + return bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); +} + + int bt_mesh_cfg_mod_pub_set(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, uint16_t mod_id, struct bt_mesh_cfg_mod_pub *pub, uint8_t *status) { - return mod_pub_set(net_idx, addr, elem_addr, mod_id, CID_NVAL, - pub, status); + if (pub->uuid) { + return mod_pub_va_set(net_idx, addr, elem_addr, mod_id, CID_NVAL, pub, status); + } else { + return mod_pub_set(net_idx, addr, elem_addr, mod_id, CID_NVAL, pub, status); + } } int bt_mesh_cfg_mod_pub_set_vnd(uint16_t net_idx, uint16_t addr, uint16_t elem_addr, - uint16_t mod_id, uint16_t cid, - struct bt_mesh_cfg_mod_pub *pub, uint8_t *status) + uint16_t mod_id, uint16_t cid, struct bt_mesh_cfg_mod_pub *pub, + uint8_t *status) { if (cid == CID_NVAL) { return -EINVAL; } - return mod_pub_set(net_idx, addr, elem_addr, mod_id, cid, pub, status); + if (pub->uuid) { + return mod_pub_va_set(net_idx, addr, elem_addr, mod_id, cid, pub, status); + } else { + return mod_pub_set(net_idx, addr, elem_addr, mod_id, cid, pub, status); + } } int bt_mesh_cfg_hb_sub_set(uint16_t net_idx, uint16_t addr, @@ -1990,16 +2380,16 @@ int bt_mesh_cfg_hb_sub_set(uint16_t net_idx, uint16_t addr, err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); goto done; } if (!status) { - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); goto done; } - err = cli_wait(); + err = bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); done: os_mbuf_free_chain(msg); return err; @@ -2031,16 +2421,16 @@ int bt_mesh_cfg_hb_sub_get(uint16_t net_idx, uint16_t addr, err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); goto done; } if (!status) { - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); goto done; } - err = cli_wait(); + err = bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); done: os_mbuf_free_chain(msg); return err; @@ -2077,16 +2467,16 @@ int bt_mesh_cfg_hb_pub_set(uint16_t net_idx, uint16_t addr, err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); goto done; } if (!status) { - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); goto done; } - err = cli_wait(); + err = bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); done: os_mbuf_free_chain(msg); return err; @@ -2118,21 +2508,138 @@ int bt_mesh_cfg_hb_pub_get(uint16_t net_idx, uint16_t addr, err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); goto done; } if (!status) { - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); goto done; } - err = cli_wait(); + err = bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); done: os_mbuf_free_chain(msg); return err; } +int bt_mesh_cfg_node_identity_set(uint16_t net_idx, uint16_t addr, + uint16_t key_net_idx, uint8_t new_identity, + uint8_t *status, uint8_t *identity) +{ + struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_NODE_IDENTITY_SET, 4); + struct bt_mesh_msg_ctx ctx = { + .net_idx = net_idx, + .app_idx = BT_MESH_KEY_DEV_REMOTE, + .addr = addr, + .send_ttl = BT_MESH_TTL_DEFAULT, + }; + struct node_idt_param param = { + .status = status, + .net_idx = key_net_idx, + .identity = identity, + }; + int err; + + err = cli_prepare(¶m, OP_NODE_IDENTITY_STATUS, addr); + if (err) { + return err; + } + + bt_mesh_model_msg_init(msg, OP_NODE_IDENTITY_SET); + net_buf_simple_add_le16(msg, key_net_idx); + net_buf_simple_add_u8(msg, new_identity); + + err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); + if (err) { + BT_ERR("model_send() failed (err %d)", err); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); + return err; + } + + if (!status) { + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); + return 0; + } + + return bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); +} + +int bt_mesh_cfg_node_identity_get(uint16_t net_idx, uint16_t addr, + uint16_t key_net_idx, uint8_t *status, + uint8_t *identity) +{ + struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_NODE_IDENTITY_GET, 2); + struct bt_mesh_msg_ctx ctx = { + .net_idx = net_idx, + .app_idx = BT_MESH_KEY_DEV_REMOTE, + .addr = addr, + .send_ttl = BT_MESH_TTL_DEFAULT, + }; + struct node_idt_param param = { + .status = status, + .net_idx = key_net_idx, + .identity = identity, + }; + int err; + + err = cli_prepare(¶m, OP_NODE_IDENTITY_STATUS, addr); + if (err) { + return err; + } + + bt_mesh_model_msg_init(msg, OP_NODE_IDENTITY_GET); + net_buf_simple_add_le16(msg, key_net_idx); + + err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); + if (err) { + BT_ERR("model_send() failed (err %d)", err); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); + return err; + } + + if (!status) { + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); + return 0; + } + + return bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); +} + +int bt_mesh_cfg_lpn_timeout_get(uint16_t net_idx, uint16_t addr, + uint16_t unicast_addr, int32_t *polltimeout) +{ + struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_LPN_TIMEOUT_GET, 2); + struct bt_mesh_msg_ctx ctx = { + .net_idx = net_idx, + .app_idx = BT_MESH_KEY_DEV_REMOTE, + .addr = addr, + .send_ttl = BT_MESH_TTL_DEFAULT, + }; + struct lpn_timeout_param param = { + .unicast_addr = unicast_addr, + .polltimeout = polltimeout, + }; + int err; + + err = cli_prepare(¶m, OP_LPN_TIMEOUT_STATUS, addr); + if (err) { + return err; + } + + bt_mesh_model_msg_init(msg, OP_LPN_TIMEOUT_GET); + net_buf_simple_add_le16(msg, unicast_addr); + + err = bt_mesh_model_send(cli->model, &ctx, msg, NULL, NULL); + if (err) { + BT_ERR("model_send() failed (err %d)", err); + bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx); + return err; + } + + return bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(msg_timeout)); +} + int32_t bt_mesh_cfg_cli_timeout_get(void) { return msg_timeout; @@ -2143,4 +2650,68 @@ void bt_mesh_cfg_cli_timeout_set(int32_t timeout) msg_timeout = timeout; } +int bt_mesh_comp_p0_get(struct bt_mesh_comp_p0 *page, + struct os_mbuf *buf) +{ + if (buf->om_len < 10) { + return -EINVAL; + } + + page->cid = net_buf_simple_pull_le16(buf); + page->pid = net_buf_simple_pull_le16(buf); + page->vid = net_buf_simple_pull_le16(buf); + page->crpl = net_buf_simple_pull_le16(buf); + page->feat = net_buf_simple_pull_le16(buf); + page->_buf = buf; + + return 0; +} + +struct bt_mesh_comp_p0_elem *bt_mesh_comp_p0_elem_pull(const struct bt_mesh_comp_p0 *page, + struct bt_mesh_comp_p0_elem *elem) +{ + size_t modlist_size; + + if (page->_buf->om_len < 4) { + return NULL; + } + + elem->loc = net_buf_simple_pull_le16(page->_buf); + elem->nsig = net_buf_simple_pull_u8(page->_buf); + elem->nvnd = net_buf_simple_pull_u8(page->_buf); + + modlist_size = elem->nsig * 2 + elem->nvnd * 4; + + if (page->_buf->om_len < modlist_size) { + return NULL; + } + + elem->_buf = net_buf_simple_pull_mem(page->_buf, modlist_size); + + return elem; +} + +uint16_t bt_mesh_comp_p0_elem_mod(struct bt_mesh_comp_p0_elem *elem, int idx) + { + CHECKIF(idx >= elem->nsig) { + return 0xffff; + } + + return sys_get_le16(&elem->_buf[idx * 2]); +} + +struct bt_mesh_mod_id_vnd bt_mesh_comp_p0_elem_mod_vnd(struct bt_mesh_comp_p0_elem *elem, int idx) + { + CHECKIF(idx >= elem->nvnd) { + return (struct bt_mesh_mod_id_vnd){ 0xffff, 0xffff }; + } + + size_t offset = elem->nsig * 2 + idx * 4; + struct bt_mesh_mod_id_vnd mod = { + .company = sys_get_le16(&elem->_buf[offset]), + .id = sys_get_le16(&elem->_buf[offset + 2]), + }; + + return mod; +} #endif diff --git a/nimble/host/mesh/src/cfg_srv.c b/nimble/host/mesh/src/cfg_srv.c index 404f7318d4..2b4c046cbd 100644 --- a/nimble/host/mesh/src/cfg_srv.c +++ b/nimble/host/mesh/src/cfg_srv.c @@ -7,7 +7,9 @@ */ #include "syscfg/syscfg.h" -#define MESH_LOG_MODULE BLE_MESH_MODEL_LOG + +#define BLE_NPL_LOG_MODULE BLE_MESH_MODEL_LOG +#include #include #include @@ -109,12 +111,13 @@ static int comp_get_page_0(struct os_mbuf *buf) return 0; } -static void dev_comp_data_get(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int dev_comp_data_get(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { struct os_mbuf *sdu = NET_BUF_SIMPLE(BT_MESH_TX_SDU_MAX); uint8_t page; + int err; BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, @@ -129,7 +132,8 @@ static void dev_comp_data_get(struct bt_mesh_model *model, bt_mesh_model_msg_init(sdu, OP_DEV_COMP_DATA_STATUS); net_buf_simple_add_u8(sdu, page); - if (comp_get_page_0(sdu) < 0) { + err = comp_get_page_0(sdu); + if (err) { BT_ERR("Unable to get composition page 0"); goto done; } @@ -140,6 +144,7 @@ static void dev_comp_data_get(struct bt_mesh_model *model, done: os_mbuf_free_chain(sdu); + return err; } static struct bt_mesh_model *get_model(struct bt_mesh_elem *elem, @@ -200,17 +205,20 @@ static uint8_t _mod_pub_set(struct bt_mesh_model *model, uint16_t pub_addr, model->pub->count = 0; if (model->pub->update) { - k_delayed_work_cancel(&model->pub->timer); + /* If this fails, the timer will check pub->addr and + * exit without transmitting. + */ + (void)k_work_cancel_delayable(&model->pub->timer); } if (IS_ENABLED(CONFIG_BT_SETTINGS) && store) { - bt_mesh_store_mod_pub(model); + bt_mesh_model_pub_store(model); } return STATUS_SUCCESS; } - if (!bt_mesh_app_key_exists(app_idx)) { + if (!bt_mesh_app_key_exists(app_idx) || !bt_mesh_model_has_key(model, app_idx)) { return STATUS_INVALID_APPKEY; } @@ -238,14 +246,17 @@ static uint8_t _mod_pub_set(struct bt_mesh_model *model, uint16_t pub_addr, BT_DBG("period %u ms", (unsigned) period_ms); if (period_ms > 0) { - k_delayed_work_submit(&model->pub->timer, period_ms); + k_work_reschedule(&model->pub->timer, period_ms); } else { - k_delayed_work_cancel(&model->pub->timer); + /* If this fails, publication will stop after the + * ongoing set of retransmits. + */ + k_work_cancel_delayable(&model->pub->timer); } } if (IS_ENABLED(CONFIG_BT_SETTINGS) && store) { - bt_mesh_store_mod_pub(model); + bt_mesh_model_pub_store(model); } return STATUS_SUCCESS; @@ -273,7 +284,7 @@ uint8_t mod_bind(struct bt_mesh_model *model, uint16_t key_idx) model->keys[i] = key_idx; if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_mod_bind(model); + bt_mesh_model_bind_store(model); } return STATUS_SUCCESS; @@ -301,7 +312,7 @@ uint8_t mod_unbind(struct bt_mesh_model *model, uint16_t key_idx, bool store) model->keys[i] = BT_MESH_KEY_UNUSED; if (IS_ENABLED(CONFIG_BT_SETTINGS) && store) { - bt_mesh_store_mod_bind(model); + bt_mesh_model_bind_store(model); } if (model->pub && model->pub->key == key_idx) { @@ -313,10 +324,10 @@ uint8_t mod_unbind(struct bt_mesh_model *model, uint16_t key_idx, bool store) return STATUS_SUCCESS; } -static void send_app_key_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - uint8_t status, - uint16_t app_idx, uint16_t net_idx) +static int send_app_key_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + uint8_t status, + uint16_t app_idx, uint16_t net_idx) { struct os_mbuf *msg = NET_BUF_SIMPLE( BT_MESH_MODEL_BUF_LEN(OP_APP_KEY_STATUS, 4)); @@ -330,11 +341,12 @@ static void send_app_key_status(struct bt_mesh_model *model, } os_mbuf_free_chain(msg); + return 0; } -static void app_key_add(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int app_key_add(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { uint16_t key_net_idx, key_app_idx; uint8_t status; @@ -345,10 +357,10 @@ static void app_key_add(struct bt_mesh_model *model, status = bt_mesh_app_key_add(key_app_idx, key_net_idx, buf->om_data); - send_app_key_status(model, ctx, status, key_app_idx, key_net_idx); + return send_app_key_status(model, ctx, status, key_app_idx, key_net_idx); } -static void app_key_update(struct bt_mesh_model *model, +static int app_key_update(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -361,7 +373,7 @@ static void app_key_update(struct bt_mesh_model *model, status = bt_mesh_app_key_update(key_app_idx, key_net_idx, buf->om_data); BT_DBG("status 0x%02x", status); - send_app_key_status(model, ctx, status, key_app_idx, key_net_idx); + return send_app_key_status(model, ctx, status, key_app_idx, key_net_idx); } static void mod_app_key_del(struct bt_mesh_model *mod, @@ -381,9 +393,9 @@ static void app_key_evt(uint16_t app_idx, uint16_t net_idx, } } -static void app_key_del(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int app_key_del(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { uint16_t key_net_idx, key_app_idx; uint8_t status; @@ -394,15 +406,15 @@ static void app_key_del(struct bt_mesh_model *model, status = bt_mesh_app_key_del(key_app_idx, key_net_idx); - send_app_key_status(model, ctx, status, key_app_idx, key_net_idx); + return send_app_key_status(model, ctx, status, key_app_idx, key_net_idx); } /* Index list length: 3 bytes for every pair and 2 bytes for an odd idx */ #define IDX_LEN(num) (((num) / 2) * 3 + ((num) % 2) * 2) -static void app_key_get(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int app_key_get(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_APP_KEY_LIST, @@ -412,10 +424,12 @@ static void app_key_get(struct bt_mesh_model *model, uint8_t status; ssize_t count; int i; + int err = 0; get_idx = net_buf_simple_pull_le16(buf); if (get_idx > 0xfff) { BT_ERR("Invalid NetKeyIndex 0x%04x", get_idx); + err = -EINVAL; goto done; } @@ -455,10 +469,11 @@ static void app_key_get(struct bt_mesh_model *model, } done: - os_mbuf_free_chain(msg); + os_mbuf_free_chain(msg); + return err; } -static void beacon_get(struct bt_mesh_model *model, +static int beacon_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -474,13 +489,16 @@ static void beacon_get(struct bt_mesh_model *model, if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { BT_ERR("Unable to send Config Beacon Status response"); } + + return 0; os_mbuf_free_chain(msg); } -static void beacon_set(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int beacon_set(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { + int err = 0; struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_BEACON_STATUS, 1); BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", @@ -489,6 +507,7 @@ static void beacon_set(struct bt_mesh_model *model, if (buf->om_data[0] != 0x00 && buf->om_data[0] != 0x01) { BT_WARN("Invalid Config Beacon value 0x%02x", buf->om_data[0]); + err = -EINVAL; goto done; } @@ -503,12 +522,12 @@ static void beacon_set(struct bt_mesh_model *model, done: os_mbuf_free_chain(msg); - + return err; } -static void default_ttl_get(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int default_ttl_get(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_DEFAULT_TTL_STATUS, 1); @@ -524,12 +543,12 @@ static void default_ttl_get(struct bt_mesh_model *model, } os_mbuf_free_chain(msg); - + return 0; } -static void default_ttl_set(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int default_ttl_set(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_DEFAULT_TTL_STATUS, 1); int err; @@ -553,9 +572,10 @@ static void default_ttl_set(struct bt_mesh_model *model, done: os_mbuf_free_chain(msg); + return err; } -static void send_gatt_proxy_status(struct bt_mesh_model *model, +static int send_gatt_proxy_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx) { struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_GATT_PROXY_STATUS, 1); @@ -569,20 +589,21 @@ static void send_gatt_proxy_status(struct bt_mesh_model *model, os_mbuf_free_chain(msg); + return 0; } -static void gatt_proxy_get(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int gatt_proxy_get(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, bt_hex(buf->om_data, buf->om_len)); - send_gatt_proxy_status(model, ctx); + return send_gatt_proxy_status(model, ctx); } -static void gatt_proxy_set(struct bt_mesh_model *model, +static int gatt_proxy_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -592,15 +613,15 @@ static void gatt_proxy_set(struct bt_mesh_model *model, if (buf->om_data[0] != 0x00 && buf->om_data[0] != 0x01) { BT_WARN("Invalid GATT Proxy value 0x%02x", buf->om_data[0]); - return; + return -EINVAL; } (void)bt_mesh_gatt_proxy_set(buf->om_data[0]); - send_gatt_proxy_status(model, ctx); + return send_gatt_proxy_status(model, ctx); } -static void net_transmit_get(struct bt_mesh_model *model, +static int net_transmit_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -619,11 +640,12 @@ static void net_transmit_get(struct bt_mesh_model *model, os_mbuf_free_chain(msg); + return 0; } -static void net_transmit_set(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int net_transmit_set(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_NET_TRANSMIT_STATUS, 1); @@ -645,9 +667,11 @@ static void net_transmit_set(struct bt_mesh_model *model, } os_mbuf_free_chain(msg); + + return 0; } -static void relay_get(struct bt_mesh_model *model, +static int relay_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -667,13 +691,15 @@ static void relay_get(struct bt_mesh_model *model, os_mbuf_free_chain(msg); + return 0; } -static void relay_set(struct bt_mesh_model *model, +static int relay_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_RELAY_STATUS, 2); + int err = 0; BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, @@ -681,6 +707,7 @@ static void relay_set(struct bt_mesh_model *model, if (buf->om_data[0] != 0x00 && buf->om_data[0] != 0x01) { BT_WARN("Invalid Relay value 0x%02x", buf->om_data[0]); + err = -EINVAL; goto done; } @@ -696,14 +723,14 @@ static void relay_set(struct bt_mesh_model *model, done: os_mbuf_free_chain(msg); - + return err; } -static void send_mod_pub_status(struct bt_mesh_model *cfg_mod, - struct bt_mesh_msg_ctx *ctx, - uint16_t elem_addr, uint16_t pub_addr, - bool vnd, struct bt_mesh_model *mod, - uint8_t status, uint8_t *mod_id) +static int send_mod_pub_status(struct bt_mesh_model *cfg_mod, + struct bt_mesh_msg_ctx *ctx, + uint16_t elem_addr, uint16_t pub_addr, + bool vnd, struct bt_mesh_model *mod, + uint8_t status, uint8_t *mod_id) { struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_MOD_PUB_STATUS, 14); @@ -737,11 +764,12 @@ static void send_mod_pub_status(struct bt_mesh_model *cfg_mod, } os_mbuf_free_chain(msg); + return 0; } -static void mod_pub_get(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int mod_pub_get(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { uint16_t elem_addr, pub_addr = 0; struct bt_mesh_model *mod; @@ -749,10 +777,15 @@ static void mod_pub_get(struct bt_mesh_model *model, uint8_t *mod_id, status; bool vnd; + if ((buf->om_len != 4U) && (buf->om_len != 6U)) { + BT_ERR("The message size for the application opcode is incorrect."); + return -EMSGSIZE; + } + elem_addr = net_buf_simple_pull_le16(buf); if (!BT_MESH_ADDR_IS_UNICAST(elem_addr)) { BT_WARN("Prohibited element address"); - return; + return -EINVAL; } mod_id = buf->om_data; @@ -782,11 +815,11 @@ static void mod_pub_get(struct bt_mesh_model *model, status = STATUS_SUCCESS; send_status: - send_mod_pub_status(model, ctx, elem_addr, pub_addr, vnd, mod, - status, mod_id); + return send_mod_pub_status(model, ctx, elem_addr, pub_addr, vnd, mod, + status, mod_id); } -static void mod_pub_set(struct bt_mesh_model *model, +static int mod_pub_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -797,10 +830,15 @@ static void mod_pub_set(struct bt_mesh_model *model, uint8_t *mod_id; bool vnd; + if ((buf->om_len != 11U) && (buf->om_len != 13U)) { + BT_ERR("The message size for the application opcode is incorrect."); + return -EMSGSIZE; + } + elem_addr = net_buf_simple_pull_le16(buf); if (!BT_MESH_ADDR_IS_UNICAST(elem_addr)) { BT_WARN("Prohibited element address"); - return; + return -EINVAL; } pub_addr = net_buf_simple_pull_le16(buf); @@ -811,7 +849,7 @@ static void mod_pub_set(struct bt_mesh_model *model, pub_ttl = net_buf_simple_pull_u8(buf); if (pub_ttl > BT_MESH_TTL_MAX && pub_ttl != BT_MESH_TTL_DEFAULT) { BT_ERR("Invalid TTL value 0x%02x", pub_ttl); - return; + return -EINVAL; } pub_period = net_buf_simple_pull_u8(buf); @@ -844,8 +882,8 @@ static void mod_pub_set(struct bt_mesh_model *model, pub_period, retransmit, true); send_status: - send_mod_pub_status(model, ctx, elem_addr, pub_addr, vnd, mod, - status, mod_id); + return send_mod_pub_status(model, ctx, elem_addr, pub_addr, vnd, mod, + status, mod_id); } static size_t mod_sub_list_clear(struct bt_mesh_model *mod) @@ -880,9 +918,9 @@ static size_t mod_sub_list_clear(struct bt_mesh_model *mod) return clear_count; } -static void mod_pub_va_set(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int mod_pub_va_set(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { uint8_t retransmit, status, pub_ttl, pub_period, cred_flag; uint16_t elem_addr, pub_addr, pub_app_idx; @@ -892,10 +930,15 @@ static void mod_pub_va_set(struct bt_mesh_model *model, uint8_t *mod_id; bool vnd; + if ((buf->om_len != 25U) && (buf->om_len != 27U)) { + BT_ERR("The message size for the application opcode is incorrect."); + return -EMSGSIZE; + } + elem_addr = net_buf_simple_pull_le16(buf); if (!BT_MESH_ADDR_IS_UNICAST(elem_addr)) { BT_WARN("Prohibited element address"); - return; + return -EINVAL; } label_uuid = net_buf_simple_pull_mem(buf, 16); @@ -905,7 +948,7 @@ static void mod_pub_va_set(struct bt_mesh_model *model, pub_ttl = net_buf_simple_pull_u8(buf); if (pub_ttl > BT_MESH_TTL_MAX && pub_ttl != BT_MESH_TTL_DEFAULT) { BT_ERR("Invalid TTL value 0x%02x", pub_ttl); - return; + return -EINVAL; } pub_period = net_buf_simple_pull_u8(buf); @@ -947,14 +990,14 @@ static void mod_pub_va_set(struct bt_mesh_model *model, } send_status: - send_mod_pub_status(model, ctx, elem_addr, pub_addr, vnd, mod, - status, mod_id); + return send_mod_pub_status(model, ctx, elem_addr, pub_addr, vnd, mod, + status, mod_id); } -static void send_mod_sub_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, uint8_t status, - uint16_t elem_addr, uint16_t sub_addr, uint8_t *mod_id, - bool vnd) +static int send_mod_sub_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, uint8_t status, + uint16_t elem_addr, uint16_t sub_addr, uint8_t *mod_id, + bool vnd) { struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_MOD_SUB_STATUS, 9); @@ -978,11 +1021,13 @@ static void send_mod_sub_status(struct bt_mesh_model *model, } os_mbuf_free_chain(msg); + + return 0; } -static void mod_sub_add(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int mod_sub_add(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { uint16_t elem_addr, sub_addr; struct bt_mesh_model *mod; @@ -992,10 +1037,15 @@ static void mod_sub_add(struct bt_mesh_model *model, uint16_t *entry; bool vnd; + if ((buf->om_len != 6U) && (buf->om_len != 8U)) { + BT_ERR("The message size for the application opcode is incorrect."); + return -EMSGSIZE; + } + elem_addr = net_buf_simple_pull_le16(buf); if (!BT_MESH_ADDR_IS_UNICAST(elem_addr)) { BT_WARN("Prohibited element address"); - return; + return -EINVAL; } sub_addr = net_buf_simple_pull_le16(buf); @@ -1040,7 +1090,7 @@ static void mod_sub_add(struct bt_mesh_model *model, status = STATUS_SUCCESS; if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_mod_sub(mod); + bt_mesh_model_sub_store(mod); } if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER)) { @@ -1049,13 +1099,13 @@ static void mod_sub_add(struct bt_mesh_model *model, send_status: - send_mod_sub_status(model, ctx, status, elem_addr, sub_addr, - mod_id, vnd); + return send_mod_sub_status(model, ctx, status, elem_addr, sub_addr, + mod_id, vnd); } -static void mod_sub_del(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int mod_sub_del(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { uint16_t elem_addr, sub_addr; struct bt_mesh_model *mod; @@ -1065,10 +1115,15 @@ static void mod_sub_del(struct bt_mesh_model *model, uint8_t status; bool vnd; + if ((buf->om_len != 6U) && (buf->om_len != 8U)) { + BT_ERR("The message size for the application opcode is incorrect."); + return -EMSGSIZE; + } + elem_addr = net_buf_simple_pull_le16(buf); if (!BT_MESH_ADDR_IS_UNICAST(elem_addr)) { BT_WARN("Prohibited element address"); - return; + return -EINVAL; } sub_addr = net_buf_simple_pull_le16(buf); @@ -1110,17 +1165,16 @@ static void mod_sub_del(struct bt_mesh_model *model, *match = BT_MESH_ADDR_UNASSIGNED; if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_mod_sub(mod); + bt_mesh_model_sub_store(mod); } } send_status: - send_mod_sub_status(model, ctx, status, elem_addr, sub_addr, - mod_id, vnd); + return send_mod_sub_status(model, ctx, status, elem_addr, sub_addr, + mod_id, vnd); } -static enum bt_mesh_walk mod_sub_clear_visitor(struct bt_mesh_model *mod, - uint32_t depth, void *user_data) +static enum bt_mesh_walk mod_sub_clear_visitor(struct bt_mesh_model *mod, void *user_data) { if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER)) { bt_mesh_lpn_group_del(mod->groups, ARRAY_SIZE(mod->groups)); @@ -1131,9 +1185,9 @@ static enum bt_mesh_walk mod_sub_clear_visitor(struct bt_mesh_model *mod, return BT_MESH_WALK_CONTINUE; } -static void mod_sub_overwrite(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int mod_sub_overwrite(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { uint16_t elem_addr, sub_addr; struct bt_mesh_model *mod; @@ -1142,10 +1196,15 @@ static void mod_sub_overwrite(struct bt_mesh_model *model, uint8_t status; bool vnd; + if ((buf->om_len != 6U) && (buf->om_len != 8U)) { + BT_ERR("The message size for the application opcode is incorrect."); + return -EMSGSIZE; + } + elem_addr = net_buf_simple_pull_le16(buf); if (!BT_MESH_ADDR_IS_UNICAST(elem_addr)) { BT_WARN("Prohibited element address"); - return; + return -EINVAL; } sub_addr = net_buf_simple_pull_le16(buf); @@ -1174,14 +1233,13 @@ static void mod_sub_overwrite(struct bt_mesh_model *model, } if (ARRAY_SIZE(mod->groups) > 0) { - bt_mesh_model_tree_walk(bt_mesh_model_root(mod), - mod_sub_clear_visitor, NULL); + bt_mesh_model_extensions_walk(mod, mod_sub_clear_visitor, NULL); mod->groups[0] = sub_addr; status = STATUS_SUCCESS; if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_mod_sub(mod); + bt_mesh_model_sub_store(mod); } if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER)) { @@ -1193,13 +1251,13 @@ static void mod_sub_overwrite(struct bt_mesh_model *model, send_status: - send_mod_sub_status(model, ctx, status, elem_addr, sub_addr, + return send_mod_sub_status(model, ctx, status, elem_addr, sub_addr, mod_id, vnd); } -static void mod_sub_del_all(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int mod_sub_del_all(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { struct bt_mesh_model *mod; struct bt_mesh_elem *elem; @@ -1208,10 +1266,15 @@ static void mod_sub_del_all(struct bt_mesh_model *model, uint8_t status; bool vnd; + if ((buf->om_len != 4U) && (buf->om_len != 6U)) { + BT_ERR("The message size for the application opcode is incorrect."); + return -EMSGSIZE; + } + elem_addr = net_buf_simple_pull_le16(buf); if (!BT_MESH_ADDR_IS_UNICAST(elem_addr)) { BT_WARN("Prohibited element address"); - return; + return -EINVAL; } BT_DBG("elem_addr 0x%04x", elem_addr); @@ -1232,18 +1295,17 @@ static void mod_sub_del_all(struct bt_mesh_model *model, goto send_status; } - bt_mesh_model_tree_walk(bt_mesh_model_root(mod), mod_sub_clear_visitor, - NULL); + bt_mesh_model_extensions_walk(mod, mod_sub_clear_visitor, NULL); if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_mod_sub(mod); + bt_mesh_model_sub_store(mod); } status = STATUS_SUCCESS; send_status: - send_mod_sub_status(model, ctx, status, elem_addr, - BT_MESH_ADDR_UNASSIGNED, mod_id, vnd); + return send_mod_sub_status(model, ctx, status, elem_addr, + BT_MESH_ADDR_UNASSIGNED, mod_id, vnd); } struct mod_sub_list_ctx { @@ -1251,8 +1313,7 @@ struct mod_sub_list_ctx { struct os_mbuf *msg; }; -static enum bt_mesh_walk mod_sub_list_visitor(struct bt_mesh_model *mod, - uint32_t depth, void *ctx) +static enum bt_mesh_walk mod_sub_list_visitor(struct bt_mesh_model *mod, void *ctx) { struct mod_sub_list_ctx *visit = ctx; int count = 0; @@ -1283,19 +1344,21 @@ static enum bt_mesh_walk mod_sub_list_visitor(struct bt_mesh_model *mod, return BT_MESH_WALK_CONTINUE; } -static void mod_sub_get(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int mod_sub_get(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { struct os_mbuf *msg = NET_BUF_SIMPLE(BT_MESH_TX_SDU_MAX); struct mod_sub_list_ctx visit_ctx; struct bt_mesh_model *mod; struct bt_mesh_elem *elem; uint16_t addr, id; + int err = 0; addr = net_buf_simple_pull_le16(buf); if (!BT_MESH_ADDR_IS_UNICAST(addr)) { BT_WARN("Prohibited element address"); + err = -EINVAL; goto done; } @@ -1328,8 +1391,7 @@ static void mod_sub_get(struct bt_mesh_model *model, visit_ctx.msg = msg; visit_ctx.elem_idx = mod->elem_idx; - bt_mesh_model_tree_walk(bt_mesh_model_root(mod), mod_sub_list_visitor, - &visit_ctx); + bt_mesh_model_extensions_walk(mod, mod_sub_list_visitor, &visit_ctx); send_list: if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { @@ -1339,21 +1401,24 @@ static void mod_sub_get(struct bt_mesh_model *model, done: os_mbuf_free_chain(msg); + return err; } -static void mod_sub_get_vnd(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int mod_sub_get_vnd(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { struct os_mbuf *msg = NET_BUF_SIMPLE(BT_MESH_TX_SDU_MAX); struct mod_sub_list_ctx visit_ctx; struct bt_mesh_model *mod; struct bt_mesh_elem *elem; uint16_t company, addr, id; + int err = 0; addr = net_buf_simple_pull_le16(buf); if (!BT_MESH_ADDR_IS_UNICAST(addr)) { BT_WARN("Prohibited element address"); + err = -EINVAL; goto done; } @@ -1390,8 +1455,7 @@ static void mod_sub_get_vnd(struct bt_mesh_model *model, visit_ctx.msg = msg; visit_ctx.elem_idx = mod->elem_idx; - bt_mesh_model_tree_walk(bt_mesh_model_root(mod), mod_sub_list_visitor, - &visit_ctx); + bt_mesh_model_extensions_walk(mod, mod_sub_list_visitor, &visit_ctx); send_list: if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { @@ -1401,11 +1465,12 @@ static void mod_sub_get_vnd(struct bt_mesh_model *model, done: os_mbuf_free_chain(msg); + return err; } -static void mod_sub_va_add(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int mod_sub_va_add(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { uint16_t elem_addr, sub_addr; struct bt_mesh_model *mod; @@ -1416,10 +1481,15 @@ static void mod_sub_va_add(struct bt_mesh_model *model, uint8_t status; bool vnd; + if ((buf->om_len != 20U) && (buf->om_len != 22U)) { + BT_ERR("The message size for the application opcode is incorrect."); + return -EMSGSIZE; + } + elem_addr = net_buf_simple_pull_le16(buf); if (!BT_MESH_ADDR_IS_UNICAST(elem_addr)) { BT_WARN("Prohibited element address"); - return; + return -EINVAL; } label_uuid = net_buf_simple_pull_mem(buf, 16); @@ -1470,19 +1540,19 @@ static void mod_sub_va_add(struct bt_mesh_model *model, } if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_mod_sub(mod); + bt_mesh_model_sub_store(mod); } status = STATUS_SUCCESS; send_status: - send_mod_sub_status(model, ctx, status, elem_addr, sub_addr, - mod_id, vnd); + return send_mod_sub_status(model, ctx, status, elem_addr, sub_addr, + mod_id, vnd); } -static void mod_sub_va_del(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int mod_sub_va_del(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { uint16_t elem_addr, sub_addr; struct bt_mesh_model *mod; @@ -1493,10 +1563,15 @@ static void mod_sub_va_del(struct bt_mesh_model *model, uint8_t status; bool vnd; + if ((buf->om_len != 20U) && (buf->om_len != 22U)) { + BT_ERR("The message size for the application opcode is incorrect."); + return -EMSGSIZE; + } + elem_addr = net_buf_simple_pull_le16(buf); if (!BT_MESH_ADDR_IS_UNICAST(elem_addr)) { BT_WARN("Prohibited element address"); - return; + return -EINVAL; } label_uuid = net_buf_simple_pull_mem(buf, 16); @@ -1535,7 +1610,7 @@ static void mod_sub_va_del(struct bt_mesh_model *model, *match = BT_MESH_ADDR_UNASSIGNED; if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_mod_sub(mod); + bt_mesh_model_sub_store(mod); } status = STATUS_SUCCESS; @@ -1544,13 +1619,13 @@ static void mod_sub_va_del(struct bt_mesh_model *model, } send_status: - send_mod_sub_status(model, ctx, status, elem_addr, sub_addr, - mod_id, vnd); + return send_mod_sub_status(model, ctx, status, elem_addr, sub_addr, + mod_id, vnd); } -static void mod_sub_va_overwrite(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int mod_sub_va_overwrite(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { uint16_t elem_addr, sub_addr = BT_MESH_ADDR_UNASSIGNED; struct bt_mesh_model *mod; @@ -1560,10 +1635,15 @@ static void mod_sub_va_overwrite(struct bt_mesh_model *model, uint8_t status; bool vnd; + if ((buf->om_len != 20U) && (buf->om_len != 22U)) { + BT_ERR("The message size for the application opcode is incorrect."); + return -EMSGSIZE; + } + elem_addr = net_buf_simple_pull_le16(buf); if (!BT_MESH_ADDR_IS_UNICAST(elem_addr)) { BT_WARN("Prohibited element address"); - return; + return -EINVAL; } label_uuid = net_buf_simple_pull_mem(buf, 16); @@ -1589,12 +1669,11 @@ static void mod_sub_va_overwrite(struct bt_mesh_model *model, if (ARRAY_SIZE(mod->groups) > 0) { status = bt_mesh_va_add(label_uuid, &sub_addr); if (status == STATUS_SUCCESS) { - bt_mesh_model_tree_walk(bt_mesh_model_root(mod), - mod_sub_clear_visitor, NULL); + bt_mesh_model_extensions_walk(mod, mod_sub_clear_visitor, NULL); mod->groups[0] = sub_addr; if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_mod_sub(mod); + bt_mesh_model_sub_store(mod); } if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER)) { @@ -1606,13 +1685,13 @@ static void mod_sub_va_overwrite(struct bt_mesh_model *model, } send_status: - send_mod_sub_status(model, ctx, status, elem_addr, sub_addr, - mod_id, vnd); + return send_mod_sub_status(model, ctx, status, elem_addr, sub_addr, + mod_id, vnd); } -static void send_net_key_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - uint16_t idx, uint8_t status) +static int send_net_key_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + uint16_t idx, uint8_t status) { struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_NET_KEY_STATUS, 3); @@ -1626,9 +1705,11 @@ static void send_net_key_status(struct bt_mesh_model *model, } os_mbuf_free_chain(msg); + + return 0; } -static void net_key_add(struct bt_mesh_model *model, +static int net_key_add(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -1638,18 +1719,18 @@ static void net_key_add(struct bt_mesh_model *model, idx = net_buf_simple_pull_le16(buf); if (idx > 0xfff) { BT_ERR("Invalid NetKeyIndex 0x%04x", idx); - return; + return -EINVAL; } BT_DBG("idx 0x%04x", idx); status = bt_mesh_subnet_add(idx, buf->om_data); - send_net_key_status(model, ctx, idx, status); + return send_net_key_status(model, ctx, idx, status); } -static void net_key_update(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int net_key_update(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { uint8_t status; uint16_t idx; @@ -1657,24 +1738,24 @@ static void net_key_update(struct bt_mesh_model *model, idx = net_buf_simple_pull_le16(buf); if (idx > 0xfff) { BT_ERR("Invalid NetKeyIndex 0x%04x", idx); - return; + return -EINVAL; } status = bt_mesh_subnet_update(idx, buf->om_data); - send_net_key_status(model, ctx, idx, status); + return send_net_key_status(model, ctx, idx, status); } -static void net_key_del(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int net_key_del(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { uint16_t del_idx; del_idx = net_buf_simple_pull_le16(buf); if (del_idx > 0xfff) { BT_ERR("Invalid NetKeyIndex 0x%04x", del_idx); - return; + return -EINVAL; } BT_DBG("idx 0x%04x", del_idx); @@ -1683,19 +1764,18 @@ static void net_key_del(struct bt_mesh_model *model, * The NetKey List must contain a minimum of one NetKey. */ if (ctx->net_idx == del_idx) { - send_net_key_status(model, ctx, del_idx, + return send_net_key_status(model, ctx, del_idx, STATUS_CANNOT_REMOVE); - return; } - bt_mesh_subnet_del(del_idx); + (void)bt_mesh_subnet_del(del_idx); - send_net_key_status(model, ctx, del_idx, STATUS_SUCCESS); + return send_net_key_status(model, ctx, del_idx, STATUS_SUCCESS); } -static void net_key_get(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int net_key_get(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_NET_KEY_LIST, @@ -1724,12 +1804,13 @@ static void net_key_get(struct bt_mesh_model *model, } os_mbuf_free_chain(msg); + return 0; } -static void send_node_id_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - uint8_t status, - uint16_t net_idx, uint8_t node_id) +static int send_node_id_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + uint8_t status, + uint16_t net_idx, uint8_t node_id) { struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_NODE_IDENTITY_STATUS, 4); @@ -1743,11 +1824,13 @@ static void send_node_id_status(struct bt_mesh_model *model, } os_mbuf_free_chain(msg); + + return 0; } -static void node_identity_get(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int node_identity_get(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { enum bt_mesh_feat_state node_id; uint8_t status; @@ -1760,17 +1843,17 @@ static void node_identity_get(struct bt_mesh_model *model, idx = net_buf_simple_pull_le16(buf); if (idx > 0xfff) { BT_ERR("Invalid NetKeyIndex 0x%04x", idx); - return; + return -EINVAL; } status = bt_mesh_subnet_node_id_get(idx, &node_id); - send_node_id_status(model, ctx, status, idx, node_id); + return send_node_id_status(model, ctx, status, idx, node_id); } -static void node_identity_set(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int node_identity_set(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { uint8_t node_id, status; uint16_t idx; @@ -1782,30 +1865,28 @@ static void node_identity_set(struct bt_mesh_model *model, idx = net_buf_simple_pull_le16(buf); if (idx > 0xfff) { BT_WARN("Invalid NetKeyIndex 0x%04x", idx); - return; + return -EINVAL; } node_id = net_buf_simple_pull_u8(buf); if (node_id != 0x00 && node_id != 0x01) { BT_WARN("Invalid Node ID value 0x%02x", node_id); - return; + return -EINVAL; } status = bt_mesh_subnet_node_id_set(idx, node_id); if (status == STATUS_INVALID_NETKEY) { - send_node_id_status(model, ctx, status, idx, - BT_MESH_NODE_IDENTITY_STOPPED); - return; + return send_node_id_status(model, ctx, status, idx, + BT_MESH_NODE_IDENTITY_STOPPED); } if (status == STATUS_FEAT_NOT_SUPP) { /* Should return success, even if feature isn't supported: */ - send_node_id_status(model, ctx, STATUS_SUCCESS, idx, - BT_MESH_NODE_IDENTITY_NOT_SUPPORTED); - return; + return send_node_id_status(model, ctx, STATUS_SUCCESS, idx, + BT_MESH_NODE_IDENTITY_NOT_SUPPORTED); } - send_node_id_status(model, ctx, status, idx, node_id); + return send_node_id_status(model, ctx, status, idx, node_id); } static void create_mod_app_status(struct os_mbuf *msg, @@ -1826,9 +1907,9 @@ static void create_mod_app_status(struct os_mbuf *msg, } } -static void mod_app_bind(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int mod_app_bind(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_MOD_APP_STATUS, 9); uint16_t elem_addr, key_app_idx; @@ -1836,10 +1917,17 @@ static void mod_app_bind(struct bt_mesh_model *model, struct bt_mesh_elem *elem; uint8_t *mod_id, status; bool vnd; + int err = 0; + + if ((buf->om_len != 6U) && (buf->om_len != 8U)) { + BT_ERR("The message size for the application opcode is incorrect."); + return -EMSGSIZE; + } elem_addr = net_buf_simple_pull_le16(buf); if (!BT_MESH_ADDR_IS_UNICAST(elem_addr)) { BT_WARN("Prohibited element address"); + err = -EINVAL; goto done; } @@ -1883,13 +1971,14 @@ static void mod_app_bind(struct bt_mesh_model *model, } done: - os_mbuf_free_chain(msg); + os_mbuf_free_chain(msg); + return err; } -static void mod_app_unbind(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int mod_app_unbind(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_MOD_APP_STATUS, 9); uint16_t elem_addr, key_app_idx; @@ -1897,10 +1986,17 @@ static void mod_app_unbind(struct bt_mesh_model *model, struct bt_mesh_elem *elem; uint8_t *mod_id, status; bool vnd; + int err = 0; + + if ((buf->om_len != 6U) && (buf->om_len != 8U)) { + BT_ERR("The message size for the application opcode is incorrect."); + return -EMSGSIZE; + } elem_addr = net_buf_simple_pull_le16(buf); if (!BT_MESH_ADDR_IS_UNICAST(elem_addr)) { BT_WARN("Prohibited element address"); + err = -EINVAL; goto done; } @@ -1937,16 +2033,18 @@ static void mod_app_unbind(struct bt_mesh_model *model, } done: - os_mbuf_free_chain(msg); + os_mbuf_free_chain(msg); + + return err; } #define KEY_LIST_LEN (MYNEWT_VAL(BLE_MESH_MODEL_KEY_COUNT) * 2) -static void mod_app_get(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int mod_app_get(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { - struct os_mbuf *msg = NET_BUF_SIMPLE(max(BT_MESH_MODEL_BUF_LEN(OP_VND_MOD_APP_LIST, + struct os_mbuf *msg = NET_BUF_SIMPLE(MAX(BT_MESH_MODEL_BUF_LEN(OP_VND_MOD_APP_LIST, 9 + KEY_LIST_LEN), BT_MESH_MODEL_BUF_LEN(OP_SIG_MOD_APP_LIST, 9 + KEY_LIST_LEN))); @@ -1956,10 +2054,17 @@ static void mod_app_get(struct bt_mesh_model *model, uint8_t *mod_id, status; uint16_t elem_addr; bool vnd; + int err = 0; + + if ((buf->om_len != 4U) && (buf->om_len != 6U)) { + BT_ERR("The message size for the application opcode is incorrect."); + return -EMSGSIZE; + } elem_addr = net_buf_simple_pull_le16(buf); if (!BT_MESH_ADDR_IS_UNICAST(elem_addr)) { BT_WARN("Prohibited element address"); + err = -EINVAL; goto done; } @@ -2015,13 +2120,31 @@ static void mod_app_get(struct bt_mesh_model *model, done: os_mbuf_free_chain(msg); + + return err; } -static void node_reset(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static void reset_send_start(uint16_t duration, int err, void *cb_data) +{ + if (err) { + BT_ERR("Sending Node Reset Status failed (err %d)", err); + bt_mesh_reset(); + } +} + +static void reset_send_end(int err, void *cb_data) +{ + bt_mesh_reset(); +} + +static int node_reset(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { - static struct bt_mesh_proxy_idle_cb proxy_idle = {.cb = bt_mesh_reset}; + static const struct bt_mesh_send_cb reset_cb = { + .start = reset_send_start, + .end = reset_send_end, + }; struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_NODE_RESET_STATUS, 0); @@ -2029,30 +2152,19 @@ static void node_reset(struct bt_mesh_model *model, ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, bt_hex(buf->om_data, buf->om_len)); - bt_mesh_model_msg_init(msg, OP_NODE_RESET_STATUS); - /* Send the response first since we wont have any keys left to - * send it later. - */ - if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { + if (bt_mesh_model_send(model, ctx, msg, &reset_cb, NULL)) { BT_ERR("Unable to send Node Reset Status"); } - if (!IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY)) { - bt_mesh_reset(); - return; - } + os_mbuf_free_chain(msg); - /* If the response goes to a proxy node, we'll wait for the sending to - * complete before moving on. - */ - bt_mesh_proxy_on_idle(&proxy_idle); - os_mbuf_free_chain(msg); + return 0; } -static void send_friend_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx) +static int send_friend_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx) { struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_FRIEND_STATUS, 1); @@ -2062,23 +2174,26 @@ static void send_friend_status(struct bt_mesh_model *model, if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { BT_ERR("Unable to send Friend Status"); } - os_mbuf_free_chain(msg); + + os_mbuf_free_chain(msg); + + return 0; } -static void friend_get(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int friend_get(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, bt_hex(buf->om_data, buf->om_len)); - send_friend_status(model, ctx); + return send_friend_status(model, ctx); } -static void friend_set(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int friend_set(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s", ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, @@ -2086,22 +2201,23 @@ static void friend_set(struct bt_mesh_model *model, if (buf->om_data[0] != 0x00 && buf->om_data[0] != 0x01) { BT_WARN("Invalid Friend value 0x%02x", buf->om_data[0]); - return; + return -EINVAL; } (void)bt_mesh_friend_set(buf->om_data[0]); - send_friend_status(model, ctx); + return send_friend_status(model, ctx); } -static void lpn_timeout_get(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int lpn_timeout_get(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_LPN_TIMEOUT_STATUS, 5); struct bt_mesh_friend *frnd; + int32_t timeout_steps; uint16_t lpn_addr; - int32_t timeout; + int err = 0; lpn_addr = net_buf_simple_pull_le16(buf); @@ -2111,6 +2227,7 @@ static void lpn_timeout_get(struct bt_mesh_model *model, /* check if it's the address of the Low Power Node? */ if (!BT_MESH_ADDR_IS_UNICAST(lpn_addr)) { BT_WARN("Invalid LPNAddress; ignoring msg"); + err = -EINVAL; goto done; } @@ -2118,20 +2235,21 @@ static void lpn_timeout_get(struct bt_mesh_model *model, net_buf_simple_add_le16(msg, lpn_addr); if (!IS_ENABLED(CONFIG_BT_MESH_FRIEND)) { - timeout = 0; + timeout_steps = 0; goto send_rsp; } frnd = bt_mesh_friend_find(BT_MESH_KEY_ANY, lpn_addr, true, true); if (!frnd) { - timeout = 0; + timeout_steps = 0; goto send_rsp; } - timeout = k_delayed_work_remaining_get(&frnd->timer) / 100; + /* PollTimeout should be reported in steps of 100ms. */ + timeout_steps = frnd->poll_to / 100; send_rsp: - net_buf_simple_add_le24(msg, timeout); + net_buf_simple_add_le24(msg, timeout_steps); if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { BT_ERR("Unable to send LPN PollTimeout Status"); @@ -2139,11 +2257,13 @@ static void lpn_timeout_get(struct bt_mesh_model *model, done: os_mbuf_free_chain(msg); + + return err; } -static void send_krp_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - uint16_t idx, uint8_t phase, uint8_t status) +static int send_krp_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + uint16_t idx, uint8_t phase, uint8_t status) { struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_KRP_STATUS, 4); @@ -2158,10 +2278,12 @@ static void send_krp_status(struct bt_mesh_model *model, } os_mbuf_free_chain(msg); + + return 0; } -static void krp_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int krp_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { uint8_t kr_phase, status; uint16_t idx; @@ -2169,18 +2291,18 @@ static void krp_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, idx = net_buf_simple_pull_le16(buf); if (idx > 0xfff) { BT_ERR("Invalid NetKeyIndex 0x%04x", idx); - return; + return -EINVAL; } BT_DBG("idx 0x%04x", idx); status = bt_mesh_subnet_kr_phase_get(idx, &kr_phase); - send_krp_status(model, ctx, idx, kr_phase, status); + return send_krp_status(model, ctx, idx, kr_phase, status); } -static void krp_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int krp_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { uint8_t phase, status; uint16_t idx; @@ -2190,16 +2312,16 @@ static void krp_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, if (idx > 0xfff) { BT_ERR("Invalid NetKeyIndex 0x%04x", idx); - return; + return -EINVAL; } status = bt_mesh_subnet_kr_phase_set(idx, &phase); if (status == STATUS_CANNOT_UPDATE) { BT_ERR("Invalid kr phase transition 0x%02x", phase); - return; + return -EINVAL; } - send_krp_status(model, ctx, idx, phase, status); + return send_krp_status(model, ctx, idx, phase, status); } static uint8_t hb_pub_count_log(uint16_t val) @@ -2224,9 +2346,9 @@ struct hb_pub_param { uint16_t net_idx; } __packed; -static void hb_pub_send_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, uint8_t status, - const struct bt_mesh_hb_pub *pub) +static int hb_pub_send_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, uint8_t status, + const struct bt_mesh_hb_pub *pub) { struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_HEARTBEAT_PUB_STATUS, 10); @@ -2248,9 +2370,11 @@ static void hb_pub_send_status(struct bt_mesh_model *model, } os_mbuf_free_chain(msg); + + return 0; } -static void heartbeat_pub_get(struct bt_mesh_model *model, +static int heartbeat_pub_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -2260,12 +2384,12 @@ static void heartbeat_pub_get(struct bt_mesh_model *model, bt_mesh_hb_pub_get(&pub); - hb_pub_send_status(model, ctx, STATUS_SUCCESS, &pub); + return hb_pub_send_status(model, ctx, STATUS_SUCCESS, &pub); } -static void heartbeat_pub_set(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int heartbeat_pub_set(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { struct hb_pub_param *param = (void *)buf->om_data; struct bt_mesh_hb_pub pub; @@ -2298,22 +2422,22 @@ static void heartbeat_pub_set(struct bt_mesh_model *model, if (param->ttl > BT_MESH_TTL_MAX && param->ttl != BT_MESH_TTL_DEFAULT) { BT_ERR("Invalid TTL value 0x%02x", param->ttl); - return; + return -EINVAL; } if (pub.net_idx > 0xfff) { BT_ERR("Invalid NetKeyIndex 0x%04x", pub.net_idx); - return; + return -EINVAL; } status = bt_mesh_hb_pub_set(&pub); rsp: - hb_pub_send_status(model, ctx, status, &pub); + return hb_pub_send_status(model, ctx, status, &pub); } -static void hb_sub_send_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - const struct bt_mesh_hb_sub *sub) +static int hb_sub_send_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + const struct bt_mesh_hb_sub *sub) { struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_HEARTBEAT_SUB_STATUS, 9); BT_DBG("src 0x%04x ", ctx->addr); @@ -2334,11 +2458,13 @@ static void hb_sub_send_status(struct bt_mesh_model *model, } os_mbuf_free_chain(msg); + + return 0; } -static void heartbeat_sub_get(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int heartbeat_sub_get(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { struct bt_mesh_hb_sub sub; @@ -2346,17 +2472,18 @@ static void heartbeat_sub_get(struct bt_mesh_model *model, bt_mesh_hb_sub_get(&sub); - hb_sub_send_status(model, ctx, &sub); + return hb_sub_send_status(model, ctx, &sub); } -static void heartbeat_sub_set(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int heartbeat_sub_set(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { uint8_t period_log, status; struct bt_mesh_hb_sub sub; uint16_t sub_src, sub_dst; uint32_t period; + int err; BT_DBG("src 0x%04x", ctx->addr); @@ -2369,7 +2496,7 @@ static void heartbeat_sub_set(struct bt_mesh_model *model, if (period_log > 0x11) { BT_WARN("Prohibited subscription period 0x%02x", period_log); - return; + return -EINVAL; } period = bt_mesh_hb_pwr2(period_log); @@ -2379,7 +2506,7 @@ static void heartbeat_sub_set(struct bt_mesh_model *model, /* All errors are caused by invalid packets, which should be * ignored. */ - return; + return -EINVAL; } bt_mesh_hb_sub_get(&sub); @@ -2391,7 +2518,10 @@ static void heartbeat_sub_set(struct bt_mesh_model *model, sub.min_hops = BT_MESH_TTL_MAX; } - hb_sub_send_status(model, ctx, &sub); + err = hb_sub_send_status(model, ctx, &sub); + if (err) { + return err; + } /* MESH/NODE/CFG/HBS/BV-02-C expects us to return previous * count value and then reset it to 0. @@ -2400,56 +2530,58 @@ static void heartbeat_sub_set(struct bt_mesh_model *model, sub.dst != BT_MESH_ADDR_UNASSIGNED && !period) { bt_mesh_hb_sub_reset_count(); } + + return 0; } const struct bt_mesh_model_op bt_mesh_cfg_srv_op[] = { - { OP_DEV_COMP_DATA_GET, 1, dev_comp_data_get }, - { OP_APP_KEY_ADD, 19, app_key_add }, - { OP_APP_KEY_UPDATE, 19, app_key_update }, - { OP_APP_KEY_DEL, 3, app_key_del }, - { OP_APP_KEY_GET, 2, app_key_get }, - { OP_BEACON_GET, 0, beacon_get }, - { OP_BEACON_SET, 1, beacon_set }, - { OP_DEFAULT_TTL_GET, 0, default_ttl_get }, - { OP_DEFAULT_TTL_SET, 1, default_ttl_set }, - { OP_GATT_PROXY_GET, 0, gatt_proxy_get }, - { OP_GATT_PROXY_SET, 1, gatt_proxy_set }, - { OP_NET_TRANSMIT_GET, 0, net_transmit_get }, - { OP_NET_TRANSMIT_SET, 1, net_transmit_set }, - { OP_RELAY_GET, 0, relay_get }, - { OP_RELAY_SET, 2, relay_set }, - { OP_MOD_PUB_GET, 4, mod_pub_get }, - { OP_MOD_PUB_SET, 11, mod_pub_set }, - { OP_MOD_PUB_VA_SET, 24, mod_pub_va_set }, - { OP_MOD_SUB_ADD, 6, mod_sub_add }, - { OP_MOD_SUB_VA_ADD, 20, mod_sub_va_add }, - { OP_MOD_SUB_DEL, 6, mod_sub_del }, - { OP_MOD_SUB_VA_DEL, 20, mod_sub_va_del }, - { OP_MOD_SUB_OVERWRITE, 6, mod_sub_overwrite }, - { OP_MOD_SUB_VA_OVERWRITE, 20, mod_sub_va_overwrite }, - { OP_MOD_SUB_DEL_ALL, 4, mod_sub_del_all }, - { OP_MOD_SUB_GET, 4, mod_sub_get }, - { OP_MOD_SUB_GET_VND, 6, mod_sub_get_vnd }, - { OP_NET_KEY_ADD, 18, net_key_add }, - { OP_NET_KEY_UPDATE, 18, net_key_update }, - { OP_NET_KEY_DEL, 2, net_key_del }, - { OP_NET_KEY_GET, 0, net_key_get }, - { OP_NODE_IDENTITY_GET, 2, node_identity_get }, - { OP_NODE_IDENTITY_SET, 3, node_identity_set }, - { OP_MOD_APP_BIND, 6, mod_app_bind }, - { OP_MOD_APP_UNBIND, 6, mod_app_unbind }, - { OP_SIG_MOD_APP_GET, 4, mod_app_get }, - { OP_VND_MOD_APP_GET, 6, mod_app_get }, - { OP_NODE_RESET, 0, node_reset }, - { OP_FRIEND_GET, 0, friend_get }, - { OP_FRIEND_SET, 1, friend_set }, - { OP_LPN_TIMEOUT_GET, 2, lpn_timeout_get }, - { OP_KRP_GET, 2, krp_get }, - { OP_KRP_SET, 3, krp_set }, - { OP_HEARTBEAT_PUB_GET, 0, heartbeat_pub_get }, - { OP_HEARTBEAT_PUB_SET, 9, heartbeat_pub_set }, - { OP_HEARTBEAT_SUB_GET, 0, heartbeat_sub_get }, - { OP_HEARTBEAT_SUB_SET, 5, heartbeat_sub_set }, + { OP_DEV_COMP_DATA_GET, BT_MESH_LEN_EXACT(1), dev_comp_data_get }, + { OP_APP_KEY_ADD, BT_MESH_LEN_EXACT(19), app_key_add }, + { OP_APP_KEY_UPDATE, BT_MESH_LEN_EXACT(19), app_key_update }, + { OP_APP_KEY_DEL, BT_MESH_LEN_EXACT(3), app_key_del }, + { OP_APP_KEY_GET, BT_MESH_LEN_EXACT(2), app_key_get }, + { OP_BEACON_GET, BT_MESH_LEN_EXACT(0), beacon_get }, + { OP_BEACON_SET, BT_MESH_LEN_EXACT(1), beacon_set }, + { OP_DEFAULT_TTL_GET, BT_MESH_LEN_EXACT(0), default_ttl_get }, + { OP_DEFAULT_TTL_SET, BT_MESH_LEN_EXACT(1), default_ttl_set }, + { OP_GATT_PROXY_GET, BT_MESH_LEN_EXACT(0), gatt_proxy_get }, + { OP_GATT_PROXY_SET, BT_MESH_LEN_EXACT(1), gatt_proxy_set }, + { OP_NET_TRANSMIT_GET, BT_MESH_LEN_EXACT(0), net_transmit_get }, + { OP_NET_TRANSMIT_SET, BT_MESH_LEN_EXACT(1), net_transmit_set }, + { OP_RELAY_GET, BT_MESH_LEN_EXACT(0), relay_get }, + { OP_RELAY_SET, BT_MESH_LEN_EXACT(2), relay_set }, + { OP_MOD_PUB_GET, BT_MESH_LEN_MIN(4), mod_pub_get }, + { OP_MOD_PUB_SET, BT_MESH_LEN_MIN(11), mod_pub_set }, + { OP_MOD_PUB_VA_SET, BT_MESH_LEN_MIN(25), mod_pub_va_set }, + { OP_MOD_SUB_ADD, BT_MESH_LEN_MIN(6), mod_sub_add }, + { OP_MOD_SUB_VA_ADD, BT_MESH_LEN_MIN(20), mod_sub_va_add }, + { OP_MOD_SUB_DEL, BT_MESH_LEN_MIN(6), mod_sub_del }, + { OP_MOD_SUB_VA_DEL, BT_MESH_LEN_MIN(20), mod_sub_va_del }, + { OP_MOD_SUB_OVERWRITE, BT_MESH_LEN_MIN(6), mod_sub_overwrite }, + { OP_MOD_SUB_VA_OVERWRITE, BT_MESH_LEN_MIN(20), mod_sub_va_overwrite }, + { OP_MOD_SUB_DEL_ALL, BT_MESH_LEN_MIN(4), mod_sub_del_all }, + { OP_MOD_SUB_GET, BT_MESH_LEN_EXACT(4), mod_sub_get }, + { OP_MOD_SUB_GET_VND, BT_MESH_LEN_EXACT(6), mod_sub_get_vnd }, + { OP_NET_KEY_ADD, BT_MESH_LEN_EXACT(18), net_key_add }, + { OP_NET_KEY_UPDATE, BT_MESH_LEN_EXACT(18), net_key_update }, + { OP_NET_KEY_DEL, BT_MESH_LEN_EXACT(2), net_key_del }, + { OP_NET_KEY_GET, BT_MESH_LEN_EXACT(0), net_key_get }, + { OP_NODE_IDENTITY_GET, BT_MESH_LEN_EXACT(2), node_identity_get }, + { OP_NODE_IDENTITY_SET, BT_MESH_LEN_EXACT(3), node_identity_set }, + { OP_MOD_APP_BIND, BT_MESH_LEN_MIN(6), mod_app_bind }, + { OP_MOD_APP_UNBIND, BT_MESH_LEN_MIN(6), mod_app_unbind }, + { OP_SIG_MOD_APP_GET, BT_MESH_LEN_MIN(4), mod_app_get }, + { OP_VND_MOD_APP_GET, BT_MESH_LEN_MIN(6), mod_app_get }, + { OP_NODE_RESET, BT_MESH_LEN_EXACT(0), node_reset }, + { OP_FRIEND_GET, BT_MESH_LEN_EXACT(0), friend_get }, + { OP_FRIEND_SET, BT_MESH_LEN_EXACT(1), friend_set }, + { OP_LPN_TIMEOUT_GET, BT_MESH_LEN_EXACT(2), lpn_timeout_get }, + { OP_KRP_GET, BT_MESH_LEN_EXACT(2), krp_get }, + { OP_KRP_SET, BT_MESH_LEN_EXACT(3), krp_set }, + { OP_HEARTBEAT_PUB_GET, BT_MESH_LEN_EXACT(0), heartbeat_pub_get }, + { OP_HEARTBEAT_PUB_SET, BT_MESH_LEN_EXACT(9), heartbeat_pub_set }, + { OP_HEARTBEAT_SUB_GET, BT_MESH_LEN_EXACT(0), heartbeat_sub_get }, + { OP_HEARTBEAT_SUB_SET, BT_MESH_LEN_EXACT(5), heartbeat_sub_set }, BT_MESH_MODEL_OP_END, }; @@ -2492,7 +2624,7 @@ static void mod_reset(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, if (IS_ENABLED(CONFIG_BT_SETTINGS)) { if (clear_count) { - bt_mesh_store_mod_sub(mod); + bt_mesh_model_sub_store(mod); } } @@ -2501,7 +2633,7 @@ static void mod_reset(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, } } -void bt_mesh_cfg_reset(void) +void bt_mesh_model_reset(void) { bt_mesh_model_foreach(mod_reset, NULL); } diff --git a/nimble/host/mesh/src/crypto.c b/nimble/host/mesh/src/crypto.c index 3111a6efa1..79378da928 100644 --- a/nimble/host/mesh/src/crypto.c +++ b/nimble/host/mesh/src/crypto.c @@ -7,7 +7,9 @@ */ #include "syscfg/syscfg.h" -#define MESH_LOG_MODULE BLE_MESH_CRYPTO_LOG + +#define BLE_NPL_LOG_MODULE BLE_MESH_CRYPTO_LOG +#include #include #include diff --git a/nimble/host/mesh/src/crypto.h b/nimble/host/mesh/src/crypto.h index 637d13e724..dbdedf1fd6 100644 --- a/nimble/host/mesh/src/crypto.h +++ b/nimble/host/mesh/src/crypto.h @@ -70,7 +70,7 @@ static inline int bt_mesh_beacon_key(const uint8_t net_key[16], } int bt_mesh_beacon_auth(const uint8_t beacon_key[16], uint8_t flags, - const uint8_t net_id[16], uint32_t iv_index, + const uint8_t net_id[8], uint32_t iv_index, uint8_t auth[8]); static inline int bt_mesh_app_id(const uint8_t app_key[16], uint8_t app_id[1]) diff --git a/nimble/host/mesh/src/foundation.h b/nimble/host/mesh/src/foundation.h index 012afbbb07..21734047ec 100644 --- a/nimble/host/mesh/src/foundation.h +++ b/nimble/host/mesh/src/foundation.h @@ -115,7 +115,7 @@ #define STATUS_UNSPECIFIED 0x10 #define STATUS_INVALID_BINDING 0x11 -void bt_mesh_cfg_reset(void); +void bt_mesh_model_reset(void); void bt_mesh_attention(struct bt_mesh_model *model, uint8_t time); diff --git a/nimble/host/mesh/src/friend.c b/nimble/host/mesh/src/friend.c index 4742e89d36..2c99d8d711 100644 --- a/nimble/host/mesh/src/friend.c +++ b/nimble/host/mesh/src/friend.c @@ -7,7 +7,10 @@ */ #include "syscfg/syscfg.h" -#define MESH_LOG_MODULE BLE_MESH_FRIEND_LOG + +#define BLE_NPL_LOG_MODULE BLE_MESH_FRIEND_LOG +#include + #if MYNEWT_VAL(BLE_MESH_FRIEND) @@ -42,8 +45,6 @@ static struct os_mempool friend_buf_mempool; #define NET_BUF_FRAGS BIT(0) -#define FRIEND_ADV(buf) CONTAINER_OF(BT_MESH_ADV(buf), struct friend_adv, adv) - /* PDUs from Friend to the LPN should only be transmitted once with the * smallest possible interval (20ms). */ @@ -66,12 +67,19 @@ static struct friend_adv { uint16_t app_idx; } adv_pool[FRIEND_BUF_COUNT]; +#define FRIEND_ADV(buf) CONTAINER_OF(BT_MESH_ADV(buf), struct friend_adv, adv) + static struct bt_mesh_adv *adv_alloc(int id) { adv_pool[id].app_idx = BT_MESH_KEY_UNUSED; return &adv_pool[id].adv; } +static bool friend_is_allocated(const struct bt_mesh_friend *frnd) +{ + return frnd->subnet != NULL; +} + static bool is_lpn_unicast(struct bt_mesh_friend *frnd, uint16_t addr) { if (frnd->lpn == BT_MESH_ADDR_UNASSIGNED) { @@ -91,7 +99,7 @@ struct bt_mesh_friend *bt_mesh_friend_find(uint16_t net_idx, uint16_t lpn_addr, for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) { struct bt_mesh_friend *frnd = &bt_mesh.frnd[i]; - if (valid && !frnd->subnet) { + if (valid && !friend_is_allocated(frnd)) { continue; } @@ -151,16 +159,11 @@ static void friend_clear(struct bt_mesh_friend *frnd) BT_DBG("LPN 0x%04x", frnd->lpn); - k_delayed_work_cancel(&frnd->timer); + (void)k_work_cancel_delayable(&frnd->timer); memset(frnd->cred, 0, sizeof(frnd->cred)); if (frnd->last) { - /* Cancel the sending if necessary */ - if (frnd->pending_buf) { - BT_MESH_ADV(frnd->last)->busy = 0; - } - net_buf_unref(frnd->last); frnd->last = NULL; } @@ -193,7 +196,7 @@ void bt_mesh_friends_clear(void) for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) { struct bt_mesh_friend *frnd = &bt_mesh.frnd[i]; - if (!frnd->subnet) { + if (!friend_is_allocated(frnd)) { continue; } @@ -212,7 +215,7 @@ void bt_mesh_friend_sec_update(uint16_t net_idx) for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) { struct bt_mesh_friend *frnd = &bt_mesh.frnd[i]; - if (!frnd->subnet) { + if (!friend_is_allocated(frnd)) { continue; } @@ -385,15 +388,21 @@ static int unseg_app_sdu_decrypt(struct bt_mesh_friend *frnd, const struct unseg_app_sdu_meta *meta) { struct net_buf_simple_state state; + struct os_mbuf *in = NET_BUF_SIMPLE(BT_MESH_RX_SDU_MAX); + struct os_mbuf *out = NET_BUF_SIMPLE(BT_MESH_RX_SDU_MAX); int err; - BT_DBG(""); - net_buf_simple_save(buf, &state); - net_buf_simple_pull_mem(buf, 10); - buf->om_len -= 4; + /* Direct the input buffer at the Upper Transport Access PDU, accounting for + * the network header and the 1 byte lower transport header + */ + net_buf_simple_clone(buf, in); + net_buf_simple_pull(buf, BT_MESH_NET_HDR_LEN); + net_buf_simple_pull(buf, 1); + in->om_len -= BT_MESH_MIC_SHORT;; - err = bt_mesh_app_decrypt(meta->key, &meta->crypto, buf, buf); + net_buf_simple_clone(in, out); + err = bt_mesh_app_decrypt(meta->key, &meta->crypto, in, out); net_buf_simple_restore(buf, &state); net_buf_unref(buf); @@ -410,8 +419,9 @@ static int unseg_app_sdu_encrypt(struct bt_mesh_friend *frnd, BT_DBG(""); net_buf_simple_save(buf, &state); - net_buf_simple_pull_mem(buf, 10); - buf->om_len -= 4; + net_buf_simple_pull_mem(buf, BT_MESH_NET_HDR_LEN); + net_buf_simple_pull_mem(buf, 1); + buf->om_len -= BT_MESH_MIC_SHORT; err = bt_mesh_app_encrypt(meta->key, &meta->crypto, buf); @@ -446,6 +456,8 @@ static int unseg_app_sdu_prepare(struct bt_mesh_friend *frnd, BT_DBG("Re-encrypting friend pdu (SeqNum %06x -> %06x)", meta.crypto.seq_num, bt_mesh.seq); + meta.crypto.seq_num = bt_mesh.seq; + err = unseg_app_sdu_decrypt(frnd, buf, &meta); if (err) { BT_WARN("Decryption failed! %d", err); @@ -463,14 +475,14 @@ static int unseg_app_sdu_prepare(struct bt_mesh_friend *frnd, } static int encrypt_friend_pdu(struct bt_mesh_friend *frnd, struct os_mbuf *buf, - bool master_cred) + bool flooding_cred) { const struct bt_mesh_net_cred *cred; uint32_t iv_index; uint16_t src; int err; - if (master_cred) { + if (flooding_cred) { cred = &frnd->subnet->keys[SUBNET_KEY_TX_IDX(frnd->subnet)] .msg; } else { @@ -479,7 +491,7 @@ static int encrypt_friend_pdu(struct bt_mesh_friend *frnd, struct os_mbuf *buf, src = sys_get_be16(&buf->om_data[5]); - if (bt_mesh_elem_find(src)) { + if (bt_mesh_has_addr(src)) { uint32_t seq; if (FRIEND_ADV(buf)->app_idx != BT_MESH_KEY_UNUSED) { @@ -527,8 +539,8 @@ static struct os_mbuf *encode_friend_ctl(struct bt_mesh_friend *frnd, info.src = bt_mesh_primary_addr(); info.dst = frnd->lpn; - info.ctl = 1; - info.ttl = 0; + info.ctl = 1U; + info.ttl = 0U; memset(info.seq, 0, sizeof(info.seq)); @@ -543,7 +555,7 @@ static struct os_mbuf *encode_update(struct bt_mesh_friend *frnd, uint8_t md) struct os_mbuf *sdu = NET_BUF_SIMPLE(1 + sizeof(*upd)); struct os_mbuf *buf; - __ASSERT_NO_MSG(frnd->subnet); + __ASSERT_NO_MSG(friend_is_allocated(frnd)); BT_DBG("lpn 0x%04x md 0x%02x", frnd->lpn, md); @@ -600,7 +612,7 @@ static void friend_recv_delay(struct bt_mesh_friend *frnd) int32_t delay = recv_delay(frnd); frnd->pending_req = 1; - k_delayed_work_submit(&frnd->timer, K_MSEC(delay)); + k_work_reschedule(&frnd->timer, K_MSEC(delay)); BT_DBG("Waiting RecvDelay of %d ms", delay); } @@ -767,7 +779,7 @@ static void friend_clear_sent(int err, void *user_data) { struct bt_mesh_friend *frnd = user_data; - k_delayed_work_submit(&frnd->clear.timer, + k_work_reschedule(&frnd->clear.timer, K_SECONDS(frnd->clear.repeat_sec)); frnd->clear.repeat_sec *= 2; } @@ -806,6 +818,11 @@ static void clear_timeout(struct ble_npl_event *work) struct bt_mesh_friend *frnd = ble_npl_event_get_arg(work); uint32_t duration; + if (frnd->clear.frnd == BT_MESH_ADDR_UNASSIGNED) { + /* Failed cancelling timer, return early. */ + return; + } + BT_DBG("LPN 0x%04x (old) Friend 0x%04x", frnd->lpn, frnd->clear.frnd); duration = k_uptime_get_32() - frnd->clear.start; @@ -862,7 +879,8 @@ int bt_mesh_friend_clear_cfm(struct bt_mesh_net_rx *rx, return 0; } - k_delayed_work_cancel(&frnd->clear.timer); + /* If this fails, the unassigned check will make the handler return early. */ + (void)k_work_cancel_delayable(&frnd->clear.timer); frnd->clear.frnd = BT_MESH_ADDR_UNASSIGNED; return 0; @@ -1027,12 +1045,12 @@ int bt_mesh_friend_req(struct bt_mesh_net_rx *rx, struct os_mbuf *buf) (unsigned) frnd->poll_to); if (BT_MESH_ADDR_IS_UNICAST(frnd->clear.frnd) && - !bt_mesh_elem_find(frnd->clear.frnd)) { + !bt_mesh_has_addr(frnd->clear.frnd)) { clear_procedure_start(frnd); } delay = offer_delay(frnd, rx->ctx.recv_rssi, msg->criteria); - k_delayed_work_submit(&frnd->timer, K_MSEC(delay)); + k_work_reschedule(&frnd->timer, K_MSEC(delay)); enqueue_offer(frnd, rx->ctx.recv_rssi); @@ -1149,12 +1167,13 @@ static void buf_send_end(int err, void *user_data) } if (frnd->established) { - k_delayed_work_submit(&frnd->timer, frnd->poll_to); + /* Always restart poll timeout timer after sending */ + k_work_reschedule(&frnd->timer, K_MSEC(frnd->poll_to)); BT_DBG("Waiting %u ms for next poll", (unsigned) frnd->poll_to); } else { /* Friend offer timeout is 1 second */ - k_delayed_work_submit(&frnd->timer, K_SECONDS(1)); + k_work_reschedule(&frnd->timer, K_SECONDS(1)); BT_DBG("Waiting for first poll"); } } @@ -1198,9 +1217,13 @@ static void friend_timeout(struct ble_npl_event *work) .start = buf_send_start, .end = buf_send_end, }; - + struct os_mbuf *buf; uint8_t md; + if (!friend_is_allocated(frnd)) { + return; + } + __ASSERT_NO_MSG(frnd->pending_buf == 0); BT_DBG("lpn 0x%04x send_last %u last %p", frnd->lpn, @@ -1243,9 +1266,17 @@ static void friend_timeout(struct ble_npl_event *work) frnd->queue_size--; send_last: + buf = bt_mesh_adv_create(BT_MESH_ADV_DATA, FRIEND_XMIT, K_NO_WAIT); + if (!buf) { + BT_ERR("Unable to allocate friend adv buffer"); + return; + } + + net_buf_add_mem(buf, frnd->last->om_data, frnd->last->om_len); frnd->pending_req = 0; frnd->pending_buf = 1; - bt_mesh_adv_send(frnd->last, &buf_sent_cb, frnd); + bt_mesh_adv_send(buf, &buf_sent_cb, frnd); + net_buf_unref(buf); } static void subnet_evt(struct bt_mesh_subnet *sub, enum bt_mesh_key_evt evt) @@ -1317,10 +1348,10 @@ int bt_mesh_friend_init(void) net_buf_slist_init(&frnd->queue); - k_delayed_work_init(&frnd->timer, friend_timeout); - k_delayed_work_add_arg(&frnd->timer, frnd); - k_delayed_work_init(&frnd->clear.timer, clear_timeout); - k_delayed_work_add_arg(&frnd->clear.timer, frnd); + k_work_init_delayable(&frnd->timer, friend_timeout); + k_work_add_arg_delayable(&frnd->timer, frnd); + k_work_init_delayable(&frnd->clear.timer, clear_timeout); + k_work_add_arg_delayable(&frnd->clear.timer, frnd); for (j = 0; j < ARRAY_SIZE(frnd->seg); j++) { net_buf_slist_init(&frnd->seg[j].queue); @@ -1403,7 +1434,7 @@ static void friend_lpn_enqueue_rx(struct bt_mesh_friend *frnd, * this rx function. These packets have already been added to the * queue, and should be ignored. */ - if (bt_mesh_elem_find(rx->ctx.addr)) { + if (bt_mesh_has_addr(rx->ctx.addr)) { return; } @@ -1663,6 +1694,11 @@ void bt_mesh_friend_enqueue_rx(struct bt_mesh_net_rx *rx, continue; } + if (friend_lpn_matches(frnd, rx->sub->net_idx, + rx->ctx.addr)) { + continue; + } + if (!friend_queue_prepare_space(frnd, rx->ctx.addr, seq_auth, seg_count)) { continue; diff --git a/nimble/host/mesh/src/glue.c b/nimble/host/mesh/src/glue.c index aab7f37414..7dfcaa3492 100644 --- a/nimble/host/mesh/src/glue.c +++ b/nimble/host/mesh/src/glue.c @@ -18,10 +18,13 @@ */ #include "syscfg/syscfg.h" -#define MESH_LOG_MODULE BLE_MESH_LOG + +#define BLE_NPL_LOG_MODULE BLE_MESH_LOG +#include #include "mesh/glue.h" #include "adv.h" +#include "../src/ble_hs_conn_priv.h" #ifndef MYNEWT #include "nimble/nimble_port.h" #endif @@ -52,7 +55,7 @@ bt_hex(const void *buf, size_t len) str = hexbufs[curbuf++]; curbuf %= ARRAY_SIZE(hexbufs); - len = min(len, (sizeof(hexbufs[0]) - 1) / 2); + len = MIN(len, (sizeof(hexbufs[0]) - 1) / 2); for (i = 0; i < len; i++) { str[i * 2] = hex[b[i] >> 4]; @@ -104,6 +107,10 @@ net_buf_unref(struct os_mbuf *om) } adv = BT_MESH_ADV(om); + if (adv->started && adv->cb && adv->cb->end) { + adv->cb->end(0, adv->cb_data); + } + if (--adv->ref_cnt > 0) { return; } @@ -112,6 +119,14 @@ net_buf_unref(struct os_mbuf *om) os_mbuf_free_chain(om); } + +void net_buf_simple_clone(const struct os_mbuf *original, + struct os_mbuf *clone) +{ + memcpy(clone, original, sizeof(struct os_mbuf)); +} + + int bt_encrypt_be(const uint8_t *key, const uint8_t *plaintext, uint8_t *enc_data) { @@ -142,6 +157,20 @@ net_buf_simple_pull_le16(struct os_mbuf *om) return val; } +uint32_t +net_buf_simple_pull_le24(struct os_mbuf *om) +{ + uint32_t val; + struct os_mbuf *old = om; + + om = os_mbuf_pullup(om, 3); + assert(om == old); + val = get_le24(om->om_data); + os_mbuf_adj(om, 3); + + return val; +} + uint16_t net_buf_simple_pull_be16(struct os_mbuf *om) { @@ -399,7 +428,7 @@ k_work_init(struct ble_npl_callout *work, ble_npl_event_fn handler) } void -k_delayed_work_init(struct k_delayed_work *w, ble_npl_event_fn *f) +k_work_init_delayable(struct k_work_delayable *w, ble_npl_event_fn *f) { #ifndef MYNEWT ble_npl_callout_init(&w->work, nimble_port_get_dflt_eventq(), f, NULL); @@ -409,26 +438,37 @@ k_delayed_work_init(struct k_delayed_work *w, ble_npl_event_fn *f) } bool -k_delayed_work_pending(struct k_delayed_work *w) +k_work_delayable_is_pending(struct k_work_delayable *w) { return ble_npl_callout_is_active(&w->work); } void -k_delayed_work_cancel(struct k_delayed_work *w) +k_work_cancel_delayable(struct k_work_delayable *w) { ble_npl_callout_stop(&w->work); } void -k_delayed_work_submit(struct k_delayed_work *w, uint32_t ms) +k_work_schedule(struct k_work_delayable *w, uint32_t ms) { - uint32_t ticks; + uint32_t ticks; - if (ble_npl_time_ms_to_ticks(ms, &ticks) != 0) { - assert(0); - } - ble_npl_callout_reset(&w->work, ticks); + if (ble_npl_time_ms_to_ticks(ms, &ticks) != 0) { + assert(0); + } + ble_npl_callout_reset(&w->work, ticks); +} + +void +k_work_reschedule(struct k_work_delayable *w, uint32_t ms) +{ + uint32_t ticks; + + if (ble_npl_time_ms_to_ticks(ms, &ticks) != 0) { + assert(0); + } + ble_npl_callout_reset(&w->work, ticks); } void @@ -444,13 +484,13 @@ k_work_add_arg(struct ble_npl_callout *w, void *arg) } void -k_delayed_work_add_arg(struct k_delayed_work *w, void *arg) +k_work_add_arg_delayable(struct k_work_delayable *w, void *arg) { k_work_add_arg(&w->work, arg); } -uint32_t -k_delayed_work_remaining_get (struct k_delayed_work *w) +ble_npl_time_t +k_work_delayable_remaining_get (struct k_work_delayable *w) { int sr; ble_npl_time_t t; @@ -461,7 +501,13 @@ k_delayed_work_remaining_get (struct k_delayed_work *w) OS_EXIT_CRITICAL(sr); - return ble_npl_time_ticks_to_ms32(t); + return t; +} + +uint32_t +k_ticks_to_ms_floor32(ble_npl_time_t ticks) +{ + return ble_npl_time_ticks_to_ms32(ticks); } int64_t k_uptime_get(void) @@ -475,6 +521,17 @@ uint32_t k_uptime_get_32(void) return k_uptime_get(); } +int64_t k_uptime_delta(int64_t *reftime) +{ + int64_t uptime, delta; + + uptime = k_uptime_get(); + delta = uptime - *reftime; + *reftime = uptime; + + return delta; +} + void k_sleep(int32_t duration) { uint32_t ticks; @@ -502,11 +559,38 @@ bt_dh_key_gen(const uint8_t remote_pk[64], bt_dh_key_cb_t cb) return 0; } +void +bt_conn_get_info(struct ble_hs_conn *conn, + struct ble_gap_conn_desc *desc) +{ + struct ble_hs_conn_addrs addrs; + + ble_hs_conn_addrs(conn, &addrs); + + desc->our_id_addr = addrs.our_id_addr; + desc->peer_id_addr = addrs.peer_id_addr; + desc->our_ota_addr = addrs.our_ota_addr; + desc->peer_ota_addr = addrs.peer_ota_addr; + + desc->conn_handle = conn->bhc_handle; + desc->conn_itvl = conn->bhc_itvl; + desc->conn_latency = conn->bhc_latency; + desc->supervision_timeout = conn->bhc_supervision_timeout; + desc->master_clock_accuracy = conn->bhc_master_clock_accuracy; + desc->sec_state = conn->bhc_sec_state; + + if (conn->bhc_flags & BLE_HS_CONN_F_MASTER) { + desc->role = BLE_GAP_ROLE_MASTER; + } else { + desc->role = BLE_GAP_ROLE_SLAVE; + } +} + int bt_rand(void *buf, size_t len) { int rc; - rc = ble_hs_hci_util_rand(buf, len); + rc = ble_hs_hci_rand(buf, len); if (rc != 0) { return -1; } @@ -705,24 +789,6 @@ bt_le_adv_start(const struct ble_gap_adv_params *param, return err; } - -int bt_le_adv_stop(bool proxy) -{ -#if MYNEWT_VAL(BLE_MESH_PROXY) - int rc; - - if (proxy) { - rc = ble_gap_ext_adv_stop(BT_MESH_ADV_GATT_INST); - } else { - rc = ble_gap_ext_adv_stop(BT_MESH_ADV_INST); - } - - return rc; -#else - return ble_gap_ext_adv_stop(BT_MESH_ADV_INST); -#endif -} - #else int @@ -769,14 +835,13 @@ bt_le_adv_start(const struct ble_gap_adv_params *param, return 0; } +#endif -int bt_le_adv_stop(bool proxy) +int bt_le_adv_stop() { - return ble_gap_adv_stop(); + return ble_gap_adv_stop(); } -#endif - #if MYNEWT_VAL(BLE_MESH_PROXY) int bt_mesh_proxy_svcs_register(void); #endif @@ -906,6 +971,7 @@ int create_free_list(struct k_mem_slab *slab) uint32_t j; char *p; + /* blocks must be word aligned */ if(((slab->block_size | (uintptr_t)slab->buffer) & (sizeof(void *) - 1)) != 0) { return -EINVAL; diff --git a/nimble/host/mesh/src/health_cli.c b/nimble/host/mesh/src/health_cli.c index 76d639c5f3..7765cf11b7 100644 --- a/nimble/host/mesh/src/health_cli.c +++ b/nimble/host/mesh/src/health_cli.c @@ -7,7 +7,9 @@ */ #include "syscfg/syscfg.h" -#define MESH_LOG_MODULE BLE_MESH_MODEL_LOG + +#define BLE_NPL_LOG_MODULE BLE_MESH_MODEL_LOG +#include #include #include @@ -33,9 +35,9 @@ struct health_fault_param { size_t *fault_count; }; -static void health_fault_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int health_fault_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { struct health_fault_param *param; uint8_t test_id; @@ -45,23 +47,21 @@ static void health_fault_status(struct bt_mesh_model *model, ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, bt_hex(buf->om_data, buf->om_len)); - if (health_cli->op_pending != OP_HEALTH_FAULT_STATUS) { - BT_WARN("Unexpected Health Fault Status message"); - return; + if (!bt_mesh_msg_ack_ctx_match(&health_cli->ack_ctx, OP_HEALTH_FAULT_STATUS, ctx->addr, + (void **)¶m)) { + return -ENOENT; } - param = health_cli->op_param; - test_id = net_buf_simple_pull_u8(buf); if (param->expect_test_id && test_id != *param->expect_test_id) { BT_WARN("Health fault with unexpected Test ID"); - return; + return -ENOENT; } cid = net_buf_simple_pull_le16(buf); if (cid != param->cid) { BT_WARN("Health fault with unexpected Company ID"); - return; + return -ENOENT; } if (param->test_id) { @@ -76,12 +76,14 @@ static void health_fault_status(struct bt_mesh_model *model, memcpy(param->faults, buf->om_data, *param->fault_count); - k_sem_give(&health_cli->op_sync); + bt_mesh_msg_ack_ctx_rx(&health_cli->ack_ctx); + + return 0; } -static void health_current_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int health_current_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { struct bt_mesh_health_cli *cli = model->user_data; uint8_t test_id; @@ -99,19 +101,21 @@ static void health_current_status(struct bt_mesh_model *model, if (!cli->current_status) { BT_WARN("No Current Status callback available"); - return; + return 0; } cli->current_status(cli, ctx->addr, test_id, cid, buf->om_data, buf->om_len); + + return 0; } struct health_period_param { uint8_t *divisor; }; -static void health_period_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int health_period_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { struct health_period_param *param; @@ -119,23 +123,23 @@ static void health_period_status(struct bt_mesh_model *model, ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, bt_hex(buf->om_data, buf->om_len)); - if (health_cli->op_pending != OP_HEALTH_PERIOD_STATUS) { - BT_WARN("Unexpected Health Period Status message"); - return; + if (!bt_mesh_msg_ack_ctx_match(&health_cli->ack_ctx, OP_HEALTH_PERIOD_STATUS, ctx->addr, + (void **)¶m)) { + return -ENOENT; } - param = health_cli->op_param; - *param->divisor = net_buf_simple_pull_u8(buf); - k_sem_give(&health_cli->op_sync); + bt_mesh_msg_ack_ctx_rx(&health_cli->ack_ctx); + + return 0; } struct health_attention_param { uint8_t *attention; }; -static void health_attention_status(struct bt_mesh_model *model, +static int health_attention_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -145,61 +149,36 @@ static void health_attention_status(struct bt_mesh_model *model, ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len, bt_hex(buf->om_data, buf->om_len)); - if (health_cli->op_pending != OP_ATTENTION_STATUS) { - BT_WARN("Unexpected Health Attention Status message"); - return; + if (!bt_mesh_msg_ack_ctx_match(&health_cli->ack_ctx, OP_ATTENTION_STATUS, ctx->addr, + (void **)¶m)) { + return -ENOENT; } - param = health_cli->op_param; - if (param->attention) { *param->attention = net_buf_simple_pull_u8(buf); } - k_sem_give(&health_cli->op_sync); + bt_mesh_msg_ack_ctx_rx(&health_cli->ack_ctx); + + return 0; } const struct bt_mesh_model_op bt_mesh_health_cli_op[] = { - { OP_HEALTH_FAULT_STATUS, 3, health_fault_status }, - { OP_HEALTH_CURRENT_STATUS, 3, health_current_status }, - { OP_HEALTH_PERIOD_STATUS, 1, health_period_status }, - { OP_ATTENTION_STATUS, 1, health_attention_status }, + { OP_HEALTH_FAULT_STATUS, BT_MESH_LEN_MIN(3), health_fault_status }, + { OP_HEALTH_CURRENT_STATUS, BT_MESH_LEN_MIN(3), health_current_status }, + { OP_HEALTH_PERIOD_STATUS, BT_MESH_LEN_EXACT(1), health_period_status }, + { OP_ATTENTION_STATUS, BT_MESH_LEN_EXACT(1), health_attention_status }, BT_MESH_MODEL_OP_END, }; -static int cli_prepare(void *param, uint32_t op) +static int cli_prepare(void *param, uint32_t op, uint16_t addr) { if (!health_cli) { BT_ERR("No available Health Client context!"); return -EINVAL; } - if (health_cli->op_pending) { - BT_WARN("Another synchronous operation pending"); - return -EBUSY; - } - - health_cli->op_param = param; - health_cli->op_pending = op; - - return 0; -} - -static void cli_reset(void) -{ - health_cli->op_pending = 0; - health_cli->op_param = NULL; -} - -static int cli_wait(void) -{ - int err; - - err = k_sem_take(&health_cli->op_sync, msg_timeout); - - cli_reset(); - - return err; + return bt_mesh_msg_ack_ctx_prepare(&health_cli->ack_ctx, op, addr, param); } int bt_mesh_health_attention_get(uint16_t addr, uint16_t app_idx, uint8_t *attention) @@ -215,7 +194,7 @@ int bt_mesh_health_attention_get(uint16_t addr, uint16_t app_idx, uint8_t *atten }; int err; - err = cli_prepare(¶m, OP_ATTENTION_STATUS); + err = cli_prepare(¶m, OP_ATTENTION_STATUS, addr); if (err) { goto done; } @@ -225,11 +204,11 @@ int bt_mesh_health_attention_get(uint16_t addr, uint16_t app_idx, uint8_t *atten err = bt_mesh_model_send(health_cli->model, &ctx, msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&health_cli->ack_ctx); goto done; } - err = cli_wait(); + err = bt_mesh_msg_ack_ctx_wait(&health_cli->ack_ctx, K_MSEC(msg_timeout)); done: os_mbuf_free_chain(msg); return err; @@ -249,7 +228,7 @@ int bt_mesh_health_attention_set(uint16_t addr, uint16_t app_idx, uint8_t attent }; int err; - err = cli_prepare(¶m, OP_ATTENTION_STATUS); + err = cli_prepare(¶m, OP_ATTENTION_STATUS, addr); if (err) { goto done; } @@ -265,16 +244,16 @@ int bt_mesh_health_attention_set(uint16_t addr, uint16_t app_idx, uint8_t attent err = bt_mesh_model_send(health_cli->model, &ctx, msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&health_cli->ack_ctx); goto done; } if (!updated_attention) { - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&health_cli->ack_ctx); goto done; } - err = cli_wait(); + err = bt_mesh_msg_ack_ctx_wait(&health_cli->ack_ctx, K_MSEC(msg_timeout)); done: os_mbuf_free_chain(msg); return err; @@ -293,7 +272,7 @@ int bt_mesh_health_period_get(uint16_t addr, uint16_t app_idx, uint8_t *divisor) }; int err; - err = cli_prepare(¶m, OP_HEALTH_PERIOD_STATUS); + err = cli_prepare(¶m, OP_HEALTH_PERIOD_STATUS, addr); if (err) { goto done; } @@ -303,11 +282,11 @@ int bt_mesh_health_period_get(uint16_t addr, uint16_t app_idx, uint8_t *divisor) err = bt_mesh_model_send(health_cli->model, &ctx, msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&health_cli->ack_ctx); goto done; } - err = cli_wait(); + err = bt_mesh_msg_ack_ctx_wait(&health_cli->ack_ctx, K_MSEC(msg_timeout)); done: os_mbuf_free_chain(msg); return err; @@ -327,7 +306,7 @@ int bt_mesh_health_period_set(uint16_t addr, uint16_t app_idx, uint8_t divisor, }; int err; - err = cli_prepare(¶m, OP_HEALTH_PERIOD_STATUS); + err = cli_prepare(¶m, OP_HEALTH_PERIOD_STATUS, addr); if (err) { goto done; } @@ -343,16 +322,16 @@ int bt_mesh_health_period_set(uint16_t addr, uint16_t app_idx, uint8_t divisor, err = bt_mesh_model_send(health_cli->model, &ctx, msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&health_cli->ack_ctx); goto done; } if (!updated_divisor) { - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&health_cli->ack_ctx); goto done; } - err = cli_wait(); + err = bt_mesh_msg_ack_ctx_wait(&health_cli->ack_ctx, K_MSEC(msg_timeout)); done: os_mbuf_free_chain(msg); return err; @@ -376,7 +355,7 @@ int bt_mesh_health_fault_test(uint16_t addr, uint16_t app_idx, uint16_t cid, }; int err; - err = cli_prepare(¶m, OP_HEALTH_FAULT_STATUS); + err = cli_prepare(¶m, OP_HEALTH_FAULT_STATUS, addr); if (err) { goto done; } @@ -393,16 +372,16 @@ int bt_mesh_health_fault_test(uint16_t addr, uint16_t app_idx, uint16_t cid, err = bt_mesh_model_send(health_cli->model, &ctx, msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&health_cli->ack_ctx); goto done; } if (!faults) { - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&health_cli->ack_ctx); goto done; } - err = cli_wait(); + err = bt_mesh_msg_ack_ctx_wait(&health_cli->ack_ctx, K_MSEC(msg_timeout)); done: os_mbuf_free_chain(msg); return err; @@ -426,7 +405,7 @@ int bt_mesh_health_fault_clear(uint16_t addr, uint16_t app_idx, uint16_t cid, }; int err; - err = cli_prepare(¶m, OP_HEALTH_FAULT_STATUS); + err = cli_prepare(¶m, OP_HEALTH_FAULT_STATUS, addr); if (err) { goto done; } @@ -442,16 +421,16 @@ int bt_mesh_health_fault_clear(uint16_t addr, uint16_t app_idx, uint16_t cid, err = bt_mesh_model_send(health_cli->model, &ctx, msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&health_cli->ack_ctx); goto done; } if (!test_id) { - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&health_cli->ack_ctx); goto done; } - err = cli_wait(); + err = bt_mesh_msg_ack_ctx_wait(&health_cli->ack_ctx, K_MSEC(msg_timeout)); done: os_mbuf_free_chain(msg); return err; @@ -475,7 +454,7 @@ int bt_mesh_health_fault_get(uint16_t addr, uint16_t app_idx, uint16_t cid, }; int err; - err = cli_prepare(¶m, OP_HEALTH_FAULT_STATUS); + err = cli_prepare(¶m, OP_HEALTH_FAULT_STATUS, addr); if (err) { goto done; } @@ -486,11 +465,11 @@ int bt_mesh_health_fault_get(uint16_t addr, uint16_t app_idx, uint16_t cid, err = bt_mesh_model_send(health_cli->model, &ctx, msg, NULL, NULL); if (err) { BT_ERR("model_send() failed (err %d)", err); - cli_reset(); + bt_mesh_msg_ack_ctx_clear(&health_cli->ack_ctx); goto done; } - err = cli_wait(); + err = bt_mesh_msg_ack_ctx_wait(&health_cli->ack_ctx, K_MSEC(msg_timeout)); done: os_mbuf_free_chain(msg); return err; @@ -532,14 +511,14 @@ static int health_cli_init(struct bt_mesh_model *model) cli = model->user_data; cli->model = model; - - k_sem_init(&cli->op_sync, 0, 1); + msg_timeout = 2 * MSEC_PER_SEC; /* Set the default health client pointer */ if (!health_cli) { health_cli = cli; } + bt_mesh_msg_ack_ctx_init(&health_cli->ack_ctx); return 0; } diff --git a/nimble/host/mesh/src/health_srv.c b/nimble/host/mesh/src/health_srv.c index dd90533be8..0ea81380e8 100644 --- a/nimble/host/mesh/src/health_srv.c +++ b/nimble/host/mesh/src/health_srv.c @@ -7,7 +7,9 @@ */ #include "syscfg/syscfg.h" -#define MESH_LOG_MODULE BLE_MESH_MODEL_LOG + +#define BLE_NPL_LOG_MODULE BLE_MESH_MODEL_LOG +#include #include #include @@ -67,7 +69,6 @@ static size_t health_get_current(struct bt_mesh_model *mod, uint8_t *test_id, *company_ptr; uint16_t company_id; uint8_t fault_count; - int err; bt_mesh_model_msg_init(msg, OP_HEALTH_CURRENT_STATUS); @@ -77,6 +78,8 @@ static size_t health_get_current(struct bt_mesh_model *mod, if (srv->cb && srv->cb->fault_get_cur) { fault_count = net_buf_simple_tailroom(msg); + int err; + err = srv->cb->fault_get_cur(mod, test_id, &company_id, net_buf_simple_tail(msg), &fault_count); @@ -99,9 +102,9 @@ static size_t health_get_current(struct bt_mesh_model *mod, return fault_count; } -static void health_fault_get(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int health_fault_get(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { struct os_mbuf *sdu = NET_BUF_SIMPLE(BT_MESH_TX_SDU_MAX); uint16_t company_id; @@ -117,11 +120,13 @@ static void health_fault_get(struct bt_mesh_model *model, } os_mbuf_free_chain(sdu); + + return 0; } -static void health_fault_clear_unrel(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int health_fault_clear_unrel(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { struct bt_mesh_health_srv *srv = model->user_data; uint16_t company_id; @@ -131,13 +136,15 @@ static void health_fault_clear_unrel(struct bt_mesh_model *model, BT_DBG("company_id 0x%04x", company_id); if (srv->cb && srv->cb->fault_clear) { - srv->cb->fault_clear(model, company_id); + return srv->cb->fault_clear(model, company_id); } + + return 0; } -static void health_fault_clear(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int health_fault_clear(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { struct os_mbuf *sdu = NET_BUF_SIMPLE(BT_MESH_TX_SDU_MAX); struct bt_mesh_health_srv *srv = model->user_data; @@ -148,7 +155,12 @@ static void health_fault_clear(struct bt_mesh_model *model, BT_DBG("company_id 0x%04x", company_id); if (srv->cb && srv->cb->fault_clear) { - srv->cb->fault_clear(model, company_id); + int err; + + err = srv->cb->fault_clear(model, company_id); + if (err) { + return err; + } } health_get_registered(model, company_id, sdu); @@ -158,9 +170,11 @@ static void health_fault_clear(struct bt_mesh_model *model, } os_mbuf_free_chain(sdu); + + return 0; } -static void health_fault_test_unrel(struct bt_mesh_model *model, +static int health_fault_test_unrel(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -174,18 +188,21 @@ static void health_fault_test_unrel(struct bt_mesh_model *model, BT_DBG("test 0x%02x company 0x%04x", test_id, company_id); if (srv->cb && srv->cb->fault_test) { - srv->cb->fault_test(model, test_id, company_id); + return srv->cb->fault_test(model, test_id, company_id); } + + return 0; } -static void health_fault_test(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int health_fault_test(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { struct os_mbuf *sdu = NET_BUF_SIMPLE(BT_MESH_TX_SDU_MAX); struct bt_mesh_health_srv *srv = model->user_data; uint16_t company_id; uint8_t test_id; + int err = 0; BT_DBG(""); @@ -195,11 +212,10 @@ static void health_fault_test(struct bt_mesh_model *model, BT_DBG("test 0x%02x company 0x%04x", test_id, company_id); if (srv->cb && srv->cb->fault_test) { - int err; - err = srv->cb->fault_test(model, test_id, company_id); if (err) { BT_WARN("Running fault test failed with err %d", err); + goto done; } } @@ -212,16 +228,19 @@ static void health_fault_test(struct bt_mesh_model *model, done: os_mbuf_free_chain(sdu); + + return err; } -static void send_attention_status(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx) +static int send_attention_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx) { struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_ATTENTION_STATUS, 1); struct bt_mesh_health_srv *srv = model->user_data; uint8_t time; - time = k_delayed_work_remaining_get(&srv->attn_timer) / 1000; + time = k_ticks_to_ms_floor32( + k_work_delayable_remaining_get(&srv->attn_timer)) / 1000; BT_DBG("%u second%s", time, (time == 1) ? "" : "s"); bt_mesh_model_msg_init(msg, OP_ATTENTION_STATUS); @@ -233,18 +252,20 @@ static void send_attention_status(struct bt_mesh_model *model, } os_mbuf_free_chain(msg); + + return 0; } -static void attention_get(struct bt_mesh_model *model, +static int attention_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { BT_DBG(""); - send_attention_status(model, ctx); + return send_attention_status(model, ctx); } -static void attention_set_unrel(struct bt_mesh_model *model, +static int attention_set_unrel(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -255,20 +276,27 @@ static void attention_set_unrel(struct bt_mesh_model *model, BT_DBG("%u second%s", time, (time == 1) ? "" : "s"); bt_mesh_attention(model, time); + + return 0; } -static void attention_set(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +static int attention_set(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) { + int err; + BT_DBG(""); - attention_set_unrel(model, ctx, buf); + err = attention_set_unrel(model, ctx, buf); + if (err) { + return err; + } - send_attention_status(model, ctx); + return send_attention_status(model, ctx); } -static void send_health_period_status(struct bt_mesh_model *model, +static int send_health_period_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx) { struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_HEALTH_PERIOD_STATUS, 1); @@ -282,18 +310,20 @@ static void send_health_period_status(struct bt_mesh_model *model, } os_mbuf_free_chain(msg); + + return 0; } -static void health_period_get(struct bt_mesh_model *model, +static int health_period_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { BT_DBG(""); - send_health_period_status(model, ctx); + return send_health_period_status(model, ctx); } -static void health_period_set_unrel(struct bt_mesh_model *model, +static int health_period_set_unrel(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -302,37 +332,44 @@ static void health_period_set_unrel(struct bt_mesh_model *model, period = net_buf_simple_pull_u8(buf); if (period > 15) { BT_WARN("Prohibited period value %u", period); - return; + return -EINVAL; } BT_DBG("period %u", period); model->pub->period_div = period; + + return 0; } -static void health_period_set(struct bt_mesh_model *model, +static int health_period_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { + int err; + BT_DBG(""); - health_period_set_unrel(model, ctx, buf); + err = health_period_set_unrel(model, ctx, buf); + if (err) { + return err; + } - send_health_period_status(model, ctx); + return send_health_period_status(model, ctx); } const struct bt_mesh_model_op bt_mesh_health_srv_op[] = { - { OP_HEALTH_FAULT_GET, 2, health_fault_get }, - { OP_HEALTH_FAULT_CLEAR, 2, health_fault_clear }, - { OP_HEALTH_FAULT_CLEAR_UNREL, 2, health_fault_clear_unrel }, - { OP_HEALTH_FAULT_TEST, 3, health_fault_test }, - { OP_HEALTH_FAULT_TEST_UNREL, 3, health_fault_test_unrel }, - { OP_HEALTH_PERIOD_GET, 0, health_period_get }, - { OP_HEALTH_PERIOD_SET, 1, health_period_set }, - { OP_HEALTH_PERIOD_SET_UNREL, 1, health_period_set_unrel }, - { OP_ATTENTION_GET, 0, attention_get }, - { OP_ATTENTION_SET, 1, attention_set }, - { OP_ATTENTION_SET_UNREL, 1, attention_set_unrel }, + { OP_HEALTH_FAULT_GET, BT_MESH_LEN_EXACT(2), health_fault_get }, + { OP_HEALTH_FAULT_CLEAR, BT_MESH_LEN_EXACT(2), health_fault_clear }, + { OP_HEALTH_FAULT_CLEAR_UNREL, BT_MESH_LEN_EXACT(2), health_fault_clear_unrel }, + { OP_HEALTH_FAULT_TEST, BT_MESH_LEN_EXACT(3), health_fault_test }, + { OP_HEALTH_FAULT_TEST_UNREL, BT_MESH_LEN_EXACT(3), health_fault_test_unrel }, + { OP_HEALTH_PERIOD_GET, BT_MESH_LEN_EXACT(0), health_period_get }, + { OP_HEALTH_PERIOD_SET, BT_MESH_LEN_EXACT(1), health_period_set }, + { OP_HEALTH_PERIOD_SET_UNREL, BT_MESH_LEN_EXACT(1), health_period_set_unrel }, + { OP_ATTENTION_GET, BT_MESH_LEN_EXACT(0), attention_get }, + { OP_ATTENTION_SET, BT_MESH_LEN_EXACT(1), attention_set }, + { OP_ATTENTION_SET_UNREL, BT_MESH_LEN_EXACT(1), attention_set_unrel }, BT_MESH_MODEL_OP_END, }; @@ -400,8 +437,8 @@ static int health_srv_init(struct bt_mesh_model *model) model->pub->update = health_pub_update; - k_delayed_work_init(&srv->attn_timer, attention_off); - k_delayed_work_add_arg(&srv->attn_timer, srv); + k_work_init_delayable(&srv->attn_timer, attention_off); + k_work_add_arg_delayable(&srv->attn_timer, srv); srv->model = model; @@ -433,17 +470,8 @@ void bt_mesh_attention(struct bt_mesh_model *model, uint8_t time) srv = model->user_data; } - if (time) { - if (srv->cb && srv->cb->attn_on) { - srv->cb->attn_on(model); - } - - k_delayed_work_submit(&srv->attn_timer, time * 1000); - } else { - k_delayed_work_cancel(&srv->attn_timer); - - if (srv->cb && srv->cb->attn_off) { - srv->cb->attn_off(model); - } + if ((time > 0) && srv->cb && srv->cb->attn_on) { + srv->cb->attn_on(model); } + k_work_reschedule(&srv->attn_timer, K_SECONDS(time)); } diff --git a/nimble/host/mesh/src/heartbeat.c b/nimble/host/mesh/src/heartbeat.c index 09d64594de..8d15d7642e 100644 --- a/nimble/host/mesh/src/heartbeat.c +++ b/nimble/host/mesh/src/heartbeat.c @@ -4,7 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 */ -#define MESH_LOG_MODULE BLE_MESH_HEARTBEAT_LOG +#define BLE_NPL_LOG_MODULE BLE_MESH_HEARTBEAT_LOG +#include #include "mesh_priv.h" #include "net.h" @@ -17,12 +18,22 @@ #include "foundation.h" #include "mesh/glue.h" +/* Heartbeat Publication information for persistent storage. */ +struct hb_pub_val { + uint16_t dst; + uint8_t period; + uint8_t ttl; + uint16_t feat; + uint16_t net_idx:12, + indefinite:1; +}; + struct bt_mesh_hb_cb hb_cb; static struct bt_mesh_hb_pub pub; static struct bt_mesh_hb_sub sub; -static struct k_delayed_work sub_timer; -static struct k_delayed_work pub_timer; +static struct k_work_delayable sub_timer; +static struct k_work_delayable pub_timer; static int64_t sub_remaining(void) { @@ -30,13 +41,15 @@ static int64_t sub_remaining(void) return 0U; } - return k_delayed_work_remaining_get(&sub_timer) / MSEC_PER_SEC; + uint32_t rem_ms = k_ticks_to_ms_floor32( + k_work_delayable_remaining_get(&sub_timer)); + return rem_ms / MSEC_PER_SEC; } static void hb_publish_end_cb(int err, void *cb_data) { if (pub.period && pub.count > 1) { - k_delayed_work_submit(&pub_timer, K_SECONDS(pub.period)); + k_work_reschedule(&pub_timer, K_SECONDS(pub.period)); } if (pub.count != 0xffff) { @@ -138,6 +151,11 @@ static void hb_publish(struct ble_npl_event *work) BT_DBG("hb_pub.count: %u", pub.count); + /* Fast exit if disabled or expired */ + if (pub.period == 0U || pub.count == 0U) { + return; + } + sub = bt_mesh_subnet_get(pub.net_idx); if (!sub) { BT_ERR("No matching subnet for idx 0x%02x", pub.net_idx); @@ -145,10 +163,6 @@ static void hb_publish(struct ble_npl_event *work) return; } - if (pub.count == 0U) { - return; - } - err = heartbeat_send(&publish_cb, NULL); if (err) { hb_publish_end_cb(err, NULL); @@ -175,8 +189,8 @@ int bt_mesh_hb_recv(struct bt_mesh_net_rx *rx, struct os_mbuf *buf) return 0; } - if (!k_delayed_work_pending(&sub_timer)) { - BT_DBG("Heartbeat subscription period expired"); + if (!k_work_delayable_is_pending(&sub_timer)) { + BT_DBG("Heartbeat subscription inactive"); return 0; } @@ -205,7 +219,7 @@ static void pub_disable(void) pub.ttl = 0U; pub.period = 0U; - k_delayed_work_cancel(&pub_timer); + k_work_cancel_delayable(&pub_timer); } uint8_t bt_mesh_hb_pub_set(struct bt_mesh_hb_pub *new_pub) @@ -215,7 +229,8 @@ uint8_t bt_mesh_hb_pub_set(struct bt_mesh_hb_pub *new_pub) if (IS_ENABLED(CONFIG_BT_SETTINGS) && bt_mesh_is_provisioned()) { - bt_mesh_store_hb_pub(); + bt_mesh_settings_store_schedule( + BT_MESH_SETTINGS_HB_PUB_PENDING); } return STATUS_SUCCESS; @@ -236,15 +251,15 @@ uint8_t bt_mesh_hb_pub_set(struct bt_mesh_hb_pub *new_pub) /* The first Heartbeat message shall be published as soon as possible * after the Heartbeat Publication Period state has been configured for * periodic publishing. + * + * If the new configuration disables publishing this flushes + * the work item. */ - if (pub.period && pub.count) { - k_delayed_work_submit(&pub_timer, K_NO_WAIT); - } else { - k_delayed_work_cancel(&pub_timer); - } + k_work_reschedule(&pub_timer, K_NO_WAIT); if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_hb_pub(); + bt_mesh_settings_store_schedule( + BT_MESH_SETTINGS_HB_PUB_PENDING); } return STATUS_SUCCESS; @@ -282,9 +297,7 @@ uint8_t bt_mesh_hb_sub_set(uint16_t src, uint16_t dst, uint32_t period) sub.min_hops = 0U; sub.max_hops = 0U; sub.count = 0U; - sub.period = sub.period - sub_remaining(); - k_delayed_work_cancel(&sub_timer); - notify_sub_end(); + sub.period = 0U; } else if (period) { sub.src = src; sub.dst = dst; @@ -292,16 +305,18 @@ uint8_t bt_mesh_hb_sub_set(uint16_t src, uint16_t dst, uint32_t period) sub.max_hops = 0U; sub.count = 0U; sub.period = period; - k_delayed_work_submit(&sub_timer, K_SECONDS(period)); } else { /* Clearing the period should stop heartbeat subscription * without clearing the parameters, so we can still read them. */ - sub.period = sub.period - sub_remaining(); - k_delayed_work_cancel(&sub_timer); - notify_sub_end(); + sub.period = 0U; } + /* Start the timer, which notifies immediately if the new + * configuration disables the subscription. + */ + k_work_reschedule(&sub_timer, K_SECONDS(sub.period)); + return STATUS_SUCCESS; } @@ -332,27 +347,119 @@ void bt_mesh_hb_feature_changed(uint16_t features) void bt_mesh_hb_init(void) { pub.net_idx = BT_MESH_KEY_UNUSED; - k_delayed_work_init(&pub_timer, hb_publish); - k_delayed_work_init(&sub_timer, sub_end); + k_work_init_delayable(&pub_timer, hb_publish); + k_work_init_delayable(&sub_timer, sub_end); } void bt_mesh_hb_start(void) { if (pub.count && pub.period) { BT_DBG("Starting heartbeat publication"); - k_delayed_work_submit(&pub_timer, K_NO_WAIT); + k_work_reschedule(&pub_timer, K_NO_WAIT); } } void bt_mesh_hb_suspend(void) { - k_delayed_work_cancel(&pub_timer); + (void)k_work_cancel_delayable(&pub_timer); } void bt_mesh_hb_resume(void) { if (pub.period && pub.count) { BT_DBG("Starting heartbeat publication"); - k_delayed_work_submit(&pub_timer, K_NO_WAIT); + k_work_reschedule(&pub_timer, K_NO_WAIT); + } +} + +#if MYNEWT_VAL(BLE_MESH_SETTINGS) +static int hb_pub_set(int argc, char **argv, char *val) +{ + struct bt_mesh_hb_pub pub; + struct hb_pub_val hb_val; + int len, err; + BT_DBG("val %s", val ? val : "(null)"); + len = sizeof(hb_val); + err = settings_bytes_from_str(val, &hb_val, &len); + if (err) { + BT_ERR("Failed to decode value %s (err %d)", val, err); + return err; } + if (len != sizeof(hb_val)) { + BT_ERR("Unexpected value length (%d != %zu)", len, + sizeof(hb_val)); + return -EINVAL; + } + pub.dst = hb_val.dst; + pub.period = bt_mesh_hb_pwr2(hb_val.period); + pub.ttl = hb_val.ttl; + pub.feat = hb_val.feat; + pub.net_idx = hb_val.net_idx; + if (hb_val.indefinite) { + pub.count = 0xffff; + } else { + pub.count = 0; + } + (void) bt_mesh_hb_pub_set(&pub); + + BT_DBG("Restored heartbeat publication"); + + return 0; +} + +void bt_mesh_hb_pub_pending_store(void) +{ + struct bt_mesh_hb_pub pub; + char buf[BT_SETTINGS_SIZE(sizeof(struct hb_pub_val))]; + struct hb_pub_val val; + int err; + char *str; + + bt_mesh_hb_pub_get(&pub); + if (pub.dst == BT_MESH_ADDR_UNASSIGNED) { + err = settings_save_one("bt_mesh/HBPub", NULL); + } else { + val.indefinite = (pub.count == 0xffff); + val.dst = pub.dst; + val.period = bt_mesh_hb_log(pub.period); + val.ttl = pub.ttl; + val.feat = pub.feat; + val.net_idx = pub.net_idx; + + str = settings_str_from_bytes(&val, sizeof(val), buf, sizeof(buf)); + if (!str) { + BT_ERR("Unable to encode configuration as value"); + return; + } + + BT_DBG("Saving configuration as value %s", str); + err = settings_save_one("bt_mesh/HBPub", str); + } + + if (err) { + BT_ERR("Failed to store Heartbeat Publication"); + } else { + BT_DBG("Stored Heartbeat Publication"); + } +} + +static struct conf_handler bt_mesh_hb_pub_conf_handler = { + .ch_name = "bt_mesh", + .ch_get = NULL, + .ch_set = hb_pub_set, + .ch_commit = NULL, + .ch_export = NULL, +}; +#endif + +void bt_mesh_hb_pub_init(void) +{ +#if MYNEWT_VAL(BLE_MESH_SETTINGS) + int rc; + + rc = conf_register(&bt_mesh_hb_pub_conf_handler); + + SYSINIT_PANIC_ASSERT_MSG(rc == 0, + "Failed to register bt_mesh_hb_pub conf"); +#endif } diff --git a/nimble/host/mesh/src/heartbeat.h b/nimble/host/mesh/src/heartbeat.h index 92b0cae9e4..a036366637 100644 --- a/nimble/host/mesh/src/heartbeat.h +++ b/nimble/host/mesh/src/heartbeat.h @@ -39,3 +39,5 @@ void bt_mesh_hb_feature_changed(uint16_t features); uint8_t bt_mesh_hb_pub_set(struct bt_mesh_hb_pub *hb_pub); uint8_t bt_mesh_hb_sub_set(uint16_t src, uint16_t dst, uint32_t period); void bt_mesh_hb_sub_reset_count(void); +void bt_mesh_hb_pub_pending_store(void); +void bt_mesh_hb_pub_init(void); diff --git a/nimble/host/mesh/src/light_model.c b/nimble/host/mesh/src/light_model.c index bc4792c637..5f0af48578 100644 --- a/nimble/host/mesh/src/light_model.c +++ b/nimble/host/mesh/src/light_model.c @@ -1,3 +1,8 @@ +/* + * Copyright (c) 2017 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ #include "syscfg/syscfg.h" @@ -55,4 +60,3 @@ int light_model_light_lightness_set(struct bt_mesh_model *model, int16_t lightne { return light_model_gen_level_set(model, lightness); } - diff --git a/nimble/host/mesh/src/lpn.c b/nimble/host/mesh/src/lpn.c index 45c9004b63..13eb7d1386 100644 --- a/nimble/host/mesh/src/lpn.c +++ b/nimble/host/mesh/src/lpn.c @@ -7,7 +7,9 @@ */ #include "syscfg/syscfg.h" -#define MESH_LOG_MODULE BLE_MESH_LOW_POWER_LOG + +#define BLE_NPL_LOG_MODULE BLE_MESH_LOW_POWER_LOG +#include #if MYNEWT_VAL(BLE_MESH_LOW_POWER) @@ -32,7 +34,7 @@ #endif #define LPN_RECV_DELAY MYNEWT_VAL(BLE_MESH_LPN_RECV_DELAY) -#define SCAN_LATENCY min(MYNEWT_VAL(BLE_MESH_LPN_SCAN_LATENCY), \ +#define SCAN_LATENCY MIN(MYNEWT_VAL(BLE_MESH_LPN_SCAN_LATENCY), \ LPN_RECV_DELAY) #define FRIEND_REQ_RETRY_TIMEOUT K_SECONDS(MYNEWT_VAL(BLE_MESH_LPN_RETRY_TIMEOUT)) @@ -152,12 +154,12 @@ static int32_t poll_timeout(struct bt_mesh_lpn *lpn) { /* If we're waiting for segment acks keep polling at high freq */ if (bt_mesh_tx_in_progress()) { - return min(POLL_TIMEOUT_MAX(lpn), K_SECONDS(1)); + return MIN(POLL_TIMEOUT_MAX(lpn), K_SECONDS(1)); } if (lpn->poll_timeout < POLL_TIMEOUT_MAX(lpn)) { lpn->poll_timeout *= 2; - lpn->poll_timeout = min(lpn->poll_timeout, + lpn->poll_timeout = MIN(lpn->poll_timeout, POLL_TIMEOUT_MAX(lpn)); } @@ -182,7 +184,7 @@ static void friend_clear_sent(int err, void *user_data) } lpn_set_state(BT_MESH_LPN_CLEAR); - k_delayed_work_submit(&lpn->timer, FRIEND_REQ_TIMEOUT); + k_work_reschedule(&lpn->timer, FRIEND_REQ_TIMEOUT); } static const struct bt_mesh_send_cb clear_sent_cb = { @@ -230,7 +232,7 @@ static void clear_friendship(bool force, bool disable) bt_mesh_rx_reset(); lpn_set_state(BT_MESH_LPN_DISABLED); - k_delayed_work_cancel(&lpn->timer); + k_work_cancel_delayable(&lpn->timer); if (lpn->clear_success) { lpn->old_friend = BT_MESH_ADDR_UNASSIGNED; @@ -267,7 +269,7 @@ static void clear_friendship(bool force, bool disable) if (!disable) { lpn_set_state(BT_MESH_LPN_DISABLED); - k_delayed_work_submit(&lpn->timer, FRIEND_REQ_RETRY_TIMEOUT); + k_work_reschedule(&lpn->timer, FRIEND_REQ_RETRY_TIMEOUT); return; } @@ -285,10 +287,10 @@ static void friend_req_sent(uint16_t duration, int err, void *user_data) lpn->adv_duration = duration; if (IS_ENABLED(CONFIG_BT_MESH_LPN_ESTABLISHMENT)) { - k_delayed_work_submit(&lpn->timer, FRIEND_REQ_WAIT); + k_work_reschedule(&lpn->timer, FRIEND_REQ_WAIT); lpn_set_state(BT_MESH_LPN_REQ_WAIT); } else { - k_delayed_work_submit(&lpn->timer, + k_work_reschedule(&lpn->timer, duration + FRIEND_REQ_TIMEOUT); lpn_set_state(BT_MESH_LPN_WAIT_OFFER); } @@ -362,11 +364,11 @@ static void req_sent(uint16_t duration, int err, void *user_data) /* We start scanning a bit early to elimitate risk of missing * response data due to HCI and other latencies. */ - k_delayed_work_submit(&lpn->timer, + k_work_reschedule(&lpn->timer, LPN_RECV_DELAY - SCAN_LATENCY); } else { lpn_set_state(BT_MESH_LPN_WAIT_UPDATE); - k_delayed_work_submit(&lpn->timer, + k_work_reschedule(&lpn->timer, LPN_RECV_DELAY + duration + lpn->recv_win); } @@ -459,7 +461,7 @@ int bt_mesh_lpn_set(bool enable) } else { if (IS_ENABLED(CONFIG_BT_MESH_LPN_AUTO) && lpn->state == BT_MESH_LPN_TIMER) { - k_delayed_work_cancel(&lpn->timer); + k_work_cancel_delayable(&lpn->timer); lpn_set_state(BT_MESH_LPN_DISABLED); } else { bt_mesh_lpn_disable(false); @@ -484,7 +486,7 @@ static void friend_response_received(struct bt_mesh_lpn *lpn) int32_t timeout = poll_timeout(lpn); - k_delayed_work_submit(&lpn->timer, K_MSEC(timeout)); + k_work_reschedule(&lpn->timer, K_MSEC(timeout)); } void bt_mesh_lpn_msg_received(struct bt_mesh_net_rx *rx) @@ -493,10 +495,18 @@ void bt_mesh_lpn_msg_received(struct bt_mesh_net_rx *rx) if (lpn->state == BT_MESH_LPN_TIMER) { BT_DBG("Restarting establishment timer"); - k_delayed_work_submit(&lpn->timer, LPN_AUTO_TIMEOUT); + k_work_reschedule(&lpn->timer, LPN_AUTO_TIMEOUT); + return; + } + + if (lpn->state != BT_MESH_LPN_WAIT_UPDATE) { return; } + /* If the message was a Friend control message, it's possible that a + * Poll was already queued for sending. In this case, we're already in + * a different state. + */ if (lpn->state != BT_MESH_LPN_WAIT_UPDATE) { return; } @@ -754,7 +764,7 @@ static void update_timeout(struct bt_mesh_lpn *lpn) BT_WARN("No response from Friend during ReceiveWindow"); bt_mesh_scan_disable(); lpn_set_state(BT_MESH_LPN_ESTABLISHED); - k_delayed_work_submit(&lpn->timer, POLL_RETRY_TIMEOUT); + k_work_reschedule(&lpn->timer, POLL_RETRY_TIMEOUT); } else { if (IS_ENABLED(CONFIG_BT_MESH_LPN_ESTABLISHMENT)) { bt_mesh_scan_disable(); @@ -799,7 +809,7 @@ static void lpn_timeout(struct ble_npl_event *work) break; case BT_MESH_LPN_REQ_WAIT: bt_mesh_scan_enable(); - k_delayed_work_submit(&lpn->timer, + k_work_reschedule(&lpn->timer, lpn->adv_duration + FRIEND_REQ_SCAN); lpn_set_state(BT_MESH_LPN_WAIT_OFFER); break; @@ -811,7 +821,7 @@ static void lpn_timeout(struct ble_npl_event *work) lpn->lpn_counter++; lpn_set_state(BT_MESH_LPN_ENABLED); lpn->sent_req = 0U; - k_delayed_work_submit(&lpn->timer, FRIEND_REQ_RETRY_TIMEOUT); + k_work_reschedule(&lpn->timer, FRIEND_REQ_RETRY_TIMEOUT); break; case BT_MESH_LPN_ESTABLISHED: if (lpn->req_attempts < REQ_ATTEMPTS(lpn)) { @@ -834,7 +844,7 @@ static void lpn_timeout(struct ble_npl_event *work) clear_friendship(false, false); break; case BT_MESH_LPN_RECV_DELAY: - k_delayed_work_submit(&lpn->timer, + k_work_reschedule(&lpn->timer, lpn->adv_duration + SCAN_LATENCY + lpn->recv_win); bt_mesh_scan_enable(); @@ -972,7 +982,7 @@ int bt_mesh_lpn_friend_update(struct bt_mesh_net_rx *rx, if (!lpn->established) { /* This is normally checked on the transport layer, however - * in this state we're also still accepting master + * in this state we're also still accepting flooding * credentials so we need to ensure the right ones (Friend * Credentials) were used for this message. */ @@ -992,7 +1002,7 @@ int bt_mesh_lpn_friend_update(struct bt_mesh_net_rx *rx, } /* Set initial poll timeout */ - lpn->poll_timeout = min(POLL_TIMEOUT_MAX(lpn), + lpn->poll_timeout = MIN(POLL_TIMEOUT_MAX(lpn), POLL_TIMEOUT_INIT); } @@ -1067,7 +1077,7 @@ int bt_mesh_lpn_init(void) BT_DBG(""); - k_delayed_work_init(&lpn->timer, lpn_timeout); + k_work_init_delayable(&lpn->timer, lpn_timeout); if (lpn->state == BT_MESH_LPN_ENABLED) { if (IS_ENABLED(CONFIG_BT_MESH_LPN_ESTABLISHMENT)) { @@ -1083,7 +1093,7 @@ int bt_mesh_lpn_init(void) if (IS_ENABLED(CONFIG_BT_MESH_LPN_AUTO)) { BT_DBG("Waiting %u ms for messages", LPN_AUTO_TIMEOUT); lpn_set_state(BT_MESH_LPN_TIMER); - k_delayed_work_submit(&lpn->timer, LPN_AUTO_TIMEOUT); + k_work_reschedule(&lpn->timer, LPN_AUTO_TIMEOUT); } } diff --git a/nimble/host/mesh/src/lpn.h b/nimble/host/mesh/src/lpn.h index 90de2ca086..cb2e1f2fef 100644 --- a/nimble/host/mesh/src/lpn.h +++ b/nimble/host/mesh/src/lpn.h @@ -47,15 +47,6 @@ static inline bool bt_mesh_lpn_waiting_update(void) #endif } -static inline bool bt_mesh_lpn_timer(void) -{ -#if MYNEWT_VAL(BLE_MESH_LOW_POWER) && MYNEWT_VAL(BLE_MESH_LPN_AUTO) - return (bt_mesh.lpn.state == BT_MESH_LPN_TIMER); -#else - return false; -#endif -} - void bt_mesh_lpn_msg_received(struct bt_mesh_net_rx *rx); void bt_mesh_lpn_group_add(uint16_t group); diff --git a/nimble/host/mesh/src/mesh.c b/nimble/host/mesh/src/mesh.c index 10c6fff991..d3ffb28d97 100644 --- a/nimble/host/mesh/src/mesh.c +++ b/nimble/host/mesh/src/mesh.c @@ -7,7 +7,9 @@ */ #include "syscfg/syscfg.h" -#define MESH_LOG_MODULE BLE_MESH_LOG + +#define BLE_NPL_LOG_MODULE BLE_MESH_LOG +#include #include #include @@ -35,6 +37,7 @@ #include "shell.h" #include "mesh_priv.h" #include "settings.h" +#include "pb_gatt_srv.h" uint8_t g_mesh_addr_type; @@ -44,7 +47,6 @@ int bt_mesh_provision(const uint8_t net_key[16], uint16_t net_idx, uint8_t flags, uint32_t iv_index, uint16_t addr, const uint8_t dev_key[16]) { - bool pb_gatt_enabled; int err; BT_INFO("Primary Element: 0x%04x", addr); @@ -55,32 +57,16 @@ int bt_mesh_provision(const uint8_t net_key[16], uint16_t net_idx, return -EALREADY; } - if ((MYNEWT_VAL(BLE_MESH_PB_GATT))) { - if (bt_mesh_proxy_prov_disable(false) == 0) { - pb_gatt_enabled = true; - } else { - pb_gatt_enabled = false; - } - } else { - pb_gatt_enabled = false; - } - /* * FIXME: * Should net_key and iv_index be over-ridden? */ - if (IS_ENABLED(BLE_MESH_CDB)) { + if (IS_ENABLED(CONFIG_BT_MESH_CDB) && + atomic_test_bit(bt_mesh_cdb.flags, BT_MESH_CDB_VALID)) { const struct bt_mesh_comp *comp; const struct bt_mesh_prov *prov; struct bt_mesh_cdb_node *node; - if (!atomic_test_bit(bt_mesh_cdb.flags, - BT_MESH_CDB_VALID)) { - BT_ERR("No valid network"); - atomic_clear_bit(bt_mesh.flags, BT_MESH_VALID); - return -EINVAL; - } - comp = bt_mesh_comp_get(); if (comp == NULL) { BT_ERR("Failed to get node composition"); @@ -108,7 +94,7 @@ int bt_mesh_provision(const uint8_t net_key[16], uint16_t net_idx, memcpy(node->dev_key, dev_key, 16); if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_cdb_node(node); + bt_mesh_cdb_node_store(node); } } @@ -116,10 +102,6 @@ int bt_mesh_provision(const uint8_t net_key[16], uint16_t net_idx, if (err) { atomic_clear_bit(bt_mesh.flags, BT_MESH_VALID); - if (MYNEWT_VAL(BLE_MESH_PB_GATT) && pb_gatt_enabled) { - (void)bt_mesh_proxy_prov_enable(); - } - return err; } @@ -134,6 +116,10 @@ int bt_mesh_provision(const uint8_t net_key[16], uint16_t net_idx, bt_mesh_lpn_group_add(BT_MESH_ADDR_ALL_NODES); } + if (IS_ENABLED(CONFIG_BT_SETTINGS)) { + bt_mesh_net_pending_net_store(); + } + bt_mesh_start(); return 0; @@ -166,14 +152,15 @@ void bt_mesh_reset(void) } bt_mesh.iv_index = 0U; + bt_mesh.ivu_duration = 0; bt_mesh.seq = 0U; memset(bt_mesh.flags, 0, sizeof(bt_mesh.flags)); - k_delayed_work_cancel(&bt_mesh.ivu_timer); - - bt_mesh_cfg_reset(); + k_work_cancel_delayable(&bt_mesh.ivu_timer); + bt_mesh_model_reset(); + bt_mesh_cfg_default_set(); bt_mesh_trans_reset(); bt_mesh_app_keys_reset(); bt_mesh_net_keys_reset(); @@ -195,11 +182,11 @@ void bt_mesh_reset(void) } if ((MYNEWT_VAL(BLE_MESH_GATT_PROXY))) { - bt_mesh_proxy_gatt_disable(); + (void)bt_mesh_proxy_gatt_disable(); } if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_clear_net(); + bt_mesh_net_clear(); } memset(bt_mesh.dev_key, 0, sizeof(bt_mesh.dev_key)); @@ -236,7 +223,10 @@ static void model_suspend(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, { if (mod->pub && mod->pub->update) { mod->pub->count = 0; - k_delayed_work_cancel(&mod->pub->timer); + /* If this fails, the work handler will check the suspend call + * and exit without transmitting. + */ + (void)k_work_cancel_delayable(&mod->pub->timer); } } @@ -277,7 +267,8 @@ static void model_resume(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, int32_t period_ms = bt_mesh_model_pub_period_get(mod); if (period_ms) { - k_delayed_work_submit(&mod->pub->timer, period_ms); + k_work_reschedule(&mod->pub->timer, + K_MSEC(period_ms)); } } } @@ -338,7 +329,18 @@ int bt_mesh_init(uint8_t own_addr_type, const struct bt_mesh_prov *prov, } #endif - bt_mesh_cfg_init(); + bt_mesh_app_key_init(); + bt_mesh_access_init(); + bt_mesh_hb_pub_init(); + bt_mesh_rpl_init(); + bt_mesh_net_key_init(); +#if CONFIG_BT_MESH_LABEL_COUNT > 0 + bt_mesh_va_init(); +#endif +#if CONFIG_BT_MESH_CDB + bt_mesh_cdb_init(); +#endif + bt_mesh_cfg_default_set(); bt_mesh_net_init(); bt_mesh_trans_init(); bt_mesh_hb_init(); @@ -365,16 +367,30 @@ static void model_start(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, int bt_mesh_start(void) { + int err; + + err = bt_mesh_adv_enable(); + if (err) { + BT_ERR("Failed enabling advertiser"); + return err; + } + if (bt_mesh_beacon_enabled()) { bt_mesh_beacon_enable(); } else { bt_mesh_beacon_disable(); } - if (IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY) && - bt_mesh_gatt_proxy_get() != BT_MESH_GATT_PROXY_NOT_SUPPORTED) { - bt_mesh_proxy_gatt_enable(); - bt_mesh_adv_update(); + if (!IS_ENABLED(CONFIG_BT_MESH_PROV) || !bt_mesh_prov_active() || + bt_mesh_prov_link.bearer->type == BT_MESH_PROV_ADV) { + if (IS_ENABLED(CONFIG_BT_MESH_PB_GATT)) { + (void)bt_mesh_pb_gatt_disable(); + } + + if (IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY)) { + (void)bt_mesh_proxy_gatt_enable(); + bt_mesh_adv_update(); + } } if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER)) { diff --git a/nimble/host/mesh/src/model_cli.c b/nimble/host/mesh/src/model_cli.c index 9755ec1fd9..72c2fa0390 100644 --- a/nimble/host/mesh/src/model_cli.c +++ b/nimble/host/mesh/src/model_cli.c @@ -5,7 +5,9 @@ */ #include "syscfg/syscfg.h" -#define MESH_LOG_MODULE BLE_MESH_MODEL_LOG + +#define BLE_NPL_LOG_MODULE BLE_MESH_MODEL_LOG +#include #include "mesh/mesh.h" #include "mesh/model_cli.h" @@ -26,7 +28,7 @@ struct gen_level_param { int16_t *level; }; -static void gen_onoff_status(struct bt_mesh_model *model, +static int gen_onoff_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -41,7 +43,7 @@ static void gen_onoff_status(struct bt_mesh_model *model, if (cli->op_pending != OP_GEN_ONOFF_STATUS) { BT_WARN("Unexpected Generic OnOff Status message"); - return; + return -ENOENT; } param = cli->op_param; @@ -54,9 +56,11 @@ static void gen_onoff_status(struct bt_mesh_model *model, BT_DBG("state: %d", state); k_sem_give(&cli->op_sync); + + return 0; } -static void gen_level_status(struct bt_mesh_model *model, +static int gen_level_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -71,7 +75,7 @@ static void gen_level_status(struct bt_mesh_model *model, if (cli->op_pending != OP_GEN_LEVEL_STATUS) { BT_WARN("Unexpected Generic LEVEL Status message"); - return; + return -EINVAL; } param = cli->op_param; @@ -84,6 +88,8 @@ static void gen_level_status(struct bt_mesh_model *model, BT_DBG("level: %d", level); k_sem_give(&cli->op_sync); + + return 0; } const struct bt_mesh_model_op gen_onoff_cli_op[] = { @@ -298,4 +304,3 @@ int bt_mesh_gen_level_set(uint16_t net_idx, uint16_t addr, uint16_t app_idx, os_mbuf_free_chain(msg); return err; } - diff --git a/nimble/host/mesh/src/model_srv.c b/nimble/host/mesh/src/model_srv.c index b6f34360aa..02b002fd1b 100644 --- a/nimble/host/mesh/src/model_srv.c +++ b/nimble/host/mesh/src/model_srv.c @@ -5,7 +5,10 @@ */ #include "syscfg/syscfg.h" -#define MESH_LOG_MODULE BLE_MESH_MODEL_LOG + +#define BLE_NPL_LOG_MODULE BLE_MESH_MODEL_LOG +#include + #include "mesh/mesh.h" #include "mesh/model_srv.h" @@ -15,9 +18,10 @@ static struct bt_mesh_gen_onoff_srv *gen_onoff_srv; static struct bt_mesh_gen_level_srv *gen_level_srv; static struct bt_mesh_light_lightness_srv *light_lightness_srv; -static void gen_onoff_status(struct bt_mesh_model *model, +static int gen_onoff_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx) { + int err; struct bt_mesh_gen_onoff_srv *cb = model->user_data; struct os_mbuf *msg = NET_BUF_SIMPLE(3); uint8_t *state; @@ -30,23 +34,26 @@ static void gen_onoff_status(struct bt_mesh_model *model, BT_DBG("state: %d", *state); - if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { + err = bt_mesh_model_send(model, ctx, msg, NULL, NULL); + if (err) { BT_ERR("Send status failed"); } os_mbuf_free_chain(msg); + + return err; } -static void gen_onoff_get(struct bt_mesh_model *model, +static int gen_onoff_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { BT_DBG(""); - gen_onoff_status(model, ctx); + return gen_onoff_status(model, ctx); } -static void gen_onoff_set_unack(struct bt_mesh_model *model, +static int gen_onoff_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -58,23 +65,26 @@ static void gen_onoff_set_unack(struct bt_mesh_model *model, BT_DBG("state: %d", state); if (cb && cb->set) { - cb->set(model, state); + return cb->set(model, state); } + + return 0; } -static void gen_onoff_set(struct bt_mesh_model *model, +static int gen_onoff_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { BT_DBG(""); gen_onoff_set_unack(model, ctx, buf); - gen_onoff_status(model, ctx); + return gen_onoff_status(model, ctx); } -static void gen_level_status(struct bt_mesh_model *model, +static int gen_level_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx) { + int err; struct bt_mesh_gen_level_srv *cb = model->user_data; struct os_mbuf *msg = NET_BUF_SIMPLE(4); int16_t *level; @@ -87,23 +97,25 @@ static void gen_level_status(struct bt_mesh_model *model, BT_DBG("level: %d", *level); - if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { + err = bt_mesh_model_send(model, ctx, msg, NULL, NULL); + if (err) { BT_ERR("Send status failed"); } os_mbuf_free_chain(msg); + return err; } -static void gen_level_get(struct bt_mesh_model *model, +static int gen_level_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { BT_DBG(""); - gen_level_status(model, ctx); + return gen_level_status(model, ctx); } -static void gen_level_set_unack(struct bt_mesh_model *model, +static int gen_level_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { struct bt_mesh_gen_level_srv *cb = model->user_data; @@ -113,21 +125,24 @@ static void gen_level_set_unack(struct bt_mesh_model *model, BT_DBG("level: %d", level); if (cb && cb->set) { - cb->set(model, level); + return cb->set(model, level); } + + return 0; } -static void gen_level_set(struct bt_mesh_model *model, +static int gen_level_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { gen_level_set_unack(model, ctx, buf); - gen_level_status(model, ctx); + return gen_level_status(model, ctx); } -static void light_lightness_status(struct bt_mesh_model *model, +static int light_lightness_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx) { + int err; struct bt_mesh_light_lightness_srv *cb = model->user_data; struct os_mbuf *msg = NET_BUF_SIMPLE(4); int16_t *lightness; @@ -140,23 +155,25 @@ static void light_lightness_status(struct bt_mesh_model *model, BT_DBG("lightness: %d", *lightness); - if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { + err = bt_mesh_model_send(model, ctx, msg, NULL, NULL); + if (err) { BT_ERR("Send status failed"); } os_mbuf_free_chain(msg); + return err; } -static void light_lightness_get(struct bt_mesh_model *model, +static int light_lightness_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { BT_DBG(""); - light_lightness_status(model, ctx); + return light_lightness_status(model, ctx); } -static void light_lightness_set_unack(struct bt_mesh_model *model, +static int light_lightness_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { struct bt_mesh_light_lightness_srv *cb = model->user_data; @@ -166,16 +183,18 @@ static void light_lightness_set_unack(struct bt_mesh_model *model, BT_DBG("lightness: %d", lightness); if (cb && cb->set) { - cb->set(model, lightness); + return cb->set(model, lightness); } + + return 0; } -static void light_lightness_set(struct bt_mesh_model *model, +static int light_lightness_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { light_lightness_set_unack(model, ctx, buf); - light_lightness_status(model, ctx); + return light_lightness_status(model, ctx); } const struct bt_mesh_model_op gen_onoff_srv_op[] = { diff --git a/nimble/host/mesh/src/msg.c b/nimble/host/mesh/src/msg.c new file mode 100644 index 0000000000..b788ffe1e9 --- /dev/null +++ b/nimble/host/mesh/src/msg.c @@ -0,0 +1,84 @@ +/* Bluetooth Mesh */ + +/* + * Copyright (c) 2021 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "mesh/mesh.h" + +void bt_mesh_model_msg_init(struct os_mbuf *msg, uint32_t opcode) +{ + net_buf_simple_init(msg, 0); + + switch (BT_MESH_MODEL_OP_LEN(opcode)) { + case 1: + net_buf_simple_add_u8(msg, opcode); + break; + case 2: + net_buf_simple_add_be16(msg, opcode); + break; + case 3: + net_buf_simple_add_u8(msg, ((opcode >> 16) & 0xff)); + /* Using LE for the CID since the model layer is defined as + * little-endian in the mesh spec and using BT_MESH_MODEL_OP_3 + * will declare the opcode in this way. + */ + net_buf_simple_add_le16(msg, opcode & 0xffff); + break; + default: + BT_WARN("Unknown opcode format"); + break; + } +} + +void bt_mesh_msg_ack_ctx_clear(struct bt_mesh_msg_ack_ctx *ack) +{ + ack->op = 0U; + ack->user_data = NULL; + ack->dst = BT_MESH_ADDR_UNASSIGNED; +} + +int bt_mesh_msg_ack_ctx_prepare(struct bt_mesh_msg_ack_ctx *ack, + uint32_t op, uint16_t dst, void *user_data) +{ + if (ack->op) { + BT_WARN("Another synchronous operation pending"); + return -EBUSY; + } + + ack->op = op; + ack->user_data = user_data; + ack->dst = dst; + + return 0; +} + +int bt_mesh_msg_ack_ctx_wait(struct bt_mesh_msg_ack_ctx *ack, int32_t timeout) +{ + int err; + + err = k_sem_take(&ack->sem, timeout); + bt_mesh_msg_ack_ctx_clear(ack); + + if (err == -EAGAIN) { + return -ETIMEDOUT; + } + + return err; +} + +bool bt_mesh_msg_ack_ctx_match(const struct bt_mesh_msg_ack_ctx *ack, + uint32_t op, uint16_t addr, void **user_data) +{ + if (ack->op != op || (BT_MESH_ADDR_IS_UNICAST(ack->dst) && ack->dst != addr)) { + return false; + } + + if (user_data != NULL) { + *user_data = ack->user_data; + } + + return true; +} diff --git a/nimble/host/mesh/src/net.c b/nimble/host/mesh/src/net.c index bbe186ec8d..15fabb1090 100644 --- a/nimble/host/mesh/src/net.c +++ b/nimble/host/mesh/src/net.c @@ -7,7 +7,9 @@ */ #include "syscfg/syscfg.h" -#define MESH_LOG_MODULE BLE_MESH_NET_LOG + +#define BLE_NPL_LOG_MODULE BLE_MESH_NET_LOG +#include #include #include @@ -39,7 +41,7 @@ #define LOOPBACK_BUF_SUB(buf) (*(struct bt_mesh_subnet **)net_buf_user_data(buf)) /* Seq limit after IV Update is triggered */ -#define IV_UPDATE_SEQ_LIMIT 8000000 +#define IV_UPDATE_SEQ_LIMIT CONFIG_BT_MESH_IV_UPDATE_SEQ_LIMIT #define IVI(pdu) ((pdu)[0] >> 7) #define NID(pdu) ((pdu)[0] & 0x7f) @@ -49,6 +51,31 @@ #define SRC(pdu) (sys_get_be16(&(pdu)[5])) #define DST(pdu) (sys_get_be16(&(pdu)[7])) +/** Define CONFIG_BT_MESH_SEQ_STORE_RATE even if settings are disabled to + * compile the code. + */ +#ifndef CONFIG_BT_SETTINGS +#define CONFIG_BT_MESH_SEQ_STORE_RATE 1 +#endif + +/* Mesh network information for persistent storage. */ +struct net_val { + uint16_t primary_addr; + uint8_t dev_key[16]; +} __packed; + +/* Sequence number information for persistent storage. */ +struct seq_val { + uint8_t val[3]; +} __packed; + +/* IV Index & IV Update information for persistent storage. */ +struct iv_val { + uint32_t iv_index; + uint8_t iv_update:1, + iv_duration:7; +} __packed; + static struct { uint32_t src : 15, /* MSb of source is always 0 */ seq : 17; @@ -60,6 +87,15 @@ struct bt_mesh_net bt_mesh = { .local_queue = STAILQ_HEAD_INITIALIZER(bt_mesh.local_queue), }; +/* Mesh Profile Specification 3.10.6 + * The node shall not execute more than one IV Index Recovery within a period of + * 192 hours. + * + * Mark that the IV Index Recovery has been done to prevent two recoveries to be + * done before a normal IV Index update has been completed within 96h+96h. + */ +static bool ivi_was_recovered; + static struct os_mbuf_pool loopback_os_mbuf_pool; static struct os_mempool loopback_buf_mempool; os_membuf_t loopback_mbuf_membuf[ @@ -112,6 +148,30 @@ static void msg_cache_add(struct bt_mesh_net_rx *rx) msg_cache_next %= ARRAY_SIZE(msg_cache); } +static void store_iv(bool only_duration) +{ +#if MYNEWT_VAL(BLE_MESH_SETTINGS) + bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_IV_PENDING); + + if (!only_duration) { + /* Always update Seq whenever IV changes */ + bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_SEQ_PENDING); + } +#endif +} + +static void store_seq(void) +{ +#if MYNEWT_VAL(BLE_MESH_SETTINGS) + if (CONFIG_BT_MESH_SEQ_STORE_RATE > 1 && + (bt_mesh.seq % CONFIG_BT_MESH_SEQ_STORE_RATE)) { + return; + } + + bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_SEQ_PENDING); +#endif +} + int bt_mesh_net_create(uint16_t idx, uint8_t flags, const uint8_t key[16], uint32_t iv_index) { @@ -139,17 +199,18 @@ int bt_mesh_net_create(uint16_t idx, uint8_t flags, const uint8_t key[16], atomic_set_bit_to(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS, BT_MESH_IV_UPDATE(flags)); - /* Set minimum required hours, since the 96-hour minimum requirement - * doesn't apply straight after provisioning (since we can't know how - * long has actually passed since the network changed its state). + /* If IV Update is already in progress, set minimum required hours, + * since the 96-hour minimum requirement doesn't apply in this case straight + * after provisioning. */ - bt_mesh.ivu_duration = BT_MESH_IVU_MIN_HOURS; + if (BT_MESH_IV_UPDATE(flags)) { + bt_mesh.ivu_duration = BT_MESH_IVU_MIN_HOURS; + } if (IS_ENABLED(CONFIG_BT_SETTINGS)) { BT_DBG("Storing network information persistently"); - bt_mesh_store_net(); - bt_mesh_store_subnet(idx); - bt_mesh_store_iv(false); + bt_mesh_subnet_store(idx); + store_iv(false); } return 0; @@ -213,24 +274,24 @@ bool bt_mesh_net_iv_update(uint32_t iv_index, bool iv_update) return false; } - if (iv_index > bt_mesh.iv_index + 1) { + if ((iv_index > bt_mesh.iv_index + 1) || + (iv_index == bt_mesh.iv_index + 1 && !iv_update)) { + if (ivi_was_recovered) { + BT_ERR("IV Index Recovery before minimum delay"); + return false; + } + /* The Mesh profile specification allows to initiate an + * IV Index Recovery procedure if previous IV update has + * been missed. This allows the node to remain + * functional. + */ BT_WARN("Performing IV Index Recovery"); + ivi_was_recovered = true; bt_mesh_rpl_clear(); bt_mesh.iv_index = iv_index; bt_mesh.seq = 0; goto do_update; } - - if (iv_index == bt_mesh.iv_index + 1 && !iv_update) { - BT_WARN("Ignoring new index in normal mode"); - return false; - } - - if (!iv_update) { - /* Nothing to do */ - BT_DBG("Already in Normal state"); - return false; - } } if (!(IS_ENABLED(CONFIG_BT_MESH_IV_UPDATE_TEST) && @@ -248,41 +309,42 @@ bool bt_mesh_net_iv_update(uint32_t iv_index, bool iv_update) return false; } -do_update: - atomic_set_bit_to(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS, iv_update); - bt_mesh.ivu_duration = 0U; - if (iv_update) { bt_mesh.iv_index = iv_index; BT_DBG("IV Update state entered. New index 0x%08x", (unsigned) bt_mesh.iv_index); bt_mesh_rpl_reset(); + ivi_was_recovered = false; } else { BT_DBG("Normal mode entered"); bt_mesh.seq = 0; } - k_delayed_work_submit(&bt_mesh.ivu_timer, BT_MESH_IVU_TIMEOUT); +do_update: + atomic_set_bit_to(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS, iv_update); + bt_mesh.ivu_duration = 0U; + + k_work_reschedule(&bt_mesh.ivu_timer, BT_MESH_IVU_TIMEOUT); /* Notify other modules */ if (IS_ENABLED(CONFIG_BT_MESH_FRIEND)) { bt_mesh_friend_sec_update(BT_MESH_KEY_ANY); } + bt_mesh_subnet_foreach(bt_mesh_beacon_update); + if (IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY) && bt_mesh_gatt_proxy_get() == BT_MESH_GATT_PROXY_ENABLED) { bt_mesh_proxy_beacon_send(NULL); } - bt_mesh_subnet_foreach(bt_mesh_beacon_update); - if (MYNEWT_VAL(BLE_MESH_CDB)) { bt_mesh_cdb_iv_update(iv_index, iv_update); } if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_iv(false); + store_iv(false); } return true; @@ -293,7 +355,7 @@ uint32_t bt_mesh_next_seq(void) uint32_t seq = bt_mesh.seq++; if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_seq(); + store_seq(); } if (!atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS) && @@ -338,14 +400,14 @@ static void bt_mesh_net_local(struct ble_npl_event *work) rx.ctx.addr, rx.seq, sub); (void) bt_mesh_trans_recv(buf, &rx); - net_buf_unref(buf); + os_mbuf_free_chain(buf); } } static const struct bt_mesh_net_cred *net_tx_cred_get(struct bt_mesh_net_tx *tx) { #if IS_ENABLED(CONFIG_BT_MESH_LOW_POWER) - if (tx->friend_cred && bt_mesh_lpn_established()) { + if (tx->friend_cred && bt_mesh.lpn.frnd) { return &bt_mesh.lpn.cred[SUBNET_KEY_TX_IDX(tx->sub)]; } #endif @@ -420,7 +482,7 @@ static int loopback(const struct bt_mesh_net_tx *tx, const uint8_t *data, { struct os_mbuf *buf; - buf = os_mbuf_get_pkthdr(&loopback_os_mbuf_pool, 0); + buf = os_mbuf_get_pkthdr(&loopback_os_mbuf_pool, BT_MESH_NET_HDR_LEN); if (!buf) { BT_WARN("Unable to allocate loopback"); return -ENOMEM; @@ -462,7 +524,7 @@ int bt_mesh_net_send(struct bt_mesh_net_tx *tx, struct os_mbuf *buf, /* Deliver to local network interface if necessary */ if (bt_mesh_fixed_group_match(tx->ctx->addr) || - bt_mesh_elem_find(tx->ctx->addr)) { + bt_mesh_has_addr(tx->ctx->addr)) { err = loopback(tx, buf->om_data, buf->om_len); /* Local unicast messages should not go out to network */ @@ -490,12 +552,13 @@ int bt_mesh_net_send(struct bt_mesh_net_tx *tx, struct os_mbuf *buf, goto done; } + BT_MESH_ADV(buf)->cb = cb; + BT_MESH_ADV(buf)->cb_data = cb_data; + /* Deliver to GATT Proxy Clients if necessary. */ if (IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY) && bt_mesh_proxy_relay(buf, tx->ctx->addr) && BT_MESH_ADDR_IS_UNICAST(tx->ctx->addr)) { - /* Notify completion if this only went through the Mesh Proxy */ - send_cb_finalize(cb, cb_data); err = 0; goto done; @@ -559,7 +622,7 @@ static bool net_decrypt(struct bt_mesh_net_rx *rx, struct os_mbuf *in, return false; } - if (bt_mesh_elem_find(rx->ctx.addr)) { + if (bt_mesh_has_addr(rx->ctx.addr)) { BT_DBG("Dropping locally originated packet"); return false; } @@ -657,7 +720,7 @@ static void bt_mesh_net_relay(struct os_mbuf *sbuf, bt_hex(buf->om_data, buf->om_len)); /* When the Friend node relays message for lpn, the message will be - * retransmitted using the managed master security credentials and + * retransmitted using the managed flooding security credentials and * the Network PDU shall be retransmitted to all network interfaces. */ if (IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY) && @@ -770,7 +833,7 @@ void bt_mesh_net_recv(struct os_mbuf *data, int8_t rssi, net_buf_simple_save(buf, &state); rx.local_match = (bt_mesh_fixed_group_match(rx.ctx.recv_dst) || - bt_mesh_elem_find(rx.ctx.recv_dst)); + bt_mesh_has_addr(rx.ctx.recv_dst)); if ((MYNEWT_VAL(BLE_MESH_GATT_PROXY)) && net_if == BT_MESH_NET_IF_PROXY) { @@ -812,6 +875,10 @@ void bt_mesh_net_recv(struct os_mbuf *data, int8_t rssi, static void ivu_refresh(struct ble_npl_event *work) { + if (!bt_mesh_is_provisioned()) { + return; + } + bt_mesh.ivu_duration = MIN(UINT8_MAX, bt_mesh.ivu_duration + BT_MESH_IVU_HOURS); @@ -822,10 +889,10 @@ static void ivu_refresh(struct ble_npl_event *work) if (bt_mesh.ivu_duration < BT_MESH_IVU_MIN_HOURS) { if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_iv(true); + store_iv(true); } - k_delayed_work_submit(&bt_mesh.ivu_timer, BT_MESH_IVU_TIMEOUT); + k_work_reschedule(&bt_mesh.ivu_timer, BT_MESH_IVU_TIMEOUT); return; } @@ -833,15 +900,169 @@ static void ivu_refresh(struct ble_npl_event *work) bt_mesh_beacon_ivu_initiator(true); bt_mesh_net_iv_update(bt_mesh.iv_index, false); } else if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_iv(true); + store_iv(true); } } +#if MYNEWT_VAL(BLE_MESH_SETTINGS) +static int net_set(int argc, char **argv, char *val) +{ + struct net_val net; + int len, err; + + BT_DBG("val %s", val ? val : "(null)"); + + if (!val) { + bt_mesh_comp_unprovision(); + memset(bt_mesh.dev_key, 0, sizeof(bt_mesh.dev_key)); + return 0; + } + + len = sizeof(net); + err = settings_bytes_from_str(val, &net, &len); + if (err) { + BT_ERR("Failed to decode value %s (err %d)", val, err); + return err; + } + + if (len != sizeof(net)) { + BT_ERR("Unexpected value length (%d != %zu)", len, sizeof(net)); + return -EINVAL; + } + + memcpy(bt_mesh.dev_key, net.dev_key, sizeof(bt_mesh.dev_key)); + bt_mesh_comp_provision(net.primary_addr); + + BT_DBG("Provisioned with primary address 0x%04x", net.primary_addr); + BT_DBG("Recovered DevKey %s", bt_hex(bt_mesh.dev_key, 16)); + + return 0; +} + +static int iv_set(int argc, char **argv, char *val) +{ + struct iv_val iv; + int len, err; + + BT_DBG("val %s", val ? val : "(null)"); + + if (!val) { + bt_mesh.iv_index = 0U; + atomic_clear_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS); + return 0; + } + + len = sizeof(iv); + err = settings_bytes_from_str(val, &iv, &len); + if (err) { + BT_ERR("Failed to decode value %s (err %d)", val, err); + return err; + } + + if (len != sizeof(iv)) { + BT_ERR("Unexpected value length (%d != %zu)", len, sizeof(iv)); + return -EINVAL; + } + + bt_mesh.iv_index = iv.iv_index; + atomic_set_bit_to(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS, iv.iv_update); + bt_mesh.ivu_duration = iv.iv_duration; + + BT_DBG("IV Index 0x%04x (IV Update Flag %u) duration %u hours", + (unsigned) iv.iv_index, iv.iv_update, iv.iv_duration); + + return 0; +} + +static int seq_set(int argc, char **argv, char *val) +{ + struct seq_val seq; + int len, err; + + BT_DBG("val %s", val ? val : "(null)"); + + if (!val) { + bt_mesh.seq = 0; + return 0; + } + + len = sizeof(seq); + err = settings_bytes_from_str(val, &seq, &len); + if (err) { + BT_ERR("Failed to decode value %s (err %d)", val, err); + return err; + } + + if (len != sizeof(seq)) { + BT_ERR("Unexpected value length (%d != %zu)", len, sizeof(seq)); + return -EINVAL; + } + + bt_mesh.seq = sys_get_le24(seq.val); + + if (CONFIG_BT_MESH_SEQ_STORE_RATE > 0) { + /* Make sure we have a large enough sequence number. We + * subtract 1 so that the first transmission causes a write + * to the settings storage. + */ + bt_mesh.seq += (CONFIG_BT_MESH_SEQ_STORE_RATE - + (bt_mesh.seq % CONFIG_BT_MESH_SEQ_STORE_RATE)); + bt_mesh.seq--; + } + + BT_DBG("Sequence Number 0x%06x", bt_mesh.seq); + + return 0; +} + +static struct conf_handler bt_mesh_net_conf_handler = { + .ch_name = "bt_mesh", + .ch_get = NULL, + .ch_set = net_set, + .ch_commit = NULL, + .ch_export = NULL, +}; + +static struct conf_handler bt_mesh_iv_conf_handler = { + .ch_name = "bt_mesh", + .ch_get = NULL, + .ch_set = iv_set, + .ch_commit = NULL, + .ch_export = NULL, +}; + +static struct conf_handler bt_mesh_seq_conf_handler = { + .ch_name = "bt_mesh", + .ch_get = NULL, + .ch_set = seq_set, + .ch_commit = NULL, + .ch_export = NULL, +}; +#endif + void bt_mesh_net_init(void) { int rc; - k_delayed_work_init(&bt_mesh.ivu_timer, ivu_refresh); +#if MYNEWT_VAL(BLE_MESH_SETTINGS) + rc = conf_register(&bt_mesh_net_conf_handler); + + SYSINIT_PANIC_ASSERT_MSG(rc == 0, + "Failed to register bt_mesh_net conf"); + + + rc = conf_register(&bt_mesh_iv_conf_handler); + + SYSINIT_PANIC_ASSERT_MSG(rc == 0, + "Failed to register bt_mesh_iv conf"); + + rc = conf_register(&bt_mesh_seq_conf_handler); + + SYSINIT_PANIC_ASSERT_MSG(rc == 0, + "Failed to register bt_mesh_seq conf"); +#endif + + k_work_init_delayable(&bt_mesh.ivu_timer, ivu_refresh); k_work_init(&bt_mesh.local_work, bt_mesh_net_local); net_buf_slist_init(&bt_mesh.local_queue); @@ -852,7 +1073,153 @@ void bt_mesh_net_init(void) assert(rc == 0); rc = os_mbuf_pool_init(&loopback_os_mbuf_pool, &loopback_buf_mempool, - LOOPBACK_MAX_PDU_LEN + BT_MESH_MBUF_HEADER_SIZE, - MYNEWT_VAL(BLE_MESH_LOOPBACK_BUFS)); + LOOPBACK_MAX_PDU_LEN + BT_MESH_MBUF_HEADER_SIZE, + MYNEWT_VAL(BLE_MESH_LOOPBACK_BUFS)); assert(rc == 0); } + +#if MYNEWT_VAL(BLE_MESH_SETTINGS) +static void clear_iv(void) +{ + int err; + + err = settings_save_one("bt_mesh/IV", NULL); + if (err) { + BT_ERR("Failed to clear IV"); + } else { + BT_DBG("Cleared IV"); + } +} + +static void store_pending_iv(void) +{ + char buf[BT_SETTINGS_SIZE(sizeof(struct iv_val))]; + struct iv_val iv; + char *str; + int err; + + iv.iv_index = bt_mesh.iv_index; + iv.iv_update = atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS); + iv.iv_duration = bt_mesh.ivu_duration; + + str = settings_str_from_bytes(&iv, sizeof(iv), buf, sizeof(buf)); + if (!str) { + BT_ERR("Unable to encode IV as value"); + return; + } + + BT_DBG("Saving IV as value %s", str); + err = settings_save_one("bt_mesh/IV", str); + if (err) { + BT_ERR("Failed to store IV"); + } else { + BT_DBG("Stored IV"); + } +} + +void bt_mesh_net_pending_iv_store(void) +{ + if (atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) { + store_pending_iv(); + } else { + clear_iv(); + } +} + +static void clear_net(void) +{ + int err; + + err = settings_save_one("bt_mesh/Net", NULL); + if (err) { + BT_ERR("Failed to clear Network"); + } else { + BT_DBG("Cleared Network"); + } +} + +static void store_pending_net(void) +{ + char buf[BT_SETTINGS_SIZE(sizeof(struct net_val))]; + struct net_val net; + char *str; + int err; + + BT_DBG("addr 0x%04x DevKey %s", bt_mesh_primary_addr(), + bt_hex(bt_mesh.dev_key, 16)); + + net.primary_addr = bt_mesh_primary_addr(); + memcpy(net.dev_key, bt_mesh.dev_key, 16); + + str = settings_str_from_bytes(&net, sizeof(net), buf, sizeof(buf)); + if (!str) { + BT_ERR("Unable to encode Network as value"); + return; + } + + BT_DBG("Saving Network as value %s", str); + err = settings_save_one("bt_mesh/Net", str); + if (err) { + BT_ERR("Failed to store Network"); + } else { + BT_DBG("Stored Network"); + } +} + +void bt_mesh_net_pending_net_store(void) +{ + if (atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) { + store_pending_net(); + } else { + clear_net(); + } +} + +void bt_mesh_net_pending_seq_store(void) +{ + char buf[BT_SETTINGS_SIZE(sizeof(struct seq_val))]; + char *str; + struct seq_val seq; + int err; + + if (atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) { + sys_put_le24(bt_mesh.seq, seq.val); + + str = settings_str_from_bytes(&seq, sizeof(seq), buf, sizeof(buf)); + if (!str) { + BT_ERR("Unable to encode Network as value"); + return; + } + + BT_DBG("Saving Network as value %s", str); + err = settings_save_one("bt_mesh/Seq", str); + if (err) { + BT_ERR("Failed to stor Seq value"); + } else { + BT_DBG("Stored Seq value"); + } + } else { + err = settings_save_one("bt_mesh/Seq", NULL); + if (err) { + BT_ERR("Failed to clear Seq value"); + } else { + BT_DBG("Cleared Seq value"); + } + } +} + +void bt_mesh_net_clear(void) +{ + bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_NET_PENDING); + bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_IV_PENDING); + bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_CFG_PENDING); + bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_SEQ_PENDING); +} +#endif + +void bt_mesh_net_settings_commit(void) +{ + if (bt_mesh.ivu_duration < BT_MESH_IVU_MIN_HOURS) { + k_work_reschedule(&bt_mesh.ivu_timer, BT_MESH_IVU_TIMEOUT); + } +} diff --git a/nimble/host/mesh/src/net.h b/nimble/host/mesh/src/net.h index 8c501540df..b8147b4d86 100644 --- a/nimble/host/mesh/src/net.h +++ b/nimble/host/mesh/src/net.h @@ -74,7 +74,7 @@ struct bt_mesh_friend { uint16_t sub_list[FRIEND_SUB_LIST_SIZE]; - struct k_delayed_work timer; + struct k_work_delayable timer; struct bt_mesh_friend_seg { struct net_buf_slist_t queue; @@ -96,7 +96,7 @@ struct bt_mesh_friend { uint32_t start; /* Clear Procedure start */ uint16_t frnd; /* Previous Friend's address */ uint16_t repeat_sec; /* Repeat timeout in seconds */ - struct k_delayed_work timer; /* Repeat timer */ + struct k_work_delayable timer; /* Repeat timer */ } clear; }; @@ -160,7 +160,7 @@ struct bt_mesh_lpn { uint16_t adv_duration; /* Next LPN related action timer */ - struct k_delayed_work timer; + struct k_work_delayable timer; /* Subscribed groups */ uint16_t groups[LPN_GROUPS]; @@ -184,17 +184,6 @@ enum { BT_MESH_IVU_TEST, /* IV Update test mode */ BT_MESH_IVU_PENDING, /* Update blocked by SDU in progress */ - /* pending storage actions, must reside within first 32 flags */ - BT_MESH_RPL_PENDING, - BT_MESH_KEYS_PENDING, - BT_MESH_NET_PENDING, - BT_MESH_IV_PENDING, - BT_MESH_SEQ_PENDING, - BT_MESH_HB_PUB_PENDING, - BT_MESH_CFG_PENDING, - BT_MESH_MOD_PENDING, - BT_MESH_VA_PENDING, - /* Feature flags */ BT_MESH_RELAY, BT_MESH_BEACON, @@ -232,7 +221,7 @@ struct bt_mesh_net { uint8_t default_ttl; /* Timer to track duration in current IV Update state */ - struct k_delayed_work ivu_timer; + struct k_work_delayable ivu_timer; uint8_t dev_key[16]; }; @@ -282,7 +271,12 @@ extern struct bt_mesh_net bt_mesh; static inline void *net_buf_user_data(const struct os_mbuf *buf) { - return (void *)buf->om_data; + /* In Zephyr at the end of net_buf (which is ported as os_mbuf) is place + * for user_data, which is array of octets, just like os_mbuf's om_data. Let's just + * use last octets (starting at start of om_data + total size of data mbuf can hold - + * intended user_data size) of om_data as Zephyr's user_data. + */ + return (void *)(buf->om_data + buf->om_omp->omp_databuf_len - MYNEWT_VAL(BLE_MESH_NET_BUF_USER_DATA_SIZE)); } int bt_mesh_net_create(uint16_t idx, uint8_t flags, const uint8_t key[16], @@ -309,7 +303,11 @@ uint32_t bt_mesh_next_seq(void); void bt_mesh_net_init(void); void bt_mesh_net_header_parse(struct os_mbuf *buf, struct bt_mesh_net_rx *rx); - +void bt_mesh_net_pending_net_store(void); +void bt_mesh_net_pending_iv_store(void); +void bt_mesh_net_pending_seq_store(void); +void bt_mesh_net_clear(void); +void bt_mesh_net_settings_commit(void); static inline void send_cb_finalize(const struct bt_mesh_send_cb *cb, void *cb_data) diff --git a/nimble/host/mesh/src/pb_adv.c b/nimble/host/mesh/src/pb_adv.c index 653ec03fa9..76b96ae365 100644 --- a/nimble/host/mesh/src/pb_adv.c +++ b/nimble/host/mesh/src/pb_adv.c @@ -8,7 +8,9 @@ */ #include "syscfg/syscfg.h" -#define MESH_LOG_MODULE BLE_MESH_PROV_LOG + +#define BLE_NPL_LOG_MODULE BLE_MESH_PROV_LOG +#include #include #include @@ -20,7 +22,6 @@ #include "adv.h" #include "crypto.h" #include "beacon.h" -#include "prov.h" #include "mesh/glue.h" #define GPCF(gpc) (gpc & 0x03) @@ -31,6 +32,7 @@ #define START_PAYLOAD_MAX 20 #define CONT_PAYLOAD_MAX 23 +#define RX_BUFFER_MAX 65 #define START_LAST_SEG(gpc) (gpc >> 2) #define CONT_SEG_INDEX(gpc) (gpc >> 2) @@ -40,7 +42,8 @@ #define LINK_ACK 0x01 #define LINK_CLOSE 0x02 -#define XACT_SEG_DATA(_seg) (&link.rx.buf->om_data[20 + ((_seg - 1) * 23)]) +#define XACT_SEG_OFFSET(_seg) (20 + ((_seg - 1) * 23)) +#define XACT_SEG_DATA(_seg) (&link.rx.buf->om_data[XACT_SEG_OFFSET(_seg)]) #define XACT_SEG_RECV(_seg) (link.rx.seg &= ~(1 << (_seg))) #define XACT_ID_MAX 0x7f @@ -55,10 +58,10 @@ /* Acked messages, will do retransmissions manually, taking acks into account: */ #define RETRANSMITS_RELIABLE 0 -/* Unacked messages: */ -#define RETRANSMITS_UNRELIABLE 2 /* PDU acks: */ #define RETRANSMITS_ACK 2 +/* Link close retransmits: */ +#define RETRANSMITS_LINK_CLOSE 2 enum { ADV_LINK_ACTIVE, /* Link has been opened */ @@ -105,11 +108,11 @@ struct pb_adv { void *cb_data; /* Retransmit timer */ - struct k_delayed_work retransmit; + struct k_work_delayable retransmit; } tx; /* Protocol timeout */ - struct k_delayed_work prot_timer; + struct k_work_delayable prot_timer; }; struct prov_rx { @@ -126,20 +129,27 @@ static void link_open(struct prov_rx *rx, struct os_mbuf *buf); static void link_ack(struct prov_rx *rx, struct os_mbuf *buf); static void link_close(struct prov_rx *rx, struct os_mbuf *buf); static void prov_link_close(enum prov_bearer_link_status status); +static void close_link(enum prov_bearer_link_status status); static void buf_sent(int err, void *user_data) { BT_DBG("buf_send"); - if (!link.tx.buf[0]) { + if (atomic_test_and_clear_bit(link.flags, ADV_LINK_CLOSING)) { + close_link(PROV_BEARER_LINK_STATUS_SUCCESS); return; } +} - BT_DBG("submit retransmit"); - k_delayed_work_submit(&link.tx.retransmit, RETRANSMIT_TIMEOUT); +static void buf_start(uint16_t duration, int err, void *user_data) +{ + if (err) { + buf_sent(err, user_data); + } } static struct bt_mesh_send_cb buf_sent_cb = { + .start = buf_start, .end = buf_sent, }; @@ -181,7 +191,12 @@ static void prov_clear_tx(void) { BT_DBG(""); - k_delayed_work_cancel(&link.tx.retransmit); + /* If this fails, the work handler will not find any buffers to send, + * and return without rescheduling. The work handler also checks the + * LINK_ACTIVE flag, so if this call is part of reset_adv_link, it'll + * exit early. + */ + (void)k_work_cancel_delayable(&link.tx.retransmit); free_segments(); } @@ -191,7 +206,10 @@ static void reset_adv_link(void) BT_DBG(""); prov_clear_tx(); - k_delayed_work_cancel(&link.prot_timer); + /* If this fails, the work handler will exit early on the LINK_ACTIVE + * check. + */ + (void)k_work_cancel_delayable(&link.prot_timer); if (atomic_test_bit(link.flags, ADV_PROVISIONER)) { /* Clear everything except the retransmit and protocol timer @@ -208,7 +226,7 @@ static void reset_adv_link(void) } link.tx.pending_ack = XACT_ID_NVAL; if (!rx_buf) { - rx_buf = NET_BUF_SIMPLE(65); + rx_buf = NET_BUF_SIMPLE(RX_BUFFER_MAX); } link.rx.buf = rx_buf; net_buf_simple_reset(link.rx.buf); @@ -258,7 +276,7 @@ static void prov_failed(uint8_t err) static void prov_msg_recv(void) { - k_delayed_work_submit(&link.prot_timer, PROTOCOL_TIMEOUT); + k_work_reschedule(&link.prot_timer, PROTOCOL_TIMEOUT); if (!bt_mesh_fcs_check(link.rx.buf, link.rx.fcs)) { BT_ERR("Incorrect FCS"); @@ -279,6 +297,10 @@ static void prov_msg_recv(void) static void protocol_timeout(struct ble_npl_event *work) { + if (!atomic_test_bit(link.flags, ADV_LINK_ACTIVE)) { + return; + } + BT_DBG(""); link.rx.seg = 0U; @@ -368,6 +390,11 @@ static void gen_prov_cont(struct prov_rx *rx, struct os_mbuf *buf) return; } + if (XACT_SEG_OFFSET(seg) + buf->om_len > RX_BUFFER_MAX) { + BT_WARN("Rx buffer overflow. Malformed generic prov frame?"); + return; + } + memcpy(XACT_SEG_DATA(seg), buf->om_data, buf->om_len); XACT_SEG_RECV(seg); @@ -544,8 +571,6 @@ static void send_reliable(void) { int i; - link.tx.start = k_uptime_get(); - for (i = 0; i < ARRAY_SIZE(link.tx.buf); i++) { struct os_mbuf *buf = link.tx.buf[i]; @@ -553,19 +578,20 @@ static void send_reliable(void) break; } - if (i + 1 < ARRAY_SIZE(link.tx.buf) && link.tx.buf[i + 1]) { - bt_mesh_adv_send(buf, NULL, NULL); - } else { - bt_mesh_adv_send(buf, &buf_sent_cb, NULL); + if (BT_MESH_ADV(buf)->busy) { + continue; } + + BT_DBG("%u bytes: %s", buf->om_len, bt_hex(buf->om_data, buf->om_len)); + + bt_mesh_adv_send(buf, NULL, NULL); } + + k_work_reschedule(&link.tx.retransmit, RETRANSMIT_TIMEOUT); } static void prov_retransmit(struct ble_npl_event *work) { - int32_t timeout_ms; - int i; - BT_DBG(""); if (!atomic_test_bit(link.flags, ADV_LINK_ACTIVE)) { @@ -573,63 +599,25 @@ static void prov_retransmit(struct ble_npl_event *work) return; } - /* - * According to mesh profile spec (5.3.1.4.3), the close message should - * be restransmitted at least three times. Retransmit the link_close - * message until CLOSING_TIMEOUT has elapsed. - */ - if (atomic_test_bit(link.flags, ADV_LINK_CLOSING)) { - timeout_ms = CLOSING_TIMEOUT; - } else { - timeout_ms = TRANSACTION_TIMEOUT; - } - - if (k_uptime_get() - link.tx.start > timeout_ms) { - if (atomic_test_bit(link.flags, ADV_LINK_CLOSING)) { - close_link(PROV_BEARER_LINK_STATUS_SUCCESS); - } else { - BT_WARN("Giving up transaction"); - close_link(PROV_BEARER_LINK_STATUS_TIMEOUT); - } - + if (k_uptime_get() - link.tx.start > TRANSACTION_TIMEOUT) { + BT_WARN("Giving up transaction"); + prov_link_close(PROV_BEARER_LINK_STATUS_FAIL); return; } - for (i = 0; i < ARRAY_SIZE(link.tx.buf); i++) { - struct os_mbuf *buf = link.tx.buf[i]; - - if (!buf) { - break; - } - - if (BT_MESH_ADV(buf)->busy) { - continue; - } - - BT_DBG("%u bytes: %s", buf->om_len, bt_hex(buf->om_data, buf->om_len)); - - if (i + 1 < ARRAY_SIZE(link.tx.buf) && link.tx.buf[i + 1]) { - bt_mesh_adv_send(buf, NULL, NULL); - } else { - bt_mesh_adv_send(buf, &buf_sent_cb, NULL); - } - } + send_reliable(); } -static int bearer_ctl_send(uint8_t op, const void *data, uint8_t data_len, - bool reliable) +static struct os_mbuf *ctl_buf_create(uint8_t op, const void *data, uint8_t data_len, + uint8_t retransmits) { struct os_mbuf *buf; BT_DBG("op 0x%02x data_len %u", op, data_len); - prov_clear_tx(); - k_delayed_work_submit(&link.prot_timer, PROTOCOL_TIMEOUT); - - buf = adv_buf_create(reliable ? RETRANSMITS_RELIABLE : - RETRANSMITS_UNRELIABLE); + buf = adv_buf_create(retransmits); if (!buf) { - return -ENOBUFS; + return NULL; } net_buf_add_be32(buf, link.id); @@ -637,15 +625,35 @@ static int bearer_ctl_send(uint8_t op, const void *data, uint8_t data_len, net_buf_add_u8(buf, 0x00); net_buf_add_u8(buf, GPC_CTL(op)); net_buf_add_mem(buf, data, data_len); + return buf; +} - if (reliable) { - link.tx.buf[0] = buf; - send_reliable(); - } else { - bt_mesh_adv_send(buf, &buf_sent_cb, NULL); - net_buf_unref(buf); +static int bearer_ctl_send(struct os_mbuf *buf) +{ + if (!buf) { + return -ENOMEM; + } + prov_clear_tx(); + k_work_reschedule(&link.prot_timer, PROTOCOL_TIMEOUT); + + link.tx.start = k_uptime_get(); + link.tx.buf[0] = buf; + send_reliable(); + + return 0; + } + +static int bearer_ctl_send_unacked(struct os_mbuf *buf) +{ + if (!buf) { + return -ENOMEM; } + prov_clear_tx(); + k_work_reschedule(&link.prot_timer, PROTOCOL_TIMEOUT); + + bt_mesh_adv_send(buf, &buf_sent_cb, NULL); + net_buf_unref(buf); return 0; } @@ -656,7 +664,7 @@ static int prov_send_adv(struct os_mbuf *msg, uint8_t seg_len, seg_id; prov_clear_tx(); - k_delayed_work_submit(&link.prot_timer, PROTOCOL_TIMEOUT); + k_work_reschedule(&link.prot_timer, PROTOCOL_TIMEOUT); start = adv_buf_create(RETRANSMITS_RELIABLE); if (!start) { @@ -674,6 +682,7 @@ static int prov_send_adv(struct os_mbuf *msg, link.tx.buf[0] = start; link.tx.cb = cb; link.tx.cb_data = cb_data; + link.tx.start = k_uptime_get(); BT_DBG("xact_id: 0x%x len: %u", link.tx.id, msg->om_len); @@ -721,6 +730,8 @@ static int prov_send_adv(struct os_mbuf *msg, static void link_open(struct prov_rx *rx, struct os_mbuf *buf) { + int err; + BT_DBG("len %u", buf->om_len); if (buf->om_len < 16) { @@ -730,13 +741,14 @@ static void link_open(struct prov_rx *rx, struct os_mbuf *buf) if (atomic_test_bit(link.flags, ADV_LINK_ACTIVE)) { /* Send another link ack if the provisioner missed the last */ - if (link.id == rx->link_id) { - BT_DBG("Resending link ack"); - bearer_ctl_send(LINK_ACK, NULL, 0, false); - } else { + if (link.id != rx->link_id) { BT_DBG("Ignoring bearer open: link already active"); + return; } + BT_DBG("Resending link ack"); + /* Ignore errors, message will be attempted again if we keep receiving link open: */ + (void)bearer_ctl_send_unacked(ctl_buf_create(LINK_ACK, NULL, 0, RETRANSMITS_ACK)); return; } @@ -749,7 +761,11 @@ static void link_open(struct prov_rx *rx, struct os_mbuf *buf) atomic_set_bit(link.flags, ADV_LINK_ACTIVE); net_buf_simple_reset(link.rx.buf); - bearer_ctl_send(LINK_ACK, NULL, 0, false); + err = bearer_ctl_send_unacked(ctl_buf_create(LINK_ACK, NULL, 0, RETRANSMITS_ACK)); + if (err) { + reset_adv_link(); + return; + } link.cb->link_opened(&pb_adv, link.cb_data); } @@ -813,8 +829,16 @@ void bt_mesh_pb_adv_recv(struct os_mbuf *buf) static int prov_link_open(const uint8_t uuid[16], int32_t timeout, const struct prov_bearer_cb *cb, void *cb_data) { + int err; + BT_DBG("uuid %s", bt_hex(uuid, 16)); + err = bt_mesh_adv_enable(); + if (err) { + BT_ERR("Failed enabling advertiser"); + return err; + } + if (atomic_test_and_set_bit(link.flags, ADV_LINK_ACTIVE)) { return -EBUSY; } @@ -829,13 +853,19 @@ static int prov_link_open(const uint8_t uuid[16], int32_t timeout, net_buf_simple_reset(link.rx.buf); - bearer_ctl_send(LINK_OPEN, uuid, 16, true); - - return 0; + return bearer_ctl_send(ctl_buf_create(LINK_OPEN, uuid, 16, RETRANSMITS_RELIABLE)); } static int prov_link_accept(const struct prov_bearer_cb *cb, void *cb_data) { + int err; + + err = bt_mesh_adv_enable(); + if (err) { + BT_ERR("Failed enabling advertiser"); + return err; + } + if (atomic_test_bit(link.flags, ADV_LINK_ACTIVE)) { return -EBUSY; } @@ -845,7 +875,7 @@ static int prov_link_accept(const struct prov_bearer_cb *cb, void *cb_data) link.cb = cb; link.cb_data = cb_data; - /* Make sure we're scanning for provisioning inviations */ + /* Make sure we're scanning for provisioning invitations */ bt_mesh_scan_enable(); /* Enable unprovisioned beacon sending */ bt_mesh_beacon_enable(); @@ -859,16 +889,17 @@ static void prov_link_close(enum prov_bearer_link_status status) return; } - bearer_ctl_send(LINK_CLOSE, &status, 1, true); + /* Ignore errors, the link will time out eventually if this doesn't get sent */ + bearer_ctl_send_unacked(ctl_buf_create(LINK_CLOSE, &status, 1, RETRANSMITS_LINK_CLOSE)); } void pb_adv_init(void) { - k_delayed_work_init(&link.prot_timer, protocol_timeout); - k_delayed_work_init(&link.tx.retransmit, prov_retransmit); + k_work_init_delayable(&link.prot_timer, protocol_timeout); + k_work_init_delayable(&link.tx.retransmit, prov_retransmit); if (!rx_buf) { - rx_buf = NET_BUF_SIMPLE(65); + rx_buf = NET_BUF_SIMPLE(RX_BUFFER_MAX); } link.rx.buf = rx_buf; net_buf_simple_reset(link.rx.buf); diff --git a/nimble/host/mesh/src/pb_gatt.c b/nimble/host/mesh/src/pb_gatt.c index bce7cf6c09..ddf8ed7363 100644 --- a/nimble/host/mesh/src/pb_gatt.c +++ b/nimble/host/mesh/src/pb_gatt.c @@ -6,28 +6,37 @@ * * SPDX-License-Identifier: Apache-2.0 */ -#define MESH_LOG_MODULE BLE_MESH_PROV_LOG + +#define BLE_NPL_LOG_MODULE BLE_MESH_PROV_LOG +#include #include "mesh/mesh.h" #include "prov.h" #include "net.h" #include "proxy.h" #include "adv.h" -#include "prov.h" +#include "syscfg/syscfg.h" +#include "pb_gatt_srv.h" + +#if MYNEWT_VAL(BLE_MESH_PB_GATT) +struct prov_bearer_send_cb { + prov_bearer_send_complete_t cb; + void *cb_data; +}; struct prov_link { uint16_t conn_handle; const struct prov_bearer_cb *cb; void *cb_data; + struct prov_bearer_send_cb comp; struct { uint8_t id; /* Transaction ID */ uint8_t prev_id; /* Previous Transaction ID */ uint8_t seg; /* Bit-field of unreceived segments */ uint8_t last_seg; /* Last segment (to check length) */ uint8_t fcs; /* Expected FCS value */ - struct os_mbuf *buf; } rx; - struct k_delayed_work prot_timer; + struct k_work_delayable prot_timer; }; static struct prov_link link; @@ -36,9 +45,8 @@ static void reset_state(void) { link.conn_handle = BLE_HS_CONN_HANDLE_NONE; - k_delayed_work_cancel(&link.prot_timer); - - link.rx.buf = bt_mesh_proxy_get_buf(); + /* If this fails, the protocol timeout handler will exit early. */ + (void)k_work_cancel_delayable(&link.prot_timer); } static void link_closed(enum prov_bearer_link_status status) @@ -54,6 +62,11 @@ static void link_closed(enum prov_bearer_link_status status) static void protocol_timeout(struct ble_npl_event *work) { + if (!link.conn_handle) { + /* Already disconnected */ + return; + } + BT_DBG("Protocol timeout"); link_closed(PROV_BEARER_LINK_STATUS_TIMEOUT); @@ -73,7 +86,7 @@ int bt_mesh_pb_gatt_recv(uint16_t conn_handle, struct os_mbuf *buf) return -EINVAL; } - k_delayed_work_submit(&link.prot_timer, PROTOCOL_TIMEOUT); + k_work_reschedule(&link.prot_timer, PROTOCOL_TIMEOUT); link.cb->recv(&pb_gatt, link.cb_data, buf); @@ -89,7 +102,7 @@ int bt_mesh_pb_gatt_open(uint16_t conn_handle) } link.conn_handle = conn_handle; - k_delayed_work_submit(&link.prot_timer, PROTOCOL_TIMEOUT); + k_work_reschedule(&link.prot_timer, PROTOCOL_TIMEOUT); link.cb->link_opened(&pb_gatt, link.cb_data); @@ -115,7 +128,7 @@ int bt_mesh_pb_gatt_close(uint16_t conn_handle) static int link_accept(const struct prov_bearer_cb *cb, void *cb_data) { - (void)bt_mesh_proxy_prov_enable(); + (void)bt_mesh_pb_gatt_enable(); bt_mesh_adv_update(); link.cb = cb; @@ -131,9 +144,12 @@ static int buf_send(struct os_mbuf *buf, prov_bearer_send_complete_t cb, return -ENOTCONN; } - k_delayed_work_submit(&link.prot_timer, PROTOCOL_TIMEOUT); + link.comp.cb = cb; + link.comp.cb_data = cb_data; - return bt_mesh_proxy_send(link.conn_handle, BT_MESH_PROXY_PROV, buf); + k_work_reschedule(&link.prot_timer, PROTOCOL_TIMEOUT); + + return bt_mesh_pb_gatt_send(link.conn_handle, buf); } static void clear_tx(void) @@ -143,7 +159,7 @@ static void clear_tx(void) void pb_gatt_init(void) { - k_delayed_work_init(&link.prot_timer, protocol_timeout); + k_work_init_delayable(&link.prot_timer, protocol_timeout); } void pb_gatt_reset(void) @@ -155,4 +171,5 @@ const struct prov_bearer pb_gatt = { .link_accept = link_accept, .send = buf_send, .clear_tx = clear_tx, -}; \ No newline at end of file +}; +#endif diff --git a/nimble/host/mesh/src/pb_gatt_srv.c b/nimble/host/mesh/src/pb_gatt_srv.c new file mode 100644 index 0000000000..2aecec0ced --- /dev/null +++ b/nimble/host/mesh/src/pb_gatt_srv.c @@ -0,0 +1,466 @@ +/* + * Copyright (c) 2017 Intel Corporation + * Copyright (c) 2021 Lingao Meng + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define BLE_NPL_LOG_MODULE BLE_MESH_PROV_LOG +#include + +#include "mesh_priv.h" +#include "adv.h" +#include "net.h" +#include "rpl.h" +#include "transport.h" +#include "prov.h" +#include "beacon.h" +#include "foundation.h" +#include "access.h" +#include "proxy.h" +#include "proxy_msg.h" +#include "pb_gatt_srv.h" +#include "syscfg/syscfg.h" +#include "services/gatt/ble_svc_gatt.h" +#include "../../host/src/ble_hs_priv.h" + +#if defined(CONFIG_BT_MESH_PB_GATT_USE_DEVICE_NAME) +#define ADV_OPT_USE_NAME BT_LE_ADV_OPT_USE_NAME +#else +#define ADV_OPT_USE_NAME 0 +#endif + +#define ADV_OPT_PROV \ +.conn_mode = (BLE_GAP_CONN_MODE_UND), \ +.disc_mode = (BLE_GAP_DISC_MODE_GEN), + +#if MYNEWT_VAL(BLE_MESH_PB_GATT) +/** @def BT_UUID_MESH_PROV + * @brief Mesh Provisioning Service + */ +ble_uuid16_t BT_UUID_MESH_PROV = BLE_UUID16_INIT(0x1827); +#define BT_UUID_MESH_PROV_VAL 0x1827 +/** @def BT_UUID_MESH_PROXY + * @brief Mesh Proxy Service + */ +ble_uuid16_t BT_UUID_MESH_PROXY = BLE_UUID16_INIT(0x1828); +#define BT_UUID_MESH_PROXY_VAL 0x1828 +/** @def BT_UUID_GATT_CCC + * @brief GATT Client Characteristic Configuration + */ +ble_uuid16_t BT_UUID_GATT_CCC = BLE_UUID16_INIT(0x2902); +#define BT_UUID_GATT_CCC_VAL 0x2902 +/** @def BT_UUID_MESH_PROV_DATA_IN + * @brief Mesh Provisioning Data In + */ +ble_uuid16_t BT_UUID_MESH_PROV_DATA_IN = BLE_UUID16_INIT(0x2adb); +#define BT_UUID_MESH_PROV_DATA_IN_VAL 0x2adb +/** @def BT_UUID_MESH_PROV_DATA_OUT + * @brief Mesh Provisioning Data Out + */ +ble_uuid16_t BT_UUID_MESH_PROV_DATA_OUT = BLE_UUID16_INIT(0x2adc); +#define BT_UUID_MESH_PROV_DATA_OUT_VAL 0x2adc +/** @def BT_UUID_MESH_PROXY_DATA_IN + * @brief Mesh Proxy Data In + */ +ble_uuid16_t BT_UUID_MESH_PROXY_DATA_IN = BLE_UUID16_INIT(0x2add); +#define BT_UUID_MESH_PROXY_DATA_IN_VAL 0x2add +/** @def BT_UUID_MESH_PROXY_DATA_OUT + * @brief Mesh Proxy Data Out + */ +ble_uuid16_t BT_UUID_MESH_PROXY_DATA_OUT = BLE_UUID16_INIT(0x2ade); +#define BT_UUID_MESH_PROXY_DATA_OUT_VAL 0x2ade +#define BT_UUID_16_ENCODE(w16) \ + (((w16) >> 0) & 0xFF), \ + (((w16) >> 8) & 0xFF) + +static bool prov_fast_adv; + +struct svc_handles svc_handles; +static atomic_t pending_notifications; + +static int gatt_send(uint16_t conn_handle, + const void *data, uint16_t len); + +static struct bt_mesh_proxy_role *cli; + +static void proxy_msg_recv(struct bt_mesh_proxy_role *role) +{ + switch (role->msg_type) { + case BT_MESH_PROXY_PROV: + BT_DBG("Mesh Provisioning PDU"); + bt_mesh_pb_gatt_recv(role->conn_handle, role->buf); + break; + default: + BT_WARN("Unhandled Message Type 0x%02x", role->msg_type); + break; + } +} + +static bool service_registered; + +static int gatt_recv_proxy(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, void *arg) +{ + const uint8_t *data = ctxt->om->om_data; + uint16_t len = ctxt->om->om_len; + struct bt_mesh_proxy_client *client = find_client(conn_handle); + + if (len < 1) { + BT_WARN("Too small Proxy PDU"); + return -EINVAL; + } + + if (PDU_TYPE(data) == BT_MESH_PROXY_PROV) { + BT_WARN("Proxy PDU type doesn't match GATT service"); + return -EINVAL; + } + + return bt_mesh_proxy_msg_recv(client->cli, data, len); +} + +static int gatt_recv_prov(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, void *arg) +{ + const uint8_t *data = ctxt->om->om_data; + uint16_t len = ctxt->om->om_len; + + if (conn_handle != cli->conn_handle) { + BT_WARN("conn_handle != cli->conn_handle"); + return -ENOTCONN; + } + + if (len < 1) { + BT_WARN("Too small Proxy PDU"); + return -EINVAL; + } + + if (PDU_TYPE(data) != BT_MESH_PROXY_PROV) { + BT_WARN("Proxy PDU type doesn't match GATT service"); + return -EINVAL; + } + + return bt_mesh_proxy_msg_recv(cli, data, len); +} + +void gatt_connected_pb_gatt(uint16_t conn_handle, uint8_t err) +{ + struct ble_gap_conn_desc info; + struct ble_hs_conn *conn; + + conn = ble_hs_conn_find(conn_handle); + bt_conn_get_info(conn, &info); + if (info.role != BLE_GAP_ROLE_SLAVE || + !service_registered || bt_mesh_is_provisioned()) { + return; + } + + cli = bt_mesh_proxy_role_setup(conn_handle, gatt_send, proxy_msg_recv); + + BT_DBG("conn %p err 0x%02x", (void *)conn, err); +} + +void gatt_disconnected_pb_gatt(struct ble_gap_conn_desc conn, uint8_t reason) +{ + if (conn.role != BLE_GAP_ROLE_SLAVE || + !service_registered) { + return; + } + + if (cli) { + bt_mesh_proxy_role_cleanup(cli); + cli = NULL; + } + + BT_DBG("conn_handle %d reason 0x%02x", conn.conn_handle, reason); + + bt_mesh_pb_gatt_close(conn.conn_handle); + + if (bt_mesh_is_provisioned()) { + (void)bt_mesh_pb_gatt_disable(); + } +} + +int prov_ccc_write(uint16_t conn_handle, uint8_t type) +{ + if (cli->conn_handle != conn_handle) { + BT_ERR("No PB-GATT Client found"); + return -ENOTCONN; + } + + if (type != BLE_GAP_EVENT_SUBSCRIBE) { + BT_WARN("Client wrote instead enabling notify"); + return BT_GATT_ERR(EINVAL); + } + + bt_mesh_pb_gatt_open(conn_handle); + + return 0; +} + +/* Mesh Provisioning Service Declaration */ + +static int +dummy_access_cb(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, void *arg) +{ + /* + * We should never never enter this callback - it's attached to notify-only + * characteristic which are notified directly from mbuf. And we can't pass + * NULL as access_cb because gatts will assert on init... + */ + BLE_HS_DBG_ASSERT(0); + return 0; +} + +static const struct ble_gatt_svc_def svc_defs [] = { + { + .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid = BLE_UUID16_DECLARE(BT_UUID_MESH_PROXY_VAL), + .characteristics = (struct ble_gatt_chr_def[]) { { + .uuid = BLE_UUID16_DECLARE(BT_UUID_MESH_PROXY_DATA_IN_VAL), + .access_cb = gatt_recv_proxy, + .flags = BLE_GATT_CHR_F_WRITE_NO_RSP, + }, { + .uuid = BLE_UUID16_DECLARE(BT_UUID_MESH_PROXY_DATA_OUT_VAL), + .access_cb = dummy_access_cb, + .flags = BLE_GATT_CHR_F_NOTIFY, + }, { + 0, /* No more characteristics in this service. */ + } }, + }, { + .type = BLE_GATT_SVC_TYPE_PRIMARY, + .uuid = BLE_UUID16_DECLARE(BT_UUID_MESH_PROV_VAL), + .characteristics = (struct ble_gatt_chr_def[]) { { + .uuid = BLE_UUID16_DECLARE(BT_UUID_MESH_PROV_DATA_IN_VAL), + .access_cb = gatt_recv_prov, + .flags = BLE_GATT_CHR_F_WRITE_NO_RSP, + }, { + .uuid = BLE_UUID16_DECLARE(BT_UUID_MESH_PROV_DATA_OUT_VAL), + .access_cb = dummy_access_cb, + .flags = BLE_GATT_CHR_F_NOTIFY, + }, { + 0, /* No more characteristics in this service. */ + } }, + }, { + 0, /* No more services. */ + }, +}; + +void resolve_svc_handles(void) +{ + int rc; + + /* Either all handles are already resolved, or none of them */ + if (svc_handles.prov_data_out_h) { + return; + } + + /* + * We assert if attribute is not found since at this stage all attributes + * shall be already registered and thus shall be found. + */ + + rc = ble_gatts_find_svc(BLE_UUID16_DECLARE(BT_UUID_MESH_PROXY_VAL), + &svc_handles.proxy_h); + assert(rc == 0); + + rc = ble_gatts_find_chr(BLE_UUID16_DECLARE(BT_UUID_MESH_PROXY_VAL), + BLE_UUID16_DECLARE(BT_UUID_MESH_PROXY_DATA_OUT_VAL), + NULL, &svc_handles.proxy_data_out_h); + assert(rc == 0); + + rc = ble_gatts_find_svc(BLE_UUID16_DECLARE(BT_UUID_MESH_PROV_VAL), + &svc_handles.prov_h); + assert(rc == 0); + + rc = ble_gatts_find_chr(BLE_UUID16_DECLARE(BT_UUID_MESH_PROV_VAL), + BLE_UUID16_DECLARE(BT_UUID_MESH_PROV_DATA_IN_VAL), + NULL, &svc_handles.prov_data_in_h); + assert(rc == 0); + + rc = ble_gatts_find_chr(BLE_UUID16_DECLARE(BT_UUID_MESH_PROV_VAL), + BLE_UUID16_DECLARE(BT_UUID_MESH_PROV_DATA_OUT_VAL), + NULL, &svc_handles.prov_data_out_h); + assert(rc == 0); +} + + +int bt_mesh_proxy_svcs_register(void) +{ + int rc; + + rc = ble_gatts_count_cfg(svc_defs); + assert(rc == 0); + + rc = ble_gatts_add_svcs(svc_defs); + assert(rc == 0); + + return 0; +} + +int bt_mesh_pb_gatt_enable(void) +{ + int rc; + uint16_t handle; + BT_DBG(""); + + if (bt_mesh_is_provisioned()) { + return -ENOTSUP; + } + + if (service_registered) { + return -EBUSY; + } + + rc = ble_gatts_find_svc(BLE_UUID16_DECLARE(BT_UUID_MESH_PROV_VAL), &handle); + assert(rc == 0); + ble_gatts_svc_set_visibility(handle, 1); + /* FIXME: figure out end handle */ + ble_svc_gatt_changed(svc_handles.prov_h, 0xffff); + + service_registered = true; + prov_fast_adv = true; + + return 0; +} + +int bt_mesh_pb_gatt_disable(void) +{ + uint16_t handle; + int rc; + + BT_DBG(""); + + if (!service_registered) { + return -EALREADY; + } + + rc = ble_gatts_find_svc(BLE_UUID16_DECLARE(BT_UUID_MESH_PROV_VAL), &handle); + assert(rc == 0); + ble_gatts_svc_set_visibility(handle, 0); + /* FIXME: figure out end handle */ + ble_svc_gatt_changed(svc_handles.prov_h, 0xffff); + service_registered = false; + + bt_mesh_adv_update(); + + return 0; +} + +static uint8_t prov_svc_data[20] = { + BT_UUID_16_ENCODE(BT_UUID_MESH_PROV_VAL), +}; + +static const struct bt_data prov_ad[] = { + BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)), + BT_DATA_BYTES(BT_DATA_UUID16_ALL, + BT_UUID_16_ENCODE(BT_UUID_MESH_PROV_VAL)), + BT_DATA(BT_DATA_SVC_DATA16, prov_svc_data, sizeof(prov_svc_data)), +}; + +int bt_mesh_pb_gatt_send(uint16_t conn_handle, struct os_mbuf *buf) +{ + if (!cli || cli->conn_handle != conn_handle) { + BT_ERR("No PB-GATT Client found"); + return -ENOTCONN; + } + + return bt_mesh_proxy_msg_send(cli, BT_MESH_PROXY_PROV, buf); +} + +static size_t gatt_prov_adv_create(struct bt_data prov_sd[1]) +{ + const struct bt_mesh_prov *prov = bt_mesh_prov_get(); + size_t uri_len; + + memcpy(prov_svc_data + 2, prov->uuid, 16); + sys_put_be16(prov->oob_info, prov_svc_data + 18); + + if (!prov->uri) { + return 0; + } + + uri_len = strlen(prov->uri); + if (uri_len > 29) { + /* There's no way to shorten an URI */ + BT_WARN("Too long URI to fit advertising packet"); + return 0; + } + + prov_sd[0].type = BT_DATA_URI; + prov_sd[0].data_len = uri_len; + prov_sd[0].data = (const uint8_t *)prov->uri; + + return 1; +} + +static int gatt_send(uint16_t conn_handle, + const void *data, uint16_t len) +{ + struct os_mbuf *om; + int err = 0; + + BT_DBG("%u bytes: %s", len, bt_hex(data, len)); + om = ble_hs_mbuf_from_flat(data, len); + assert(om); + err = ble_gatts_notify_custom(conn_handle, svc_handles.prov_data_out_h, om); + notify_complete(); + + if (!err) { + atomic_inc(&pending_notifications); + } + + return err; +} + +int bt_mesh_pb_gatt_adv_start(void) +{ + BT_DBG(""); + + if (!service_registered || bt_mesh_is_provisioned()) { + return -ENOTSUP; + } + + struct ble_gap_adv_params fast_adv_param = { + ADV_OPT_PROV + ADV_FAST_INT + }; +#if ADV_OPT_USE_NAME + const char *name = CONFIG_BT_DEVICE_NAME; + size_t name_len = strlen(name); + struct bt_data prov_sd = { + .type = BT_DATA_NAME_COMPLETE, + .data_len = name_len, + .data = (void *)name + }; +#else + struct bt_data *prov_sd = NULL; +#endif + + size_t prov_sd_len; + int err; + + prov_sd_len = gatt_prov_adv_create(prov_sd); + + if (!prov_fast_adv) { + struct ble_gap_adv_params slow_adv_param = { + ADV_OPT_PROV + ADV_SLOW_INT + }; + + return bt_mesh_adv_start(&slow_adv_param, K_FOREVER, prov_ad, + ARRAY_SIZE(prov_ad), prov_sd, prov_sd_len); + } + + /* Advertise 60 seconds using fast interval */ + err = bt_mesh_adv_start(&fast_adv_param, (60 * MSEC_PER_SEC), + prov_ad, ARRAY_SIZE(prov_ad), + prov_sd, prov_sd_len); + if (!err) { + prov_fast_adv = false; + } + + return err; +} +#endif diff --git a/nimble/host/mesh/src/pb_gatt_srv.h b/nimble/host/mesh/src/pb_gatt_srv.h new file mode 100644 index 0000000000..d143392635 --- /dev/null +++ b/nimble/host/mesh/src/pb_gatt_srv.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2017 Intel Corporation + * Copyright (c) 2021 Lingao Meng + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __PB_GATT_SRV_H__ +#define __PB_GATT_SRV_H__ + +int bt_mesh_pb_gatt_send(uint16_t conn_handle, struct os_mbuf *buf); + +int bt_mesh_pb_gatt_enable(void); +int bt_mesh_pb_gatt_disable(void); + +int prov_ccc_write(uint16_t conn_handle, uint8_t type); +void gatt_disconnected_pb_gatt(struct ble_gap_conn_desc conn, uint8_t err); +void gatt_connected_pb_gatt(uint16_t conn_handle, uint8_t err); +void resolve_svc_handles(void); + +int bt_mesh_pb_gatt_adv_start(void); + +extern struct svc_handles { + uint16_t proxy_h; + uint16_t proxy_data_out_h; + uint16_t prov_h; + uint16_t prov_data_in_h; + uint16_t prov_data_out_h; +} svc_handles; + +#endif /* __PB_GATT_SRV_H__ */ diff --git a/nimble/host/mesh/src/prov.c b/nimble/host/mesh/src/prov.c index 170fc1d099..730061bb1b 100644 --- a/nimble/host/mesh/src/prov.c +++ b/nimble/host/mesh/src/prov.c @@ -7,7 +7,9 @@ */ #include "syscfg/syscfg.h" -#define MESH_LOG_MODULE BLE_MESH_PROV_LOG + +#define BLE_NPL_LOG_MODULE BLE_MESH_PROV_LOG +#include #include @@ -25,6 +27,10 @@ struct bt_mesh_prov_link bt_mesh_prov_link; const struct bt_mesh_prov *bt_mesh_prov; +/* Verify specification defined length: */ +BUILD_ASSERT(sizeof(bt_mesh_prov_link.conf_inputs) == 145, + "Confirmation inputs shall be 145 bytes"); + static void pub_key_ready(const uint8_t *pkey) { if (!pkey) { @@ -34,7 +40,7 @@ static void pub_key_ready(const uint8_t *pkey) BT_DBG("Local public key ready"); } -int bt_mesh_prov_reset_state(void (*func)(const uint8_t key[64])) +int bt_mesh_prov_reset_state(void (*func)(const uint8_t key[BT_PUB_KEY_LEN])) { BT_DBG("bt_mesh_prov_reset_state"); @@ -45,7 +51,7 @@ int bt_mesh_prov_reset_state(void (*func)(const uint8_t key[64])) pub_key_cb.func = func ? func : pub_key_ready; /* Disable Attention Timer if it was set */ - if (bt_mesh_prov_link.conf_inputs[0]) { + if (bt_mesh_prov_link.conf_inputs.invite[0]) { bt_mesh_attention(NULL, 0); } @@ -95,10 +101,98 @@ static bt_mesh_input_action_t input_action(uint8_t action) } } -int bt_mesh_prov_auth(uint8_t method, uint8_t action, uint8_t size) +static int check_output_auth(bt_mesh_output_action_t output, uint8_t size) +{ + if (!output) { + return -EINVAL; + } + + if (!(bt_mesh_prov->output_actions & output)) { + return -EINVAL; + } + + if (size > bt_mesh_prov->output_size) { + return -EINVAL; + } + + return 0; +} + +static int check_input_auth(bt_mesh_input_action_t input, uint8_t size) +{ + if (!input) { + return -EINVAL; + } + + if (!(bt_mesh_prov->input_actions & input)) { + return -EINVAL; + } + + if (size > bt_mesh_prov->input_size) { + return -EINVAL; + } + + return 0; +} + +static void get_auth_string(char *str, uint8_t size) +{ + uint64_t value; + + bt_rand(&value, sizeof(value)); + + static const char characters[36] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + for (int i = 0; i < size; i++) { + /* pull base-36 digits: */ + int idx = value % 36; + + value = value / 36; + str[i] = characters[idx]; + } + + str[size] = '\0'; + + memcpy(bt_mesh_prov_link.auth, str, size); + memset(bt_mesh_prov_link.auth + size, 0, + sizeof(bt_mesh_prov_link.auth) - size); +} + +static uint32_t get_auth_number(bt_mesh_output_action_t output, + bt_mesh_input_action_t input, uint8_t size) + { + const uint32_t divider[PROV_IO_OOB_SIZE_MAX] = { 10, 100, 1000, 10000, + 100000, 1000000, 10000000, 100000000 }; + uint32_t num = 0; + + bt_rand(&num, sizeof(num)); + + if (output == BT_MESH_BLINK || + output == BT_MESH_BEEP || + output == BT_MESH_VIBRATE || + input == BT_MESH_PUSH || + input == BT_MESH_TWIST) { + /* According to the Bluetooth Mesh Profile + * Specification Section 5.4.2.4, blink, beep + * vibrate, push and twist should be a random integer + * between 0 and 10^size, *exclusive*: + */ + num = (num % (divider[size - 1] - 1)) + 1; + } else { + num %= divider[size - 1]; + } + + sys_put_be32(num, &bt_mesh_prov_link.auth[12]); + memset(bt_mesh_prov_link.auth, 0, 12); + + return num; + } + +int bt_mesh_prov_auth(bool is_provisioner, uint8_t method, uint8_t action, uint8_t size) { bt_mesh_output_action_t output; bt_mesh_input_action_t input; + int err; switch (method) { case AUTH_METHOD_NO_OOB: @@ -119,77 +213,63 @@ int bt_mesh_prov_auth(uint8_t method, uint8_t action, uint8_t size) case AUTH_METHOD_OUTPUT: output = output_action(action); - if (!output) { - return -EINVAL; - } + if (is_provisioner) { + if (output == BT_MESH_DISPLAY_STRING) { + input = BT_MESH_ENTER_STRING; + atomic_set_bit(bt_mesh_prov_link.flags, WAIT_STRING); + } else { + input = BT_MESH_ENTER_NUMBER; + atomic_set_bit(bt_mesh_prov_link.flags, WAIT_NUMBER); + } - if (!(bt_mesh_prov->output_actions & output)) { - return -EINVAL; + return bt_mesh_prov->input(input, size); } - if (size > bt_mesh_prov->output_size) { - return -EINVAL; + err = check_output_auth(output, size); + if (err) { + return err; } - atomic_set_bit(bt_mesh_prov_link.flags, NOTIFY_INPUT_COMPLETE); - if (output == BT_MESH_DISPLAY_STRING) { - unsigned char str[9]; - uint8_t i; - - bt_rand(str, size); - - /* Normalize to '0' .. '9' & 'A' .. 'Z' */ - for (i = 0; i < size; i++) { - str[i] %= 36; - if (str[i] < 10) { - str[i] += '0'; - } else { - str[i] += 'A' - 10; - } - } - str[size] = '\0'; - - memcpy(bt_mesh_prov_link.auth, str, size); - memset(bt_mesh_prov_link.auth + size, 0, - sizeof(bt_mesh_prov_link.auth) - size); - - return bt_mesh_prov->output_string((char *)str); - } else { - uint32_t div[8] = { 10, 100, 1000, 10000, 100000, - 1000000, 10000000, 100000000 }; - uint32_t num; - - bt_rand(&num, sizeof(num)); - num %= div[size - 1]; - - sys_put_be32(num, &bt_mesh_prov_link.auth[12]); - memset(bt_mesh_prov_link.auth, 0, 12); + char str[9]; - return bt_mesh_prov->output_number(output, num); + atomic_set_bit(bt_mesh_prov_link.flags, NOTIFY_INPUT_COMPLETE); + get_auth_string(str, size); + return bt_mesh_prov->output_string(str); } + atomic_set_bit(bt_mesh_prov_link.flags, NOTIFY_INPUT_COMPLETE); + return bt_mesh_prov->output_number(output, + get_auth_number(output, BT_MESH_NO_INPUT, size)); case AUTH_METHOD_INPUT: input = input_action(action); - if (!input) { - return -EINVAL; - } + if (!is_provisioner) { + err = check_input_auth(input, size); + if (err) { + return err; + } - if (!(bt_mesh_prov->input_actions & input)) { - return -EINVAL; - } + if (input == BT_MESH_ENTER_STRING) { + atomic_set_bit(bt_mesh_prov_link.flags, WAIT_STRING); + } else { + atomic_set_bit(bt_mesh_prov_link.flags, WAIT_NUMBER); + } - if (size > bt_mesh_prov->input_size) { - return -EINVAL; + return bt_mesh_prov->input(input, size); } if (input == BT_MESH_ENTER_STRING) { - atomic_set_bit(bt_mesh_prov_link.flags, WAIT_STRING); - } else { - atomic_set_bit(bt_mesh_prov_link.flags, WAIT_NUMBER); + char str[9]; + + atomic_set_bit(bt_mesh_prov_link.flags, NOTIFY_INPUT_COMPLETE); + get_auth_string(str, size); + return bt_mesh_prov->output_string(str); } - return bt_mesh_prov->input(input, size); + atomic_set_bit(bt_mesh_prov_link.flags, NOTIFY_INPUT_COMPLETE); + output = BT_MESH_DISPLAY_NUMBER; + return bt_mesh_prov->output_number(output, + get_auth_number(BT_MESH_NO_OUTPUT, input, size)); default: return -EINVAL; @@ -215,11 +295,16 @@ int bt_mesh_input_string(const char *str) { BT_DBG("%s", str); + if (strlen(str) > PROV_IO_OOB_SIZE_MAX || + strlen(str) > bt_mesh_prov_link.oob_size) { + return -ENOTSUP; + } + if (!atomic_test_and_clear_bit(bt_mesh_prov_link.flags, WAIT_STRING)) { return -EINVAL; } - strncpy((char *)bt_mesh_prov_link.auth, str, bt_mesh_prov->input_size); + strcpy((char *)bt_mesh_prov_link.auth, str); bt_mesh_prov_link.role->input_complete(); @@ -240,16 +325,16 @@ static void prov_recv(const struct prov_bearer *bearer, void *cb_data, struct os_mbuf *buf) { static const uint8_t op_len[10] = { - [PROV_INVITE] = 1, - [PROV_CAPABILITIES] = 11, - [PROV_START] = 5, - [PROV_PUB_KEY] = 64, - [PROV_INPUT_COMPLETE] = 0, - [PROV_CONFIRM] = 16, - [PROV_RANDOM] = 16, - [PROV_DATA] = 33, - [PROV_COMPLETE] = 0, - [PROV_FAILED] = 1, + [PROV_INVITE] = PDU_LEN_INVITE, + [PROV_CAPABILITIES] = PDU_LEN_CAPABILITIES, + [PROV_START] = PDU_LEN_START, + [PROV_PUB_KEY] = PDU_LEN_PUB_KEY, + [PROV_INPUT_COMPLETE] = PDU_LEN_INPUT_COMPLETE, + [PROV_CONFIRM] = PDU_LEN_CONFIRM, + [PROV_RANDOM] = PDU_LEN_RANDOM, + [PROV_DATA] = PDU_LEN_DATA, + [PROV_COMPLETE] = PDU_LEN_COMPLETE, + [PROV_FAILED] = PDU_LEN_FAILED, }; uint8_t type = buf->om_data[0]; diff --git a/nimble/host/mesh/src/prov.h b/nimble/host/mesh/src/prov.h index 89f027256a..d18ee0ebb7 100644 --- a/nimble/host/mesh/src/prov.h +++ b/nimble/host/mesh/src/prov.h @@ -56,10 +56,25 @@ #define PROV_NO_PDU 0xff +#define PDU_LEN_INVITE 1 +#define PDU_LEN_CAPABILITIES 11 +#define PDU_LEN_START 5 +#define PDU_LEN_PUB_KEY 64 +#define PDU_LEN_INPUT_COMPLETE 0 +#define PDU_LEN_CONFIRM 16 +#define PDU_LEN_RANDOM 16 +#define PDU_LEN_DATA 33 +#define PDU_LEN_COMPLETE 0 +#define PDU_LEN_FAILED 1 + +#define PDU_OP_LEN 1 + #define PROV_ALG_P256 0x00 +#define PROV_IO_OOB_SIZE_MAX 8 /* in bytes */ + #define PROV_BUF(len) \ - NET_BUF_SIMPLE(PROV_BEARER_BUF_HEADROOM + len) + NET_BUF_SIMPLE(PROV_BEARER_BUF_HEADROOM + PDU_OP_LEN + len) enum { WAIT_PUB_KEY, /* Waiting for local PubKey to be generated */ @@ -75,6 +90,7 @@ enum { WAIT_CONFIRM, /* Wait for send confirm */ WAIT_AUTH, /* Wait for auth response */ OOB_STATIC_KEY, /* OOB Static Authentication */ + WAIT_DH_KEY, /* Wait for DH Key */ NUM_FLAGS, }; @@ -103,14 +119,21 @@ struct bt_mesh_prov_link { uint8_t oob_size; /* Authen size */ uint8_t auth[16]; /* Authen value */ - uint8_t dhkey[32]; /* Calculated DHKey */ + uint8_t dhkey[BT_DH_KEY_LEN]; /* Calculated DHKey */ uint8_t expect; /* Next expected PDU */ - uint8_t conf[16]; /* Remote Confirmation */ + uint8_t conf[16]; /* Local/Remote Confirmation */ uint8_t rand[16]; /* Local Random */ uint8_t conf_salt[16]; /* ConfirmationSalt */ uint8_t conf_key[16]; /* ConfirmationKey */ - uint8_t conf_inputs[145]; /* ConfirmationInputs */ + /* ConfirmationInput fields: */ + struct { + uint8_t invite[PDU_LEN_INVITE]; + uint8_t capabilities[PDU_LEN_CAPABILITIES]; + uint8_t start[PDU_LEN_START]; + uint8_t pub_key_provisioner[PDU_LEN_PUB_KEY]; /* big-endian */ + uint8_t pub_key_device[PDU_LEN_PUB_KEY]; /* big-endian */ + } conf_inputs; uint8_t prov_salt[16]; /* Provisioning Salt */ }; @@ -129,11 +152,11 @@ static inline void bt_mesh_prov_buf_init(struct os_mbuf *buf, uint8_t type) net_buf_simple_add_u8(buf, type); } -int bt_mesh_prov_reset_state(void (*func)(const uint8_t key[64])); +int bt_mesh_prov_reset_state(void (*func)(const uint8_t key[BT_PUB_KEY_LEN])); bool bt_mesh_prov_active(void); -int bt_mesh_prov_auth(uint8_t method, uint8_t action, uint8_t size); +int bt_mesh_prov_auth(bool is_provisioner, uint8_t method, uint8_t action, uint8_t size); int bt_mesh_pb_gatt_open(uint16_t conn_handle); int bt_mesh_pb_gatt_close(uint16_t conn_handle); diff --git a/nimble/host/mesh/src/prov_device.c b/nimble/host/mesh/src/prov_device.c index 38a96e7a6b..ba15c175b2 100644 --- a/nimble/host/mesh/src/prov_device.c +++ b/nimble/host/mesh/src/prov_device.c @@ -7,7 +7,8 @@ * SPDX-License-Identifier: Apache-2.0 */ -#define MESH_LOG_MODULE BLE_MESH_PROV_LOG +#define BLE_NPL_LOG_MODULE BLE_MESH_PROV_LOG +#include #include "testing.h" #include "crypto.h" @@ -21,6 +22,7 @@ #include "proxy.h" #include "prov.h" #include "settings.h" +#include "pb_gatt_srv.h" static void send_pub_key(void); static void pub_key_ready(const uint8_t *pkey); @@ -32,7 +34,7 @@ static int reset_state(void) static void prov_send_fail_msg(uint8_t err) { - struct os_mbuf *buf = PROV_BUF(2); + struct os_mbuf *buf = PROV_BUF(PDU_LEN_FAILED); BT_DBG("%u", err); @@ -58,7 +60,7 @@ static void prov_fail(uint8_t reason) static void prov_invite(const uint8_t *data) { - struct os_mbuf *buf = PROV_BUF(12); + struct os_mbuf *buf = PROV_BUF(PDU_LEN_CAPABILITIES); BT_DBG("Attention Duration: %u seconds", data[0]); @@ -66,7 +68,7 @@ static void prov_invite(const uint8_t *data) bt_mesh_attention(NULL, data[0]); } - bt_mesh_prov_link.conf_inputs[0] = data[0]; + memcpy(bt_mesh_prov_link.conf_inputs.invite, data, PDU_LEN_INVITE); bt_mesh_prov_buf_init(buf, PROV_CAPABILITIES); @@ -76,8 +78,9 @@ static void prov_invite(const uint8_t *data) /* Supported algorithms - FIPS P-256 Eliptic Curve */ net_buf_simple_add_be16(buf, BIT(PROV_ALG_P256)); - /* Public Key Type, Only "No OOB" Public Key is supported */ - net_buf_simple_add_u8(buf, PUB_KEY_NO_OOB); + /* Public Key Type */ + net_buf_simple_add_u8(buf, + bt_mesh_prov->public_key_be == NULL ? PUB_KEY_NO_OOB : PUB_KEY_OOB); /* Static OOB Type */ net_buf_simple_add_u8(buf, bt_mesh_prov->static_val ? BIT(0) : 0x00); @@ -94,7 +97,7 @@ static void prov_invite(const uint8_t *data) /* Input OOB Action */ net_buf_simple_add_be16(buf, bt_mesh_prov->input_actions); - memcpy(&bt_mesh_prov_link.conf_inputs[1], &buf->om_data[1], 11); + memcpy(bt_mesh_prov_link.conf_inputs.capabilities, &buf->om_data[1], PDU_LEN_CAPABILITIES); if (bt_mesh_prov_send(buf, NULL)) { BT_ERR("Failed to send capabilities"); @@ -118,17 +121,24 @@ static void prov_start(const uint8_t *data) return; } - if (data[1] != PUB_KEY_NO_OOB) { + if (data[1] > PUB_KEY_OOB || + (data[1] == PUB_KEY_OOB && + (!MYNEWT_VAL(BLE_MESH_PROV_OOB_PUBLIC_KEY) || !bt_mesh_prov->public_key_be))) { BT_ERR("Invalid public key type: 0x%02x", data[1]); prov_fail(PROV_ERR_NVAL_FMT); return; } - memcpy(&bt_mesh_prov_link.conf_inputs[12], data, 5); + atomic_set_bit_to(bt_mesh_prov_link.flags, OOB_PUB_KEY, data[1] == PUB_KEY_OOB); + + memcpy(bt_mesh_prov_link.conf_inputs.start, data, PDU_LEN_START); bt_mesh_prov_link.expect = PROV_PUB_KEY; + bt_mesh_prov_link.oob_method = data[2]; + bt_mesh_prov_link.oob_action = data[3]; + bt_mesh_prov_link.oob_size = data[4]; - if (bt_mesh_prov_auth(data[2], data[3], data[4]) < 0) { + if (bt_mesh_prov_auth(false, data[2], data[3], data[4]) < 0) { BT_ERR("Invalid authentication method: 0x%02x; " "action: 0x%02x; size: 0x%02x", data[2], data[3], data[4]); @@ -145,14 +155,15 @@ static void prov_start(const uint8_t *data) static void send_confirm(void) { - struct os_mbuf *cfm = PROV_BUF(17); + struct os_mbuf *cfm = PROV_BUF(PDU_LEN_CONFIRM); + + uint8_t *inputs = (uint8_t *)&bt_mesh_prov_link.conf_inputs; - BT_DBG("ConfInputs[0] %s", bt_hex(bt_mesh_prov_link.conf_inputs, 64)); - BT_DBG("ConfInputs[64] %s", bt_hex(&bt_mesh_prov_link.conf_inputs[64], 64)); - BT_DBG("ConfInputs[128] %s", bt_hex(&bt_mesh_prov_link.conf_inputs[128], 17)); + BT_DBG("ConfInputs[0] %s", bt_hex(inputs, 64)); + BT_DBG("ConfInputs[64] %s", bt_hex(&inputs[64], 64)); + BT_DBG("ConfInputs[128] %s", bt_hex(&inputs[128], 17)); - if (bt_mesh_prov_conf_salt(bt_mesh_prov_link.conf_inputs, - bt_mesh_prov_link.conf_salt)) { + if (bt_mesh_prov_conf_salt(inputs, bt_mesh_prov_link.conf_salt)) { BT_ERR("Unable to generate confirmation salt"); prov_fail(PROV_ERR_UNEXP_ERR); return; @@ -197,7 +208,7 @@ static void send_confirm(void) static void send_input_complete(void) { - struct os_mbuf *buf = PROV_BUF(1); + struct os_mbuf *buf = PROV_BUF(PDU_LEN_INPUT_COMPLETE); bt_mesh_prov_buf_init(buf, PROV_INPUT_COMPLETE); if (bt_mesh_prov_send(buf, NULL)) { @@ -216,9 +227,19 @@ static void public_key_sent(int err, void *cb_data) } } +static void start_auth(void) +{ + if (atomic_test_bit(bt_mesh_prov_link.flags, WAIT_NUMBER) || + atomic_test_bit(bt_mesh_prov_link.flags, WAIT_STRING)) { + bt_mesh_prov_link.expect = PROV_NO_PDU; /* Wait for input */ + } else { + bt_mesh_prov_link.expect = PROV_CONFIRM; + } +} + static void send_pub_key(void) { - struct os_mbuf *buf = PROV_BUF(65); + struct os_mbuf *buf = PROV_BUF(PDU_LEN_PUB_KEY); const uint8_t *key; key = bt_pub_key_get(); @@ -228,31 +249,38 @@ static void send_pub_key(void) return; } - BT_DBG("Local Public Key: %s", bt_hex(key, 64)); - bt_mesh_prov_buf_init(buf, PROV_PUB_KEY); /* Swap X and Y halves independently to big-endian */ - sys_memcpy_swap(net_buf_simple_add(buf, 32), key, 32); - sys_memcpy_swap(net_buf_simple_add(buf, 32), &key[32], 32); + sys_memcpy_swap(net_buf_simple_add(buf, BT_PUB_KEY_COORD_LEN), key, BT_PUB_KEY_COORD_LEN); + sys_memcpy_swap(net_buf_simple_add(buf, BT_PUB_KEY_COORD_LEN), &key[BT_PUB_KEY_COORD_LEN], 32); + + BT_DBG("Local Public Key: %s", bt_hex(buf->om_data + 1, BT_PUB_KEY_LEN)); - /* PublicKeyRemote */ - memcpy(&bt_mesh_prov_link.conf_inputs[81], &buf->om_data[1], 64); + /* PublicKeyDevice */ + memcpy(bt_mesh_prov_link.conf_inputs.pub_key_device, &buf->om_data[1], PDU_LEN_PUB_KEY); if (bt_mesh_prov_send(buf, public_key_sent)) { BT_ERR("Failed to send Public Key"); return; } - if (atomic_test_bit(bt_mesh_prov_link.flags, WAIT_NUMBER) || - atomic_test_bit(bt_mesh_prov_link.flags, WAIT_STRING)) { - bt_mesh_prov_link.expect = PROV_NO_PDU; /* Wait for input */ - } else { - bt_mesh_prov_link.expect = PROV_CONFIRM; + start_auth(); +} + +static void dh_key_gen_complete(void) +{ + BT_DBG("DHkey: %s", bt_hex(bt_mesh_prov_link.dhkey, BT_DH_KEY_LEN)); + + if (!atomic_test_and_clear_bit(bt_mesh_prov_link.flags, WAIT_DH_KEY) && + atomic_test_bit(bt_mesh_prov_link.flags, OOB_PUB_KEY)) { + send_confirm(); + } else if (!atomic_test_bit(bt_mesh_prov_link.flags, OOB_PUB_KEY)) { + send_pub_key(); } } -static void prov_dh_key_cb(const uint8_t dhkey[32]) +static void prov_dh_key_cb(const uint8_t dhkey[BT_DH_KEY_LEN]) { BT_DBG("%p", dhkey); @@ -262,25 +290,41 @@ static void prov_dh_key_cb(const uint8_t dhkey[32]) return; } - sys_memcpy_swap(bt_mesh_prov_link.dhkey, dhkey, 32); - - BT_DBG("DHkey: %s", bt_hex(bt_mesh_prov_link.dhkey, 32)); + sys_memcpy_swap(bt_mesh_prov_link.dhkey, dhkey, BT_DH_KEY_LEN); - send_pub_key(); + dh_key_gen_complete(); } static void prov_dh_key_gen(void) { - uint8_t remote_pk_le[64], *remote_pk; + const uint8_t *remote_pk; + uint8_t remote_pk_le[BT_PUB_KEY_LEN]; + + remote_pk = bt_mesh_prov_link.conf_inputs.pub_key_provisioner; + if (MYNEWT_VAL(BLE_MESH_PROV_OOB_PUBLIC_KEY) && + atomic_test_bit(bt_mesh_prov_link.flags, OOB_PUB_KEY)) { + if (uECC_valid_public_key(remote_pk, &curve_secp256r1)) { + BT_ERR("Public key is not valid"); + } else if (uECC_shared_secret(remote_pk, bt_mesh_prov->private_key_be, + bt_mesh_prov_link.dhkey, + &curve_secp256r1) != TC_CRYPTO_SUCCESS) { + BT_ERR("DHKey generation failed"); + } else { + dh_key_gen_complete(); + return; + } - remote_pk = &bt_mesh_prov_link.conf_inputs[17]; + prov_fail(PROV_ERR_UNEXP_ERR); + return; + } /* Copy remote key in little-endian for bt_dh_key_gen(). * X and Y halves are swapped independently. The bt_dh_key_gen() * will also take care of validating the remote public key. */ - sys_memcpy_swap(remote_pk_le, remote_pk, 32); - sys_memcpy_swap(&remote_pk_le[32], &remote_pk[32], 32); + sys_memcpy_swap(remote_pk_le, remote_pk, BT_PUB_KEY_COORD_LEN); + sys_memcpy_swap(&remote_pk_le[BT_PUB_KEY_COORD_LEN], &remote_pk[BT_PUB_KEY_COORD_LEN], + BT_PUB_KEY_COORD_LEN); if (bt_dh_key_gen(remote_pk_le, prov_dh_key_cb)) { BT_ERR("Failed to generate DHKey"); @@ -290,12 +334,27 @@ static void prov_dh_key_gen(void) static void prov_pub_key(const uint8_t *data) { - BT_DBG("Remote Public Key: %s", bt_hex(data, 64)); + BT_DBG("Remote Public Key: %s", bt_hex(data, BT_PUB_KEY_LEN)); /* PublicKeyProvisioner */ - memcpy(&bt_mesh_prov_link.conf_inputs[17], data, 64); + memcpy(bt_mesh_prov_link.conf_inputs.pub_key_provisioner, data, PDU_LEN_PUB_KEY); + + if (MYNEWT_VAL(BLE_MESH_PROV_OOB_PUBLIC_KEY) && + atomic_test_bit(bt_mesh_prov_link.flags, OOB_PUB_KEY)) { + if (!bt_mesh_prov->public_key_be || !bt_mesh_prov->private_key_be) { + BT_ERR("Public or private key is not ready"); + prov_fail(PROV_ERR_UNEXP_ERR); + return; + } + + /* No swap needed since user provides public key in big-endian */ + memcpy(bt_mesh_prov_link.conf_inputs.pub_key_device, bt_mesh_prov->public_key_be, + PDU_LEN_PUB_KEY); + + atomic_set_bit(bt_mesh_prov_link.flags, WAIT_DH_KEY); - if (!bt_pub_key_get()) { + start_auth(); + } else if (!bt_pub_key_get()) { /* Clear retransmit timer */ bt_mesh_prov_link.bearer->clear_tx(); atomic_set_bit(bt_mesh_prov_link.flags, WAIT_PUB_KEY); @@ -331,7 +390,7 @@ static void notify_input_complete(void) static void send_random(void) { - struct os_mbuf *rnd = PROV_BUF(17); + struct os_mbuf *rnd = PROV_BUF(PDU_LEN_RANDOM); bt_mesh_prov_buf_init(rnd, PROV_RANDOM); net_buf_simple_add_mem(rnd, bt_mesh_prov_link.rand, 16); @@ -390,7 +449,9 @@ static void prov_confirm(const uint8_t *data) notify_input_complete(); - send_confirm(); + if (!atomic_test_and_clear_bit(bt_mesh_prov_link.flags, WAIT_DH_KEY)) { + send_confirm(); + } } static inline bool is_pb_gatt(void) @@ -401,7 +462,7 @@ static inline bool is_pb_gatt(void) static void prov_data(const uint8_t *data) { - struct os_mbuf *msg = PROV_BUF(1); + struct os_mbuf *msg = PROV_BUF(PDU_LEN_COMPLETE); uint8_t session_key[16]; uint8_t nonce[13]; uint8_t dev_key[16]; @@ -492,7 +553,8 @@ static void prov_data(const uint8_t *data) static void local_input_complete(void) { - if (atomic_test_bit(bt_mesh_prov_link.flags, PUB_KEY_SENT)) { + if (atomic_test_bit(bt_mesh_prov_link.flags, PUB_KEY_SENT) || + atomic_test_bit(bt_mesh_prov_link.flags, OOB_PUB_KEY)) { send_input_complete(); } else { atomic_set_bit(bt_mesh_prov_link.flags, INPUT_COMPLETE); @@ -554,6 +616,10 @@ int bt_mesh_prov_disable(bt_mesh_prov_bearer_t bearers) return -EALREADY; } + if (bt_mesh_prov_active()) { + return -EBUSY; + } + if (IS_ENABLED(CONFIG_BT_MESH_PB_ADV) && (bearers & BT_MESH_PROV_ADV)) { bt_mesh_beacon_disable(); @@ -562,7 +628,7 @@ int bt_mesh_prov_disable(bt_mesh_prov_bearer_t bearers) if (IS_ENABLED(CONFIG_BT_MESH_PB_GATT) && (bearers & BT_MESH_PROV_GATT)) { - bt_mesh_proxy_prov_disable(true); + (void)bt_mesh_pb_gatt_disable(); } return 0; diff --git a/nimble/host/mesh/src/provisioner.c b/nimble/host/mesh/src/provisioner.c index c51a769674..2c9fab313e 100644 --- a/nimble/host/mesh/src/provisioner.c +++ b/nimble/host/mesh/src/provisioner.c @@ -3,11 +3,13 @@ /* * Copyright (c) 2017 Intel Corporation * Copyright (c) 2020 Lingao Meng + * Copyright (c) 2021 Manulytica Limited * * SPDX-License-Identifier: Apache-2.0 */ -#define MESH_LOG_MODULE BLE_MESH_PROV_LOG +#define BLE_NPL_LOG_MODULE BLE_MESH_PROV_LOG +#include #include "testing.h" @@ -31,6 +33,10 @@ static struct { uint8_t uuid[16]; } prov_device; +#if !MYNEWT_VAL(BLE_MESH_CDB) +static struct bt_mesh_cdb_node prov_node; +#endif + static void send_pub_key(void); static void prov_dh_key_gen(void); static void pub_key_ready(const uint8_t *pkey); @@ -65,14 +71,15 @@ static void prov_fail(uint8_t reason) static void send_invite(void) { - struct os_mbuf *inv = PROV_BUF(2); + struct os_mbuf *inv = PROV_BUF(PDU_LEN_INVITE); BT_DBG(""); bt_mesh_prov_buf_init(inv, PROV_INVITE); net_buf_simple_add_u8(inv, prov_device.attention_duration); - bt_mesh_prov_link.conf_inputs[0] = prov_device.attention_duration; + memcpy(bt_mesh_prov_link.conf_inputs.invite, &prov_device.attention_duration, + PDU_LEN_INVITE); if (bt_mesh_prov_send(inv, NULL)) { BT_ERR("Failed to send invite"); @@ -95,54 +102,35 @@ static void start_sent(int err, void *cb_data) static void send_start(void) { BT_DBG(""); - uint8_t method, action; - struct os_mbuf *start = PROV_BUF(6); + struct os_mbuf *start = PROV_BUF(PDU_LEN_START); - const uint8_t *data = &bt_mesh_prov_link.conf_inputs[1 + 3]; + bool oob_pub_key = bt_mesh_prov_link.conf_inputs.capabilities[3] == PUB_KEY_OOB; bt_mesh_prov_buf_init(start, PROV_START); net_buf_simple_add_u8(start, PROV_ALG_P256); - if (atomic_test_bit(bt_mesh_prov_link.flags, REMOTE_PUB_KEY) && - *data == PUB_KEY_OOB) { + memcpy(bt_mesh_prov_link.conf_inputs.start, &start->om_data[1], PDU_LEN_START); + + if (atomic_test_bit(bt_mesh_prov_link.flags, REMOTE_PUB_KEY) && oob_pub_key) { net_buf_simple_add_u8(start, PUB_KEY_OOB); atomic_set_bit(bt_mesh_prov_link.flags, OOB_PUB_KEY); } else { net_buf_simple_add_u8(start, PUB_KEY_NO_OOB); } - if (bt_mesh_prov_link.oob_method == AUTH_METHOD_INPUT) { - method = AUTH_METHOD_OUTPUT; - if (bt_mesh_prov_link.oob_action == INPUT_OOB_STRING) { - action = OUTPUT_OOB_STRING; - } else { - action = OUTPUT_OOB_NUMBER; - } - - } else if (bt_mesh_prov_link.oob_method == AUTH_METHOD_OUTPUT) { - method = AUTH_METHOD_INPUT; - if (bt_mesh_prov_link.oob_action == OUTPUT_OOB_STRING) { - action = INPUT_OOB_STRING; - } else { - action = INPUT_OOB_NUMBER; - } - } else { - method = bt_mesh_prov_link.oob_method; - action = 0x00; - } - net_buf_simple_add_u8(start, bt_mesh_prov_link.oob_method); net_buf_simple_add_u8(start, bt_mesh_prov_link.oob_action); net_buf_simple_add_u8(start, bt_mesh_prov_link.oob_size); - memcpy(&bt_mesh_prov_link.conf_inputs[12], &start->om_data[1], 5); + memcpy(bt_mesh_prov_link.conf_inputs.invite, &start->om_data[1], PDU_LEN_INVITE); - if (bt_mesh_prov_auth(method, action, bt_mesh_prov_link.oob_size) < 0) { + if (bt_mesh_prov_auth(true, bt_mesh_prov_link.oob_method, + bt_mesh_prov_link.oob_action, bt_mesh_prov_link.oob_size) < 0) { BT_ERR("Invalid authentication method: 0x%02x; " - "action: 0x%02x; size: 0x%02x", method, - action, bt_mesh_prov_link.oob_size); + "action: 0x%02x; size: 0x%02x", bt_mesh_prov_link.oob_method, + bt_mesh_prov_link.oob_action, bt_mesh_prov_link.oob_size); return; } @@ -250,8 +238,16 @@ static void prov_capabilities(const uint8_t *data) prov_fail(PROV_ERR_RESOURCES); return; } +#else + prov_device.node = &prov_node; + memset(&prov_node, 0, sizeof(struct bt_mesh_cdb_node)); + memcpy(prov_node.uuid, prov_device.uuid, 16); + prov_node.addr = prov_device.addr; + prov_node.num_elem = data[0]; + prov_node.net_idx = prov_device.net_idx; + atomic_set(prov_node.flags, 0); #endif - memcpy(&bt_mesh_prov_link.conf_inputs[1], data, 11); + memcpy(bt_mesh_prov_link.conf_inputs.capabilities, data, PDU_LEN_CAPABILITIES); if (bt_mesh_prov->capabilities) { bt_mesh_prov->capabilities(&caps); @@ -267,14 +263,14 @@ static void prov_capabilities(const uint8_t *data) static void send_confirm(void) { - struct os_mbuf *cfm = PROV_BUF(17); + struct os_mbuf *cfm = PROV_BUF(PDU_LEN_CONFIRM); + uint8_t *inputs = (uint8_t *)&bt_mesh_prov_link.conf_inputs; - BT_DBG("ConfInputs[0] %s", bt_hex(bt_mesh_prov_link.conf_inputs, 64)); - BT_DBG("ConfInputs[64] %s", bt_hex(&bt_mesh_prov_link.conf_inputs[64], 64)); - BT_DBG("ConfInputs[128] %s", bt_hex(&bt_mesh_prov_link.conf_inputs[128], 17)); + BT_DBG("ConfInputs[0] %s", bt_hex(inputs, 64)); + BT_DBG("ConfInputs[64] %s", bt_hex(&inputs[64], 64)); + BT_DBG("ConfInputs[128] %s", bt_hex(&inputs[128], 17)); - if (bt_mesh_prov_conf_salt(bt_mesh_prov_link.conf_inputs, - bt_mesh_prov_link.conf_salt)) { + if (bt_mesh_prov_conf_salt(inputs, bt_mesh_prov_link.conf_salt)) { BT_ERR("Unable to generate confirmation salt"); prov_fail(PROV_ERR_UNEXP_ERR); return; @@ -303,12 +299,14 @@ static void send_confirm(void) if (bt_mesh_prov_conf(bt_mesh_prov_link.conf_key, bt_mesh_prov_link.rand, bt_mesh_prov_link.auth, - net_buf_simple_add(cfm, 16))) { + bt_mesh_prov_link.conf)) { BT_ERR("Unable to generate confirmation value"); prov_fail(PROV_ERR_UNEXP_ERR); return; } + net_buf_simple_add_mem(cfm, bt_mesh_prov_link.conf, 16); + if (bt_mesh_prov_send(cfm, NULL)) { BT_ERR("Failed to send Provisioning Confirm"); return; @@ -330,7 +328,7 @@ static void public_key_sent(int err, void *cb_data) static void send_pub_key(void) { - struct os_mbuf *buf = PROV_BUF(65); + struct os_mbuf *buf = PROV_BUF(PDU_LEN_PUB_KEY); const uint8_t *key; key = bt_pub_key_get(); @@ -340,16 +338,17 @@ static void send_pub_key(void) return; } - BT_DBG("Local Public Key: %s", bt_hex(key, 64)); + BT_DBG("Local Public Key: %s", bt_hex(key, BT_PUB_KEY_LEN)); bt_mesh_prov_buf_init(buf, PROV_PUB_KEY); /* Swap X and Y halves independently to big-endian */ - sys_memcpy_swap(net_buf_simple_add(buf, 32), key, 32); - sys_memcpy_swap(net_buf_simple_add(buf, 32), &key[32], 32); + sys_memcpy_swap(net_buf_simple_add(buf, BT_PUB_KEY_COORD_LEN), key, BT_PUB_KEY_COORD_LEN); + sys_memcpy_swap(net_buf_simple_add(buf, BT_PUB_KEY_COORD_LEN), &key[BT_PUB_KEY_COORD_LEN], + BT_PUB_KEY_COORD_LEN); /* PublicKeyProvisioner */ - memcpy(&bt_mesh_prov_link.conf_inputs[17], &buf->om_databuf[1], 64); + memcpy(bt_mesh_prov_link.conf_inputs.pub_key_provisioner, &buf->om_data[1], PDU_LEN_PUB_KEY); if (bt_mesh_prov_send(buf, public_key_sent)) { BT_ERR("Failed to send Public Key"); @@ -359,7 +358,7 @@ static void send_pub_key(void) bt_mesh_prov_link.expect = PROV_PUB_KEY; } -static void prov_dh_key_cb(const uint8_t dhkey[32]) +static void prov_dh_key_cb(const uint8_t dhkey[BT_DH_KEY_LEN]) { BT_DBG("%p", dhkey); @@ -369,9 +368,9 @@ static void prov_dh_key_cb(const uint8_t dhkey[32]) return; } - sys_memcpy_swap(bt_mesh_prov_link.dhkey, dhkey, 32); + sys_memcpy_swap(bt_mesh_prov_link.dhkey, dhkey, BT_DH_KEY_LEN); - BT_DBG("DHkey: %s", bt_hex(bt_mesh_prov_link.dhkey, 32)); + BT_DBG("DHkey: %s", bt_hex(bt_mesh_prov_link.dhkey, BT_DH_KEY_LEN)); if (atomic_test_bit(bt_mesh_prov_link.flags, WAIT_STRING) || atomic_test_bit(bt_mesh_prov_link.flags, WAIT_NUMBER) || @@ -385,16 +384,26 @@ static void prov_dh_key_cb(const uint8_t dhkey[32]) static void prov_dh_key_gen(void) { - uint8_t remote_pk_le[64], *remote_pk; + uint8_t remote_pk_le[BT_PUB_KEY_LEN]; + const uint8_t *remote_pk; + const uint8_t *local_pk; - remote_pk = &bt_mesh_prov_link.conf_inputs[81]; + local_pk = bt_mesh_prov_link.conf_inputs.pub_key_provisioner; + remote_pk = bt_mesh_prov_link.conf_inputs.pub_key_device; /* Copy remote key in little-endian for bt_dh_key_gen(). * X and Y halves are swapped independently. The bt_dh_key_gen() * will also take care of validating the remote public key. */ - sys_memcpy_swap(remote_pk_le, remote_pk, 32); - sys_memcpy_swap(&remote_pk_le[32], &remote_pk[32], 32); + sys_memcpy_swap(remote_pk_le, remote_pk, BT_PUB_KEY_COORD_LEN); + sys_memcpy_swap(&remote_pk_le[BT_PUB_KEY_COORD_LEN], &remote_pk[BT_PUB_KEY_COORD_LEN], + BT_PUB_KEY_COORD_LEN); + + if (!memcmp(local_pk, remote_pk, BT_PUB_KEY_LEN)) { + BT_ERR("Public keys are identical"); + prov_fail(PROV_ERR_NVAL_FMT); + return; + } if (bt_dh_key_gen(remote_pk_le, prov_dh_key_cb)) { BT_ERR("Failed to generate DHKey"); @@ -408,12 +417,12 @@ static void prov_dh_key_gen(void) static void prov_pub_key(const uint8_t *data) { - BT_DBG("Remote Public Key: %s", bt_hex(data, 64)); + BT_DBG("Remote Public Key: %s", bt_hex(data, BT_PUB_KEY_LEN)); atomic_set_bit(bt_mesh_prov_link.flags, REMOTE_PUB_KEY); /* PublicKeyDevice */ - memcpy(&bt_mesh_prov_link.conf_inputs[81], data, 64); + memcpy(bt_mesh_prov_link.conf_inputs.pub_key_device, data, BT_PUB_KEY_LEN); bt_mesh_prov_link.bearer->clear_tx(); prov_dh_key_gen(); @@ -455,9 +464,11 @@ static void prov_input_complete(const uint8_t *data) static void send_prov_data(void) { - struct os_mbuf *pdu = PROV_BUF(34); + struct os_mbuf *pdu = PROV_BUF(PDU_LEN_DATA); #if MYNEWT_VAL(BLE_MESH_CDB) - struct bt_mesh_cdb_subnet *sub; + struct bt_mesh_cdb_subnet *sub; +#else + struct bt_mesh_subnet *sub; #endif uint8_t session_key[16]; uint8_t nonce[13]; @@ -500,6 +511,14 @@ static void send_prov_data(void) prov_fail(PROV_ERR_UNEXP_ERR); return; } +#else + sub = bt_mesh_subnet_get(prov_device.node->net_idx); + if (sub == NULL) { + BT_ERR("No subnet with net_idx %u", + prov_device.node->net_idx); + prov_fail(PROV_ERR_UNEXP_ERR); + return; + } #endif bt_mesh_prov_buf_init(pdu, PROV_DATA); #if MYNEWT_VAL(BLE_MESH_CDB) @@ -507,6 +526,11 @@ static void send_prov_data(void) net_buf_simple_add_be16(pdu, prov_device.node->net_idx); net_buf_simple_add_u8(pdu, bt_mesh_cdb_subnet_flags(sub)); net_buf_simple_add_be32(pdu, bt_mesh_cdb.iv_index); +#else + net_buf_simple_add_mem(pdu, sub->keys[SUBNET_KEY_TX_IDX(sub)].net, 16); + net_buf_simple_add_be16(pdu, prov_device.node->net_idx); + net_buf_simple_add_u8(pdu, bt_mesh_net_flags(sub)); + net_buf_simple_add_be32(pdu, bt_mesh.iv_index); #endif net_buf_simple_add_be16(pdu, prov_device.node->addr); net_buf_simple_add(pdu, 8); /* For MIC */ @@ -541,7 +565,7 @@ static void prov_complete(const uint8_t *data) #if MYNEWT_VAL(BLE_MESH_CDB) if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_cdb_node(node); + bt_mesh_cdb_node_store(node); } #endif @@ -556,7 +580,7 @@ static void prov_complete(const uint8_t *data) static void send_random(void) { - struct os_mbuf *rnd = PROV_BUF(17); + struct os_mbuf *rnd = PROV_BUF(PDU_LEN_RANDOM); bt_mesh_prov_buf_init(rnd, PROV_RANDOM); net_buf_simple_add_mem(rnd, bt_mesh_prov_link.rand, 16); @@ -611,6 +635,12 @@ static void prov_confirm(const uint8_t *data) { BT_DBG("Remote Confirm: %s", bt_hex(data, 16)); + if (!memcmp(data, bt_mesh_prov_link.conf, 16)) { + BT_ERR("Confirm value is identical to ours, rejecting."); + prov_fail(PROV_ERR_CFM_FAILED); + return; + } + memcpy(bt_mesh_prov_link.conf, data, 16); send_random(); @@ -664,7 +694,7 @@ static void prov_set_method(uint8_t method, uint8_t action, uint8_t size) int bt_mesh_auth_method_set_input(bt_mesh_input_action_t action, uint8_t size) { - if (!action || !size || size > 8) { + if (!action || !size || size > PROV_IO_OOB_SIZE_MAX) { return -EINVAL; } @@ -674,7 +704,7 @@ int bt_mesh_auth_method_set_input(bt_mesh_input_action_t action, uint8_t size) int bt_mesh_auth_method_set_output(bt_mesh_output_action_t action, uint8_t size) { - if (!action || !size || size > 8) { + if (!action || !size || size > PROV_IO_OOB_SIZE_MAX) { return -EINVAL; } @@ -704,7 +734,7 @@ int bt_mesh_auth_method_set_none(void) return 0; } -int bt_mesh_prov_remote_pub_key_set(const uint8_t public_key[64]) +int bt_mesh_prov_remote_pub_key_set(const uint8_t public_key[BT_PUB_KEY_LEN]) { if (public_key == NULL) { return -EINVAL; @@ -715,8 +745,7 @@ int bt_mesh_prov_remote_pub_key_set(const uint8_t public_key[64]) } /* Swap X and Y halves independently to big-endian */ - memcpy(&bt_mesh_prov_link.conf_inputs[81], public_key, 32); - memcpy(&bt_mesh_prov_link.conf_inputs[81 + 32], &public_key[32], 32); + memcpy(bt_mesh_prov_link.conf_inputs.pub_key_device, public_key, PDU_LEN_PUB_KEY); return 0; } diff --git a/nimble/host/mesh/src/provisioner.h b/nimble/host/mesh/src/provisioner.h index ccda47efed..315bde299f 100644 --- a/nimble/host/mesh/src/provisioner.h +++ b/nimble/host/mesh/src/provisioner.h @@ -7,4 +7,4 @@ */ int bt_mesh_pb_adv_open(const uint8_t uuid[16], uint16_t net_idx, uint16_t addr, - uint8_t attention_duration); \ No newline at end of file + uint8_t attention_duration); diff --git a/nimble/host/mesh/src/proxy.c b/nimble/host/mesh/src/proxy.c deleted file mode 100644 index d013c79894..0000000000 --- a/nimble/host/mesh/src/proxy.c +++ /dev/null @@ -1,1568 +0,0 @@ -/* Bluetooth Mesh */ - -/* - * Copyright (c) 2017 Intel Corporation - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "syscfg/syscfg.h" -#define MESH_LOG_MODULE BLE_MESH_PROXY_LOG - -#if MYNEWT_VAL(BLE_MESH_PROXY) - -#include "mesh/mesh.h" -#include "host/ble_att.h" -#include "services/gatt/ble_svc_gatt.h" -#include "../../host/src/ble_hs_priv.h" - -#include "mesh_priv.h" -#include "adv.h" -#include "net.h" -#include "rpl.h" -#include "prov.h" -#include "beacon.h" -#include "foundation.h" -#include "access.h" -#include "proxy.h" - -#define PDU_TYPE(data) (data[0] & BIT_MASK(6)) -#define PDU_SAR(data) (data[0] >> 6) - -#define BT_UUID_16_ENCODE(w16) \ - (((w16) >> 0) & 0xFF), \ - (((w16) >> 8) & 0xFF) -/* Mesh Profile 1.0 Section 6.6: - * "The timeout for the SAR transfer is 20 seconds. When the timeout - * expires, the Proxy Server shall disconnect." - */ -#define PROXY_SAR_TIMEOUT K_SECONDS(20) - -#define SAR_COMPLETE 0x00 -#define SAR_FIRST 0x01 -#define SAR_CONT 0x02 -#define SAR_LAST 0x03 - -#define CFG_FILTER_SET 0x00 -#define CFG_FILTER_ADD 0x01 -#define CFG_FILTER_REMOVE 0x02 -#define CFG_FILTER_STATUS 0x03 - -/** @def BT_UUID_MESH_PROV - * @brief Mesh Provisioning Service - */ -ble_uuid16_t BT_UUID_MESH_PROV = BLE_UUID16_INIT(0x1827); -#define BT_UUID_MESH_PROV_VAL 0x1827 -/** @def BT_UUID_MESH_PROXY - * @brief Mesh Proxy Service - */ -ble_uuid16_t BT_UUID_MESH_PROXY = BLE_UUID16_INIT(0x1828); -#define BT_UUID_MESH_PROXY_VAL 0x1828 -/** @def BT_UUID_GATT_CCC - * @brief GATT Client Characteristic Configuration - */ -ble_uuid16_t BT_UUID_GATT_CCC = BLE_UUID16_INIT(0x2902); -#define BT_UUID_GATT_CCC_VAL 0x2902 -/** @def BT_UUID_MESH_PROV_DATA_IN - * @brief Mesh Provisioning Data In - */ -ble_uuid16_t BT_UUID_MESH_PROV_DATA_IN = BLE_UUID16_INIT(0x2adb); -#define BT_UUID_MESH_PROV_DATA_IN_VAL 0x2adb -/** @def BT_UUID_MESH_PROV_DATA_OUT - * @brief Mesh Provisioning Data Out - */ -ble_uuid16_t BT_UUID_MESH_PROV_DATA_OUT = BLE_UUID16_INIT(0x2adc); -#define BT_UUID_MESH_PROV_DATA_OUT_VAL 0x2adc -/** @def BT_UUID_MESH_PROXY_DATA_IN - * @brief Mesh Proxy Data In - */ -ble_uuid16_t BT_UUID_MESH_PROXY_DATA_IN = BLE_UUID16_INIT(0x2add); -#define BT_UUID_MESH_PROXY_DATA_IN_VAL 0x2add -/** @def BT_UUID_MESH_PROXY_DATA_OUT - * @brief Mesh Proxy Data Out - */ -ble_uuid16_t BT_UUID_MESH_PROXY_DATA_OUT = BLE_UUID16_INIT(0x2ade); -#define BT_UUID_MESH_PROXY_DATA_OUT_VAL 0x2ade - -#define PDU_HDR(sar, type) (sar << 6 | (type & BIT_MASK(6))) - -#define CLIENT_BUF_SIZE 65 - -static const struct ble_gap_adv_params slow_adv_param = { - .conn_mode = (BLE_GAP_CONN_MODE_UND), - .disc_mode = (BLE_GAP_DISC_MODE_GEN), - .itvl_min = BT_GAP_ADV_SLOW_INT_MIN, - .itvl_max = BT_GAP_ADV_SLOW_INT_MAX, -}; - -static const struct ble_gap_adv_params fast_adv_param = { - .conn_mode = (BLE_GAP_CONN_MODE_UND), - .disc_mode = (BLE_GAP_DISC_MODE_GEN), - .itvl_min = BT_GAP_ADV_FAST_INT_MIN_2, - .itvl_max = BT_GAP_ADV_FAST_INT_MAX_2, -}; - -static bool proxy_adv_enabled; - -#if (MYNEWT_VAL(BLE_MESH_GATT_PROXY)) -static void proxy_send_beacons(struct ble_npl_event *work); -#endif - -#if (MYNEWT_VAL(BLE_MESH_PB_GATT)) -static bool prov_fast_adv; -#endif - -static struct bt_mesh_proxy_client { - uint16_t conn_handle; - uint16_t filter[MYNEWT_VAL(BLE_MESH_PROXY_FILTER_SIZE)]; - enum __packed { - NONE, - WHITELIST, - BLACKLIST, - PROV, - } filter_type; - uint8_t msg_type; -#if (MYNEWT_VAL(BLE_MESH_GATT_PROXY)) - struct ble_npl_callout send_beacons; -#endif - struct k_delayed_work sar_timer; - struct os_mbuf *buf; -} clients[MYNEWT_VAL(BLE_MAX_CONNECTIONS)] = { - [0 ... (MYNEWT_VAL(BLE_MAX_CONNECTIONS) - 1)] = { 0 }, -}; - -static sys_slist_t idle_waiters; -static atomic_t pending_notifications; - -/* Track which service is enabled */ -static enum { - MESH_GATT_NONE, - MESH_GATT_PROV, - MESH_GATT_PROXY, -} gatt_svc = MESH_GATT_NONE; - -static struct { - uint16_t proxy_h; - uint16_t proxy_data_out_h; - uint16_t prov_h; - uint16_t prov_data_in_h; - uint16_t prov_data_out_h; -} svc_handles; - -static void resolve_svc_handles(void) -{ - int rc; - - /* Either all handles are already resolved, or none of them */ - if (svc_handles.prov_data_out_h) { - return; - } - - /* - * We assert if attribute is not found since at this stage all attributes - * shall be already registered and thus shall be found. - */ - - rc = ble_gatts_find_svc(BLE_UUID16_DECLARE(BT_UUID_MESH_PROXY_VAL), - &svc_handles.proxy_h); - assert(rc == 0); - - rc = ble_gatts_find_chr(BLE_UUID16_DECLARE(BT_UUID_MESH_PROXY_VAL), - BLE_UUID16_DECLARE(BT_UUID_MESH_PROXY_DATA_OUT_VAL), - NULL, &svc_handles.proxy_data_out_h); - assert(rc == 0); - - rc = ble_gatts_find_svc(BLE_UUID16_DECLARE(BT_UUID_MESH_PROV_VAL), - &svc_handles.prov_h); - assert(rc == 0); - - rc = ble_gatts_find_chr(BLE_UUID16_DECLARE(BT_UUID_MESH_PROV_VAL), - BLE_UUID16_DECLARE(BT_UUID_MESH_PROV_DATA_IN_VAL), - NULL, &svc_handles.prov_data_in_h); - assert(rc == 0); - - rc = ble_gatts_find_chr(BLE_UUID16_DECLARE(BT_UUID_MESH_PROV_VAL), - BLE_UUID16_DECLARE(BT_UUID_MESH_PROV_DATA_OUT_VAL), - NULL, &svc_handles.prov_data_out_h); - assert(rc == 0); -} - -static struct bt_mesh_proxy_client *find_client(uint16_t conn_handle) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(clients); i++) { - if (clients[i].conn_handle == conn_handle) { - return &clients[i]; - } - } - - return NULL; -} - -#if (MYNEWT_VAL(BLE_MESH_GATT_PROXY)) -/* Next subnet in queue to be advertised */ -static struct bt_mesh_subnet *beacon_sub; - -static int proxy_segment_and_send(uint16_t conn_handle, uint8_t type, - struct os_mbuf *msg); - -static int filter_set(struct bt_mesh_proxy_client *client, - struct os_mbuf *buf) -{ - uint8_t type; - - if (buf->om_len < 1) { - BT_WARN("Too short Filter Set message"); - return -EINVAL; - } - - type = net_buf_simple_pull_u8(buf); - BT_DBG("type 0x%02x", type); - - switch (type) { - case 0x00: - memset(client->filter, 0, sizeof(client->filter)); - client->filter_type = WHITELIST; - break; - case 0x01: - memset(client->filter, 0, sizeof(client->filter)); - client->filter_type = BLACKLIST; - break; - default: - BT_WARN("Prohibited Filter Type 0x%02x", type); - return -EINVAL; - } - - return 0; -} - -static void filter_add(struct bt_mesh_proxy_client *client, uint16_t addr) -{ - int i; - - BT_DBG("addr 0x%04x", addr); - - if (addr == BT_MESH_ADDR_UNASSIGNED) { - return; - } - - for (i = 0; i < ARRAY_SIZE(client->filter); i++) { - if (client->filter[i] == addr) { - return; - } - } - - for (i = 0; i < ARRAY_SIZE(client->filter); i++) { - if (client->filter[i] == BT_MESH_ADDR_UNASSIGNED) { - client->filter[i] = addr; - return; - } - } -} - -static void filter_remove(struct bt_mesh_proxy_client *client, uint16_t addr) -{ - int i; - - BT_DBG("addr 0x%04x", addr); - - if (addr == BT_MESH_ADDR_UNASSIGNED) { - return; - } - - for (i = 0; i < ARRAY_SIZE(client->filter); i++) { - if (client->filter[i] == addr) { - client->filter[i] = BT_MESH_ADDR_UNASSIGNED; - return; - } - } -} - -static void send_filter_status(struct bt_mesh_proxy_client *client, - struct bt_mesh_net_rx *rx, - struct os_mbuf *buf) -{ - struct bt_mesh_net_tx tx = { - .sub = rx->sub, - .ctx = &rx->ctx, - .src = bt_mesh_primary_addr(), - }; - uint16_t filter_size; - int i, err; - - /* Configuration messages always have dst unassigned */ - tx.ctx->addr = BT_MESH_ADDR_UNASSIGNED; - - net_buf_simple_init(buf, 10); - - net_buf_simple_add_u8(buf, CFG_FILTER_STATUS); - - if (client->filter_type == WHITELIST) { - net_buf_simple_add_u8(buf, 0x00); - } else { - net_buf_simple_add_u8(buf, 0x01); - } - - for (filter_size = 0, i = 0; i < ARRAY_SIZE(client->filter); i++) { - if (client->filter[i] != BT_MESH_ADDR_UNASSIGNED) { - filter_size++; - } - } - - net_buf_simple_add_be16(buf, filter_size); - - BT_DBG("%u bytes: %s", buf->om_len, bt_hex(buf->om_data, buf->om_len)); - - err = bt_mesh_net_encode(&tx, buf, true); - if (err) { - BT_ERR("Encoding Proxy cfg message failed (err %d)", err); - return; - } - - err = proxy_segment_and_send(client->conn_handle, BT_MESH_PROXY_CONFIG, buf); - if (err) { - BT_ERR("Failed to send proxy cfg message (err %d)", err); - } -} - -static void proxy_cfg(struct bt_mesh_proxy_client *client) -{ - struct os_mbuf *buf = NET_BUF_SIMPLE(BT_MESH_NET_MAX_PDU_LEN); - struct bt_mesh_net_rx rx; - uint8_t opcode; - int err; - - err = bt_mesh_net_decode(client->buf, BT_MESH_NET_IF_PROXY_CFG, - &rx, buf); - if (err) { - BT_ERR("Failed to decode Proxy Configuration (err %d)", err); - goto done; - } - - rx.local_match = 1U; - - if (bt_mesh_rpl_check(&rx, NULL)) { - BT_WARN("Replay: src 0x%04x dst 0x%04x seq 0x%06x", - rx.ctx.addr, rx.ctx.recv_dst, rx.seq); - goto done; - } - - /* Remove network headers */ - net_buf_simple_pull_mem(buf, BT_MESH_NET_HDR_LEN); - - BT_DBG("%u bytes: %s", buf->om_len, bt_hex(buf->om_data, buf->om_len)); - - if (buf->om_len < 1) { - BT_WARN("Too short proxy configuration PDU"); - goto done; - } - - opcode = net_buf_simple_pull_u8(buf); - switch (opcode) { - case CFG_FILTER_SET: - filter_set(client, buf); - send_filter_status(client, &rx, buf); - break; - case CFG_FILTER_ADD: - while (buf->om_len >= 2) { - uint16_t addr; - - addr = net_buf_simple_pull_be16(buf); - filter_add(client, addr); - } - send_filter_status(client, &rx, buf); - break; - case CFG_FILTER_REMOVE: - while (buf->om_len >= 2) { - uint16_t addr; - - addr = net_buf_simple_pull_be16(buf); - filter_remove(client, addr); - } - send_filter_status(client, &rx, buf); - break; - default: - BT_WARN("Unhandled configuration OpCode 0x%02x", opcode); - break; - } - -done: - os_mbuf_free_chain(buf); -} - -static int beacon_send(uint16_t conn_handle, struct bt_mesh_subnet *sub) -{ - struct os_mbuf *buf = NET_BUF_SIMPLE(23); - int rc; - - net_buf_simple_init(buf, 1); - bt_mesh_beacon_create(sub, buf); - - rc = proxy_segment_and_send(conn_handle, BT_MESH_PROXY_BEACON, buf); - os_mbuf_free_chain(buf); - return rc; -} - -static int send_beacon_cb(struct bt_mesh_subnet *sub, void *cb_data) -{ - struct bt_mesh_proxy_client *client = cb_data; - - return beacon_send(client->conn_handle, sub); -} - -static void proxy_send_beacons(struct ble_npl_event *work) -{ - struct bt_mesh_proxy_client *client; - - client = ble_npl_event_get_arg(work); - - (void)bt_mesh_subnet_find(send_beacon_cb, client); -} - -static void proxy_sar_timeout(struct ble_npl_event *work) -{ - struct bt_mesh_proxy_client *client; - int rc; - - BT_WARN("Proxy SAR timeout"); - - client = ble_npl_event_get_arg(work); - assert(client != NULL); - - if ((client->conn_handle != BLE_HS_CONN_HANDLE_NONE)) { - rc = ble_gap_terminate(client->conn_handle, - BLE_ERR_REM_USER_CONN_TERM); - assert(rc == 0); - } -} - -void bt_mesh_proxy_beacon_send(struct bt_mesh_subnet *sub) -{ - int i; - - if (!sub) { - /* NULL means we send on all subnets */ - bt_mesh_subnet_foreach(bt_mesh_proxy_beacon_send); - return; - } - - for (i = 0; i < ARRAY_SIZE(clients); i++) { - if (clients[i].conn_handle != BLE_HS_CONN_HANDLE_NONE) { - beacon_send(clients[i].conn_handle, sub); - } - } -} - -static void node_id_start(struct bt_mesh_subnet *sub) -{ - sub->node_id = BT_MESH_NODE_IDENTITY_RUNNING; - sub->node_id_start = k_uptime_get_32(); -} - -void bt_mesh_proxy_identity_start(struct bt_mesh_subnet *sub) -{ - node_id_start(sub); - /* Prioritize the recently enabled subnet */ - beacon_sub = sub; -} - -void bt_mesh_proxy_identity_stop(struct bt_mesh_subnet *sub) -{ - sub->node_id = BT_MESH_NODE_IDENTITY_STOPPED; - sub->node_id_start = 0; -} - -int bt_mesh_proxy_identity_enable(void) -{ - BT_DBG(""); - - if (!bt_mesh_is_provisioned()) { - return -EAGAIN; - } - - if (bt_mesh_subnet_foreach(node_id_start)) { - bt_mesh_adv_update(); - } - - return 0; -} - -#endif /* GATT_PROXY */ - -static void proxy_complete_pdu(struct bt_mesh_proxy_client *client) -{ - switch (client->msg_type) { -#if (MYNEWT_VAL(BLE_MESH_GATT_PROXY)) - case BT_MESH_PROXY_NET_PDU: - BT_INFO("Mesh Network PDU"); - bt_mesh_net_recv(client->buf, 0, BT_MESH_NET_IF_PROXY); - break; - case BT_MESH_PROXY_BEACON: - BT_INFO("Mesh Beacon PDU"); - bt_mesh_beacon_recv(client->buf); - break; - case BT_MESH_PROXY_CONFIG: - BT_INFO("Mesh Configuration PDU"); - proxy_cfg(client); - break; -#endif -#if (MYNEWT_VAL(BLE_MESH_PB_GATT)) - case BT_MESH_PROXY_PROV: - BT_INFO("Mesh Provisioning PDU"); - bt_mesh_pb_gatt_recv(client->conn_handle, client->buf); - break; -#endif - default: - BT_WARN("Unhandled Message Type 0x%02x", client->msg_type); - break; - } - - net_buf_simple_init(client->buf, 0); -} - -static int proxy_recv(uint16_t conn_handle, uint16_t attr_handle, - struct ble_gatt_access_ctxt *ctxt, void *arg) -{ - struct bt_mesh_proxy_client *client = find_client(conn_handle); - const uint8_t *data = ctxt->om->om_data; - uint16_t len = ctxt->om->om_len; - - client = find_client(conn_handle); - - if (!client) { - return -ENOTCONN; - } - - if (len < 1) { - BT_WARN("Too small Proxy PDU"); - return -EINVAL; - } - - if ((attr_handle == svc_handles.prov_data_in_h) != - (PDU_TYPE(data) == BT_MESH_PROXY_PROV)) { - BT_WARN("Proxy PDU type doesn't match GATT service"); - return -EINVAL; - } - - if (len - 1 > net_buf_simple_tailroom(client->buf)) { - BT_WARN("Too big proxy PDU"); - return -EINVAL; - } - - switch (PDU_SAR(data)) { - case SAR_COMPLETE: - if (client->buf->om_len) { - BT_WARN("Complete PDU while a pending incomplete one"); - return -EINVAL; - } - - client->msg_type = PDU_TYPE(data); - net_buf_simple_add_mem(client->buf, data + 1, len - 1); - proxy_complete_pdu(client); - break; - - case SAR_FIRST: - if (client->buf->om_len) { - BT_WARN("First PDU while a pending incomplete one"); - return -EINVAL; - } - - k_delayed_work_submit(&client->sar_timer, PROXY_SAR_TIMEOUT); - client->msg_type = PDU_TYPE(data); - net_buf_simple_add_mem(client->buf, data + 1, len - 1); - break; - - case SAR_CONT: - if (!client->buf->om_len) { - BT_WARN("Continuation with no prior data"); - return -EINVAL; - } - - if (client->msg_type != PDU_TYPE(data)) { - BT_WARN("Unexpected message type in continuation"); - return -EINVAL; - } - - k_delayed_work_submit(&client->sar_timer, PROXY_SAR_TIMEOUT); - net_buf_simple_add_mem(client->buf, data + 1, len - 1); - break; - - case SAR_LAST: - if (!client->buf->om_len) { - BT_WARN("Last SAR PDU with no prior data"); - return -EINVAL; - } - - if (client->msg_type != PDU_TYPE(data)) { - BT_WARN("Unexpected message type in last SAR PDU"); - return -EINVAL; - } - - k_delayed_work_cancel(&client->sar_timer); - net_buf_simple_add_mem(client->buf, data + 1, len - 1); - proxy_complete_pdu(client); - break; - } - - return len; -} - -static int conn_count; - -static void proxy_connected(uint16_t conn_handle) -{ - struct bt_mesh_proxy_client *client; - int i; - - BT_INFO("conn_handle %d", conn_handle); - - conn_count++; - - /* Since we use ADV_OPT_ONE_TIME */ - proxy_adv_enabled = false; - - /* Try to re-enable advertising in case it's possible */ - if (conn_count < CONFIG_BT_MAX_CONN) { - bt_mesh_adv_update(); - } - - for (client = NULL, i = 0; i < ARRAY_SIZE(clients); i++) { - if (clients[i].conn_handle == BLE_HS_CONN_HANDLE_NONE) { - client = &clients[i]; - break; - } - } - - if (!client) { - BT_ERR("No free Proxy Client objects"); - return; - } - - client->conn_handle = conn_handle; - client->filter_type = NONE; - memset(client->filter, 0, sizeof(client->filter)); - net_buf_simple_init(client->buf, 0); -} - -static void proxy_disconnected(uint16_t conn_handle, int reason) -{ - int i; - - BT_DBG("conn handle %u reason 0x%02x", conn_handle, reason); - conn_count--; - - for (i = 0; i < ARRAY_SIZE(clients); i++) { - struct bt_mesh_proxy_client *client = &clients[i]; - - if (client->conn_handle == conn_handle) { - if ((MYNEWT_VAL(BLE_MESH_PB_GATT)) && - client->filter_type == PROV) { - bt_mesh_pb_gatt_close(conn_handle); - } - - k_delayed_work_cancel(&client->sar_timer); - client->conn_handle = BLE_HS_CONN_HANDLE_NONE; - break; - } - } - - bt_mesh_adv_update(); -} - -struct os_mbuf *bt_mesh_proxy_get_buf(void) -{ - struct os_mbuf *buf = clients[0].buf; - - if (buf != NULL) { - net_buf_simple_init(buf, 0); - } - - return buf; -} - -#if (MYNEWT_VAL(BLE_MESH_PB_GATT)) -static void prov_ccc_write(uint16_t conn_handle) -{ - struct bt_mesh_proxy_client *client; - - BT_DBG("conn_handle %d", conn_handle); - - /* If a connection exists there must be a client */ - client = find_client(conn_handle); - __ASSERT(client, "No client for connection"); - - if (client->filter_type == NONE) { - client->filter_type = PROV; - bt_mesh_pb_gatt_open(conn_handle); - } -} - -int bt_mesh_proxy_prov_enable(void) -{ - uint16_t handle; - int rc; - int i; - - BT_DBG(""); - - if (gatt_svc == MESH_GATT_PROV) { - return -EALREADY; - } - - if (gatt_svc != MESH_GATT_NONE) { - return -EBUSY; - } - - rc = ble_gatts_find_svc(BLE_UUID16_DECLARE(BT_UUID_MESH_PROV_VAL), &handle); - assert(rc == 0); - ble_gatts_svc_set_visibility(handle, 1); - /* FIXME: figure out end handle */ - ble_svc_gatt_changed(svc_handles.prov_h, 0xffff); - - gatt_svc = MESH_GATT_PROV; - prov_fast_adv = true; - - for (i = 0; i < ARRAY_SIZE(clients); i++) { - if (clients[i].conn_handle != BLE_HS_CONN_HANDLE_NONE) { - clients[i].filter_type = PROV; - } - } - - - return 0; -} - -int bt_mesh_proxy_prov_disable(bool disconnect) -{ - uint16_t handle; - int rc; - int i; - - BT_DBG(""); - - if (gatt_svc == MESH_GATT_NONE) { - return -EALREADY; - } - - if (gatt_svc != MESH_GATT_PROV) { - return -EBUSY; - } - - rc = ble_gatts_find_svc(BLE_UUID16_DECLARE(BT_UUID_MESH_PROV_VAL), &handle); - assert(rc == 0); - ble_gatts_svc_set_visibility(handle, 0); - /* FIXME: figure out end handle */ - ble_svc_gatt_changed(svc_handles.prov_h, 0xffff); - - gatt_svc = MESH_GATT_NONE; - - for (i = 0; i < ARRAY_SIZE(clients); i++) { - struct bt_mesh_proxy_client *client = &clients[i]; - - if ((client->conn_handle == BLE_HS_CONN_HANDLE_NONE) - || (client->filter_type != PROV)) { - continue; - } - - if (disconnect) { - rc = ble_gap_terminate(client->conn_handle, - BLE_ERR_REM_USER_CONN_TERM); - assert(rc == 0); - } else { - bt_mesh_pb_gatt_close(client->conn_handle); - client->filter_type = NONE; - } - } - - bt_mesh_adv_update(); - - return 0; -} -#endif /* MYNEWT_VAL(BLE_MESH_PB_GATT) */ - -#if (MYNEWT_VAL(BLE_MESH_GATT_PROXY)) -static void proxy_ccc_write(uint16_t conn_handle) -{ - struct bt_mesh_proxy_client *client; - - BT_DBG("conn_handle %d", conn_handle); - - client = find_client(conn_handle); - __ASSERT(client, "No client for connection"); - - if (client->filter_type == NONE) { - client->filter_type = WHITELIST; - k_work_add_arg(&client->send_beacons, client); - k_work_submit(&client->send_beacons); - } -} - -int bt_mesh_proxy_gatt_enable(void) -{ - uint16_t handle; - int rc; - int i; - - BT_DBG(""); - - if (gatt_svc == MESH_GATT_PROXY) { - return -EALREADY; - } - - if (gatt_svc != MESH_GATT_NONE) { - return -EBUSY; - } - - rc = ble_gatts_find_svc(BLE_UUID16_DECLARE(BT_UUID_MESH_PROXY_VAL), &handle); - assert(rc == 0); - ble_gatts_svc_set_visibility(handle, 1); - /* FIXME: figure out end handle */ - ble_svc_gatt_changed(svc_handles.proxy_h, 0xffff); - - gatt_svc = MESH_GATT_PROXY; - - for (i = 0; i < ARRAY_SIZE(clients); i++) { - if (clients[i].conn_handle != BLE_HS_CONN_HANDLE_NONE) { - clients[i].filter_type = WHITELIST; - } - } - - return 0; -} - -void bt_mesh_proxy_gatt_disconnect(void) -{ - int rc; - int i; - - BT_DBG(""); - - for (i = 0; i < ARRAY_SIZE(clients); i++) { - struct bt_mesh_proxy_client *client = &clients[i]; - - if ((client->conn_handle != BLE_HS_CONN_HANDLE_NONE) && - (client->filter_type == WHITELIST || - client->filter_type == BLACKLIST)) { - client->filter_type = NONE; - rc = ble_gap_terminate(client->conn_handle, - BLE_ERR_REM_USER_CONN_TERM); - assert(rc == 0); - } - } -} - -int bt_mesh_proxy_gatt_disable(void) -{ - uint16_t handle; - int rc; - - BT_DBG(""); - - if (gatt_svc == MESH_GATT_NONE) { - return -EALREADY; - } - - if (gatt_svc != MESH_GATT_PROXY) { - return -EBUSY; - } - - bt_mesh_proxy_gatt_disconnect(); - - rc = ble_gatts_find_svc(BLE_UUID16_DECLARE(BT_UUID_MESH_PROXY_VAL), &handle); - assert(rc == 0); - ble_gatts_svc_set_visibility(handle, 0); - /* FIXME: figure out end handle */ - ble_svc_gatt_changed(svc_handles.proxy_h, 0xffff); - - gatt_svc = MESH_GATT_NONE; - - return 0; -} - -void bt_mesh_proxy_addr_add(struct os_mbuf *buf, uint16_t addr) -{ - struct bt_mesh_proxy_client *client = NULL; - int i; - - for (i = 0; i < ARRAY_SIZE(clients); i++) { - client = &clients[i]; - if (client->buf == buf) { - break; - } - } - - assert(client); - - BT_DBG("filter_type %u addr 0x%04x", client->filter_type, addr); - - if (client->filter_type == WHITELIST) { - filter_add(client, addr); - } else if (client->filter_type == BLACKLIST) { - filter_remove(client, addr); - } -} - -static bool client_filter_match(struct bt_mesh_proxy_client *client, - uint16_t addr) -{ - int i; - - BT_DBG("filter_type %u addr 0x%04x", client->filter_type, addr); - - if (client->filter_type == BLACKLIST) { - for (i = 0; i < ARRAY_SIZE(client->filter); i++) { - if (client->filter[i] == addr) { - return false; - } - } - - return true; - } - - if (addr == BT_MESH_ADDR_ALL_NODES) { - return true; - } - - if (client->filter_type == WHITELIST) { - for (i = 0; i < ARRAY_SIZE(client->filter); i++) { - if (client->filter[i] == addr) { - return true; - } - } - } - - return false; -} - -bool bt_mesh_proxy_relay(struct os_mbuf *buf, uint16_t dst) -{ - bool relayed = false; - int i; - - BT_DBG("%u bytes to dst 0x%04x", buf->om_len, dst); - - for (i = 0; i < ARRAY_SIZE(clients); i++) { - struct bt_mesh_proxy_client *client = &clients[i]; - struct os_mbuf *msg; - - if (client->conn_handle == BLE_HS_CONN_HANDLE_NONE) { - continue; - } - - if (!client_filter_match(client, dst)) { - continue; - } - - /* Proxy PDU sending modifies the original buffer, - * so we need to make a copy. - */ - msg = NET_BUF_SIMPLE(32); - net_buf_simple_init(msg, 1); - net_buf_simple_add_mem(msg, buf->om_data, buf->om_len); - - bt_mesh_proxy_send(client->conn_handle, BT_MESH_PROXY_NET_PDU, msg); - os_mbuf_free_chain(msg); - relayed = true; - } - - return relayed; -} - -#endif /* MYNEWT_VAL(BLE_MESH_GATT_PROXY) */ - -static void notify_complete(void) -{ - sys_snode_t *n; - - if (atomic_dec(&pending_notifications) > 1) { - return; - } - - BT_DBG(""); - - while ((n = sys_slist_get(&idle_waiters))) { - CONTAINER_OF(n, struct bt_mesh_proxy_idle_cb, n)->cb(); - } -} - -static int proxy_send(uint16_t conn_handle, const void *data, uint16_t len) -{ - struct os_mbuf *om; - int err = 0; - - BT_DBG("%u bytes: %s", len, bt_hex(data, len)); - -#if (MYNEWT_VAL(BLE_MESH_GATT_PROXY)) - if (gatt_svc == MESH_GATT_PROXY) { - om = ble_hs_mbuf_from_flat(data, len); - assert(om); - err = ble_gattc_notify_custom(conn_handle, svc_handles.proxy_data_out_h, om); - notify_complete(); - } -#endif - -#if (MYNEWT_VAL(BLE_MESH_PB_GATT)) - if (gatt_svc == MESH_GATT_PROV) { - om = ble_hs_mbuf_from_flat(data, len); - assert(om); - err = ble_gattc_notify_custom(conn_handle, svc_handles.prov_data_out_h, om); - notify_complete(); - } -#endif - - if (!err) { - atomic_inc(&pending_notifications); - } - - return err; -} - -static int proxy_segment_and_send(uint16_t conn_handle, uint8_t type, - struct os_mbuf *msg) -{ - uint16_t mtu; - - BT_DBG("conn_handle %d type 0x%02x len %u: %s", conn_handle, type, msg->om_len, - bt_hex(msg->om_data, msg->om_len)); - - /* ATT_MTU - OpCode (1 byte) - Handle (2 bytes) */ - mtu = ble_att_mtu(conn_handle) - 3; - if (mtu > msg->om_len) { - net_buf_simple_push_u8(msg, PDU_HDR(SAR_COMPLETE, type)); - return proxy_send(conn_handle, msg->om_data, msg->om_len); - } - - net_buf_simple_push_u8(msg, PDU_HDR(SAR_FIRST, type)); - proxy_send(conn_handle, msg->om_data, mtu); - net_buf_simple_pull_mem(msg, mtu); - - while (msg->om_len) { - if (msg->om_len + 1 < mtu) { - net_buf_simple_push_u8(msg, PDU_HDR(SAR_LAST, type)); - proxy_send(conn_handle, msg->om_data, msg->om_len); - break; - } - - net_buf_simple_push_u8(msg, PDU_HDR(SAR_CONT, type)); - proxy_send(conn_handle, msg->om_data, mtu); - net_buf_simple_pull_mem(msg, mtu); - } - - return 0; -} - -int bt_mesh_proxy_send(uint16_t conn_handle, uint8_t type, - struct os_mbuf *msg) -{ - struct bt_mesh_proxy_client *client = find_client(conn_handle); - - if (!client) { - BT_ERR("No Proxy Client found"); - return -ENOTCONN; - } - - if ((client->filter_type == PROV) != (type == BT_MESH_PROXY_PROV)) { - BT_ERR("Invalid PDU type for Proxy Client"); - return -EINVAL; - } - - return proxy_segment_and_send(conn_handle, type, msg); -} - -#if (MYNEWT_VAL(BLE_MESH_PB_GATT)) -static uint8_t prov_svc_data[20] = { - BT_UUID_16_ENCODE(BT_UUID_MESH_PROV_VAL), -}; - -static const struct bt_data prov_ad[] = { - BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)), - BT_DATA_BYTES(BT_DATA_UUID16_ALL, - BT_UUID_16_ENCODE(BT_UUID_MESH_PROV_VAL)), - BT_DATA(BT_DATA_SVC_DATA16, prov_svc_data, sizeof(prov_svc_data)), -}; -#endif /* PB_GATT */ - -#if (MYNEWT_VAL(BLE_MESH_GATT_PROXY)) - -#define ID_TYPE_NET 0x00 -#define ID_TYPE_NODE 0x01 - -#define NODE_ID_LEN 19 -#define NET_ID_LEN 11 - -#define NODE_ID_TIMEOUT K_SECONDS(CONFIG_BT_MESH_NODE_ID_TIMEOUT) - -static uint8_t proxy_svc_data[NODE_ID_LEN] = { - BT_UUID_16_ENCODE(BT_UUID_MESH_PROXY_VAL), -}; - -static const struct bt_data node_id_ad[] = { - BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)), - BT_DATA_BYTES(BT_DATA_UUID16_ALL, - BT_UUID_16_ENCODE(BT_UUID_MESH_PROXY_VAL)), - BT_DATA(BT_DATA_SVC_DATA16, proxy_svc_data, NODE_ID_LEN), -}; - -static const struct bt_data net_id_ad[] = { - BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)), - BT_DATA_BYTES(BT_DATA_UUID16_ALL, - BT_UUID_16_ENCODE(BT_UUID_MESH_PROXY_VAL)), - BT_DATA(BT_DATA_SVC_DATA16, proxy_svc_data, NET_ID_LEN), -}; - -static int node_id_adv(struct bt_mesh_subnet *sub) -{ - uint8_t tmp[16]; - int err; - - BT_DBG(""); - - proxy_svc_data[2] = ID_TYPE_NODE; - - err = bt_rand(proxy_svc_data + 11, 8); - if (err) { - return err; - } - - memset(tmp, 0, 6); - memcpy(tmp + 6, proxy_svc_data + 11, 8); - sys_put_be16(bt_mesh_primary_addr(), tmp + 14); - - err = bt_encrypt_be(sub->keys[SUBNET_KEY_TX_IDX(sub)].identity, tmp, - tmp); - if (err) { - return err; - } - - memcpy(proxy_svc_data + 3, tmp + 8, 8); - - err = bt_le_adv_start(&fast_adv_param, node_id_ad, - ARRAY_SIZE(node_id_ad), NULL, 0); - if (err) { - BT_WARN("Failed to advertise using Node ID (err %d)", err); - return err; - } - - proxy_adv_enabled = true; - - return 0; -} - -static int net_id_adv(struct bt_mesh_subnet *sub) -{ - int err; - - BT_DBG(""); - - proxy_svc_data[2] = ID_TYPE_NET; - - BT_DBG("Advertising with NetId %s", - bt_hex(sub->keys[SUBNET_KEY_TX_IDX(sub)].net_id, 8)); - - memcpy(proxy_svc_data + 3, sub->keys[SUBNET_KEY_TX_IDX(sub)].net_id, 8); - - err = bt_le_adv_start(&slow_adv_param, net_id_ad, - ARRAY_SIZE(net_id_ad), NULL, 0); - if (err) { - BT_WARN("Failed to advertise using Network ID (err %d)", err); - return err; - } - - proxy_adv_enabled = true; - - return 0; -} - -static bool advertise_subnet(struct bt_mesh_subnet *sub) -{ - if (sub->net_idx == BT_MESH_KEY_UNUSED) { - return false; - } - - return (sub->node_id == BT_MESH_NODE_IDENTITY_RUNNING || - bt_mesh_gatt_proxy_get() == BT_MESH_GATT_PROXY_ENABLED); -} - -static struct bt_mesh_subnet *next_sub(void) -{ - struct bt_mesh_subnet *sub = NULL; - - if (!beacon_sub) { - beacon_sub = bt_mesh_subnet_next(NULL); - if (!beacon_sub) { - /* No valid subnets */ - return NULL; - } - } - - sub = beacon_sub; - do { - if (advertise_subnet(sub)) { - beacon_sub = sub; - return sub; - } - - sub = bt_mesh_subnet_next(sub); - } while (sub != beacon_sub); - - /* No subnets to advertise on */ - - return NULL; -} - -static int sub_count_cb(struct bt_mesh_subnet *sub, void *cb_data) -{ - int *count = cb_data; - - if (advertise_subnet(sub)) { - (*count)++; - } - - return 0; -} - -static int sub_count(void) -{ - int count = 0; - - (void)bt_mesh_subnet_find(sub_count_cb, &count); - return count; -} - -static int32_t gatt_proxy_advertise(struct bt_mesh_subnet *sub) -{ - int32_t remaining = K_FOREVER; - int subnet_count; - - BT_DBG(""); - - if (conn_count == CONFIG_BT_MAX_CONN) { - BT_DBG("Connectable advertising deferred (max connections %d)", conn_count); - return -ENOMEM; - } - - sub = beacon_sub ? beacon_sub : bt_mesh_subnet_next(beacon_sub); - if (!sub) { - BT_WARN("No subnets to advertise on"); - return -ENOENT; - } - - if (sub->node_id == BT_MESH_NODE_IDENTITY_RUNNING) { - uint32_t active = k_uptime_get_32() - sub->node_id_start; - - if (active < NODE_ID_TIMEOUT) { - remaining = NODE_ID_TIMEOUT - active; - BT_DBG("Node ID active for %u ms, %d ms remaining", - (unsigned) active, (int) remaining); - node_id_adv(sub); - } else { - bt_mesh_proxy_identity_stop(sub); - BT_DBG("Node ID stopped"); - } - } - - if (sub->node_id == BT_MESH_NODE_IDENTITY_STOPPED) { - net_id_adv(sub); - } - - subnet_count = sub_count(); - BT_DBG("sub_count %u", subnet_count); - if (subnet_count > 1) { - int32_t max_timeout; - - /* We use NODE_ID_TIMEOUT as a starting point since it may - * be less than 60 seconds. Divide this period into at least - * 6 slices, but make sure that a slice is at least one - * second long (to avoid excessive rotation). - */ - max_timeout = NODE_ID_TIMEOUT / max(subnet_count, 6); - max_timeout = max(max_timeout, K_SECONDS(1)); - - if (remaining > max_timeout || remaining < 0) { - remaining = max_timeout; - } - } - - BT_DBG("Advertising %d ms for net_idx 0x%04x", - (int) remaining, sub->net_idx); - - beacon_sub = bt_mesh_subnet_next(beacon_sub); - - return remaining; -} -#endif /* GATT_PROXY */ - -#if (MYNEWT_VAL(BLE_MESH_PB_GATT)) -static size_t gatt_prov_adv_create(struct bt_data prov_sd[2]) -{ - const struct bt_mesh_prov *prov = bt_mesh_prov_get(); - const char *name = CONFIG_BT_DEVICE_NAME; - size_t name_len = strlen(name); - size_t prov_sd_len = 0; - size_t sd_space = 31; - - memcpy(prov_svc_data + 2, prov->uuid, 16); - sys_put_be16(prov->oob_info, prov_svc_data + 18); - - if (prov->uri) { - size_t uri_len = strlen(prov->uri); - - if (uri_len > 29) { - /* There's no way to shorten an URI */ - BT_WARN("Too long URI to fit advertising packet"); - } else { - prov_sd[0].type = BT_DATA_URI; - prov_sd[0].data_len = uri_len; - prov_sd[0].data = (void *)prov->uri; - sd_space -= 2 + uri_len; - prov_sd_len++; - } - } - - if (sd_space > 2 && name_len > 0) { - sd_space -= 2; - - if (sd_space < name_len) { - prov_sd[prov_sd_len].type = BT_DATA_NAME_SHORTENED; - prov_sd[prov_sd_len].data_len = sd_space; - } else { - prov_sd[prov_sd_len].type = BT_DATA_NAME_COMPLETE; - prov_sd[prov_sd_len].data_len = name_len; - } - - prov_sd[prov_sd_len].data = (void *)name; - prov_sd_len++; - } - - return prov_sd_len; -} -#endif /* PB_GATT */ - -int32_t bt_mesh_proxy_adv_start(void) -{ - BT_DBG(""); - - if (gatt_svc == MESH_GATT_NONE) { - return K_FOREVER; - } - -#if (MYNEWT_VAL(BLE_MESH_PB_GATT)) - if (!bt_mesh_is_provisioned()) { - const struct ble_gap_adv_params *param; - struct bt_data prov_sd[2]; - size_t prov_sd_len; - - if (prov_fast_adv) { - param = &fast_adv_param; - } else { - param = &slow_adv_param; - } - - prov_sd_len = gatt_prov_adv_create(prov_sd); - - if (bt_le_adv_start(param, prov_ad, ARRAY_SIZE(prov_ad), - prov_sd, prov_sd_len) == 0) { - proxy_adv_enabled = true; - - /* Advertise 60 seconds using fast interval */ - if (prov_fast_adv) { - prov_fast_adv = false; - return K_SECONDS(60); - } - } - } -#endif /* PB_GATT */ - -#if (MYNEWT_VAL(BLE_MESH_GATT_PROXY)) - if (bt_mesh_is_provisioned()) { - return gatt_proxy_advertise(next_sub()); - } -#endif /* GATT_PROXY */ - - return K_FOREVER; -} - -void bt_mesh_proxy_adv_stop(void) -{ - int err; - - BT_DBG("adv_enabled %u", proxy_adv_enabled); - - if (!proxy_adv_enabled) { - return; - } - - err = bt_le_adv_stop(true); - if (err) { - BT_ERR("Failed to stop advertising (err %d)", err); - } else { - proxy_adv_enabled = false; - } -} - -#if defined(CONFIG_BT_MESH_GATT_PROXY) -static void subnet_evt(struct bt_mesh_subnet *sub, enum bt_mesh_key_evt evt) -{ - if (evt == BT_MESH_KEY_DELETED) { - if (sub == beacon_sub) { - beacon_sub = NULL; - } - } else { - bt_mesh_proxy_beacon_send(sub); - } -} -#endif - -static void ble_mesh_handle_connect(struct ble_gap_event *event, void *arg) -{ -#if MYNEWT_VAL(BLE_EXT_ADV) - /* When EXT ADV is enabled then mesh proxy is connected - * when proxy advertising instance is completed. - * Therefore no need to handle BLE_GAP_EVENT_CONNECT - */ - if (event->type == BLE_GAP_EVENT_ADV_COMPLETE) { - /* Reason 0 means advertising has been completed because - * connection has been established - */ - if (event->adv_complete.reason != 0) { - return; - } - - if (event->adv_complete.instance != BT_MESH_ADV_GATT_INST) { - return; - } - - proxy_connected(event->adv_complete.conn_handle); - } -#else - if (event->type == BLE_GAP_EVENT_CONNECT) { - proxy_connected(event->connect.conn_handle); - } -#endif -} - -int ble_mesh_proxy_gap_event(struct ble_gap_event *event, void *arg) -{ - if ((event->type == BLE_GAP_EVENT_CONNECT) || - (event->type == BLE_GAP_EVENT_ADV_COMPLETE)) { - ble_mesh_handle_connect(event, arg); - } else if (event->type == BLE_GAP_EVENT_DISCONNECT) { - proxy_disconnected(event->disconnect.conn.conn_handle, - event->disconnect.reason); - } else if (event->type == BLE_GAP_EVENT_SUBSCRIBE) { - if (event->subscribe.attr_handle == svc_handles.proxy_data_out_h) { -#if (MYNEWT_VAL(BLE_MESH_GATT_PROXY)) - proxy_ccc_write(event->subscribe.conn_handle); -#endif - } else if (event->subscribe.attr_handle == - svc_handles.prov_data_out_h) { -#if (MYNEWT_VAL(BLE_MESH_PB_GATT)) - prov_ccc_write(event->subscribe.conn_handle); -#endif - } - } - - return 0; -} - -static int -dummy_access_cb(uint16_t conn_handle, uint16_t attr_handle, - struct ble_gatt_access_ctxt *ctxt, void *arg) -{ - /* - * We should never never enter this callback - it's attached to notify-only - * characteristic which are notified directly from mbuf. And we can't pass - * NULL as access_cb because gatts will assert on init... - */ - BLE_HS_DBG_ASSERT(0); - return 0; -} - -static const struct ble_gatt_svc_def svc_defs [] = { - { - .type = BLE_GATT_SVC_TYPE_PRIMARY, - .uuid = BLE_UUID16_DECLARE(BT_UUID_MESH_PROXY_VAL), - .characteristics = (struct ble_gatt_chr_def[]) { { - .uuid = BLE_UUID16_DECLARE(BT_UUID_MESH_PROXY_DATA_IN_VAL), - .access_cb = proxy_recv, - .flags = BLE_GATT_CHR_F_WRITE_NO_RSP, - }, { - .uuid = BLE_UUID16_DECLARE(BT_UUID_MESH_PROXY_DATA_OUT_VAL), - .access_cb = dummy_access_cb, - .flags = BLE_GATT_CHR_F_NOTIFY, - }, { - 0, /* No more characteristics in this service. */ - } }, - }, { - .type = BLE_GATT_SVC_TYPE_PRIMARY, - .uuid = BLE_UUID16_DECLARE(BT_UUID_MESH_PROV_VAL), - .characteristics = (struct ble_gatt_chr_def[]) { { - .uuid = BLE_UUID16_DECLARE(BT_UUID_MESH_PROV_DATA_IN_VAL), - .access_cb = proxy_recv, - .flags = BLE_GATT_CHR_F_WRITE_NO_RSP, - }, { - .uuid = BLE_UUID16_DECLARE(BT_UUID_MESH_PROV_DATA_OUT_VAL), - .access_cb = dummy_access_cb, - .flags = BLE_GATT_CHR_F_NOTIFY, - }, { - 0, /* No more characteristics in this service. */ - } }, - }, { - 0, /* No more services. */ - }, -}; - -int bt_mesh_proxy_svcs_register(void) -{ - int rc; - - rc = ble_gatts_count_cfg(svc_defs); - assert(rc == 0); - - rc = ble_gatts_add_svcs(svc_defs); - assert(rc == 0); - - return 0; -} - -int bt_mesh_proxy_init(void) -{ - int i; - -#if (MYNEWT_VAL(BLE_MESH_GATT_PROXY)) - if (!bt_mesh_subnet_cb_list[4]) { - bt_mesh_subnet_cb_list[4] = subnet_evt; - } -#endif - - for (i = 0; i < MYNEWT_VAL(BLE_MAX_CONNECTIONS); ++i) { -#if (MYNEWT_VAL(BLE_MESH_GATT_PROXY)) - k_work_init(&clients[i].send_beacons, proxy_send_beacons); -#endif - clients[i].buf = NET_BUF_SIMPLE(CLIENT_BUF_SIZE); - clients[i].conn_handle = BLE_HS_CONN_HANDLE_NONE; - - k_delayed_work_init(&clients[i].sar_timer, proxy_sar_timeout); - k_delayed_work_add_arg(&clients[i].sar_timer, &clients[i]); - } - - resolve_svc_handles(); - - ble_gatts_svc_set_visibility(svc_handles.proxy_h, 0); - ble_gatts_svc_set_visibility(svc_handles.prov_h, 0); - - return 0; -} - -void bt_mesh_proxy_on_idle(struct bt_mesh_proxy_idle_cb *cb) -{ - if (!atomic_get(&pending_notifications)) { - cb->cb(); - return; - } - - sys_slist_append(&idle_waiters, &cb->n); -} - -#endif /* MYNEWT_VAL(BLE_MESH_PROXY) */ diff --git a/nimble/host/mesh/src/proxy.h b/nimble/host/mesh/src/proxy.h index ebade45ab6..42530293e9 100644 --- a/nimble/host/mesh/src/proxy.h +++ b/nimble/host/mesh/src/proxy.h @@ -9,34 +9,35 @@ #ifndef __PROXY_H__ #define __PROXY_H__ -#define BT_MESH_PROXY_NET_PDU 0x00 -#define BT_MESH_PROXY_BEACON 0x01 -#define BT_MESH_PROXY_CONFIG 0x02 -#define BT_MESH_PROXY_PROV 0x03 - -#include "mesh/mesh.h" #include "mesh/slist.h" +#if CONFIG_BT_MESH_DEBUG_USE_ID_ADDR +#define ADV_OPT_USE_IDENTITY BT_LE_ADV_OPT_USE_IDENTITY +#else +#define ADV_OPT_USE_IDENTITY 0 +#endif + +#define ADV_SLOW_INT \ +.itvl_min = BT_GAP_ADV_SLOW_INT_MIN, \ +.itvl_max = BT_GAP_ADV_SLOW_INT_MAX, + +#define ADV_FAST_INT \ +.itvl_min = BT_GAP_ADV_FAST_INT_MIN_2, \ +.itvl_max = BT_GAP_ADV_FAST_INT_MAX_2, + struct bt_mesh_proxy_idle_cb { sys_snode_t n; void (*cb)(void); }; -int bt_mesh_proxy_send(uint16_t conn_handle, uint8_t type, struct os_mbuf *msg); - -int bt_mesh_proxy_prov_enable(void); -int bt_mesh_proxy_prov_disable(bool disconnect); - +void notify_complete(void); int bt_mesh_proxy_gatt_enable(void); int bt_mesh_proxy_gatt_disable(void); void bt_mesh_proxy_gatt_disconnect(void); void bt_mesh_proxy_beacon_send(struct bt_mesh_subnet *sub); -struct os_mbuf *bt_mesh_proxy_get_buf(void); - -int32_t bt_mesh_proxy_adv_start(void); -void bt_mesh_proxy_adv_stop(void); +int bt_mesh_proxy_adv_start(void); void bt_mesh_proxy_identity_start(struct bt_mesh_subnet *sub); void bt_mesh_proxy_identity_stop(struct bt_mesh_subnet *sub); @@ -44,9 +45,7 @@ void bt_mesh_proxy_identity_stop(struct bt_mesh_subnet *sub); bool bt_mesh_proxy_relay(struct os_mbuf *buf, uint16_t dst); void bt_mesh_proxy_addr_add(struct os_mbuf *buf, uint16_t addr); -int bt_mesh_proxy_init(void); -void bt_mesh_proxy_on_idle(struct bt_mesh_proxy_idle_cb *cb); - int ble_mesh_proxy_gap_event(struct ble_gap_event *event, void *arg); +int bt_mesh_proxy_init(void); -#endif +#endif /* __PROXY_H__ */ diff --git a/nimble/host/mesh/src/proxy_msg.c b/nimble/host/mesh/src/proxy_msg.c new file mode 100644 index 0000000000..ef03b7d7cf --- /dev/null +++ b/nimble/host/mesh/src/proxy_msg.c @@ -0,0 +1,274 @@ +/* Bluetooth Mesh */ + +/* + * Copyright (c) 2017 Intel Corporation + * Copyright (c) 2021 Lingao Meng + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "syscfg/syscfg.h" + +#define BLE_NPL_LOG_MODULE BLE_MESH_PROXY_LOG +#include + +#if MYNEWT_VAL(BLE_MESH_PROXY) + +#include "mesh/mesh.h" +#include "host/ble_att.h" +#include "services/gatt/ble_svc_gatt.h" +#include "../../host/src/ble_hs_priv.h" + +#include "mesh_priv.h" +#include "adv.h" +#include "net.h" +#include "rpl.h" +#include "prov.h" +#include "beacon.h" +#include "foundation.h" +#include "access.h" +#include "proxy.h" +#include "proxy_msg.h" + +#define PDU_SAR(data) (data[0] >> 6) + +#define BT_UUID_16_ENCODE(w16) \ + (((w16) >> 0) & 0xFF), \ + (((w16) >> 8) & 0xFF) +/* Mesh Profile 1.0 Section 6.6: + * "The timeout for the SAR transfer is 20 seconds. When the timeout + * expires, the Proxy Server shall disconnect." + */ +#define PROXY_SAR_TIMEOUT K_SECONDS(20) + +#define SAR_COMPLETE 0x00 +#define SAR_FIRST 0x01 +#define SAR_CONT 0x02 +#define SAR_LAST 0x03 + +#define PDU_HDR(sar, type) (sar << 6 | (type & BIT_MASK(6))) + +static uint8_t bufs[CONFIG_BT_MAX_CONN * CONFIG_BT_MESH_PROXY_MSG_LEN]; + +static struct bt_mesh_proxy_role roles[CONFIG_BT_MAX_CONN]; + +static void proxy_sar_timeout(struct ble_npl_event *work) +{ + struct bt_mesh_proxy_role *role; + int rc; + role = ble_npl_event_get_arg(work); + + + BT_WARN("Proxy SAR timeout"); + + if (role->conn_handle != BLE_HS_CONN_HANDLE_NONE) { + rc = ble_gap_terminate(role->conn_handle, + BLE_ERR_REM_USER_CONN_TERM); + assert(rc == 0); + } +} + +int bt_mesh_proxy_msg_recv(struct bt_mesh_proxy_role *role, + const void *buf, uint16_t len) +{ + const uint8_t *data = buf; + + switch (PDU_SAR(data)) { + case SAR_COMPLETE: + if (role->buf->om_len) { + BT_WARN("Complete PDU while a pending incomplete one"); + return -EINVAL; + } + + role->msg_type = PDU_TYPE(data); + net_buf_simple_add_mem(role->buf, data + 1, len - 1); + role->cb.recv(role); + net_buf_simple_reset(role->buf); + break; + + case SAR_FIRST: + if (role->buf->om_len) { + BT_WARN("First PDU while a pending incomplete one"); + return -EINVAL; + } + + k_work_reschedule(&role->sar_timer, PROXY_SAR_TIMEOUT); + role->msg_type = PDU_TYPE(data); + net_buf_simple_add_mem(role->buf, data + 1, len - 1); + break; + + case SAR_CONT: + if (!role->buf->om_len) { + BT_WARN("Continuation with no prior data"); + return -EINVAL; + } + + if (role->msg_type != PDU_TYPE(data)) { + BT_WARN("Unexpected message type in continuation"); + return -EINVAL; + } + + k_work_reschedule(&role->sar_timer, PROXY_SAR_TIMEOUT); + net_buf_simple_add_mem(role->buf, data + 1, len - 1); + break; + + case SAR_LAST: + if (!role->buf->om_len) { + BT_WARN("Last SAR PDU with no prior data"); + return -EINVAL; + } + + if (role->msg_type != PDU_TYPE(data)) { + BT_WARN("Unexpected message type in last SAR PDU"); + return -EINVAL; + } + + /* If this fails, the work handler exits early, as there's no + * active SAR buffer. + */ + (void)k_work_cancel_delayable(&role->sar_timer); + net_buf_simple_add_mem(role->buf, data + 1, len - 1); + role->cb.recv(role); + net_buf_simple_reset(role->buf); + break; + } + + return len; +} + +int bt_mesh_proxy_msg_send(struct bt_mesh_proxy_role *role, uint8_t type, + struct os_mbuf *msg) +{ + int err; + uint16_t mtu; + uint16_t conn_handle = role->conn_handle; + + BT_DBG("conn_handle %d type 0x%02x len %u: %s", conn_handle, type, msg->om_len, + bt_hex(msg->om_data, msg->om_len)); + + /* ATT_MTU - OpCode (1 byte) - Handle (2 bytes) */ + mtu = ble_att_mtu(conn_handle) - 3; + if (mtu > msg->om_len) { + net_buf_simple_push_u8(msg, PDU_HDR(SAR_COMPLETE, type)); + return role->cb.send(conn_handle, msg->om_data, msg->om_len); + } + + net_buf_simple_push_u8(msg, PDU_HDR(SAR_FIRST, type)); + err = role->cb.send(conn_handle, msg->om_data, mtu); + if (err) { + return err; + } + net_buf_simple_pull_mem(msg, mtu); + + while (msg->om_len) { + if (msg->om_len + 1 < mtu) { + net_buf_simple_push_u8(msg, PDU_HDR(SAR_LAST, type)); + err = role->cb.send(conn_handle, msg->om_data, msg->om_len); + if (err) { + return err; + } + break; + } + + net_buf_simple_push_u8(msg, PDU_HDR(SAR_CONT, type)); + err = role->cb.send(conn_handle, msg->om_data, mtu); + if (err) { + return err; + } + net_buf_simple_pull_mem(msg, mtu); + } + + return 0; +} + +static void proxy_msg_init(struct bt_mesh_proxy_role *role) +{ + + /* Check if buf has been allocated, in this way, we no longer need + * to repeat the operation. + */ + if (role->buf != NULL) { + net_buf_simple_reset(role->buf); + return; + } + + role->buf = NET_BUF_SIMPLE(CONFIG_BT_MESH_PROXY_MSG_LEN); + net_buf_simple_init_with_data(role->buf, + &bufs[role->index * + CONFIG_BT_MESH_PROXY_MSG_LEN], + CONFIG_BT_MESH_PROXY_MSG_LEN); + + net_buf_simple_reset(role->buf); + + k_work_init_delayable(&role->sar_timer, proxy_sar_timeout); + k_work_add_arg_delayable(&role->sar_timer, role); +} + +struct bt_mesh_proxy_role *bt_mesh_proxy_role_find_with_buf(const struct os_mbuf *buf) +{ + unsigned int i; + + for (i = 0; i < CONFIG_BT_MAX_CONN; i++) { + if (roles[i].buf == buf) { + return &roles[i]; + } + } + + return NULL; +} + +struct bt_mesh_proxy_role *get_role(uint16_t conn_handle) +{ + unsigned int i; + + for (i = 0; i < CONFIG_BT_MAX_CONN; i++) { + if (roles[i].conn_handle == BLE_HS_CONN_HANDLE_NONE) { + roles[i].conn_handle = conn_handle; + return &roles[i]; + } + } + + return NULL; +} + +struct bt_mesh_proxy_role *bt_mesh_proxy_role_setup(uint16_t conn_handle, + proxy_send_cb_t send, + proxy_recv_cb_t recv) +{ + struct bt_mesh_proxy_role *role; + + role = get_role(conn_handle); + assert(role); + + proxy_msg_init(role); + + role->cb.recv = recv; + role->cb.send = send; + + return role; +} + +void bt_mesh_proxy_role_cleanup(struct bt_mesh_proxy_role *role) +{ + + /* If this fails, the work handler exits early, as + * there's no active connection. + */ + (void)k_work_cancel_delayable(&role->sar_timer); + + role->conn_handle = BLE_HS_CONN_HANDLE_NONE; + + bt_mesh_adv_update(); +} + +void bt_mesh_proxy_msg_init(void) +{ + unsigned int i; + + for (i = 0; i < MYNEWT_VAL(BLE_MAX_CONNECTIONS); i++) { + roles[i].index = i; + roles[i].conn_handle = 0xffff; + } +} + +#endif /* MYNEWT_VAL(BLE_MESH_PROXY) */ diff --git a/nimble/host/mesh/src/proxy_msg.h b/nimble/host/mesh/src/proxy_msg.h new file mode 100644 index 0000000000..447224bcd0 --- /dev/null +++ b/nimble/host/mesh/src/proxy_msg.h @@ -0,0 +1,71 @@ +/* Bluetooth Mesh */ + +/* + * Copyright (c) 2017 Intel Corporation + * Copyright (c) 2021 Lingao Meng + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_SUBSYS_BLUETOOTH_MESH_PROXY_MSG_H_ +#define ZEPHYR_SUBSYS_BLUETOOTH_MESH_PROXY_MSG_H_ + +#define PDU_TYPE(data) (data[0] & BIT_MASK(6)) +#define CFG_FILTER_SET 0x00 +#define CFG_FILTER_ADD 0x01 +#define CFG_FILTER_REMOVE 0x02 +#define CFG_FILTER_STATUS 0x03 + +#define BT_MESH_PROXY_NET_PDU 0x00 +#define BT_MESH_PROXY_BEACON 0x01 +#define BT_MESH_PROXY_CONFIG 0x02 +#define BT_MESH_PROXY_PROV 0x03 + +#define PDU_HDR(sar, type) (sar << 6 | (type & BIT_MASK(6))) + +struct bt_mesh_proxy_role; + +typedef int (*proxy_send_cb_t)(uint16_t conn_handle, + const void *data, uint16_t len); + +typedef void (*proxy_recv_cb_t)(struct bt_mesh_proxy_role *role); + +struct bt_mesh_proxy_role { + unsigned int index; + uint16_t conn_handle; + uint8_t msg_type; + + struct { + proxy_send_cb_t send; + proxy_recv_cb_t recv; + } cb; + + struct k_work_delayable sar_timer; + struct os_mbuf *buf; +}; + +struct bt_mesh_proxy_client { + struct bt_mesh_proxy_role *cli; + uint16_t conn_handle; + uint16_t filter[MYNEWT_VAL(BLE_MESH_PROXY_FILTER_SIZE)]; + enum __packed { + NONE, + ACCEPT, + REJECT, + } filter_type; + struct ble_npl_callout send_beacons; +}; + +int bt_mesh_proxy_msg_recv(struct bt_mesh_proxy_role *role, + const void *buf, uint16_t len); +int bt_mesh_proxy_msg_send(struct bt_mesh_proxy_role *role, uint8_t type, struct os_mbuf *msg); +void bt_mesh_proxy_role_cleanup(struct bt_mesh_proxy_role *role); +struct bt_mesh_proxy_role *bt_mesh_proxy_role_setup(uint16_t conn_handle, + proxy_send_cb_t send, + proxy_recv_cb_t recv); +struct bt_mesh_proxy_client *find_client(uint16_t conn_handle); + +struct bt_mesh_proxy_role *bt_mesh_proxy_role_find_with_buf(const struct os_mbuf *buf); + +void bt_mesh_proxy_msg_init(void); +#endif /* ZEPHYR_SUBSYS_BLUETOOTH_MESH_PROXY_MSG_H_ */ diff --git a/nimble/host/mesh/src/proxy_srv.c b/nimble/host/mesh/src/proxy_srv.c new file mode 100644 index 0000000000..22d9082cd1 --- /dev/null +++ b/nimble/host/mesh/src/proxy_srv.c @@ -0,0 +1,1011 @@ +/* Bluetooth Mesh */ + +/* + * Copyright (c) 2017 Intel Corporation + * Copyright (c) 2021 Lingao Meng + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define BLE_NPL_LOG_MODULE BLE_MESH_PROXY_LOG +#include + +#include "mesh/slist.h" +#include "mesh/mesh.h" +#include "../../host/src/ble_hs_priv.h" +#include "services/gatt/ble_svc_gatt.h" + +#include "mesh_priv.h" +#include "adv.h" +#include "net.h" +#include "rpl.h" +#include "transport.h" +#include "prov.h" +#include "beacon.h" +#include "foundation.h" +#include "access.h" +#include "proxy.h" +#include "proxy_msg.h" +#include "pb_gatt_srv.h" + +#if defined(CONFIG_BT_MESH_PROXY_USE_DEVICE_NAME) +#define ADV_OPT_USE_NAME BT_LE_ADV_OPT_USE_NAME +#else +#define ADV_OPT_USE_NAME 0 +#endif + +#define ADV_OPT_PROXY \ +.conn_mode = (BLE_GAP_CONN_MODE_UND), \ +.disc_mode = (BLE_GAP_DISC_MODE_GEN), + + +#define BT_UUID_MESH_PROXY_VAL 0x1828 +#define CLIENT_BUF_SIZE 66 + +#define BT_UUID_16_ENCODE(w16) \ + (((w16) >> 0) & 0xFF), \ + (((w16) >> 8) & 0xFF) + +static sys_slist_t idle_waiters; +static atomic_t pending_notifications; + +static void proxy_send_beacons(struct ble_npl_event *work); + +static int proxy_send(uint16_t conn_handle, + const void *data, uint16_t len); + + +static struct bt_mesh_proxy_client clients[CONFIG_BT_MAX_CONN]; + +static bool service_registered; + +static int conn_count; + +struct bt_mesh_proxy_client *find_client(uint16_t conn_handle) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(clients); i++) { + if (clients[i].conn_handle == conn_handle) { + return &clients[i]; + } + } + return NULL; +} + +static struct bt_mesh_proxy_client *get_client(uint16_t conn_handle) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(clients); i++) { + if (clients[i].conn_handle == 0xffff) { + clients[i].conn_handle = conn_handle; + return &clients[i]; + } + } + return NULL; +} + +/* Next subnet in queue to be advertised */ +static struct bt_mesh_subnet *beacon_sub; + +static int filter_set(struct bt_mesh_proxy_client *client, + struct os_mbuf *buf) +{ + uint8_t type; + + if (buf->om_len < 1) { + BT_WARN("Too short Filter Set message"); + return -EINVAL; + } + + type = net_buf_simple_pull_u8(buf); + BT_DBG("type 0x%02x", type); + + switch (type) { + case 0x00: + (void)memset(client->filter, 0, sizeof(client->filter)); + client->filter_type = ACCEPT; + break; + case 0x01: + (void)memset(client->filter, 0, sizeof(client->filter)); + client->filter_type = REJECT; + break; + default: + BT_WARN("Prohibited Filter Type 0x%02x", type); + return -EINVAL; + } + + return 0; +} + +static void filter_add(struct bt_mesh_proxy_client *client, uint16_t addr) +{ + int i; + + BT_DBG("addr 0x%04x", addr); + + if (addr == BT_MESH_ADDR_UNASSIGNED) { + return; + } + + for (i = 0; i < ARRAY_SIZE(client->filter); i++) { + if (client->filter[i] == addr) { + return; + } + } + + for (i = 0; i < ARRAY_SIZE(client->filter); i++) { + if (client->filter[i] == BT_MESH_ADDR_UNASSIGNED) { + client->filter[i] = addr; + return; + } + } +} + +static void filter_remove(struct bt_mesh_proxy_client *client, uint16_t addr) +{ + int i; + + BT_DBG("addr 0x%04x", addr); + + if (addr == BT_MESH_ADDR_UNASSIGNED) { + return; + } + + for (i = 0; i < ARRAY_SIZE(client->filter); i++) { + if (client->filter[i] == addr) { + client->filter[i] = BT_MESH_ADDR_UNASSIGNED; + return; + } + } +} + +static void send_filter_status(struct bt_mesh_proxy_client *client, + struct bt_mesh_net_rx *rx, + struct os_mbuf *buf) +{ + struct bt_mesh_net_tx tx = { + .sub = rx->sub, + .ctx = &rx->ctx, + .src = bt_mesh_primary_addr(), + }; + uint16_t filter_size; + int i, err; + + /* Configuration messages always have dst unassigned */ + tx.ctx->addr = BT_MESH_ADDR_UNASSIGNED; + + net_buf_simple_init(buf, 10); + + net_buf_simple_add_u8(buf, CFG_FILTER_STATUS); + + if (client->filter_type == ACCEPT) { + net_buf_simple_add_u8(buf, 0x00); + } else { + net_buf_simple_add_u8(buf, 0x01); + } + + for (filter_size = 0U, i = 0; i < ARRAY_SIZE(client->filter); i++) { + if (client->filter[i] != BT_MESH_ADDR_UNASSIGNED) { + filter_size++; + } + } + + net_buf_simple_add_be16(buf, filter_size); + + BT_DBG("%u bytes: %s", buf->om_len, bt_hex(buf->om_data, buf->om_len)); + + err = bt_mesh_net_encode(&tx, buf, true); + if (err) { + BT_ERR("Encoding Proxy cfg message failed (err %d)", err); + return; + } + + err = bt_mesh_proxy_msg_send(client->cli, BT_MESH_PROXY_CONFIG, buf); + if (err) { + BT_ERR("Failed to send proxy cfg message (err %d)", err); + } +} + +static void proxy_filter_recv(uint16_t conn_handle, + struct bt_mesh_net_rx *rx, struct os_mbuf *buf) +{ + struct bt_mesh_proxy_client *client; + uint8_t opcode; + + client = find_client(conn_handle); + + opcode = net_buf_simple_pull_u8(buf); + switch (opcode) { + case CFG_FILTER_SET: + filter_set(client, buf); + send_filter_status(client, rx, buf); + break; + case CFG_FILTER_ADD: + while (buf->om_len >= 2) { + uint16_t addr; + + addr = net_buf_simple_pull_be16(buf); + filter_add(client, addr); + } + send_filter_status(client, rx, buf); + break; + case CFG_FILTER_REMOVE: + while (buf->om_len >= 2) { + uint16_t addr; + + addr = net_buf_simple_pull_be16(buf); + filter_remove(client, addr); + } + send_filter_status(client, rx, buf); + break; + default: + BT_WARN("Unhandled configuration OpCode 0x%02x", opcode); + break; + } +} + +static void proxy_cfg(struct bt_mesh_proxy_role *role) +{ + struct os_mbuf *buf = NET_BUF_SIMPLE(BT_MESH_NET_MAX_PDU_LEN); + struct bt_mesh_net_rx rx; + int err; + + err = bt_mesh_net_decode(role->buf, BT_MESH_NET_IF_PROXY_CFG, + &rx, buf); + if (err) { + BT_ERR("Failed to decode Proxy Configuration (err %d)", err); + return; + } + + rx.local_match = 1U; + + if (bt_mesh_rpl_check(&rx, NULL)) { + BT_WARN("Replay: src 0x%04x dst 0x%04x seq 0x%06x", + rx.ctx.addr, rx.ctx.recv_dst, rx.seq); + return; + } + + /* Remove network headers */ + net_buf_simple_pull(buf, BT_MESH_NET_HDR_LEN); + + BT_DBG("%u bytes: %s", buf->om_len, bt_hex(buf->om_data, buf->om_len)); + + if (buf->om_len < 1) { + BT_WARN("Too short proxy configuration PDU"); + return; + } + + proxy_filter_recv(role->conn_handle, &rx, buf); +} + +static void proxy_msg_recv(struct bt_mesh_proxy_role *role) +{ + switch (role->msg_type) { + case BT_MESH_PROXY_NET_PDU: + BT_DBG("Mesh Network PDU"); + bt_mesh_net_recv(role->buf, 0, BT_MESH_NET_IF_PROXY); + break; + case BT_MESH_PROXY_BEACON: + BT_DBG("Mesh Beacon PDU"); + bt_mesh_beacon_recv(role->buf); + break; + case BT_MESH_PROXY_CONFIG: + BT_DBG("Mesh Configuration PDU"); + proxy_cfg(role); + break; + default: + BT_WARN("Unhandled Message Type 0x%02x", role->msg_type); + break; + } +} + +static int beacon_send(struct bt_mesh_proxy_client *client, struct bt_mesh_subnet *sub) +{ + struct os_mbuf *buf = NET_BUF_SIMPLE(23); + int rc; + + net_buf_simple_init(buf, 1); + bt_mesh_beacon_create(sub, buf); + + rc = bt_mesh_proxy_msg_send(client->cli, BT_MESH_PROXY_BEACON, buf); + os_mbuf_free_chain(buf); + return rc; +} + +static int send_beacon_cb(struct bt_mesh_subnet *sub, void *cb_data) +{ + struct bt_mesh_proxy_client *client = cb_data; + + return beacon_send(client, sub); +} + +static void proxy_send_beacons(struct ble_npl_event *work) +{ + struct bt_mesh_proxy_client *client; + + client = ble_npl_event_get_arg(work); + + (void)bt_mesh_subnet_find(send_beacon_cb, client); +} + +void bt_mesh_proxy_beacon_send(struct bt_mesh_subnet *sub) +{ + int i; + + if (!sub) { + /* NULL means we send on all subnets */ + bt_mesh_subnet_foreach(bt_mesh_proxy_beacon_send); + return; + } + + for (i = 0; i < ARRAY_SIZE(clients); i++) { + if (clients[i].cli) { + beacon_send(&clients[i], sub); + } + } +} + +static void node_id_start(struct bt_mesh_subnet *sub) +{ + sub->node_id = BT_MESH_NODE_IDENTITY_RUNNING; + sub->node_id_start = k_uptime_get_32(); +} + +void bt_mesh_proxy_identity_start(struct bt_mesh_subnet *sub) +{ + node_id_start(sub); + + /* Prioritize the recently enabled subnet */ + beacon_sub = sub; +} + +void bt_mesh_proxy_identity_stop(struct bt_mesh_subnet *sub) + { + sub->node_id = BT_MESH_NODE_IDENTITY_STOPPED; + sub->node_id_start = 0U; +} + +int bt_mesh_proxy_identity_enable(void) +{ + BT_DBG(""); + + if (!bt_mesh_is_provisioned()) { + return -EAGAIN; + } + + if (bt_mesh_subnet_foreach(node_id_start)) { + bt_mesh_adv_update(); + } + + return 0; +} + +#define ID_TYPE_NET 0x00 +#define ID_TYPE_NODE 0x01 + +#define NODE_ID_LEN 19 +#define NET_ID_LEN 11 + +#define NODE_ID_TIMEOUT (CONFIG_BT_MESH_NODE_ID_TIMEOUT * MSEC_PER_SEC) + +static uint8_t proxy_svc_data[NODE_ID_LEN] = { + BT_UUID_16_ENCODE(BT_UUID_MESH_PROXY_VAL), +}; + +static const struct bt_data node_id_ad[] = { + BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)), + BT_DATA_BYTES(BT_DATA_UUID16_ALL, + BT_UUID_16_ENCODE(BT_UUID_MESH_PROXY_VAL)), + BT_DATA(BT_DATA_SVC_DATA16, proxy_svc_data, NODE_ID_LEN), +}; + +static const struct bt_data net_id_ad[] = { + BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)), + BT_DATA_BYTES(BT_DATA_UUID16_ALL, + BT_UUID_16_ENCODE(BT_UUID_MESH_PROXY_VAL)), + BT_DATA(BT_DATA_SVC_DATA16, proxy_svc_data, NET_ID_LEN), +}; + +static int node_id_adv(struct bt_mesh_subnet *sub, int32_t duration) +{ + struct ble_gap_adv_params fast_adv_param = { + ADV_OPT_PROXY + ADV_FAST_INT + }; +#if ADV_OPT_USE_NAME + const char *name = CONFIG_BT_DEVICE_NAME; + size_t name_len = strlen(name); + struct bt_data sd = { + .type = BT_DATA_NAME_COMPLETE, + .data_len = name_len, + .data = (void *)name + }; +#else + struct bt_data *sd = NULL; +#endif + uint8_t tmp[16]; + int err; + + BT_DBG(""); + + proxy_svc_data[2] = ID_TYPE_NODE; + + err = bt_rand(proxy_svc_data + 11, 8); + if (err) { + return err; + } + + (void)memset(tmp, 0, 6); + memcpy(tmp + 6, proxy_svc_data + 11, 8); + sys_put_be16(bt_mesh_primary_addr(), tmp + 14); + + err = bt_encrypt_be(sub->keys[SUBNET_KEY_TX_IDX(sub)].identity, tmp, + tmp); + if (err) { + return err; + } + + memcpy(proxy_svc_data + 3, tmp + 8, 8); + + err = bt_mesh_adv_start(&fast_adv_param, duration, node_id_ad, + ARRAY_SIZE(node_id_ad), sd, 0); + if (err) { + BT_WARN("Failed to advertise using Node ID (err %d)", err); + return err; + } + + return 0; +} + +static int net_id_adv(struct bt_mesh_subnet *sub, int32_t duration) +{ + struct ble_gap_adv_params slow_adv_param = { + ADV_OPT_PROXY + ADV_SLOW_INT + }; +#if ADV_OPT_USE_NAME + const char *name = CONFIG_BT_DEVICE_NAME; + size_t name_len = strlen(name); + struct bt_data sd = { + .type = BT_DATA_NAME_COMPLETE, + .data_len = name_len, + .data = (void *)name + }; +#else + struct bt_data *sd = NULL; +#endif + int err; + + BT_DBG(""); + + proxy_svc_data[2] = ID_TYPE_NET; + + BT_DBG("Advertising with NetId %s", + bt_hex(sub->keys[SUBNET_KEY_TX_IDX(sub)].net_id, 8)); + + memcpy(proxy_svc_data + 3, sub->keys[SUBNET_KEY_TX_IDX(sub)].net_id, 8); + + err = bt_mesh_adv_start(&slow_adv_param, duration, net_id_ad, + ARRAY_SIZE(net_id_ad), sd, 0); + if (err) { + BT_WARN("Failed to advertise using Network ID (err %d)", err); + return err; + } + + return 0; +} + +static bool advertise_subnet(struct bt_mesh_subnet *sub) +{ + if (sub->net_idx == BT_MESH_KEY_UNUSED) { + return false; + } + + return (sub->node_id == BT_MESH_NODE_IDENTITY_RUNNING || + bt_mesh_gatt_proxy_get() == BT_MESH_GATT_PROXY_ENABLED); +} + +static struct bt_mesh_subnet *next_sub(void) +{ + struct bt_mesh_subnet *sub = NULL; + + if (!beacon_sub) { + beacon_sub = bt_mesh_subnet_next(NULL); + if (!beacon_sub) { + /* No valid subnets */ + return NULL; + } + } + + sub = beacon_sub; + do { + if (advertise_subnet(sub)) { + beacon_sub = sub; + return sub; + } + + sub = bt_mesh_subnet_next(sub); + } while (sub != beacon_sub); + + /* No subnets to advertise on */ + return NULL; +} + +static int sub_count_cb(struct bt_mesh_subnet *sub, void *cb_data) +{ + int *count = cb_data; + + if (advertise_subnet(sub)) { + (*count)++; + } + + return 0; +} + +static int sub_count(void) +{ + int count = 0; + + (void)bt_mesh_subnet_find(sub_count_cb, &count); + + return count; +} + +static int gatt_proxy_advertise(struct bt_mesh_subnet *sub) +{ + int32_t remaining = K_FOREVER; + int subnet_count; + int err = -EBUSY; + + BT_DBG(""); + + if (conn_count == CONFIG_BT_MAX_CONN) { + BT_DBG("Connectable advertising deferred (max connections %d)", conn_count); + return -ENOMEM; + } + + sub = beacon_sub ? beacon_sub : bt_mesh_subnet_next(beacon_sub); + if (!sub) { + BT_WARN("No subnets to advertise on"); + return -ENOENT; + } + + subnet_count = sub_count(); + BT_DBG("sub_count %u", subnet_count); + if (subnet_count > 1) { + int32_t max_timeout; + + /* We use NODE_ID_TIMEOUT as a starting point since it may + * be less than 60 seconds. Divide this period into at least + * 6 slices, but make sure that a slice is at least one + * second long (to avoid excessive rotation). + */ + max_timeout = NODE_ID_TIMEOUT / MAX(subnet_count, 6); + max_timeout = MAX(max_timeout, K_SECONDS(1)); + + if (remaining > max_timeout || remaining < 0) { + remaining = max_timeout; + } + } + + if (sub->node_id == BT_MESH_NODE_IDENTITY_RUNNING) { + uint32_t active = k_uptime_get_32() - sub->node_id_start; + + if (active < NODE_ID_TIMEOUT) { + remaining = NODE_ID_TIMEOUT - active; + BT_DBG("Node ID active for %u ms, %d ms remaining", + active, remaining); + err = node_id_adv(sub, remaining); + } else { + bt_mesh_proxy_identity_stop(sub); + BT_DBG("Node ID stopped"); + } + } + + if (sub->node_id == BT_MESH_NODE_IDENTITY_STOPPED) { + err = net_id_adv(sub, remaining); + } + + BT_DBG("Advertising %d ms for net_idx 0x%04x", + (int) remaining, sub->net_idx); + + beacon_sub = bt_mesh_subnet_next(beacon_sub); + + return err; +} + +static void subnet_evt(struct bt_mesh_subnet *sub, enum bt_mesh_key_evt evt) +{ + if (evt == BT_MESH_KEY_DELETED) { + if (sub == beacon_sub) { + beacon_sub = NULL; + } + } else { + bt_mesh_proxy_beacon_send(sub); + } +} + +static void proxy_ccc_write(uint16_t conn_handle) +{ + struct bt_mesh_proxy_client *client; + + BT_DBG("conn_handle %d", conn_handle); + + client = find_client(conn_handle); + + if (client->filter_type == NONE) { + client->filter_type = ACCEPT; + k_work_add_arg(&client->send_beacons, client); + k_work_submit(&client->send_beacons); + } +} + +int bt_mesh_proxy_gatt_enable(void) +{ + uint16_t handle; + int rc; + int i; + + BT_DBG(""); + + if (!bt_mesh_is_provisioned()) { + return -ENOTSUP; + } + + if (service_registered) { + return -EBUSY; + } + + rc = ble_gatts_find_svc(BLE_UUID16_DECLARE(BT_UUID_MESH_PROXY_VAL), &handle); + assert(rc == 0); + ble_gatts_svc_set_visibility(handle, 1); + /* FIXME: figure out end handle */ + ble_svc_gatt_changed(svc_handles.proxy_h, 0xffff); + + service_registered = true; + + for (i = 0; i < ARRAY_SIZE(clients); i++) { + if (clients[i].cli) { + clients[i].filter_type = ACCEPT; + } + } + return 0; +} + +void bt_mesh_proxy_gatt_disconnect(void) +{ + int rc; + int i; + + BT_DBG(""); + + for (i = 0; i < ARRAY_SIZE(clients); i++) { + struct bt_mesh_proxy_client *client = &clients[i]; + + if ((client->cli) && + (client->filter_type == ACCEPT || + client->filter_type == REJECT)) { + client->filter_type = NONE; + rc = ble_gap_terminate(client->cli->conn_handle, + BLE_ERR_REM_USER_CONN_TERM); + assert(rc == 0); + } + } +} + +int bt_mesh_proxy_gatt_disable(void) +{ + uint16_t handle; + int rc; + BT_DBG(""); + + if (!service_registered) { + return -EALREADY; + } + + bt_mesh_proxy_gatt_disconnect(); + + rc = ble_gatts_find_svc(BLE_UUID16_DECLARE(BT_UUID_MESH_PROXY_VAL), &handle); + assert(rc == 0); + ble_gatts_svc_set_visibility(handle, 0); + /* FIXME: figure out end handle */ + ble_svc_gatt_changed(svc_handles.proxy_h, 0xffff); + service_registered = false; + + return 0; +} + +void bt_mesh_proxy_addr_add(struct os_mbuf *buf, uint16_t addr) +{ + struct bt_mesh_proxy_client *client; + struct bt_mesh_proxy_role *cli; + + cli = bt_mesh_proxy_role_find_with_buf(buf); + assert(cli); + + client = find_client(cli->conn_handle); + assert(client); + + BT_DBG("filter_type %u addr 0x%04x", client->filter_type, addr); + + if (client->filter_type == ACCEPT) { + filter_add(client, addr); + } else if (client->filter_type == REJECT) { + filter_remove(client, addr); + } +} + +static bool client_filter_match(struct bt_mesh_proxy_client *client, + uint16_t addr) +{ + int i; + + BT_DBG("filter_type %u addr 0x%04x", client->filter_type, addr); + + if (client->filter_type == REJECT) { + for (i = 0; i < ARRAY_SIZE(client->filter); i++) { + if (client->filter[i] == addr) { + return false; + } + } + + return true; + } + + if (addr == BT_MESH_ADDR_ALL_NODES) { + return true; + } + + if (client->filter_type == ACCEPT) { + for (i = 0; i < ARRAY_SIZE(client->filter); i++) { + if (client->filter[i] == addr) { + return true; + } + } + } + + return false; +} + +bool bt_mesh_proxy_relay(struct os_mbuf *buf, uint16_t dst) +{ + const struct bt_mesh_send_cb *cb = BT_MESH_ADV(buf)->cb; + void *cb_data = BT_MESH_ADV(buf)->cb_data; + bool relayed = false; + int i, err; + + BT_DBG("%u bytes to dst 0x%04x", buf->om_len, dst); + + for (i = 0; i < ARRAY_SIZE(clients); i++) { + struct bt_mesh_proxy_client *client = &clients[i]; + struct os_mbuf *msg; + + if (!client->cli) { + continue; + } + + if (!client_filter_match(client, dst)) { + continue; + } + + /* Proxy PDU sending modifies the original buffer, + * so we need to make a copy. + */ + msg = NET_BUF_SIMPLE(32); + net_buf_simple_init(msg, 1); + net_buf_simple_add_mem(msg, buf->om_data, buf->om_len); + + err = bt_mesh_proxy_msg_send(client->cli, BT_MESH_PROXY_NET_PDU, + msg); + + adv_send_start(0, err, cb, cb_data); + if (err) { + BT_ERR("Failed to send proxy message (err %d)", err); + + /* If segment_and_send() fails the buf_send_end() callback will + * not be called, so we need to clear the user data (net_buf, + * which is just opaque data to segment_and send) reference given + * to segment_and_send() here. + */ + net_buf_unref(buf); + continue; + } + os_mbuf_free_chain(msg); + relayed = true; + } + + return relayed; +} + +static void gatt_connected(uint16_t conn_handle) +{ + struct bt_mesh_proxy_client *client; + struct ble_gap_conn_desc info; + struct ble_hs_conn *conn; + + conn = ble_hs_conn_find(conn_handle); + bt_conn_get_info(conn, &info); + if (info.role != BLE_GAP_ROLE_SLAVE || + !service_registered) { + return; + } + BT_DBG("conn %d", conn_handle); + + conn_count++; + + client = get_client(conn_handle); + assert(client); + + client->filter_type = NONE; + (void)memset(client->filter, 0, sizeof(client->filter)); + + client->cli = bt_mesh_proxy_role_setup(conn_handle, proxy_send, + proxy_msg_recv); + + /* Try to re-enable advertising in case it's possible */ + if (conn_count < CONFIG_BT_MAX_CONN) { + bt_mesh_adv_update(); + } +} + +static void gatt_disconnected(struct ble_gap_conn_desc conn, uint8_t reason) +{ + struct bt_mesh_proxy_client *client; + + if (conn.role != BLE_GAP_ROLE_SLAVE) { + return; + } + + if (!service_registered && bt_mesh_is_provisioned()) { + (void)bt_mesh_proxy_gatt_enable(); + return; + } + + conn_count--; + client = find_client(conn.conn_handle); + if (client->cli) { + bt_mesh_proxy_role_cleanup(client->cli); + client->cli = NULL; + } + + client->conn_handle = 0xffff; +} + +void notify_complete(void) +{ + sys_snode_t *n; + + if (atomic_dec(&pending_notifications) > 1) { + return; + } + + BT_DBG(""); + + while ((n = sys_slist_get(&idle_waiters))) { + CONTAINER_OF(n, struct bt_mesh_proxy_idle_cb, n)->cb(); + } +} + +static int proxy_send(uint16_t conn_handle, + const void *data, uint16_t len) +{ + struct os_mbuf *om; + int err = 0; + + BT_DBG("%u bytes: %s", len, bt_hex(data, len)); + + om = ble_hs_mbuf_from_flat(data, len); + assert(om); + err = ble_gatts_notify_custom(conn_handle, svc_handles.proxy_data_out_h, om); + notify_complete(); + + if (!err) { + atomic_inc(&pending_notifications); + } + + return err; +} + +int bt_mesh_proxy_adv_start(void) +{ + BT_DBG(""); + + if (!service_registered || !bt_mesh_is_provisioned()) { + return -ENOTSUP; + } + + return gatt_proxy_advertise(next_sub()); +} + + +static void ble_mesh_handle_connect(struct ble_gap_event *event, void *arg) +{ +#if MYNEWT_VAL(BLE_EXT_ADV) + /* When EXT ADV is enabled then mesh proxy is connected + * when proxy advertising instance is completed. + * Therefore no need to handle BLE_GAP_EVENT_CONNECT + */ + if (event->type == BLE_GAP_EVENT_ADV_COMPLETE) { + /* Reason 0 means advertising has been completed because + * connection has been established + */ + if (event->adv_complete.reason != 0) { + return; + } + + if (event->adv_complete.instance != BT_MESH_ADV_GATT_INST) { + return; + } + + gatt_connected(event->adv_complete.conn_handle); +#if MYNEWT_VAL(BLE_MESH_PB_GATT) + gatt_connected_pb_gatt(event->adv_complete.conn_handle, + event->adv_complete.reason); +#endif + } +#else + if (event->type == BLE_GAP_EVENT_CONNECT) { + gatt_connected(event->connect.conn_handle); +#if MYNEWT_VAL(BLE_MESH_PB_GATT) + gatt_connected_pb_gatt(event->connect.conn_handle, event->connect.status); +#endif + } +#endif +} + +int ble_mesh_proxy_gap_event(struct ble_gap_event *event, void *arg) +{ + if ((event->type == BLE_GAP_EVENT_CONNECT) || + (event->type == BLE_GAP_EVENT_ADV_COMPLETE)) { + ble_mesh_handle_connect(event, arg); + } else if (event->type == BLE_GAP_EVENT_DISCONNECT) { + gatt_disconnected(event->disconnect.conn, + event->disconnect.reason); +#if MYNEWT_VAL(BLE_MESH_PB_GATT) + gatt_disconnected_pb_gatt(event->disconnect.conn, + event->disconnect.reason); +#endif + } else if (event->type == BLE_GAP_EVENT_SUBSCRIBE) { + if (event->subscribe.attr_handle == svc_handles.proxy_data_out_h) { +#if (MYNEWT_VAL(BLE_MESH_GATT_PROXY)) + proxy_ccc_write(event->subscribe.conn_handle); +#endif + } else if (event->subscribe.attr_handle == + svc_handles.prov_data_out_h) { +#if (MYNEWT_VAL(BLE_MESH_PB_GATT)) + prov_ccc_write(event->subscribe.conn_handle, event->type); +#endif + } + } + + return 0; +} + +int bt_mesh_proxy_init(void) +{ + int i; + +#if (MYNEWT_VAL(BLE_MESH_GATT_PROXY)) + if (!bt_mesh_subnet_cb_list[4]) { + bt_mesh_subnet_cb_list[4] = subnet_evt; + } +#endif + + for (i = 0; i < MYNEWT_VAL(BLE_MAX_CONNECTIONS); ++i) { +#if (MYNEWT_VAL(BLE_MESH_GATT_PROXY)) + k_work_init(&clients[i].send_beacons, proxy_send_beacons); +#endif + clients[i].conn_handle = 0xffff; + } + + bt_mesh_proxy_msg_init(); + + resolve_svc_handles(); + + ble_gatts_svc_set_visibility(svc_handles.proxy_h, 0); + ble_gatts_svc_set_visibility(svc_handles.prov_h, 0); + + return 0; +} diff --git a/nimble/host/mesh/src/rpl.c b/nimble/host/mesh/src/rpl.c index 93c2e1a885..ffee94a5d7 100644 --- a/nimble/host/mesh/src/rpl.c +++ b/nimble/host/mesh/src/rpl.c @@ -7,9 +7,10 @@ * SPDX-License-Identifier: Apache-2.0 */ -#define MESH_LOG_MODULE BLE_MESH_RPL_LOG +#define BLE_NPL_LOG_MODULE BLE_MESH_RPL_LOG +#include -#include "log/log.h" +#include #include "mesh_priv.h" #include "adv.h" @@ -17,17 +18,81 @@ #include "rpl.h" #include "settings.h" +/* Replay Protection List information for persistent storage. */ +struct rpl_val { + uint32_t seq:24, + old_iv:1; +}; + static struct bt_mesh_rpl replay_list[MYNEWT_VAL(BLE_MESH_CRPL)]; +static ATOMIC_DEFINE(store, MYNEWT_VAL(BLE_MESH_CRPL)); + +static inline int rpl_idx(const struct bt_mesh_rpl *rpl) +{ + return rpl - &replay_list[0]; +} + +static void clear_rpl(struct bt_mesh_rpl *rpl) +{ +#if MYNEWT_VAL(BLE_MESH_SETTINGS) + int err; + char path[18]; + + if (!rpl->src) { + return; + } + + snprintk(path, sizeof(path), "bt_mesh/RPL/%x", rpl->src); + err = settings_save_one(path, NULL); + if (err) { + BT_ERR("Failed to clear RPL"); + } else { + BT_DBG("Cleared RPL"); + } + + (void)memset(rpl, 0, sizeof(*rpl)); + atomic_clear_bit(store, rpl_idx(rpl)); +#endif +} + +static void schedule_rpl_store(struct bt_mesh_rpl *entry, bool force) +{ +#if MYNEWT_VAL(BLE_MESH_SETTINGS) + atomic_set_bit(store, rpl_idx(entry)); + bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_RPL_PENDING); + if (force +#ifdef CONFIG_BT_MESH_RPL_STORE_TIMEOUT + || CONFIG_BT_MESH_RPL_STORE_TIMEOUT >= 0 +#endif + ) { + bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_RPL_PENDING); + } +#endif +} + +static void schedule_rpl_clear(void) +{ +#if MYNEWT_VAL(BLE_MESH_SETTINGS) + bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_RPL_PENDING); +#endif +} void bt_mesh_rpl_update(struct bt_mesh_rpl *rpl, struct bt_mesh_net_rx *rx) { + /* If this is the first message on the new IV index, we should reset it + * to zero to avoid invalid combinations of IV index and seg. + */ + if (rpl->old_iv && !rx->old_iv) { + rpl->seg = 0; + } + rpl->src = rx->ctx.addr; rpl->seq = rx->seq; rpl->old_iv = rx->old_iv; if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_rpl(rpl); + schedule_rpl_store(rpl, false); } } @@ -95,13 +160,14 @@ void bt_mesh_rpl_clear(void) BT_DBG(""); if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_clear_rpl(); + schedule_rpl_clear(); } else { (void)memset(replay_list, 0, sizeof(replay_list)); } } -struct bt_mesh_rpl *bt_mesh_rpl_find(uint16_t src) +#if MYNEWT_VAL(BLE_MESH_SETTINGS) +static struct bt_mesh_rpl *bt_mesh_rpl_find(uint16_t src) { int i; @@ -114,7 +180,7 @@ struct bt_mesh_rpl *bt_mesh_rpl_find(uint16_t src) return NULL; } -struct bt_mesh_rpl *bt_mesh_rpl_alloc(uint16_t src) +static struct bt_mesh_rpl *bt_mesh_rpl_alloc(uint16_t src) { int i; @@ -127,15 +193,7 @@ struct bt_mesh_rpl *bt_mesh_rpl_alloc(uint16_t src) return NULL; } - -void bt_mesh_rpl_foreach(bt_mesh_rpl_func_t func, void *user_data) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(replay_list); i++) { - func(&replay_list[i], user_data); - } -} +#endif void bt_mesh_rpl_reset(void) { @@ -149,14 +207,174 @@ void bt_mesh_rpl_reset(void) if (rpl->src) { if (rpl->old_iv) { - (void)memset(rpl, 0, sizeof(*rpl)); + if (IS_ENABLED(CONFIG_BT_SETTINGS)) { + clear_rpl(rpl); + } else { + (void)memset(rpl, 0, sizeof(*rpl)); + } } else { rpl->old_iv = true; + if (IS_ENABLED(CONFIG_BT_SETTINGS)) { + schedule_rpl_store(rpl, true); + } } + } + } +} - if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_rpl(rpl); - } +#if MYNEWT_VAL(BLE_MESH_SETTINGS) +static int rpl_set(int argc, char **argv, char *val) +{ + struct bt_mesh_rpl *entry; + struct rpl_val rpl; + int len, err; + uint16_t src; + + if (argc < 1) { + BT_ERR("Invalid argc (%d)", argc); + return -ENOENT; + } + + BT_DBG("argv[0] %s val %s", argv[0], val ? val : "(null)"); + + src = strtol(argv[0], NULL, 16); + entry = bt_mesh_rpl_find(src); + + if (!val) { + if (entry) { + memset(entry, 0, sizeof(*entry)); + } else { + BT_WARN("Unable to find RPL entry for 0x%04x", src); + } + + return 0; + } + + if (!entry) { + entry = bt_mesh_rpl_alloc(src); + if (!entry) { + BT_ERR("Unable to allocate RPL entry for 0x%04x", src); + return -ENOMEM; } } -} \ No newline at end of file + + len = sizeof(rpl); + err = settings_bytes_from_str(val, &rpl, &len); + if (err) { + BT_ERR("Failed to decode value %s (err %d)", val, err); + return err; + } + + if (len != sizeof(rpl)) { + BT_ERR("Unexpected value length (%d != %zu)", len, sizeof(rpl)); + return -EINVAL; + } + + entry->seq = rpl.seq; + entry->old_iv = rpl.old_iv; + + BT_DBG("RPL entry for 0x%04x: Seq 0x%06x old_iv %u", entry->src, + (unsigned) entry->seq, entry->old_iv); + return 0; +} +#endif + +static void store_rpl(struct bt_mesh_rpl *entry) +{ +#if MYNEWT_VAL(BLE_MESH_SETTINGS) + char buf[BT_SETTINGS_SIZE(sizeof(struct rpl_val))]; + struct rpl_val rpl; + char path[18]; + char *str; + int err; + + if (!entry->src) { + return; + } + + BT_DBG("src 0x%04x seq 0x%06x old_iv %u", entry->src, + (unsigned) entry->seq, entry->old_iv); + + rpl.seq = entry->seq; + rpl.old_iv = entry->old_iv; + + str = settings_str_from_bytes(&rpl, sizeof(rpl), buf, sizeof(buf)); + if (!str) { + BT_ERR("Unable to encode RPL as value"); + return; + } + + snprintk(path, sizeof(path), "bt_mesh/RPL/%x", entry->src); + + BT_DBG("Saving RPL %s as value %s", path, str); + err = settings_save_one(path, str); + if (err) { + BT_ERR("Failed to store RPL"); + } else { + BT_DBG("Stored RPL"); + } +#endif +} + +static void store_pending_rpl(struct bt_mesh_rpl *rpl) +{ + BT_DBG(""); + + if (atomic_test_and_clear_bit(store, rpl_idx(rpl))) { + store_rpl(rpl); + } +} + +void bt_mesh_rpl_pending_store(uint16_t addr) +{ + int i; + + if (!IS_ENABLED(CONFIG_BT_SETTINGS) || + (!BT_MESH_ADDR_IS_UNICAST(addr) && + addr != BT_MESH_ADDR_ALL_NODES)) { + return; + } + + if (addr == BT_MESH_ADDR_ALL_NODES) { + bt_mesh_settings_store_cancel(BT_MESH_SETTINGS_RPL_PENDING); + } + + for (i = 0; i < ARRAY_SIZE(replay_list); i++) { + if (addr != BT_MESH_ADDR_ALL_NODES && + addr != replay_list[i].src) { + continue; + } + + if (atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) { + store_pending_rpl(&replay_list[i]); + } else { + clear_rpl(&replay_list[i]); + } + + if (addr != BT_MESH_ADDR_ALL_NODES) { + break; + } + } +} + +#if MYNEWT_VAL(BLE_MESH_SETTINGS) +static struct conf_handler bt_mesh_rpl_conf_handler = { + .ch_name = "bt_mesh", + .ch_get = NULL, + .ch_set = rpl_set, + .ch_commit = NULL, + .ch_export = NULL, +}; +#endif + +void bt_mesh_rpl_init(void) +{ +#if MYNEWT_VAL(BLE_MESH_SETTINGS) + int rc; + + rc = conf_register(&bt_mesh_rpl_conf_handler); + + SYSINIT_PANIC_ASSERT_MSG(rc == 0, + "Failed to register bt_mesh_rpl conf"); +#endif +} diff --git a/nimble/host/mesh/src/rpl.h b/nimble/host/mesh/src/rpl.h index 0592712f87..9d110d9dab 100644 --- a/nimble/host/mesh/src/rpl.h +++ b/nimble/host/mesh/src/rpl.h @@ -8,12 +8,16 @@ */ struct bt_mesh_rpl { - uint16_t src; - bool old_iv; -#if defined(CONFIG_BT_SETTINGS) - bool store; -#endif - uint32_t seq; + uint64_t src:15, + old_iv:1, + seq:24, + /** Sequence authentication value for the previous segmented + * message received from this address. + * + * This value is used to manage the parallel RPL of the + * SeqAuth values in transport. + */ + seg:24; }; typedef void (*bt_mesh_rpl_func_t)(struct bt_mesh_rpl *rpl, @@ -23,8 +27,6 @@ void bt_mesh_rpl_reset(void); bool bt_mesh_rpl_check(struct bt_mesh_net_rx *rx, struct bt_mesh_rpl **match); void bt_mesh_rpl_clear(void); -struct bt_mesh_rpl *bt_mesh_rpl_find(uint16_t src); -struct bt_mesh_rpl *bt_mesh_rpl_alloc(uint16_t src); -void bt_mesh_rpl_foreach(bt_mesh_rpl_func_t func, void *user_data); void bt_mesh_rpl_update(struct bt_mesh_rpl *rpl, - struct bt_mesh_net_rx *rx); \ No newline at end of file + struct bt_mesh_net_rx *rx); +void bt_mesh_rpl_init(void); diff --git a/nimble/host/mesh/src/settings.c b/nimble/host/mesh/src/settings.c index 903230d1b5..a3b6ae6dc0 100644 --- a/nimble/host/mesh/src/settings.c +++ b/nimble/host/mesh/src/settings.c @@ -5,149 +5,33 @@ */ #include "syscfg/syscfg.h" -#define MESH_LOG_MODULE BLE_MESH_SETTINGS_LOG + +#define BLE_NPL_LOG_MODULE BLE_MESH_SETTINGS_LOG +#include #if MYNEWT_VAL(BLE_MESH_SETTINGS) #include "mesh_priv.h" -#include "mesh/mesh.h" #include "mesh/glue.h" #include "subnet.h" #include "app_keys.h" #include "net.h" +#include "cdb_priv.h" #include "rpl.h" #include "crypto.h" #include "transport.h" #include "heartbeat.h" #include "access.h" -#include "foundation.h" +#include "pb_gatt_srv.h" #include "proxy.h" #include "settings.h" -#include "lpn.h" #include "cfg.h" #include "config/config.h" -/* Tracking of what storage changes are pending for App and Net Keys. We - * track this in a separate array here instead of within the respective - * bt_mesh_app_key and bt_mesh_subnet structs themselves, since once a key - * gets deleted its struct becomes invalid and may be reused for other keys. - */ -struct key_update { - uint16_t key_idx:12, /* AppKey or NetKey Index */ - valid:1, /* 1 if this entry is valid, 0 if not */ - app_key:1, /* 1 if this is an AppKey, 0 if a NetKey */ - clear:1; /* 1 if key needs clearing, 0 if storing */ -}; - -static struct key_update key_updates[CONFIG_BT_MESH_APP_KEY_COUNT + - CONFIG_BT_MESH_SUBNET_COUNT]; - -static struct k_delayed_work pending_store; - -/* Mesh network storage information */ -struct net_val { - uint16_t primary_addr; - uint8_t dev_key[16]; -} __packed; - -/* Sequence number storage */ -struct seq_val { - uint8_t val[3]; -} __packed; - -/* Heartbeat Publication storage */ -struct hb_pub_val { - uint16_t dst; - uint8_t period; - uint8_t ttl; - uint16_t feat; - uint16_t net_idx:12, - indefinite:1; -}; - -/* Miscelaneous configuration server model states */ -struct cfg_val { - uint8_t net_transmit; - uint8_t relay; - uint8_t relay_retransmit; - uint8_t beacon; - uint8_t gatt_proxy; - uint8_t frnd; - uint8_t default_ttl; -}; - -/* IV Index & IV Update storage */ -struct iv_val { - uint32_t iv_index; - uint8_t iv_update:1, - iv_duration:7; -} __packed; - -/* Replay Protection List storage */ -struct rpl_val { - uint32_t seq:24, - old_iv:1; -}; - -/* NetKey storage information */ -struct net_key_val { - uint8_t kr_flag:1, - kr_phase:7; - uint8_t val[2][16]; -} __packed; - -/* AppKey storage information */ -struct app_key_val { - uint16_t net_idx; - bool updated; - uint8_t val[2][16]; -} __packed; - -struct mod_pub_val { - uint16_t addr; - uint16_t key; - uint8_t ttl; - uint8_t retransmit; - uint8_t period; - uint8_t period_div:4, - cred:1; -}; - -/* Virtual Address information */ -struct va_val { - uint16_t ref; - uint16_t addr; - uint8_t uuid[16]; -} __packed; - -struct cdb_net_val { - uint32_t iv_index; - bool iv_update; -} __packed; - -/* Node storage information */ -struct node_val { - uint16_t net_idx; - uint8_t num_elem; - uint8_t flags; -#define F_NODE_CONFIGURED 0x01 - uint8_t uuid[16]; - uint8_t dev_key[16]; -} __packed; - -struct node_update { - uint16_t addr; - bool clear; -}; - -#if MYNEWT_VAL(BLE_MESH_CDB) -static struct node_update cdb_node_updates[MYNEWT_VAL(BLE_MESH_CDB_NODE_COUNT)]; -static struct key_update cdb_key_updates[ - MYNEWT_VAL(BLE_MESH_CDB_SUBNET_COUNT) + - MYNEWT_VAL(BLE_MESH_CDB_APP_KEY_COUNT)]; -#endif +static struct k_work_delayable pending_store; +static ATOMIC_DEFINE(pending_flags, BT_MESH_SETTINGS_FLAG_COUNT); int settings_name_next(char *name, char **next) { @@ -181,2269 +65,140 @@ int settings_name_next(char *name, char **next) return rc; } -static int net_set(int argc, char **argv, char *val) -{ - struct net_val net; - int len, err; - - BT_DBG("val %s", val ? val : "(null)"); - - if (!val) { - bt_mesh_comp_unprovision(); - memset(bt_mesh.dev_key, 0, sizeof(bt_mesh.dev_key)); - return 0; - } - - len = sizeof(net); - err = settings_bytes_from_str(val, &net, &len); - if (err) { - BT_ERR("Failed to decode value %s (err %d)", val, err); - return err; - } - - if (len != sizeof(net)) { - BT_ERR("Unexpected value length (%d != %zu)", len, sizeof(net)); - return -EINVAL; - } - - memcpy(bt_mesh.dev_key, net.dev_key, sizeof(bt_mesh.dev_key)); - bt_mesh_comp_provision(net.primary_addr); - - BT_DBG("Provisioned with primary address 0x%04x", net.primary_addr); - BT_DBG("Recovered DevKey %s", bt_hex(bt_mesh.dev_key, 16)); - - return 0; -} - -static int iv_set(int argc, char **argv, char *val) -{ - struct iv_val iv; - int len, err; - - BT_DBG("val %s", val ? val : "(null)"); - - if (!val) { - bt_mesh.iv_index = 0U; - atomic_clear_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS); - return 0; - } - - len = sizeof(iv); - err = settings_bytes_from_str(val, &iv, &len); - if (err) { - BT_ERR("Failed to decode value %s (err %d)", val, err); - return err; - } - - if (len != sizeof(iv)) { - BT_ERR("Unexpected value length (%d != %zu)", len, sizeof(iv)); - return -EINVAL; - } - - bt_mesh.iv_index = iv.iv_index; - atomic_set_bit_to(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS, iv.iv_update); - bt_mesh.ivu_duration = iv.iv_duration; - - BT_DBG("IV Index 0x%04x (IV Update Flag %u) duration %u hours", - (unsigned) iv.iv_index, iv.iv_update, iv.iv_duration); - - return 0; -} - -static int seq_set(int argc, char **argv, char *val) -{ - struct seq_val seq; - int len, err; - - BT_DBG("val %s", val ? val : "(null)"); - - if (!val) { - bt_mesh.seq = 0; - return 0; - } - - len = sizeof(seq); - err = settings_bytes_from_str(val, &seq, &len); - if (err) { - BT_ERR("Failed to decode value %s (err %d)", val, err); - return err; - } - - if (len != sizeof(seq)) { - BT_ERR("Unexpected value length (%d != %zu)", len, sizeof(seq)); - return -EINVAL; - } - - bt_mesh.seq = sys_get_le24(seq.val); - - if (CONFIG_BT_MESH_SEQ_STORE_RATE > 0) { - /* Make sure we have a large enough sequence number. We - * subtract 1 so that the first transmission causes a write - * to the settings storage. - */ - bt_mesh.seq += (CONFIG_BT_MESH_SEQ_STORE_RATE - - (bt_mesh.seq % CONFIG_BT_MESH_SEQ_STORE_RATE)); - bt_mesh.seq--; - } - - BT_DBG("Sequence Number 0x%06x", bt_mesh.seq); - - return 0; -} - -static int rpl_set(int argc, char **argv, char *val) +static int mesh_commit(void) { - struct bt_mesh_rpl *entry; - struct rpl_val rpl; - int len, err; - uint16_t src; - - if (argc < 1) { - BT_ERR("Invalid argc (%d)", argc); - return -ENOENT; - } - - BT_DBG("argv[0] %s val %s", argv[0], val ? val : "(null)"); - - src = strtol(argv[0], NULL, 16); - entry = bt_mesh_rpl_find(src); - - if (!val) { - if (entry) { - memset(entry, 0, sizeof(*entry)); - } else { - BT_WARN("Unable to find RPL entry for 0x%04x", src); - } - + if (!bt_mesh_subnet_next(NULL)) { + /* Nothing to do since we're not yet provisioned */ return 0; } - if (!entry) { - entry = bt_mesh_rpl_alloc(src); - if (!entry) { - BT_ERR("Unable to allocate RPL entry for 0x%04x", src); - return -ENOMEM; - } - } - - len = sizeof(rpl); - err = settings_bytes_from_str(val, &rpl, &len); - if (err) { - BT_ERR("Failed to decode value %s (err %d)", val, err); - return err; - } - - if (len != sizeof(rpl)) { - BT_ERR("Unexpected value length (%d != %zu)", len, sizeof(rpl)); - return -EINVAL; + if (IS_ENABLED(CONFIG_BT_MESH_PB_GATT)) { + (void)bt_mesh_pb_gatt_disable(); } - entry->seq = rpl.seq; - entry->old_iv = rpl.old_iv; + bt_mesh_net_settings_commit(); + bt_mesh_model_settings_commit(); - BT_DBG("RPL entry for 0x%04x: Seq 0x%06x old_iv %u", entry->src, - (unsigned) entry->seq, entry->old_iv); + atomic_set_bit(bt_mesh.flags, BT_MESH_VALID); + bt_mesh_start(); return 0; } -static int net_key_set(int argc, char **argv, char *val) -{ - struct net_key_val key; - int len, err; - uint16_t net_idx; - - BT_DBG("argv[0] %s val %s", argv[0], val ? val : "(null)"); - - net_idx = strtol(argv[0], NULL, 16); - - len = sizeof(key); - err = settings_bytes_from_str(val, &key, &len); - if (err) { - BT_ERR("Failed to decode value %s (err %d)", val, err); - return err; - } - - if (len != sizeof(key)) { - BT_ERR("Unexpected value length (%d != %zu)", len, sizeof(key)); - return -EINVAL; - } - - BT_DBG("NetKeyIndex 0x%03x recovered from storage", net_idx); - - return bt_mesh_subnet_set( - net_idx, key.kr_phase, key.val[0], - (key.kr_phase != BT_MESH_KR_NORMAL) ? key.val[1] : NULL); -} - -static int app_key_set(int argc, char **argv, char *val) -{ - struct app_key_val key; - uint16_t app_idx; - int len_rd, err; - - BT_DBG("argv[0] %s val %s", argv[0], val ? val : "(null)"); - - app_idx = strtol(argv[0], NULL, 16); - len_rd = strtol(argv[1], NULL, 16); - - if (!len_rd) { - return 0; - } - - err = settings_bytes_from_str(val, &key, &len_rd); - if (err) { - BT_ERR("Failed to decode value %s (err %d)", val, err); - return err; - } - - err = bt_mesh_app_key_set(app_idx, key.net_idx, key.val[0], - key.updated ? key.val[1] : NULL); - if (err) { - BT_ERR("Failed to set \'app-key\'"); - return err; - } - - BT_DBG("AppKeyIndex 0x%03x recovered from storage", app_idx); +/* Pending flags that use K_NO_WAIT as the storage timeout */ +#define NO_WAIT_PENDING_BITS (BIT(BT_MESH_SETTINGS_NET_PENDING) | \ + BIT(BT_MESH_SETTINGS_IV_PENDING) | \ + BIT(BT_MESH_SETTINGS_SEQ_PENDING) | \ + BIT(BT_MESH_SETTINGS_CDB_PENDING)) - return 0; -} +/* Pending flags that use CONFIG_BT_MESH_STORE_TIMEOUT */ +#define GENERIC_PENDING_BITS (BIT(BT_MESH_SETTINGS_NET_KEYS_PENDING) | \ + BIT(BT_MESH_SETTINGS_APP_KEYS_PENDING) | \ + BIT(BT_MESH_SETTINGS_HB_PUB_PENDING) | \ + BIT(BT_MESH_SETTINGS_CFG_PENDING) | \ + BIT(BT_MESH_SETTINGS_MOD_PENDING) | \ + BIT(BT_MESH_SETTINGS_VA_PENDING)) -static int hb_pub_set(int argc, char **argv, char *val) +void bt_mesh_settings_store_schedule(enum bt_mesh_settings_flag flag) { - struct bt_mesh_hb_pub pub; - struct hb_pub_val hb_val; - int len, err; - - BT_DBG("val %s", val ? val : "(null)"); - - len = sizeof(hb_val); - err = settings_bytes_from_str(val, &hb_val, &len); - if (err) { - BT_ERR("Failed to decode value %s (err %d)", val, err); - return err; - } - - if (len != sizeof(hb_val)) { - BT_ERR("Unexpected value length (%d != %zu)", len, - sizeof(hb_val)); - return -EINVAL; - } + int32_t timeout_ms, remaining_ms; - pub.dst = hb_val.dst; - pub.period = bt_mesh_hb_pwr2(hb_val.period); - pub.ttl = hb_val.ttl; - pub.feat = hb_val.feat; - pub.net_idx = hb_val.net_idx; + atomic_set_bit(pending_flags, flag); - if (hb_val.indefinite) { - pub.count = 0xffff; + if (atomic_get(pending_flags) & NO_WAIT_PENDING_BITS) { + timeout_ms = 0; + } else if (CONFIG_BT_MESH_RPL_STORE_TIMEOUT >= 0 && + atomic_test_bit(pending_flags, BT_MESH_SETTINGS_RPL_PENDING) && + !(atomic_get(pending_flags) & GENERIC_PENDING_BITS)) { + timeout_ms = CONFIG_BT_MESH_RPL_STORE_TIMEOUT * MSEC_PER_SEC; } else { - pub.count = 0; - } - - (void)bt_mesh_hb_pub_set(&pub); - - BT_DBG("Restored heartbeat publication"); - - return 0; -} - -static int cfg_set(int argc, char **argv, char *val) -{ - struct cfg_val cfg; - int len, err; - - BT_DBG("val %s", val ? val : "(null)"); - - if (!val) { - BT_DBG("Cleared configuration state"); - return 0; - } - - len = sizeof(cfg); - err = settings_bytes_from_str(val, &cfg, &len); - if (err) { - BT_ERR("Failed to decode value %s (err %d)", val, err); - return err; - } - - if (len != sizeof(cfg)) { - BT_ERR("Unexpected value length (%d != %zu)", len, - sizeof(cfg)); - return -EINVAL; - } - - bt_mesh_net_transmit_set(cfg.net_transmit); - bt_mesh_relay_set(cfg.relay, cfg.relay_retransmit); - bt_mesh_beacon_set(cfg.beacon); - bt_mesh_gatt_proxy_set(cfg.gatt_proxy); - bt_mesh_friend_set(cfg.frnd); - bt_mesh_default_ttl_set(cfg.default_ttl); - - BT_DBG("Restored configuration state"); - - return 0; -} - -static int mod_set_bind(struct bt_mesh_model *mod, char *val) -{ - int len, err, i; - - /* Start with empty array regardless of cleared or set value */ - for (i = 0; i < ARRAY_SIZE(mod->keys); i++) { - mod->keys[i] = BT_MESH_KEY_UNUSED; - } - - if (!val) { - BT_DBG("Cleared bindings for model"); - return 0; - } - - len = sizeof(mod->keys); - err = settings_bytes_from_str(val, mod->keys, &len); - if (err) { - BT_ERR("Failed to decode value %s (err %d)", val, err); - return -EINVAL; - } - - BT_DBG("Decoded %u bound keys for model", len / sizeof(mod->keys[0])); - return 0; -} - -static int mod_set_sub(struct bt_mesh_model *mod, char *val) -{ - int len, err; - - /* Start with empty array regardless of cleared or set value */ - memset(mod->groups, 0, sizeof(mod->groups)); - - if (!val) { - BT_DBG("Cleared subscriptions for model"); - return 0; - } - - len = sizeof(mod->groups); - err = settings_bytes_from_str(val, mod->groups, &len); - if (err) { - BT_ERR("Failed to decode value %s (err %d)", val, err); - return -EINVAL; - } - - BT_DBG("Decoded %u subscribed group addresses for model", - len / sizeof(mod->groups[0])); - return 0; -} - -static int mod_set_pub(struct bt_mesh_model *mod, char *val) -{ - struct mod_pub_val pub; - int len, err; - - if (!mod->pub) { - BT_WARN("Model has no publication context!"); - return -EINVAL; + timeout_ms = CONFIG_BT_MESH_STORE_TIMEOUT * MSEC_PER_SEC; } - if (!val) { - mod->pub->addr = BT_MESH_ADDR_UNASSIGNED; - mod->pub->key = 0; - mod->pub->cred = 0; - mod->pub->ttl = 0; - mod->pub->period = 0; - mod->pub->retransmit = 0; - mod->pub->period_div = pub.period_div; - mod->pub->count = 0; - - BT_DBG("Cleared publication for model"); - return 0; - } - - len = sizeof(pub); - err = settings_bytes_from_str(val, &pub, &len); - if (err) { - BT_ERR("Failed to decode value %s (err %d)", val, err); - return -EINVAL; - } - - if (len != sizeof(pub)) { - BT_ERR("Invalid length for model publication"); - return -EINVAL; + remaining_ms = k_ticks_to_ms_floor32( + k_work_delayable_remaining_get(&pending_store)); + BT_DBG("Waiting %u ms vs rem %u ms", timeout_ms, remaining_ms); + /* If the new deadline is sooner, override any existing + * deadline; otherwise schedule without changing any existing + * deadline. + */ + if (timeout_ms < remaining_ms) { + k_work_reschedule(&pending_store, K_MSEC(timeout_ms)); + } else { + k_work_schedule(&pending_store, K_MSEC(timeout_ms)); } - - mod->pub->addr = pub.addr; - mod->pub->key = pub.key; - mod->pub->cred = pub.cred; - mod->pub->ttl = pub.ttl; - mod->pub->period = pub.period; - mod->pub->retransmit = pub.retransmit; - mod->pub->count = 0; - - BT_DBG("Restored model publication, dst 0x%04x app_idx 0x%03x", - pub.addr, pub.key); - - return 0; } -static int mod_data_set(struct bt_mesh_model *mod, - char *name, char *len_rd) +void bt_mesh_settings_store_cancel(enum bt_mesh_settings_flag flag) { - char *next; - - settings_name_next(name, &next); - - if (mod->cb && mod->cb->settings_set) { - return mod->cb->settings_set(mod, next, len_rd); - } - - return 0; + atomic_clear_bit(pending_flags, flag); } -static int mod_set(bool vnd, int argc, char **argv, char *val) +static void store_pending(struct ble_npl_event *work) { - struct bt_mesh_model *mod; - uint8_t elem_idx, mod_idx; - uint16_t mod_key; - - if (argc < 2) { - BT_ERR("Too small argc (%d)", argc); - return -ENOENT; - } - - mod_key = strtol(argv[0], NULL, 16); - elem_idx = mod_key >> 8; - mod_idx = mod_key; - - BT_DBG("Decoded mod_key 0x%04x as elem_idx %u mod_idx %u", - mod_key, elem_idx, mod_idx); - - mod = bt_mesh_model_get(vnd, elem_idx, mod_idx); - if (!mod) { - BT_ERR("Failed to get model for elem_idx %u mod_idx %u", - elem_idx, mod_idx); - return -ENOENT; + BT_DBG(""); + if (atomic_test_and_clear_bit(pending_flags, + BT_MESH_SETTINGS_RPL_PENDING)) { + bt_mesh_rpl_pending_store(BT_MESH_ADDR_ALL_NODES); } - if (!strcmp(argv[1], "bind")) { - return mod_set_bind(mod, val); + if (atomic_test_and_clear_bit(pending_flags, + BT_MESH_SETTINGS_NET_KEYS_PENDING)) { + bt_mesh_subnet_pending_store(); } - if (!strcmp(argv[1], "sub")) { - return mod_set_sub(mod, val); + if (atomic_test_and_clear_bit(pending_flags, + BT_MESH_SETTINGS_APP_KEYS_PENDING)) { + bt_mesh_app_key_pending_store(); } - if (!strcmp(argv[1], "pub")) { - return mod_set_pub(mod, val); + if (atomic_test_and_clear_bit(pending_flags, + BT_MESH_SETTINGS_NET_PENDING)) { + bt_mesh_net_pending_net_store(); } - if (!strcmp(argv[1], "data")) { - return mod_data_set(mod, argv[1], val); + if (atomic_test_and_clear_bit(pending_flags, + BT_MESH_SETTINGS_IV_PENDING)) { + bt_mesh_net_pending_iv_store(); } - BT_WARN("Unknown module key %s", argv[1]); - return -ENOENT; -} - -static int sig_mod_set(int argc, char **argv, char *val) -{ - return mod_set(false, argc, argv, val); -} - -static int vnd_mod_set(int argc, char **argv, char *val) -{ - return mod_set(true, argc, argv, val); -} - -#if CONFIG_BT_MESH_LABEL_COUNT > 0 -static int va_set(int argc, char **argv, char *val) -{ - struct va_val va; - struct bt_mesh_va *lab; - uint16_t index; - int len, err; - - if (argc < 1) { - BT_ERR("Insufficient number of arguments"); - return -ENOENT; + if (atomic_test_and_clear_bit(pending_flags, + BT_MESH_SETTINGS_SEQ_PENDING)) { + bt_mesh_net_pending_seq_store(); } - index = strtol(argv[0], NULL, 16); - - if (val == NULL) { - BT_WARN("Mesh Virtual Address length = 0"); - return 0; + if (atomic_test_and_clear_bit(pending_flags, + BT_MESH_SETTINGS_HB_PUB_PENDING)) { + bt_mesh_hb_pub_pending_store(); } - err = settings_bytes_from_str(val, &va, &len); - if (err) { - BT_ERR("Failed to decode value %s (err %d)", val, err); - return -EINVAL; + if (atomic_test_and_clear_bit(pending_flags, + BT_MESH_SETTINGS_CFG_PENDING)) { + bt_mesh_cfg_pending_store(); } - if (len != sizeof(struct va_val)) { - BT_ERR("Invalid length for virtual address"); - return -EINVAL; + if (atomic_test_and_clear_bit(pending_flags, + BT_MESH_SETTINGS_MOD_PENDING)) { + bt_mesh_model_pending_store(); } - if (va.ref == 0) { - BT_WARN("Ignore Mesh Virtual Address ref = 0"); - return 0; + if (atomic_test_and_clear_bit(pending_flags, + BT_MESH_SETTINGS_VA_PENDING)) { + bt_mesh_va_pending_store(); } - lab = bt_mesh_va_get(index); - if (lab == NULL) { - BT_WARN("Out of labels buffers"); - return -ENOBUFS; +#if IS_ENABLED(CONFIG_BT_MESH_CDB) + if (atomic_test_and_clear_bit(pending_flags, + BT_MESH_SETTINGS_CDB_PENDING)) { + bt_mesh_cdb_pending_store(); } - - memcpy(lab->uuid, va.uuid, 16); - lab->addr = va.addr; - lab->ref = va.ref; - - BT_DBG("Restored Virtual Address, addr 0x%04x ref 0x%04x", - lab->addr, lab->ref); - - return 0; -} #endif - -#if MYNEWT_VAL(BLE_MESH_CDB) -static int cdb_net_set(int argc, char *val) -{ - struct cdb_net_val net; - int len, err; - - len = sizeof(net); - err = settings_bytes_from_str(val, &net, &len); - if (err) { - BT_ERR("Failed to set \'cdb_net\'"); - return err; - } - - bt_mesh_cdb.iv_index = net.iv_index; - - if (net.iv_update) { - atomic_set_bit(bt_mesh_cdb.flags, BT_MESH_CDB_IVU_IN_PROGRESS); - } - - atomic_set_bit(bt_mesh_cdb.flags, BT_MESH_CDB_VALID); - - return 0; -} - -static int cdb_node_set(int argc, char *str) -{ - struct bt_mesh_cdb_node *node; - struct node_val val; - uint16_t addr; - int len, err; - - if (argc < 1) { - BT_ERR("Insufficient number of arguments"); - return -ENOENT; - } - - addr = strtol(str, NULL, 16); - len = sizeof(str); - - if (argc < 1) { - BT_DBG("val (null)"); - BT_DBG("Deleting node 0x%04x", addr); - - node = bt_mesh_cdb_node_get(addr); - if (node) { - bt_mesh_cdb_node_del(node, false); - } - - return 0; - } - - err = settings_bytes_from_str(str, &val, &len); - if (err) { - BT_ERR("Failed to decode value %s (err %d)", val, err); - return -EINVAL; - } - - if (len != sizeof(struct node_val)) { - BT_ERR("Invalid length for node_val"); - return -EINVAL; - } - - node = bt_mesh_cdb_node_get(addr); - if (!node) { - node = bt_mesh_cdb_node_alloc(val.uuid, addr, val.num_elem, - val.net_idx); - } - - if (!node) { - BT_ERR("No space for a new node"); - return -ENOMEM; - } - - if (val.flags & F_NODE_CONFIGURED) { - atomic_set_bit(node->flags, BT_MESH_CDB_NODE_CONFIGURED); - } - - memcpy(node->uuid, val.uuid, 16); - memcpy(node->dev_key, val.dev_key, 16); - - BT_DBG("Node 0x%04x recovered from storage", addr); - - return 0; -} - -static int cdb_subnet_set(int argc, char *name) -{ - struct bt_mesh_cdb_subnet *sub; - struct net_key_val key; - uint16_t net_idx; - int len, len_rd, err; - - if (!name) { - BT_ERR("Insufficient number of arguments"); - return -ENOENT; - } - - len_rd = sizeof(sub); - net_idx = strtol(name, NULL, 16); - sub = bt_mesh_cdb_subnet_get(net_idx); - - if (len_rd == 0) { - BT_DBG("val (null)"); - if (!sub) { - BT_ERR("No subnet with NetKeyIndex 0x%03x", net_idx); - return -ENOENT; - } - - BT_DBG("Deleting NetKeyIndex 0x%03x", net_idx); - bt_mesh_cdb_subnet_del(sub, false); - return 0; - } - - len = sizeof(key); - err = settings_bytes_from_str(name, &key, &len); - if (err) { - BT_ERR("Failed to set \'net-key\'"); - return err; - } - - if (sub) { - BT_DBG("Updating existing NetKeyIndex 0x%03x", net_idx); - - sub->kr_phase = key.kr_phase; - memcpy(sub->keys[0].net_key, &key.val[0], 16); - memcpy(sub->keys[1].net_key, &key.val[1], 16); - - return 0; - } - - sub = bt_mesh_cdb_subnet_alloc(net_idx); - if (!sub) { - BT_ERR("No space to allocate a new subnet"); - return -ENOMEM; - } - - sub->kr_phase = key.kr_phase; - memcpy(sub->keys[0].net_key, &key.val[0], 16); - memcpy(sub->keys[1].net_key, &key.val[1], 16); - - BT_DBG("NetKeyIndex 0x%03x recovered from storage", net_idx); - - return 0; -} - -static int cdb_app_key_set(int argc, char *name) -{ - struct bt_mesh_cdb_app_key *app; - struct app_key_val key; - uint16_t app_idx; - int len_rd, err; - - app_idx = strtol(name, NULL, 16); - len_rd = sizeof(key); - - if (len_rd == 0) { - BT_DBG("val (null)"); - BT_DBG("Deleting AppKeyIndex 0x%03x", app_idx); - - app = bt_mesh_cdb_app_key_get(app_idx); - if (app) { - bt_mesh_cdb_app_key_del(app, false); - } - - return 0; - } - - err = settings_bytes_from_str(name, &key, &len_rd); - if (err) { - BT_ERR("Failed to set \'app-key\'"); - return err; - } - - app = bt_mesh_cdb_app_key_get(app_idx); - if (!app) { - app = bt_mesh_cdb_app_key_alloc(key.net_idx, app_idx); - } - - if (!app) { - BT_ERR("No space for a new app key"); - return -ENOMEM; - } - - memcpy(app->keys[0].app_key, key.val[0], 16); - memcpy(app->keys[1].app_key, key.val[1], 16); - - BT_DBG("AppKeyIndex 0x%03x recovered from storage", app_idx); - - return 0; -} - -static int cdb_set(int argc, char **argv, char *name) -{ - int len; - char *next; - - if (argc < 1) { - BT_ERR("Insufficient number of arguments"); - return -ENOENT; - } - - if (!strcmp(name, "Net")) { - return cdb_net_set(1, name); - } - - - len = settings_name_next(name, &next); - - if (!next) { - BT_ERR("Insufficient number of arguments"); - return -ENOENT; - } - - if (!strncmp(name, "Node", len)) { - return cdb_node_set(1, next); - } - - if (!strncmp(name, "Subnet", len)) { - return cdb_subnet_set(1, next); - } - - if (!strncmp(name, "AppKey", len)) { - return cdb_app_key_set(1, next); - } - - BT_WARN("Unknown module key %s", name); - return -ENOENT; -} -#endif - -const struct mesh_setting { - const char *name; - int (*func)(int argc, char **argv, char *val); -} settings[] = { - { "Net", net_set }, - { "IV", iv_set }, - { "Seq", seq_set }, - { "RPL", rpl_set }, - { "NetKey", net_key_set }, - { "AppKey", app_key_set }, - { "HBPub", hb_pub_set }, - { "Cfg", cfg_set }, - { "s", sig_mod_set }, - { "v", vnd_mod_set }, -#if CONFIG_BT_MESH_LABEL_COUNT > 0 - { "Va", va_set }, -#endif -#if MYNEWT_VAL(BLE_MESH_CDB) - { "cdb", cdb_set }, -#endif -}; - -static int mesh_set(int argc, char **argv, char *val) -{ - int i; - - if (argc < 1) { - BT_ERR("Insufficient number of arguments"); - return -EINVAL; - } - - BT_DBG("argv[0] %s val %s", argv[0], val ? val : "(null)"); - - for (i = 0; i < ARRAY_SIZE(settings); i++) { - if (!strcmp(settings[i].name, argv[0])) { - argc--; - argv++; - - return settings[i].func(argc, argv, val); - } - } - - BT_WARN("No matching handler for key %s", argv[0]); - - return -ENOENT; -} - -static void commit_mod(struct bt_mesh_model *mod, struct bt_mesh_elem *elem, - bool vnd, bool primary, void *user_data) -{ - if (mod->pub && mod->pub->update && - mod->pub->addr != BT_MESH_ADDR_UNASSIGNED) { - int32_t ms = bt_mesh_model_pub_period_get(mod); - if (ms) { - BT_DBG("Starting publish timer (period %u ms)", - (unsigned) ms); - k_delayed_work_submit(&mod->pub->timer, ms); - } - } - - if (!IS_ENABLED(CONFIG_BT_MESH_LOW_POWER)) { - return; - } - - for (int i = 0; i < ARRAY_SIZE(mod->groups); i++) { - if (mod->groups[i] != BT_MESH_ADDR_UNASSIGNED) { - bt_mesh_lpn_group_add(mod->groups[i]); - } - } -} - -static int mesh_commit(void) -{ - if (!bt_mesh_subnet_next(NULL)) { - /* Nothing to do since we're not yet provisioned */ - return 0; - } - - if (IS_ENABLED(CONFIG_BT_MESH_PB_GATT)) { - bt_mesh_proxy_prov_disable(true); - } - - if (bt_mesh.ivu_duration < BT_MESH_IVU_MIN_HOURS) { - k_delayed_work_submit(&bt_mesh.ivu_timer, BT_MESH_IVU_TIMEOUT); - } - - bt_mesh_model_foreach(commit_mod, NULL); - - atomic_set_bit(bt_mesh.flags, BT_MESH_VALID); - - bt_mesh_start(); - - return 0; -} - -/* Pending flags that use K_NO_WAIT as the storage timeout */ -#define NO_WAIT_PENDING_BITS (BIT(BT_MESH_NET_PENDING) | \ - BIT(BT_MESH_IV_PENDING) | \ - BIT(BT_MESH_SEQ_PENDING)) - -/* Pending flags that use CONFIG_BT_MESH_STORE_TIMEOUT */ -#define GENERIC_PENDING_BITS (BIT(BT_MESH_KEYS_PENDING) | \ - BIT(BT_MESH_HB_PUB_PENDING) | \ - BIT(BT_MESH_CFG_PENDING) | \ - BIT(BT_MESH_MOD_PENDING)) - -static void schedule_store(int flag) -{ - int32_t timeout, remaining; - - atomic_set_bit(bt_mesh.flags, flag); - - if (atomic_get(bt_mesh.flags) & NO_WAIT_PENDING_BITS) { - timeout = K_NO_WAIT; - } else if (atomic_test_bit(bt_mesh.flags, BT_MESH_RPL_PENDING) && - (!(atomic_get(bt_mesh.flags) & GENERIC_PENDING_BITS) || - (CONFIG_BT_MESH_RPL_STORE_TIMEOUT < - CONFIG_BT_MESH_STORE_TIMEOUT))) { - timeout = K_SECONDS(CONFIG_BT_MESH_RPL_STORE_TIMEOUT); - } else { - timeout = K_SECONDS(CONFIG_BT_MESH_STORE_TIMEOUT); - } - - remaining = k_delayed_work_remaining_get(&pending_store); - if (remaining && remaining < timeout) { - BT_DBG("Not rescheduling due to existing earlier deadline"); - return; - } - - BT_DBG("Waiting %d seconds", (int) (timeout / MSEC_PER_SEC)); - - k_delayed_work_submit(&pending_store, timeout); -} - -static void clear_iv(void) -{ - int err; - - err = settings_save_one("bt_mesh/IV", NULL); - if (err) { - BT_ERR("Failed to clear IV"); - } else { - BT_DBG("Cleared IV"); - } -} - -static void clear_net(void) -{ - int err; - - err = settings_save_one("bt_mesh/Net", NULL); - if (err) { - BT_ERR("Failed to clear Network"); - } else { - BT_DBG("Cleared Network"); - } -} - -static void store_pending_net(void) -{ - char buf[BT_SETTINGS_SIZE(sizeof(struct net_val))]; - struct net_val net; - char *str; - int err; - - BT_DBG("addr 0x%04x DevKey %s", bt_mesh_primary_addr(), - bt_hex(bt_mesh.dev_key, 16)); - - net.primary_addr = bt_mesh_primary_addr(); - memcpy(net.dev_key, bt_mesh.dev_key, 16); - - str = settings_str_from_bytes(&net, sizeof(net), buf, sizeof(buf)); - if (!str) { - BT_ERR("Unable to encode Network as value"); - return; - } - - BT_DBG("Saving Network as value %s", str); - err = settings_save_one("bt_mesh/Net", str); - if (err) { - BT_ERR("Failed to store Network"); - } else { - BT_DBG("Stored Network"); - } -} - -void bt_mesh_store_net(void) -{ - schedule_store(BT_MESH_NET_PENDING); -} - -static void store_pending_iv(void) -{ - char buf[BT_SETTINGS_SIZE(sizeof(struct iv_val))]; - struct iv_val iv; - char *str; - int err; - - iv.iv_index = bt_mesh.iv_index; - iv.iv_update = atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS); - iv.iv_duration = bt_mesh.ivu_duration; - - str = settings_str_from_bytes(&iv, sizeof(iv), buf, sizeof(buf)); - if (!str) { - BT_ERR("Unable to encode IV as value"); - return; - } - - BT_DBG("Saving IV as value %s", str); - err = settings_save_one("bt_mesh/IV", str); - if (err) { - BT_ERR("Failed to store IV"); - } else { - BT_DBG("Stored IV"); - } -} - -void bt_mesh_store_iv(bool only_duration) -{ - schedule_store(BT_MESH_IV_PENDING); - - if (!only_duration) { - /* Always update Seq whenever IV changes */ - schedule_store(BT_MESH_SEQ_PENDING); - } -} - -static void store_pending_seq(void) -{ - char buf[BT_SETTINGS_SIZE(sizeof(struct seq_val))]; - struct seq_val seq; - char *str; - int err; - - sys_put_le24(bt_mesh.seq, seq.val); - - str = settings_str_from_bytes(&seq, sizeof(seq), buf, sizeof(buf)); - if (!str) { - BT_ERR("Unable to encode Seq as value"); - return; - } - - BT_DBG("Saving Seq as value %s", str); - err = settings_save_one("bt_mesh/Seq", str); - if (err) { - BT_ERR("Failed to store Seq"); - } else { - BT_DBG("Stored Seq"); - } -} - -void bt_mesh_store_seq(void) -{ - if (CONFIG_BT_MESH_SEQ_STORE_RATE > 1 && - (bt_mesh.seq % CONFIG_BT_MESH_SEQ_STORE_RATE)) { - return; - } - - schedule_store(BT_MESH_SEQ_PENDING); -} - -static void store_rpl(struct bt_mesh_rpl *entry) -{ - char buf[BT_SETTINGS_SIZE(sizeof(struct rpl_val))]; - struct rpl_val rpl; - char path[18]; - char *str; - int err; - - BT_DBG("src 0x%04x seq 0x%06x old_iv %u", entry->src, - (unsigned) entry->seq, entry->old_iv); - - rpl.seq = entry->seq; - rpl.old_iv = entry->old_iv; - - str = settings_str_from_bytes(&rpl, sizeof(rpl), buf, sizeof(buf)); - if (!str) { - BT_ERR("Unable to encode RPL as value"); - return; - } - - snprintk(path, sizeof(path), "bt_mesh/RPL/%x", entry->src); - - BT_DBG("Saving RPL %s as value %s", path, str); - err = settings_save_one(path, str); - if (err) { - BT_ERR("Failed to store RPL"); - } else { - BT_DBG("Stored RPL"); - } -} - -static void clear_rpl(struct bt_mesh_rpl *rpl, void *user_data) -{ - int err; - char path[18]; - - if (!rpl->src) { - return; - } - - snprintk(path, sizeof(path), "bt_mesh/RPL/%x", rpl->src); - err = settings_save_one(path, NULL); - if (err) { - BT_ERR("Failed to clear RPL"); - } else { - BT_DBG("Cleared RPL"); - } - - (void)memset(rpl, 0, sizeof(*rpl)); -} - -static void store_pending_rpl(struct bt_mesh_rpl *rpl, void *user_data) -{ - BT_DBG(""); - - if (rpl->store) { - rpl->store = false; - store_rpl(rpl); - } -} - -static void store_pending_hb_pub(void) -{ - char buf[BT_SETTINGS_SIZE(sizeof(struct hb_pub_val))]; - struct bt_mesh_hb_pub pub; - struct hb_pub_val val; - char *str; - int err; - - bt_mesh_hb_pub_get(&pub); - if (pub.dst == BT_MESH_ADDR_UNASSIGNED) { - str = NULL; - } else { - val.indefinite = (pub.count == 0xffff); - val.dst = pub.dst; - val.period = bt_mesh_hb_log(pub.period); - val.ttl = pub.ttl; - val.feat = pub.feat; - val.net_idx = pub.net_idx; - - str = settings_str_from_bytes(&val, sizeof(val), - buf, sizeof(buf)); - if (!str) { - BT_ERR("Unable to encode hb pub as value"); - return; - } - } - - BT_DBG("Saving Heartbeat Publication as value %s", - str ? str : "(null)"); - err = settings_save_one("bt_mesh/HBPub", str); - if (err) { - BT_ERR("Failed to store Heartbeat Publication"); - } else { - BT_DBG("Stored Heartbeat Publication"); - } -} - -static void store_pending_cfg(void) -{ - char buf[BT_SETTINGS_SIZE(sizeof(struct cfg_val))]; - struct cfg_val val; - char *str; - int err; - - val.net_transmit = bt_mesh_net_transmit_get(); - val.relay = bt_mesh_relay_get(); - val.relay_retransmit = bt_mesh_relay_retransmit_get(); - val.beacon = bt_mesh_beacon_enabled(); - val.gatt_proxy = bt_mesh_gatt_proxy_get(); - val.frnd = bt_mesh_friend_get(); - val.default_ttl = bt_mesh_default_ttl_get(); - - str = settings_str_from_bytes(&val, sizeof(val), buf, sizeof(buf)); - if (!str) { - BT_ERR("Unable to encode configuration as value"); - return; - } - - BT_DBG("Saving configuration as value %s", str); - err = settings_save_one("bt_mesh/Cfg", str); - if (err) { - BT_ERR("Failed to store configuration"); - } else { - BT_DBG("Stored configuration"); - } -} - -static void clear_cfg(void) -{ - int err; - - err = settings_save_one("bt_mesh/Cfg", NULL); - if (err) { - BT_ERR("Failed to clear configuration"); - } else { - BT_DBG("Cleared configuration"); - } -} - -static void clear_app_key(uint16_t app_idx) -{ - char path[20]; - int err; - - BT_DBG("AppKeyIndex 0x%03x", app_idx); - - snprintk(path, sizeof(path), "bt_mesh/AppKey/%x", app_idx); - err = settings_save_one(path, NULL); - if (err) { - BT_ERR("Failed to clear AppKeyIndex 0x%03x", app_idx); - } else { - BT_DBG("Cleared AppKeyIndex 0x%03x", app_idx); - } -} - -static void clear_net_key(uint16_t net_idx) -{ - char path[20]; - int err; - - BT_DBG("NetKeyIndex 0x%03x", net_idx); - - snprintk(path, sizeof(path), "bt_mesh/NetKey/%x", net_idx); - err = settings_save_one(path, NULL); - if (err) { - BT_ERR("Failed to clear NetKeyIndex 0x%03x", net_idx); - } else { - BT_DBG("Cleared NetKeyIndex 0x%03x", net_idx); - } -} - -static void store_subnet(uint16_t net_idx) -{ - const struct bt_mesh_subnet *sub; - struct net_key_val key; - char buf[BT_SETTINGS_SIZE(sizeof(struct app_key_val))]; - char path[20]; - char *str; - int err; - - sub = bt_mesh_subnet_get(net_idx); - if (!sub) { - BT_WARN("NetKeyIndex 0x%03x not found", net_idx); - return; - } - - BT_DBG("NetKeyIndex 0x%03x", net_idx); - - snprintk(path, sizeof(path), "bt_mesh/NetKey/%x", net_idx); - - memcpy(&key.val[0], sub->keys[0].net, 16); - memcpy(&key.val[1], sub->keys[1].net, 16); - key.kr_flag = 0U; /* Deprecated */ - key.kr_phase = sub->kr_phase; - - str = settings_str_from_bytes(&key, sizeof(key), buf, sizeof(buf)); - if (!str) { - BT_ERR("Unable to encode AppKey as value"); - return; - } - - err = settings_save_one(path, str); - if (err) { - BT_ERR("Failed to store NetKey"); - } else { - BT_DBG("Stored NetKey"); - } -} - -static void store_app(uint16_t app_idx) -{ - const struct bt_mesh_app_key *app; - char buf[BT_SETTINGS_SIZE(sizeof(struct app_key_val))]; - struct app_key_val key; - char path[20]; - char *str; - int err; - - snprintk(path, sizeof(path), "bt_mesh/AppKey/%x", app_idx); - - app = bt_mesh_app_key_get(app_idx); - if (!app) { - BT_WARN("ApKeyIndex 0x%03x not found", app_idx); - return; - } - - key.net_idx = app->net_idx, - key.updated = app->updated, - - memcpy(key.val[0], app->keys[0].val, 16); - memcpy(key.val[1], app->keys[1].val, 16); - - str = settings_str_from_bytes(&key, sizeof(key), buf, sizeof(buf)); - if (!str) { - BT_ERR("Unable to encode AppKey as value"); - return; - } - - snprintk(path, sizeof(path), "bt_mesh/AppKey/%x", app->app_idx); - - BT_DBG("Saving AppKey %s as value %s", path, str); - err = settings_save_one(path, str); - if (err) { - BT_ERR("Failed to store AppKey"); - } else { - BT_DBG("Stored AppKey"); - } -} - -static void store_pending_keys(void) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(key_updates); i++) { - struct key_update *update = &key_updates[i]; - - if (!update->valid) { - continue; - } - - if (update->clear) { - if (update->app_key) { - clear_app_key(update->key_idx); - } else { - clear_net_key(update->key_idx); - } - } else { - store_subnet(update->key_idx); - } - - update->valid = 0; - } -} - -#if MYNEWT_VAL(BLE_MESH_CDB) -static void clear_cdb(void) -{ - int err; - - err = settings_save_one("bt/mesh/cdb/Net", NULL); - if (err) { - BT_ERR("Failed to clear Network"); - } else { - BT_DBG("Cleared Network"); - } -} - -static void store_pending_cdb(void) -{ - char buf[BT_SETTINGS_SIZE(sizeof(struct cdb_net_val))]; - struct cdb_net_val net; - int err; - char *str; - - BT_DBG(""); - - net.iv_index = bt_mesh_cdb.iv_index; - net.iv_update = atomic_test_bit(bt_mesh_cdb.flags, - BT_MESH_CDB_IVU_IN_PROGRESS); - - str = settings_str_from_bytes(&net, sizeof(net), buf, sizeof(buf)); - if (!str) { - BT_ERR("Unable to encode Network as value"); - return; - } - err = settings_save_one("bt/mesh/cdb/Net", str); - if (err) { - BT_ERR("Failed to store Network value"); - } else { - BT_DBG("Stored Network value"); - } -} - -static void store_cdb_node(const struct bt_mesh_cdb_node *node) -{ - char buf[BT_SETTINGS_SIZE(sizeof(struct node_val))]; - struct node_val val; - char path[30]; - char *str; - int err; - - val.net_idx = node->net_idx; - val.num_elem = node->num_elem; - val.flags = 0; - - if (atomic_test_bit(node->flags, BT_MESH_CDB_NODE_CONFIGURED)) { - val.flags |= F_NODE_CONFIGURED; - } - - memcpy(val.uuid, node->uuid, 16); - memcpy(val.dev_key, node->dev_key, 16); - - snprintk(path, sizeof(path), "bt_mesh/cdb/Node/%x", node->addr); - - str = settings_str_from_bytes(&val, sizeof(val), buf, sizeof(buf)); - if (!str) { - BT_ERR("Unable to encode Node as value"); - return; - } - - - err = settings_save_one(path, str); - if (err) { - BT_ERR("Failed to store Node %s value", path); - } else { - BT_DBG("Stored Node %s value", path); - } -} - -static void clear_cdb_node(uint16_t addr) -{ - char path[30]; - int err; - - BT_DBG("Node 0x%04x", addr); - - snprintk(path, sizeof(path), "bt/mesh/cdb/Node/%x", addr); - err = settings_save_one(path, NULL); - if (err) { - BT_ERR("Failed to clear Node 0x%04x", addr); - } else { - BT_DBG("Cleared Node 0x%04x", addr); - } -} - -static void store_pending_cdb_nodes(void) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(cdb_node_updates); ++i) { - struct node_update *update = &cdb_node_updates[i]; - - if (update->addr == BT_MESH_ADDR_UNASSIGNED) { - continue; - } - - BT_DBG("addr: 0x%04x, clear: %d", update->addr, update->clear); - - if (update->clear) { - clear_cdb_node(update->addr); - } else { - struct bt_mesh_cdb_node *node; - - node = bt_mesh_cdb_node_get(update->addr); - if (node) { - store_cdb_node(node); - } else { - BT_WARN("Node 0x%04x not found", update->addr); - } - } - - update->addr = BT_MESH_ADDR_UNASSIGNED; - } -} - -static void store_cdb_subnet(const struct bt_mesh_cdb_subnet *sub) -{ - char buf[BT_SETTINGS_SIZE(sizeof(struct net_key_val))]; - struct net_key_val key; - char path[30]; - int err; - char *str; - - BT_DBG("NetKeyIndex 0x%03x NetKey %s", sub->net_idx, - bt_hex(sub->keys[0].net_key, 16)); - - memcpy(&key.val[0], sub->keys[0].net_key, 16); - memcpy(&key.val[1], sub->keys[1].net_key, 16); - key.kr_flag = 0U; /* Deprecated */ - key.kr_phase = sub->kr_phase; - - snprintk(path, sizeof(path), "bt/mesh/cdb/Subnet/%x", sub->net_idx); - - - str = settings_str_from_bytes(&key, sizeof(key), buf, sizeof(buf)); - if (!str) { - BT_ERR("Unable to encode Subnet as value"); - return; - } - err = settings_save_one(path, str); - if (err) { - BT_ERR("Failed to store Subnet value"); - } else { - BT_DBG("Stored Subnet value"); - } -} - -static void clear_cdb_subnet(uint16_t net_idx) -{ - char path[30]; - int err; - - BT_DBG("NetKeyIndex 0x%03x", net_idx); - - snprintk(path, sizeof(path), "bt/mesh/cdb/Subnet/%x", net_idx); - err = settings_save_one(path, NULL); - if (err) { - BT_ERR("Failed to clear NetKeyIndex 0x%03x", net_idx); - } else { - BT_DBG("Cleared NetKeyIndex 0x%03x", net_idx); - } -} - -static void store_cdb_app_key(const struct bt_mesh_cdb_app_key *app) -{ - char buf[BT_SETTINGS_SIZE(sizeof(struct app_key_val))]; - struct app_key_val key; - char path[30]; - int err; - char *str; - - key.net_idx = app->net_idx; - key.updated = false; - memcpy(key.val[0], app->keys[0].app_key, 16); - memcpy(key.val[1], app->keys[1].app_key, 16); - - snprintk(path, sizeof(path), "bt/mesh/cdb/AppKey/%x", app->app_idx); - - str = settings_str_from_bytes(&key, sizeof(key), buf, sizeof(buf)); - err = settings_save_one(path, str); - if (err) { - BT_ERR("Failed to store AppKey"); - } else { - BT_DBG("Stored AppKey"); - } -} - -static void clear_cdb_app_key(uint16_t app_idx) -{ - char path[30]; - int err; - - snprintk(path, sizeof(path), "bt/mesh/cdb/AppKey/%x", app_idx); - err = settings_save_one(path, NULL); - if (err) { - BT_ERR("Failed to clear AppKeyIndex 0x%03x", app_idx); - } else { - BT_DBG("Cleared AppKeyIndex 0x%03x", app_idx); - } -} - -static void store_pending_cdb_keys(void) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(cdb_key_updates); i++) { - struct key_update *update = &cdb_key_updates[i]; - - if (!update->valid) { - continue; - } - - if (update->clear) { - if (update->app_key) { - clear_cdb_app_key(update->key_idx); - } else { - clear_cdb_subnet(update->key_idx); - } - } else { - if (update->app_key) { - struct bt_mesh_cdb_app_key *key; - - key = bt_mesh_cdb_app_key_get(update->key_idx); - if (key) { - store_cdb_app_key(key); - } else { - BT_WARN("AppKeyIndex 0x%03x not found", - update->key_idx); - } - } else { - struct bt_mesh_cdb_subnet *sub; - - sub = bt_mesh_cdb_subnet_get(update->key_idx); - if (sub) { - store_cdb_subnet(sub); - } else { - BT_WARN("NetKeyIndex 0x%03x not found", - update->key_idx); - } - } - } - - update->valid = 0U; - } -} - -static struct node_update *cdb_node_update_find(uint16_t addr, - struct node_update **free_slot) -{ - struct node_update *match; - int i; - - match = NULL; - *free_slot = NULL; - - for (i = 0; i < ARRAY_SIZE(cdb_node_updates); i++) { - struct node_update *update = &cdb_node_updates[i]; - - if (update->addr == BT_MESH_ADDR_UNASSIGNED) { - *free_slot = update; - continue; - } - - if (update->addr == addr) { - match = update; - } - } - - return match; -} -#endif - -static void encode_mod_path(struct bt_mesh_model *mod, bool vnd, - const char *key, char *path, size_t path_len) -{ - uint16_t mod_key = (((uint16_t)mod->elem_idx << 8) | mod->mod_idx); - - if (vnd) { - snprintk(path, path_len, "bt_mesh/v/%x/%s", mod_key, key); - } else { - snprintk(path, path_len, "bt_mesh/s/%x/%s", mod_key, key); - } -} - -static void store_pending_mod_bind(struct bt_mesh_model *mod, bool vnd) -{ - uint16_t keys[CONFIG_BT_MESH_MODEL_KEY_COUNT]; - char buf[BT_SETTINGS_SIZE(sizeof(keys))]; - char path[20]; - int i, count, err; - char *val; - - for (i = 0, count = 0; i < ARRAY_SIZE(mod->keys); i++) { - if (mod->keys[i] != BT_MESH_KEY_UNUSED) { - keys[count++] = mod->keys[i]; - } - } - - if (count) { - val = settings_str_from_bytes(keys, count * sizeof(keys[0]), - buf, sizeof(buf)); - if (!val) { - BT_ERR("Unable to encode model bindings as value"); - return; - } - } else { - val = NULL; - } - - encode_mod_path(mod, vnd, "bind", path, sizeof(path)); - - BT_DBG("Saving %s as %s", path, val ? val : "(null)"); - err = settings_save_one(path, val); - if (err) { - BT_ERR("Failed to store bind"); - } else { - BT_DBG("Stored bind"); - } -} - -static void store_pending_mod_sub(struct bt_mesh_model *mod, bool vnd) -{ - uint16_t groups[CONFIG_BT_MESH_MODEL_GROUP_COUNT]; - char buf[BT_SETTINGS_SIZE(sizeof(groups))]; - char path[20]; - int i, count, err; - char *val; - - for (i = 0, count = 0; i < CONFIG_BT_MESH_MODEL_GROUP_COUNT; i++) { - if (mod->groups[i] != BT_MESH_ADDR_UNASSIGNED) { - groups[count++] = mod->groups[i]; - } - } - - if (count) { - val = settings_str_from_bytes(groups, count * sizeof(groups[0]), - buf, sizeof(buf)); - if (!val) { - BT_ERR("Unable to encode model subscription as value"); - return; - } - } else { - val = NULL; - } - - encode_mod_path(mod, vnd, "sub", path, sizeof(path)); - - BT_DBG("Saving %s as %s", path, val ? val : "(null)"); - err = settings_save_one(path, val); - if (err) { - BT_ERR("Failed to store sub"); - } else { - BT_DBG("Stored sub"); - } -} - -static void store_pending_mod_pub(struct bt_mesh_model *mod, bool vnd) -{ - char buf[BT_SETTINGS_SIZE(sizeof(struct mod_pub_val))]; - struct mod_pub_val pub; - char path[20]; - char *val; - int err; - - if (!mod->pub || mod->pub->addr == BT_MESH_ADDR_UNASSIGNED) { - val = NULL; - } else { - pub.addr = mod->pub->addr; - pub.key = mod->pub->key; - pub.ttl = mod->pub->ttl; - pub.retransmit = mod->pub->retransmit; - pub.period = mod->pub->period; - pub.period_div = mod->pub->period_div; - pub.cred = mod->pub->cred; - - val = settings_str_from_bytes(&pub, sizeof(pub), - buf, sizeof(buf)); - if (!val) { - BT_ERR("Unable to encode model publication as value"); - return; - } - } - - encode_mod_path(mod, vnd, "pub", path, sizeof(path)); - - BT_DBG("Saving %s as %s", path, val ? val : "(null)"); - err = settings_save_one(path, val); - if (err) { - BT_ERR("Failed to store pub"); - } else { - BT_DBG("Stored pub"); - } -} - -static void store_pending_mod(struct bt_mesh_model *mod, - struct bt_mesh_elem *elem, bool vnd, - bool primary, void *user_data) -{ - if (!mod->flags) { - return; - } - - if (mod->flags & BT_MESH_MOD_BIND_PENDING) { - mod->flags &= ~BT_MESH_MOD_BIND_PENDING; - store_pending_mod_bind(mod, vnd); - } - - if (mod->flags & BT_MESH_MOD_SUB_PENDING) { - mod->flags &= ~BT_MESH_MOD_SUB_PENDING; - store_pending_mod_sub(mod, vnd); - } - - if (mod->flags & BT_MESH_MOD_PUB_PENDING) { - mod->flags &= ~BT_MESH_MOD_PUB_PENDING; - store_pending_mod_pub(mod, vnd); - } -} - -#define IS_VA_DEL(_label) ((_label)->ref == 0) -static void store_pending_va(void) -{ - char buf[BT_SETTINGS_SIZE(sizeof(struct va_val))]; - struct bt_mesh_va *lab; - struct va_val va; - char path[18]; - char *val; - uint16_t i; - int err = 0; - - for (i = 0; (lab = bt_mesh_va_get(i)) != NULL; i++) { - if (!lab->changed) { - continue; - } - - lab->changed = 0U; - - snprintk(path, sizeof(path), "bt_mesh/Va/%x", i); - - if (IS_VA_DEL(lab)) { - val = NULL; - } else { - va.ref = lab->ref; - va.addr = lab->addr; - memcpy(va.uuid, lab->uuid, 16); - - val = settings_str_from_bytes(&va, sizeof(va), - buf, sizeof(buf)); - if (!val) { - BT_ERR("Unable to encode model publication as value"); - return; - } - - err = settings_save_one(path, val); - } - - if (err) { - BT_ERR("Failed to %s %s value (err %d)", - IS_VA_DEL(lab) ? "delete" : "store", path, err); - } else { - BT_DBG("%s %s value", - IS_VA_DEL(lab) ? "Deleted" : "Stored", path); - } - } -} - -static void store_pending(struct ble_npl_event *work) -{ - BT_DBG(""); - - if (atomic_test_and_clear_bit(bt_mesh.flags, BT_MESH_RPL_PENDING)) { - if (atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) { - bt_mesh_rpl_foreach(store_pending_rpl, NULL); - } else { - bt_mesh_rpl_foreach(clear_rpl, NULL); - } - } - - if (atomic_test_and_clear_bit(bt_mesh.flags, BT_MESH_KEYS_PENDING)) { - store_pending_keys(); - } - - if (atomic_test_and_clear_bit(bt_mesh.flags, BT_MESH_NET_PENDING)) { - if (atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) { - store_pending_net(); - } else { - clear_net(); - } - } - - if (atomic_test_and_clear_bit(bt_mesh.flags, BT_MESH_IV_PENDING)) { - if (atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) { - store_pending_iv(); - } else { - clear_iv(); - } - } - - if (atomic_test_and_clear_bit(bt_mesh.flags, BT_MESH_SEQ_PENDING)) { - store_pending_seq(); - } - - if (atomic_test_and_clear_bit(bt_mesh.flags, BT_MESH_HB_PUB_PENDING)) { - store_pending_hb_pub(); - } - - if (atomic_test_and_clear_bit(bt_mesh.flags, BT_MESH_CFG_PENDING)) { - if (atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) { - store_pending_cfg(); - } else { - clear_cfg(); - } - } - - if (atomic_test_and_clear_bit(bt_mesh.flags, BT_MESH_MOD_PENDING)) { - bt_mesh_model_foreach(store_pending_mod, NULL); - } - - if (atomic_test_and_clear_bit(bt_mesh.flags, BT_MESH_VA_PENDING)) { - store_pending_va(); - } - -#if MYNEWT_VAL(BLE_MESH_CDB) - if (IS_ENABLED(CONFIG_BT_MESH_CDB)) { - if (atomic_test_and_clear_bit(bt_mesh_cdb.flags, - BT_MESH_CDB_SUBNET_PENDING)) { - if (atomic_test_bit(bt_mesh_cdb.flags, - BT_MESH_CDB_VALID)) { - store_pending_cdb(); - } else { - clear_cdb(); - } - } - - if (atomic_test_and_clear_bit(bt_mesh_cdb.flags, - BT_MESH_CDB_NODES_PENDING)) { - store_pending_cdb_nodes(); - } - - if (atomic_test_and_clear_bit(bt_mesh_cdb.flags, - BT_MESH_CDB_KEYS_PENDING)) { - store_pending_cdb_keys(); - } - } -#endif -} - -void bt_mesh_store_rpl(struct bt_mesh_rpl *entry) -{ - entry->store = true; - schedule_store(BT_MESH_RPL_PENDING); -} - -static struct key_update *key_update_find(bool app_key, uint16_t key_idx, - struct key_update **free_slot) -{ - struct key_update *match; - int i; - - match = NULL; - *free_slot = NULL; - - for (i = 0; i < ARRAY_SIZE(key_updates); i++) { - struct key_update *update = &key_updates[i]; - - if (!update->valid) { - *free_slot = update; - continue; - } - - if (update->app_key != app_key) { - continue; - } - - if (update->key_idx == key_idx) { - match = update; - } - } - - return match; -} - -void bt_mesh_store_subnet(uint16_t net_idx) -{ - struct key_update *update, *free_slot; - - BT_DBG("NetKeyIndex 0x%03x", net_idx); - - update = key_update_find(false, net_idx, &free_slot); - if (update) { - update->clear = 0; - schedule_store(BT_MESH_KEYS_PENDING); - return; - } - - if (!free_slot) { - store_subnet(net_idx); - return; - } - - free_slot->valid = 1; - free_slot->key_idx = net_idx; - free_slot->app_key = 0; - free_slot->clear = 0; - - schedule_store(BT_MESH_KEYS_PENDING); -} - -void bt_mesh_store_app_key(uint16_t app_idx) -{ - struct key_update *update, *free_slot; - - BT_DBG("AppKeyIndex 0x%03x", app_idx); - - update = key_update_find(true, app_idx, &free_slot); - if (update) { - update->clear = 0; - schedule_store(BT_MESH_KEYS_PENDING); - return; - } - - if (!free_slot) { - store_app(app_idx); - return; - } - - free_slot->valid = 1; - free_slot->key_idx = app_idx; - free_slot->app_key = 1; - free_slot->clear = 0; - - schedule_store(BT_MESH_KEYS_PENDING); -} - -void bt_mesh_store_hb_pub(void) -{ - schedule_store(BT_MESH_HB_PUB_PENDING); -} - -void bt_mesh_store_cfg(void) -{ - schedule_store(BT_MESH_CFG_PENDING); -} - -void bt_mesh_clear_net(void) -{ - schedule_store(BT_MESH_NET_PENDING); - schedule_store(BT_MESH_IV_PENDING); - schedule_store(BT_MESH_CFG_PENDING); -} - -void bt_mesh_clear_subnet(uint16_t net_idx) -{ - struct key_update *update, *free_slot; - - BT_DBG("NetKeyIndex 0x%03x", net_idx); - - update = key_update_find(false, net_idx, &free_slot); - if (update) { - update->clear = 1; - schedule_store(BT_MESH_KEYS_PENDING); - return; - } - - if (!free_slot) { - clear_net_key(net_idx); - return; - } - - free_slot->valid = 1; - free_slot->key_idx = net_idx; - free_slot->app_key = 0; - free_slot->clear = 1; - - schedule_store(BT_MESH_KEYS_PENDING); -} - -void bt_mesh_clear_app_key(uint16_t app_idx) -{ - struct key_update *update, *free_slot; - - BT_DBG("AppKeyIndex 0x%03x", app_idx); - - update = key_update_find(true, app_idx, &free_slot); - if (update) { - update->clear = 1; - schedule_store(BT_MESH_KEYS_PENDING); - return; - } - - if (!free_slot) { - clear_app_key(app_idx); - return; - } - - free_slot->valid = 1; - free_slot->key_idx = app_idx; - free_slot->app_key = 1; - free_slot->clear = 1; - - schedule_store(BT_MESH_KEYS_PENDING); -} - -void bt_mesh_clear_rpl(void) -{ - schedule_store(BT_MESH_RPL_PENDING); -} - -void bt_mesh_store_mod_bind(struct bt_mesh_model *mod) -{ - mod->flags |= BT_MESH_MOD_BIND_PENDING; - schedule_store(BT_MESH_MOD_PENDING); -} - -void bt_mesh_store_mod_sub(struct bt_mesh_model *mod) -{ - mod->flags |= BT_MESH_MOD_SUB_PENDING; - schedule_store(BT_MESH_MOD_PENDING); -} - -void bt_mesh_store_mod_pub(struct bt_mesh_model *mod) -{ - mod->flags |= BT_MESH_MOD_PUB_PENDING; - schedule_store(BT_MESH_MOD_PENDING); -} - - -void bt_mesh_store_label(void) -{ - schedule_store(BT_MESH_VA_PENDING); -} - -#if MYNEWT_VAL(BLE_MESH_CDB) -static void schedule_cdb_store(int flag) -{ - atomic_set_bit(bt_mesh_cdb.flags, flag); - k_delayed_work_submit(&pending_store, K_NO_WAIT); -} - -void bt_mesh_store_cdb(void) -{ - schedule_cdb_store(BT_MESH_CDB_SUBNET_PENDING); -} - -void bt_mesh_store_cdb_node(const struct bt_mesh_cdb_node *node) -{ - struct node_update *update, *free_slot; - - BT_DBG("Node 0x%04x", node->addr); - - update = cdb_node_update_find(node->addr, &free_slot); - if (update) { - update->clear = false; - schedule_cdb_store(BT_MESH_CDB_NODES_PENDING); - return; - } - - if (!free_slot) { - store_cdb_node(node); - return; - } - - free_slot->addr = node->addr; - free_slot->clear = false; - - schedule_cdb_store(BT_MESH_CDB_NODES_PENDING); -} - -void bt_mesh_clear_cdb_node(struct bt_mesh_cdb_node *node) -{ - struct node_update *update, *free_slot; - - BT_DBG("Node 0x%04x", node->addr); - - update = cdb_node_update_find(node->addr, &free_slot); - if (update) { - update->clear = true; - schedule_cdb_store(BT_MESH_CDB_NODES_PENDING); - return; - } - - if (!free_slot) { - clear_cdb_node(node->addr); - return; - } - - free_slot->addr = node->addr; - free_slot->clear = true; - - schedule_cdb_store(BT_MESH_CDB_NODES_PENDING); -} - -/* TODO: Could be shared with key_update_find? */ -static struct key_update *cdb_key_update_find(bool app_key, uint16_t key_idx, - struct key_update **free_slot) -{ - struct key_update *match; - int i; - - match = NULL; - *free_slot = NULL; - - for (i = 0; i < ARRAY_SIZE(cdb_key_updates); i++) { - struct key_update *update = &cdb_key_updates[i]; - - if (!update->valid) { - *free_slot = update; - continue; - } - - if (update->app_key != app_key) { - continue; - } - - if (update->key_idx == key_idx) { - match = update; - } - } - - return match; -} - -void bt_mesh_store_cdb_subnet(const struct bt_mesh_cdb_subnet *sub) -{ - struct key_update *update, *free_slot; - - BT_DBG("NetKeyIndex 0x%03x", sub->net_idx); - - update = cdb_key_update_find(false, sub->net_idx, &free_slot); - if (update) { - update->clear = 0U; - schedule_cdb_store(BT_MESH_CDB_KEYS_PENDING); - return; - } - - if (!free_slot) { - store_cdb_subnet(sub); - return; - } - - free_slot->valid = 1U; - free_slot->key_idx = sub->net_idx; - free_slot->app_key = 0U; - free_slot->clear = 0U; - - schedule_cdb_store(BT_MESH_CDB_KEYS_PENDING); -} - -void bt_mesh_clear_cdb_subnet(struct bt_mesh_cdb_subnet *sub) -{ - struct key_update *update, *free_slot; - - BT_DBG("NetKeyIndex 0x%03x", sub->net_idx); - - update = cdb_key_update_find(false, sub->net_idx, &free_slot); - if (update) { - update->clear = 1U; - schedule_cdb_store(BT_MESH_CDB_KEYS_PENDING); - return; - } - - if (!free_slot) { - clear_cdb_subnet(sub->net_idx); - return; - } - - free_slot->valid = 1U; - free_slot->key_idx = sub->net_idx; - free_slot->app_key = 0U; - free_slot->clear = 1U; - - schedule_cdb_store(BT_MESH_CDB_KEYS_PENDING); -} - -void bt_mesh_store_cdb_app_key(const struct bt_mesh_cdb_app_key *key) -{ - struct key_update *update, *free_slot; - - BT_DBG("AppKeyIndex 0x%03x", key->app_idx); - - update = cdb_key_update_find(true, key->app_idx, &free_slot); - if (update) { - update->clear = 0U; - schedule_cdb_store(BT_MESH_CDB_KEYS_PENDING); - return; - } - - if (!free_slot) { - store_cdb_app_key(key); - return; - } - - free_slot->valid = 1U; - free_slot->key_idx = key->app_idx; - free_slot->app_key = 1U; - free_slot->clear = 0U; - - schedule_cdb_store(BT_MESH_CDB_KEYS_PENDING); -} - -void bt_mesh_clear_cdb_app_key(struct bt_mesh_cdb_app_key *key) -{ - struct key_update *update, *free_slot; - - BT_DBG("AppKeyIndex 0x%03x", key->app_idx); - - update = cdb_key_update_find(true, key->app_idx, &free_slot); - if (update) { - update->clear = 1U; - schedule_cdb_store(BT_MESH_CDB_KEYS_PENDING); - return; - } - - if (!free_slot) { - clear_cdb_app_key(key->app_idx); - return; - } - - free_slot->valid = 1U; - free_slot->key_idx = key->app_idx; - free_slot->app_key = 1U; - free_slot->clear = 1U; - - schedule_cdb_store(BT_MESH_CDB_KEYS_PENDING); -} -#endif - -int bt_mesh_model_data_store(struct bt_mesh_model *mod, bool vnd, - const char *name, const void *data, - size_t data_len) -{ - char path[30]; - char buf[BT_SETTINGS_SIZE(sizeof(struct mod_pub_val))]; - char *val; - int err; - - encode_mod_path(mod, vnd, "data", path, sizeof(path)); - if (name) { - strcat(path, "/"); - strncat(path, name, 8); - } - - if (data_len) { - val = settings_str_from_bytes(data, data_len, - buf, sizeof(buf)); - if (!val) { - BT_ERR("Unable to encode model publication as value"); - return -EINVAL; - } - err = settings_save_one(path, val); - } else { - err = settings_save_one(path, NULL); - } - - if (err) { - BT_ERR("Failed to store %s value", path); - } else { - BT_DBG("Stored %s value", path); - } - return err; } static struct conf_handler bt_mesh_settings_conf_handler = { .ch_name = "bt_mesh", .ch_get = NULL, - .ch_set = mesh_set, + .ch_set = NULL, .ch_commit = mesh_commit, .ch_export = NULL, }; @@ -2457,7 +212,7 @@ void bt_mesh_settings_init(void) SYSINIT_PANIC_ASSERT_MSG(rc == 0, "Failed to register bt_mesh_settings conf"); - k_delayed_work_init(&pending_store, store_pending); + k_work_init_delayable(&pending_store, store_pending); } #endif /* MYNEWT_VAL(BLE_MESH_SETTINGS) */ diff --git a/nimble/host/mesh/src/settings.h b/nimble/host/mesh/src/settings.h index 9060a14a72..73105fb345 100644 --- a/nimble/host/mesh/src/settings.h +++ b/nimble/host/mesh/src/settings.h @@ -3,30 +3,24 @@ * * SPDX-License-Identifier: Apache-2.0 */ +/* Pending storage actions. */ +enum bt_mesh_settings_flag { + BT_MESH_SETTINGS_RPL_PENDING, + BT_MESH_SETTINGS_NET_KEYS_PENDING, + BT_MESH_SETTINGS_APP_KEYS_PENDING, + BT_MESH_SETTINGS_NET_PENDING, + BT_MESH_SETTINGS_IV_PENDING, + BT_MESH_SETTINGS_SEQ_PENDING, + BT_MESH_SETTINGS_HB_PUB_PENDING, + BT_MESH_SETTINGS_CFG_PENDING, + BT_MESH_SETTINGS_MOD_PENDING, + BT_MESH_SETTINGS_VA_PENDING, + BT_MESH_SETTINGS_CDB_PENDING, -void bt_mesh_store_net(void); -void bt_mesh_store_iv(bool only_duration); -void bt_mesh_store_seq(void); -void bt_mesh_store_rpl(struct bt_mesh_rpl *rpl); -void bt_mesh_store_subnet(uint16_t net_idx); -void bt_mesh_store_app_key(uint16_t app_idx); -void bt_mesh_store_hb_pub(void); -void bt_mesh_store_cfg(void); -void bt_mesh_store_mod_bind(struct bt_mesh_model *mod); -void bt_mesh_store_mod_sub(struct bt_mesh_model *mod); -void bt_mesh_store_mod_pub(struct bt_mesh_model *mod); -void bt_mesh_store_label(void); -void bt_mesh_store_cdb(void); -void bt_mesh_store_cdb_node(const struct bt_mesh_cdb_node *node); -void bt_mesh_store_cdb_subnet(const struct bt_mesh_cdb_subnet *sub); -void bt_mesh_store_cdb_app_key(const struct bt_mesh_cdb_app_key *app); - -void bt_mesh_clear_net(void); -void bt_mesh_clear_subnet(uint16_t net_idx); -void bt_mesh_clear_app_key(uint16_t app_idx); -void bt_mesh_clear_rpl(void); -void bt_mesh_clear_cdb_node(struct bt_mesh_cdb_node *node); -void bt_mesh_clear_cdb_subnet(struct bt_mesh_cdb_subnet *sub); -void bt_mesh_clear_cdb_app_key(struct bt_mesh_cdb_app_key *app); + BT_MESH_SETTINGS_FLAG_COUNT, +}; void bt_mesh_settings_init(void); +int settings_name_next(char *name, char **next); +void bt_mesh_settings_store_schedule(enum bt_mesh_settings_flag flag); +void bt_mesh_settings_store_cancel(enum bt_mesh_settings_flag flag); diff --git a/nimble/host/mesh/src/shell.c b/nimble/host/mesh/src/shell.c index 0a27e274e7..e905231081 100644 --- a/nimble/host/mesh/src/shell.c +++ b/nimble/host/mesh/src/shell.c @@ -169,7 +169,7 @@ static struct bt_mesh_cfg_cli cfg_cli = { #endif /* MYNEWT_VAL(BLE_MESH_CFG_CLI) */ #if MYNEWT_VAL(BLE_MESH_HEALTH_CLI) -void show_faults(uint8_t test_id, uint16_t cid, uint8_t *faults, size_t fault_count) +static void show_faults(uint8_t test_id, uint16_t cid, uint8_t *faults, size_t fault_count) { size_t i; @@ -707,10 +707,9 @@ static int check_pub_addr_unassigned(void) #ifdef ARCH_sim return 0; #else - uint8_t zero_addr[BLE_DEV_ADDR_LEN] = { 0 }; + uint8_t addr[BLE_DEV_ADDR_LEN]; - return memcmp(MYNEWT_VAL(BLE_PUBLIC_DEV_ADDR), - zero_addr, BLE_DEV_ADDR_LEN) == 0; + return ble_hs_id_copy_addr(BLE_ADDR_PUBLIC, addr, NULL) != 0; #endif } @@ -997,78 +996,79 @@ struct shell_cmd_help cmd_timeout_help = { static int cmd_get_comp(int argc, char *argv[]) { - struct os_mbuf *comp = NET_BUF_SIMPLE(BT_MESH_RX_SDU_MAX); - uint8_t status, page = 0x00; + struct os_mbuf *buf = NET_BUF_SIMPLE(BT_MESH_RX_SDU_MAX); + struct bt_mesh_comp_p0_elem elem; + struct bt_mesh_comp_p0 comp; + uint8_t page = 0x00; int err = 0; if (argc > 1) { page = strtol(argv[1], NULL, 0); } - net_buf_simple_init(comp, 0); - err = bt_mesh_cfg_comp_data_get(net.net_idx, net.dst, page, - &status, comp); + net_buf_simple_init(buf, 0); + err = bt_mesh_cfg_comp_data_get(net.net_idx, net.dst, page, &page, + buf); if (err) { printk("Getting composition failed (err %d)\n", err); goto done; } - if (status != 0x00) { - printk("Got non-success status 0x%02x\n", status); + if (page != 0x00) { + printk("Got page 0x%02x. No parser available.", + page); goto done; } - printk("Got Composition Data for 0x%04x:\n", net.dst); - printk("\tCID 0x%04x\n", net_buf_simple_pull_le16(comp)); - printk("\tPID 0x%04x\n", net_buf_simple_pull_le16(comp)); - printk("\tVID 0x%04x\n", net_buf_simple_pull_le16(comp)); - printk("\tCRPL 0x%04x\n", net_buf_simple_pull_le16(comp)); - printk("\tFeatures 0x%04x\n", net_buf_simple_pull_le16(comp)); - - while (comp->om_len > 4) { - uint8_t sig, vnd; - uint16_t loc; - int i; - - loc = net_buf_simple_pull_le16(comp); - sig = net_buf_simple_pull_u8(comp); - vnd = net_buf_simple_pull_u8(comp); + err = bt_mesh_comp_p0_get(&comp, buf); + if (err) { + printk("Getting composition failed (err %d)\n", err); + goto done; + } - printk("\n\tElement @ 0x%04x:\n", loc); + printk("Got Composition Data for 0x%04x:", net.dst); + printk("\tCID 0x%04x", comp.cid); + printk("\tPID 0x%04x", comp.pid); + printk("\tVID 0x%04x", comp.vid); + printk("\tCRPL 0x%04x", comp.crpl); + printk("\tFeatures 0x%04x", comp.feat); - if (comp->om_len < ((sig * 2) + (vnd * 4))) { - printk("\t\t...truncated data!\n"); - break; - } + while (bt_mesh_comp_p0_elem_pull(&comp, &elem)) { + int i; - if (sig) { + printk("\tElement @ 0x%04x:", elem.loc); + if (elem.nsig) { printk("\t\tSIG Models:\n"); } else { printk("\t\tNo SIG Models\n"); } - for (i = 0; i < sig; i++) { - uint16_t mod_id = net_buf_simple_pull_le16(comp); + for (i = 0; i < elem.nsig; i++) { + uint16_t mod_id = bt_mesh_comp_p0_elem_mod(&elem, i); printk("\t\t\t0x%04x\n", mod_id); } - if (vnd) { + if (elem.nvnd) { printk("\t\tVendor Models:\n"); } else { printk("\t\tNo Vendor Models\n"); } - for (i = 0; i < vnd; i++) { - uint16_t cid = net_buf_simple_pull_le16(comp); - uint16_t mod_id = net_buf_simple_pull_le16(comp); + for (i = 0; i < elem.nvnd; i++) { + struct bt_mesh_mod_id_vnd mod = + bt_mesh_comp_p0_elem_mod_vnd(&elem, i); - printk("\t\t\tCompany 0x%04x: 0x%04x\n", cid, mod_id); + printk("\t\t\tCompany 0x%04x: 0x%04x", + mod.company, mod.id); } } + if (buf->om_len) { + printk("\t\t...truncated data!"); + } done: - os_mbuf_free_chain(comp); + os_mbuf_free_chain(buf); return err; } @@ -2001,6 +2001,7 @@ static int mod_pub_set(uint16_t addr, uint16_t mod_id, uint16_t cid, char *argv[ int err; pub.addr = strtoul(argv[0], NULL, 0); + pub.uuid = NULL; pub.app_idx = strtoul(argv[1], NULL, 0); pub.cred_flag = str2bool(argv[2]); pub.ttl = strtoul(argv[3], NULL, 0); @@ -2906,7 +2907,7 @@ static int cmd_cdb_node_add(int argc, char *argv[]) memcpy(node->dev_key, dev_key, 16); if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_cdb_node(node); + bt_mesh_cdb_node_store(node); } printk("Added node 0x%04x", addr); @@ -2960,7 +2961,7 @@ static int cmd_cdb_subnet_add(int argc, memcpy(sub->keys[0].net_key, net_key, 16); if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_cdb_subnet(sub); + bt_mesh_cdb_subnet_store(sub); } printk("Added Subnet 0x%03x", net_idx); @@ -3016,7 +3017,7 @@ static int cmd_cdb_app_key_add(int argc, memcpy(key->keys[0].app_key, app_key, 16); if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_cdb_app_key(key); + bt_mesh_cdb_app_key_store(key); } printk("Added AppKey 0x%03x", app_idx); diff --git a/nimble/host/mesh/src/shell.h b/nimble/host/mesh/src/shell.h index 53cc83a278..98d3f8c667 100644 --- a/nimble/host/mesh/src/shell.h +++ b/nimble/host/mesh/src/shell.h @@ -1,3 +1,9 @@ +/* + * Copyright (c) 2017 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + #ifndef __SHELL_H__ #define __SHELL_H__ diff --git a/nimble/host/mesh/src/subnet.c b/nimble/host/mesh/src/subnet.c index d6fcfbeee7..d8c27c371a 100644 --- a/nimble/host/mesh/src/subnet.c +++ b/nimble/host/mesh/src/subnet.c @@ -4,11 +4,11 @@ * * SPDX-License-Identifier: Apache-2.0 */ - +#include #include "syscfg/syscfg.h" -#define MESH_LOG_MODULE BLE_MESH_NET_KEYS_LOG -#include "log/log.h" +#define BLE_NPL_LOG_MODULE BLE_MESH_NET_KEYS_LOG +#include #include "crypto.h" #include "adv.h" @@ -26,6 +26,26 @@ #include "settings.h" #include "prov.h" +/* Tracking of what storage changes are pending for Net Keys. We track this in + * a separate array here instead of within the respective bt_mesh_subnet + * struct itselve, since once a key gets deleted its struct becomes invalid + * and may be reused for other keys. + */ +struct net_key_update { + uint16_t key_idx:12, /* NetKey Index */ + valid:1, /* 1 if this entry is valid, 0 if not */ + clear:1; /* 1 if key needs clearing, 0 if storing */ +}; + +/* NetKey storage information */ +struct net_key_val { + uint8_t kr_flag:1, + kr_phase:7; + uint8_t val[2][16]; +} __packed; + +static struct net_key_update net_key_updates[CONFIG_BT_MESH_SUBNET_COUNT]; + #ifdef CONFIG_BT_MESH_GATT_PROXY void (*bt_mesh_subnet_cb_list[5]) (struct bt_mesh_subnet *sub, enum bt_mesh_key_evt evt); @@ -51,6 +71,91 @@ static void subnet_evt(struct bt_mesh_subnet *sub, enum bt_mesh_key_evt evt) } } +static void clear_net_key(uint16_t net_idx) +{ +#if MYNEWT_VAL(BLE_MESH_SETTINGS) + char path[20]; + int err; + + BT_DBG("NetKeyIndex 0x%03x", net_idx); + + snprintk(path, sizeof(path), "bt_mesh/NetKey/%x", net_idx); + err = settings_save_one(path, NULL); + if (err) { + BT_ERR("Failed to clear NetKeyIndex 0x%03x", net_idx); + } else { + BT_DBG("Cleared NetKeyIndex 0x%03x", net_idx); + } +#endif +} + +static void store_subnet(uint16_t net_idx) +{ +#if MYNEWT_VAL(BLE_MESH_SETTINGS) + const struct bt_mesh_subnet *sub; + struct net_key_val key; + char buf[BT_SETTINGS_SIZE(sizeof(struct net_key_val))]; + char path[20]; + char *str; + int err; + + sub = bt_mesh_subnet_get(net_idx); + if (!sub) { + BT_WARN("NetKeyIndex 0x%03x not found", net_idx); + return; + } + + BT_DBG("NetKeyIndex 0x%03x", net_idx); + + snprintk(path, sizeof(path), "bt_mesh/NetKey/%x", net_idx); + + memcpy(&key.val[0], sub->keys[0].net, 16); + memcpy(&key.val[1], sub->keys[1].net, 16); + key.kr_flag = 0U; /* Deprecated */ + key.kr_phase = sub->kr_phase; + + str = settings_str_from_bytes(&key, sizeof(key), buf, sizeof(buf)); + if (!str) { + BT_ERR("Unable to encode AppKey as value"); + return; + } + + err = settings_save_one(path, str); + if (err) { + BT_ERR("Failed to store NetKey"); + } else { + BT_DBG("Stored NetKey"); + } +#endif +} + +#if MYNEWT_VAL(BLE_MESH_SETTINGS) +static struct net_key_update *net_key_update_find(uint16_t key_idx, + struct net_key_update **free_slot) +{ + struct net_key_update *match; + int i; + + match = NULL; + *free_slot = NULL; + + for (i = 0; i < ARRAY_SIZE(net_key_updates); i++) { + struct net_key_update *update = &net_key_updates[i]; + + if (!update->valid) { + *free_slot = update; + continue; + } + + if (update->key_idx == key_idx) { + match = update; + } + } + + return match; +} +#endif + uint8_t bt_mesh_net_flags(struct bt_mesh_subnet *sub) { uint8_t flags = 0x00; @@ -66,6 +171,46 @@ uint8_t bt_mesh_net_flags(struct bt_mesh_subnet *sub) return flags; } +static void update_subnet_settings(uint16_t net_idx, bool store) +{ +#if MYNEWT_VAL(BLE_MESH_SETTINGS) + struct net_key_update *update, *free_slot; + uint8_t clear = store ? 0U : 1U; + + BT_DBG("NetKeyIndex 0x%03x", net_idx); + + update = net_key_update_find(net_idx, &free_slot); + if (update) { + update->clear = clear; + bt_mesh_settings_store_schedule( + BT_MESH_SETTINGS_NET_KEYS_PENDING); + return; + } + + if (!free_slot) { + if (store) { + store_subnet(net_idx); + } else { + clear_net_key(net_idx); + } + return; + } + + free_slot->valid = 1U; + free_slot->key_idx = net_idx; + free_slot->clear = clear; + + bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_NET_KEYS_PENDING); +#endif +} + +#if MYNEWT_VAL(BLE_MESH_SETTINGS) +void bt_mesh_subnet_store(uint16_t net_idx) +{ + update_subnet_settings(net_idx, true); +} +#endif + static void key_refresh(struct bt_mesh_subnet *sub, uint8_t new_phase) { BT_DBG("Phase 0x%02x -> 0x%02x", sub->kr_phase, new_phase); @@ -97,7 +242,7 @@ static void key_refresh(struct bt_mesh_subnet *sub, uint8_t new_phase) if (IS_ENABLED(CONFIG_BT_SETTINGS)) { BT_DBG("Storing Updated NetKey persistently"); - bt_mesh_store_subnet(sub->net_idx); + bt_mesh_subnet_store(sub->net_idx); } } @@ -139,7 +284,7 @@ static struct bt_mesh_subnet *subnet_alloc(uint16_t net_idx) static void subnet_del(struct bt_mesh_subnet *sub) { if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_clear_subnet(sub->net_idx); + update_subnet_settings(sub->net_idx, false); } bt_mesh_net_loopback_clear(sub->net_idx); @@ -242,7 +387,7 @@ uint8_t bt_mesh_subnet_add(uint16_t net_idx, const uint8_t key[16]) if (IS_ENABLED(CONFIG_BT_SETTINGS)) { BT_DBG("Storing NetKey persistently"); - bt_mesh_store_subnet(sub->net_idx); + bt_mesh_subnet_store(sub->net_idx); } return STATUS_SUCCESS; @@ -664,3 +809,77 @@ bool bt_mesh_net_cred_find(struct bt_mesh_net_rx *rx, struct os_mbuf *in, return false; } + +#if MYNEWT_VAL(BLE_MESH_SETTINGS) +static int net_key_set(int argc, char **argv, char *val) +{ + struct net_key_val key; + int len, err; + uint16_t net_idx; + + BT_DBG("argv[0] %s val %s", argv[0], val ? val : "(null)"); + + net_idx = strtol(argv[0], NULL, 16); + + len = sizeof(key); + err = settings_bytes_from_str(val, &key, &len); + if (err) { + BT_ERR("Failed to decode value %s (err %d)", val, err); + return err; + } + + if (len != sizeof(key)) { + BT_ERR("Unexpected value length (%d != %zu)", len, sizeof(key)); + return -EINVAL; + } + + BT_DBG("NetKeyIndex 0x%03x recovered from storage", net_idx); + + return bt_mesh_subnet_set( + net_idx, key.kr_phase, key.val[0], + (key.kr_phase != BT_MESH_KR_NORMAL) ? key.val[1] : NULL); +} +#endif + +void bt_mesh_subnet_pending_store(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(net_key_updates); i++) { + struct net_key_update *update = &net_key_updates[i]; + + if (!update->valid) { + continue; + } + + if (update->clear) { + clear_net_key(update->key_idx); + } else { + store_subnet(update->key_idx); + } + + update->valid = 0U; + } +} + +#if MYNEWT_VAL(BLE_MESH_SETTINGS) +static struct conf_handler bt_mesh_net_key_conf_handler = { + .ch_name = "bt_mesh", + .ch_get = NULL, + .ch_set = net_key_set, + .ch_commit = NULL, + .ch_export = NULL, +}; +#endif + +void bt_mesh_net_key_init(void) +{ +#if MYNEWT_VAL(BLE_MESH_SETTINGS) + int rc; + + rc = conf_register(&bt_mesh_net_key_conf_handler); + + SYSINIT_PANIC_ASSERT_MSG(rc == 0, + "Failed to register bt_mesh_net_key conf"); +#endif +} diff --git a/nimble/host/mesh/src/subnet.h b/nimble/host/mesh/src/subnet.h index 154b5d4e31..b64177d364 100644 --- a/nimble/host/mesh/src/subnet.h +++ b/nimble/host/mesh/src/subnet.h @@ -37,7 +37,7 @@ struct bt_mesh_subnet { uint8_t beacons_last; /* Number of beacons during last * observation window */ - uint8_t beacons_cur; /* Number of beaconds observed during + uint8_t beacons_cur; /* Number of beacons observed during * currently ongoing window. */ @@ -194,4 +194,13 @@ bt_mesh_subnet_has_new_key(const struct bt_mesh_subnet *sub) return sub->kr_phase != BT_MESH_KR_NORMAL; } -#endif /* _BLUETOOTH_MESH_SUBNET_H_ */ \ No newline at end of file +/** @brief Store the Subnet information in persistent storage. + * + * @param net_idx Network index to store. + */ +void bt_mesh_subnet_store(uint16_t net_idx); + +/** @brief Store the pending Subnets in persistent storage. */ +void bt_mesh_subnet_pending_store(void); +void bt_mesh_net_key_init(void); +#endif /* _BLUETOOTH_MESH_SUBNET_H_ */ diff --git a/nimble/host/mesh/src/testing.c b/nimble/host/mesh/src/testing.c index 7ee11a1373..b8e46366b1 100644 --- a/nimble/host/mesh/src/testing.c +++ b/nimble/host/mesh/src/testing.c @@ -94,16 +94,22 @@ void bt_test_mesh_trans_incomp_timer_exp(void) int bt_test_mesh_lpn_group_add(uint16_t group) { - bt_mesh_lpn_group_add(group); - - return 0; +#if MYNEWT_VAL(BLE_MESH_LOW_POWER) + bt_mesh_lpn_group_add(group); + return 0; +#else + return -ENOTSUP; +#endif } int bt_test_mesh_lpn_group_remove(uint16_t *groups, size_t groups_count) { - bt_mesh_lpn_group_del(groups, groups_count); - - return 0; +#if MYNEWT_VAL(BLE_MESH_LOW_POWER) + bt_mesh_lpn_group_del(groups, groups_count); + return 0; +#else + return -ENOTSUP; +#endif } int bt_test_mesh_rpl_clear(void) diff --git a/nimble/host/mesh/src/transport.c b/nimble/host/mesh/src/transport.c index 6391272d02..10d4442013 100644 --- a/nimble/host/mesh/src/transport.c +++ b/nimble/host/mesh/src/transport.c @@ -7,10 +7,13 @@ */ #include "syscfg/syscfg.h" -#define MESH_LOG_MODULE BLE_MESH_TRANS_LOG + +#define BLE_NPL_LOG_MODULE BLE_MESH_TRANS_LOG +#include #include #include +#include #include "mesh/mesh.h" #include "mesh/glue.h" @@ -69,6 +72,20 @@ /* How long to wait for available buffers before giving up */ #define BUF_TIMEOUT K_NO_WAIT +struct virtual_addr { + uint16_t ref:15, + changed:1; + uint16_t addr; + uint8_t uuid[16]; +}; + +/* Virtual Address information for persistent storage. */ +struct va_val { + uint16_t ref; + uint16_t addr; + uint8_t uuid[16]; +} __packed; + static struct seg_tx { struct bt_mesh_subnet *sub; void *seg[CONFIG_BT_MESH_TX_SEG_MAX]; @@ -92,7 +109,7 @@ static struct seg_tx { friend_cred:1; /* Using Friend credentials */ const struct bt_mesh_send_cb *cb; void *cb_data; - struct k_delayed_work retransmit; /* Retransmit timer */ + struct k_work_delayable retransmit; /* Retransmit timer */ } seg_tx[MYNEWT_VAL(BLE_MESH_TX_SEG_MSG_COUNT)]; static struct seg_rx { @@ -110,20 +127,21 @@ static struct seg_rx { uint8_t ttl; uint32_t block; uint32_t last; - struct k_delayed_work ack; + struct k_work_delayable ack; } seg_rx[CONFIG_BT_MESH_RX_SEG_MSG_COUNT]; -char _k_mem_slab_buffer_[(BT_MESH_APP_SEG_SDU_MAX*CONFIG_BT_MESH_SEG_BUFS)]; + +char _k_mem_slab_buffer_[OS_ALIGN((BT_MESH_APP_SEG_SDU_MAX)*(CONFIG_BT_MESH_SEG_BUFS), OS_ALIGNMENT)]; struct k_mem_slab segs = { .num_blocks = CONFIG_BT_MESH_SEG_BUFS, - .block_size = BT_MESH_APP_SEG_SDU_MAX, + .block_size = OS_ALIGN(BT_MESH_APP_SEG_SDU_MAX, OS_ALIGNMENT), .buffer = _k_mem_slab_buffer_, .free_list = NULL, .num_used = 0 }; -static struct bt_mesh_va virtual_addrs[CONFIG_BT_MESH_LABEL_COUNT]; +static struct virtual_addr virtual_addrs[CONFIG_BT_MESH_LABEL_COUNT]; static int send_unseg(struct bt_mesh_net_tx *tx, struct os_mbuf *sdu, const struct bt_mesh_send_cb *cb, void *cb_data, @@ -232,7 +250,7 @@ static void seg_tx_unblock_check(struct seg_tx *tx) BT_DBG("Unblocked 0x%04x", (uint16_t)(blocked->seq_auth & TRANS_SEQ_ZERO_MASK)); blocked->blocked = false; - k_delayed_work_submit(&blocked->retransmit, 0); + k_work_reschedule(&blocked->retransmit, 0); } } @@ -240,7 +258,8 @@ static void seg_tx_reset(struct seg_tx *tx) { int i; - k_delayed_work_cancel(&tx->retransmit); + /* If this call fails, the handler will exit early, as nack_count is 0. */ + (void)k_work_cancel_delayable(&tx->retransmit); tx->cb = NULL; tx->cb_data = NULL; @@ -301,8 +320,9 @@ static void schedule_retransmit(struct seg_tx *tx) * called this from inside bt_mesh_net_send), we should continue the * retransmit immediately, as we just freed up a tx buffer. */ - k_delayed_work_submit(&tx->retransmit, - tx->seg_o ? 0 : K_MSEC(SEG_RETRANSMIT_TIMEOUT(tx))); + k_work_reschedule(&tx->retransmit, + tx->seg_o ? K_NO_WAIT : + K_MSEC(SEG_RETRANSMIT_TIMEOUT(tx))); } static void seg_send_start(uint16_t duration, int err, void *user_data) @@ -423,8 +443,8 @@ static void seg_tx_send_unacked(struct seg_tx *tx) tx->attempts--; end: if (!tx->seg_pending) { - k_delayed_work_submit(&tx->retransmit, - SEG_RETRANSMIT_TIMEOUT(tx)); + k_work_reschedule(&tx->retransmit, + K_MSEC(SEG_RETRANSMIT_TIMEOUT(tx))); } tx->sending = 0U; @@ -614,12 +634,12 @@ int bt_mesh_trans_send(struct bt_mesh_net_tx *tx, struct os_mbuf *msg, return -EINVAL; } - if (msg->om_len > BT_MESH_TX_SDU_MAX) { - BT_ERR("Not enough segment buffers for length %u", msg->om_len); + if (msg->om_len > BT_MESH_TX_SDU_MAX - BT_MESH_MIC_SHORT) { + BT_ERR("Message too big: %u", msg->om_len); return -EMSGSIZE; } - if (net_buf_simple_tailroom(msg) < 4) { + if (net_buf_simple_tailroom(msg) < BT_MESH_MIC_SHORT) { BT_ERR("Insufficient tailroom for Transport MIC"); return -EINVAL; } @@ -844,8 +864,6 @@ static int trans_ack(struct bt_mesh_net_rx *rx, uint8_t hdr, return -EINVAL; } - k_delayed_work_cancel(&tx->retransmit); - while ((bit = find_lsb_set(ack))) { if (tx->seg[bit - 1]) { BT_DBG("seg %u/%u acked", bit - 1, tx->seg_n); @@ -856,7 +874,11 @@ static int trans_ack(struct bt_mesh_net_rx *rx, uint8_t hdr, } if (tx->nack_count) { - seg_tx_send_unacked(tx); + /* According to the Bluetooth Mesh Profile specification, + * section 3.5.3.3, we should reset the retransmit timer and + * retransmit immediately when receiving a valid ack message: + */ + k_work_reschedule(&tx->retransmit, K_NO_WAIT); } else { BT_DBG("SDU TX complete"); seg_tx_complete(tx, 0); @@ -988,7 +1010,7 @@ static inline int32_t ack_timeout(struct seg_rx *rx) /* Make sure we don't send more frequently than the duration for * each packet (default is 300ms). */ - return max(to, K_MSEC(400)); + return MAX(to, K_MSEC(400)); } int bt_mesh_ctl_send(struct bt_mesh_net_tx *tx, uint8_t ctl_op, void *data, @@ -1078,7 +1100,10 @@ static void seg_rx_reset(struct seg_rx *rx, bool full_reset) BT_DBG("rx %p", rx); - k_delayed_work_cancel(&rx->ack); + /* If this fails, the handler will exit early on the next execution, as + * it checks rx->in_use. + */ + (void)k_work_cancel_delayable(&rx->ack); if (IS_ENABLED(CONFIG_BT_MESH_FRIEND) && rx->obo && rx->block != BLOCK_COMPLETE(rx->seg_n)) { @@ -1115,6 +1140,16 @@ static void seg_ack(struct ble_npl_event *work) struct seg_rx *rx = ble_npl_event_get_arg(work); int32_t timeout; + if (!rx->in_use || rx->block == BLOCK_COMPLETE(rx->seg_n)) { + /* Cancellation of this timer may have failed. If it fails as + * part of seg_reset, in_use will be false. + * If it fails as part of the processing of a fully received + * SDU, the ack is already being sent from the receive handler, + * and the timer based ack sending can be ignored. + */ + return; + } + BT_DBG("rx %p", rx); if (k_uptime_get_32() - rx->last > K_SECONDS(60)) { @@ -1132,7 +1167,7 @@ static void seg_ack(struct ble_npl_event *work) rx->block, rx->obo); timeout = ack_timeout(rx); - k_delayed_work_submit(&rx->ack, K_MSEC(timeout)); + k_work_schedule(&rx->ack, K_MSEC(timeout)); } static inline bool sdu_len_is_ok(bool ctl, uint8_t seg_n) @@ -1247,6 +1282,7 @@ static int trans_seg(struct os_mbuf *buf, struct bt_mesh_net_rx *net_rx, struct seg_rx *rx; uint8_t *hdr = buf->om_data; uint16_t seq_zero; + uint32_t auth_seqnum; uint8_t seg_n; uint8_t seg_o; int err; @@ -1298,6 +1334,7 @@ static int trans_seg(struct os_mbuf *buf, struct bt_mesh_net_rx *net_rx, ((((net_rx->seq & BIT_MASK(14)) - seq_zero)) & BIT_MASK(13)))); + auth_seqnum = *seq_auth & BIT_MASK(24); *seg_count = seg_n + 1; /* Look for old RX sessions */ @@ -1366,6 +1403,28 @@ static int trans_seg(struct os_mbuf *buf, struct bt_mesh_net_rx *net_rx, return -ENOBUFS; } + /* Keep track of the received SeqAuth values received from this address + * and discard segmented messages that are not newer, as described in + * the Bluetooth Mesh specification section 3.5.3.4. + * + * The logic on the first segmented receive is a bit special, since the + * initial value of rpl->seg is 0, which would normally fail the + * comparison check with auth_seqnum: + * - If this is the first time we receive from this source, rpl->src + * will be 0, and we can skip this check. + * - If this is the first time we receive from this source on the new IV + * index, rpl->old_iv will be set, and the check is also skipped. + * - If this is the first segmented message on the new IV index, but we + * have received an unsegmented message already, the unsegmented + * message will have reset rpl->seg to 0, and this message's SeqAuth + * cannot be zero. + */ + if (rpl && rpl->src && auth_seqnum <= rpl->seg && + (!rpl->old_iv || net_rx->old_iv)) { + BT_WARN("Ignoring old SeqAuth 0x%06x", auth_seqnum); + return -EALREADY; + } + /* Look for free slot for a new RX session */ rx = seg_rx_alloc(net_rx, hdr, seq_auth, seg_n); if (!rx) { @@ -1413,11 +1472,10 @@ static int trans_seg(struct os_mbuf *buf, struct bt_mesh_net_rx *net_rx, /* Reset the Incomplete Timer */ rx->last = k_uptime_get_32(); - if (!k_delayed_work_remaining_get(&rx->ack) && - !bt_mesh_lpn_established()) { + if (!bt_mesh_lpn_established()) { int32_t timeout = ack_timeout(rx); - - k_delayed_work_submit(&rx->ack, K_MSEC(timeout)); + /* Should only start ack timer if it isn't running already: */ + k_work_schedule(&rx->ack, K_MSEC(timeout)); } /* Allocated segment here */ @@ -1444,11 +1502,20 @@ static int trans_seg(struct os_mbuf *buf, struct bt_mesh_net_rx *net_rx, if (rpl) { bt_mesh_rpl_update(rpl, net_rx); + /* Update the seg, unless it has already been surpassed: + * This needs to happen after rpl_update to ensure that the IV + * update reset logic inside rpl_update doesn't overwrite the + * change. + */ + rpl->seg = MAX(rpl->seg, auth_seqnum); } *pdu_type = BT_MESH_FRIEND_PDU_COMPLETE; - k_delayed_work_cancel(&rx->ack); + /* If this fails, the work handler will either exit early because the + * block is fully received, or rx->in_use is false. + */ + (void)k_work_cancel_delayable(&rx->ack); send_ack(net_rx->sub, net_rx->ctx.recv_dst, net_rx->ctx.addr, net_rx->ctx.send_ttl, seq_auth, rx->block, rx->obo); @@ -1540,20 +1607,8 @@ int bt_mesh_trans_recv(struct os_mbuf *buf, struct bt_mesh_net_rx *rx) err = trans_unseg(buf, rx, &seq_auth); } - /* Notify LPN state machine so a Friend Poll will be sent. If the - * message was a Friend Update it's possible that a Poll was already - * queued for sending, however that's fine since then the - * bt_mesh_lpn_waiting_update() function will return false: - * we still need to go through the actual sending to the bearer and - * wait for ReceiveDelay before transitioning to WAIT_UPDATE state. - * Another situation where we want to notify the LPN state machine - * is if it's configured to use an automatic Friendship establishment - * timer, in which case we want to reset the timer at this point. - * - */ - if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER) && - (bt_mesh_lpn_timer() || - (bt_mesh_lpn_established() && bt_mesh_lpn_waiting_update()))) { + /* Notify LPN state machine so a Friend Poll will be sent. */ + if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER)) { bt_mesh_lpn_msg_received(rx); } @@ -1583,6 +1638,13 @@ void bt_mesh_rx_reset(void) } } +static void store_va_label(void) +{ +#if MYNEWT_VAL(BLE_MESH_SETTINGS) + bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_VA_PENDING); +#endif +} + void bt_mesh_trans_reset(void) { int i; @@ -1605,7 +1667,7 @@ void bt_mesh_trans_reset(void) bt_mesh_rpl_clear(); if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_label(); + store_va_label(); } } @@ -1616,43 +1678,34 @@ void bt_mesh_trans_init(void) /* We need to initialize memslab free list here */ rc = create_free_list(&segs); if (rc) { - BT_ERR("Failed to create free memslab list") + BT_ERR("Failed to create free memslab list (error: %d)", rc); } for (i = 0; i < ARRAY_SIZE(seg_tx); i++) { - k_delayed_work_init(&seg_tx[i].retransmit, seg_retransmit); - k_delayed_work_add_arg(&seg_tx[i].retransmit, &seg_tx[i]); + k_work_init_delayable(&seg_tx[i].retransmit, seg_retransmit); + k_work_add_arg_delayable(&seg_tx[i].retransmit, &seg_tx[i]); } /* XXX Probably we need mempool for that. * For now we increase MSYS_1_BLOCK_COUNT */ for (i = 0; i < ARRAY_SIZE(seg_rx); i++) { - k_delayed_work_init(&seg_rx[i].ack, seg_ack); - k_delayed_work_add_arg(&seg_rx[i].ack, &seg_rx[i]); + k_work_init_delayable(&seg_rx[i].ack, seg_ack); + k_work_add_arg_delayable(&seg_rx[i].ack, &seg_rx[i]); } } -struct bt_mesh_va *bt_mesh_va_get(uint16_t index) -{ - if (index >= ARRAY_SIZE(virtual_addrs)) { - return NULL; - } - - return &virtual_addrs[index]; -} - -static inline void va_store(struct bt_mesh_va *store) +static inline void va_store(struct virtual_addr *store) { store->changed = 1U; if (IS_ENABLED(CONFIG_BT_SETTINGS)) { - bt_mesh_store_label(); + store_va_label(); } } uint8_t bt_mesh_va_add(const uint8_t uuid[16], uint16_t *addr) { - struct bt_mesh_va *va = NULL; + struct virtual_addr *va = NULL; int err; for (int i = 0; i < ARRAY_SIZE(virtual_addrs); i++) { @@ -1694,7 +1747,7 @@ uint8_t bt_mesh_va_add(const uint8_t uuid[16], uint16_t *addr) uint8_t bt_mesh_va_del(const uint8_t uuid[16], uint16_t *addr) { - struct bt_mesh_va *va = NULL; + struct virtual_addr *va = NULL; for (int i = 0; i < ARRAY_SIZE(virtual_addrs); i++) { if (virtual_addrs[i].ref && @@ -1718,19 +1771,6 @@ uint8_t bt_mesh_va_del(const uint8_t uuid[16], uint16_t *addr) return STATUS_SUCCESS; } -struct bt_mesh_va *bt_mesh_va_find(uint8_t uuid[16]) -{ - for (int i = 0; i < ARRAY_SIZE(virtual_addrs); i++) { - if (virtual_addrs[i].ref && - !memcmp(uuid, virtual_addrs[i].uuid, - ARRAY_SIZE(virtual_addrs[i].uuid))) { - return &virtual_addrs[i]; - } - } - - return NULL; -} - uint8_t *bt_mesh_va_label_get(uint16_t addr) { int i; @@ -1749,3 +1789,140 @@ uint8_t *bt_mesh_va_label_get(uint16_t addr) return NULL; } + +#if CONFIG_BT_MESH_LABEL_COUNT > 0 +#if MYNEWT_VAL(BLE_MESH_SETTINGS) +static struct virtual_addr *bt_mesh_va_get(uint16_t index) +{ + if (index >= ARRAY_SIZE(virtual_addrs)) { + return NULL; + } + + return &virtual_addrs[index]; +} + +static int va_set(int argc, char **argv, char *val) +{ + struct va_val va; + struct virtual_addr *lab; + uint16_t index; + int len, err; + + if (argc < 1) { + BT_ERR("Insufficient number of arguments"); + return -ENOENT; + } + + index = strtol(argv[0], NULL, 16); + + if (val == NULL) { + BT_WARN("Mesh Virtual Address length = 0"); + return 0; + } + + err = settings_bytes_from_str(val, &va, &len); + if (err) { + BT_ERR("Failed to decode value %s (err %d)", val, err); + return -EINVAL; + } + + if (len != sizeof(struct va_val)) { + BT_ERR("Invalid length for virtual address"); + return -EINVAL; + } + + if (va.ref == 0) { + BT_WARN("Ignore Mesh Virtual Address ref = 0"); + return 0; + } + + lab = bt_mesh_va_get(index); + if (lab == NULL) { + BT_WARN("Out of labels buffers"); + return -ENOBUFS; + } + + memcpy(lab->uuid, va.uuid, 16); + lab->addr = va.addr; + lab->ref = va.ref; + + BT_DBG("Restored Virtual Address, addr 0x%04x ref 0x%04x", + lab->addr, lab->ref); + + return 0; +} + +#define IS_VA_DEL(_label) ((_label)->ref == 0) +void bt_mesh_va_pending_store(void) +{ + char buf[BT_SETTINGS_SIZE(sizeof(struct va_val))]; + struct virtual_addr *lab; + struct va_val va; + char path[18]; + char *val; + uint16_t i; + int err = 0; + + for (i = 0; (lab = bt_mesh_va_get(i)) != NULL; i++) { + if (!lab->changed) { + continue; + } + + lab->changed = 0U; + + snprintk(path, sizeof(path), "bt_mesh/Va/%x", i); + + if (IS_VA_DEL(lab)) { + val = NULL; + } else { + va.ref = lab->ref; + va.addr = lab->addr; + memcpy(va.uuid, lab->uuid, 16); + + val = settings_str_from_bytes(&va, sizeof(va), + buf, sizeof(buf)); + if (!val) { + BT_ERR("Unable to encode model publication as value"); + return; + } + + err = settings_save_one(path, val); + } + + if (err) { + BT_ERR("Failed to %s %s value (err %d)", + IS_VA_DEL(lab) ? "delete" : "store", path, err); + } else { + BT_DBG("%s %s value", + IS_VA_DEL(lab) ? "Deleted" : "Stored", path); + } + } +} + +static struct conf_handler bt_mesh_va_conf_handler = { + .ch_name = "bt_mesh", + .ch_get = NULL, + .ch_set = va_set, + .ch_commit = NULL, + .ch_export = NULL, + }; +#endif + +void bt_mesh_va_init(void) +{ +#if MYNEWT_VAL(BLE_MESH_SETTINGS) + int rc; + + rc = conf_register(&bt_mesh_va_conf_handler); + + SYSINIT_PANIC_ASSERT_MSG(rc == 0, + "Failed to register bt_mesh_hb_pub conf"); +#endif +} + +#else +void bt_mesh_va_pending_store(void) +{ + /* Do nothing. */ +} +#endif /* CONFIG_BT_MESH_LABEL_COUNT > 0 */ diff --git a/nimble/host/mesh/src/transport.h b/nimble/host/mesh/src/transport.h index bf458e83c8..ad7a59f236 100644 --- a/nimble/host/mesh/src/transport.h +++ b/nimble/host/mesh/src/transport.h @@ -79,13 +79,6 @@ struct bt_mesh_ctl_friend_sub_confirm { uint8_t xact; }__attribute__((__packed__)); -struct bt_mesh_va { - uint16_t ref:15, - changed:1; - uint16_t addr; - uint8_t uuid[16]; -}; - bool bt_mesh_tx_in_progress(void); void bt_mesh_rx_reset(void); @@ -102,12 +95,12 @@ void bt_mesh_trans_init(void); void bt_mesh_trans_reset(void); -struct bt_mesh_va *bt_mesh_va_get(uint16_t index); - -struct bt_mesh_va *bt_mesh_va_find(uint8_t uuid[16]); - uint8_t bt_mesh_va_add(const uint8_t uuid[16], uint16_t *addr); uint8_t bt_mesh_va_del(const uint8_t uuid[16], uint16_t *addr); -uint8_t *bt_mesh_va_label_get(uint16_t addr); \ No newline at end of file +uint8_t *bt_mesh_va_label_get(uint16_t addr); + +void bt_mesh_va_pending_store(void); + +void bt_mesh_va_init(void); diff --git a/nimble/host/mesh/syscfg.yml b/nimble/host/mesh/syscfg.yml index d110a3888a..73bef03aac 100644 --- a/nimble/host/mesh/syscfg.yml +++ b/nimble/host/mesh/syscfg.yml @@ -23,6 +23,11 @@ syscfg.defs: BLE_MESH_PB_ADV or BLE_MESH_PB_GATT is set. value: 1 + BLE_MESH_PROV_OOB_PUBLIC_KEY: + description: > + Enable this option if public key is to be exchanged via Out of Band (OOB) technology. + value: 0 + BLE_MESH_PB_ADV: description: > Enable this option to allow the device to be provisioned over @@ -63,7 +68,7 @@ syscfg.defs: description: > This option specifies how many nodes each network can at most save in the configuration database. - value: 1 + value: 8 BLE_MESH_CDB_SUBNET_COUNT: description: > @@ -82,17 +87,44 @@ syscfg.defs: Use this option to enable configuration database debug logs. value: 1 + BLE_MESH_DEBUG_CFG: + description: + Use this option to enable node configuration debug logs for the + Bluetooth Mesh functionality. + value: 1 + BLE_MESH_PROXY: description: > Enable proxy. This is automatically set whenever BLE_MESH_PB_GATT or BLE_MESH_GATT_PROXY is set. value: 0 + BLE_MESH_GATT: + value: 1 + + BLE_MESH_PROXY_MSG_LEN: + description: > + Integer value + value: + restrictions: BLE_MESH_GATT + + BLE_MESH_GATT_SERVER: + value: 1 + restrictions: BLE_MESH_GATT + BLE_MESH_PB_GATT: description: > Enable this option to allow the device to be provisioned over the GATT bearer. value: 1 + restrictions: + - '(BLE_MESH_GATT_SERVER && BLE_MESH_PROV)' + + BLE_MESH_PB_GATT_USE_DEVICE_NAME: + description: > + This option includes GAP device name in scan response when + the PB-GATT is enabled. + value: 1 BLE_MESH_GATT_PROXY: description: > @@ -100,6 +132,8 @@ syscfg.defs: i.e. the ability to act as a proxy between a Mesh GATT Client and a Mesh network. value: 1 + restrictions: + - '(BLE_MESH_GATT_SERVER && BLE_MESH_PROXY)' BLE_MESH_GATT_PROXY_ENABLED: description: > @@ -127,8 +161,22 @@ syscfg.defs: descryption: > This option specifies how many Proxy Filter entries the local node supports. + value: 3 + restrictions: BLE_MESH_GATT_PROXY + + BLE_MESH_ACCESS_LAYER_MSG: + descryption: > + This option allows the applicaiton to directly access + Bluetooth access layer messages without the need to + instantiate Bluetooth mesh models. value: 1 + BLE_MESH_PROXY_USE_DEVICE_NAME: + description: > + Include Bluetooth device name in scan response + value: 0 + restrictions: BLE_MESH_GATT_PROXY + BLE_MESH_SUBNET_COUNT: description: > This option specifies how many subnets a Mesh network can @@ -153,6 +201,12 @@ syscfg.defs: at most be subscribed to. value: 1 + BLE_MESH_MODEL_VND_MSG_CID_FORCE: + description: > + This option forces vendor model to use messages for the + corresponding CID field. + value: 1 + BLE_MESH_LABEL_COUNT: description: > This option specifies how many Label UUIDs can be stored. @@ -179,6 +233,11 @@ syscfg.defs: but has a different purpose. value: 10 + BLE_MESH_NET_BUF_USER_DATA_SIZE: + description: > + Number of octets that are used as user_data at the end of os_mbufs + value: 4 + BLE_MESH_ADV_BUF_COUNT: description: > Number of advertising buffers available. This should be chosen @@ -189,6 +248,37 @@ syscfg.defs: supported outgoing segment count (BT_MESH_TX_SEG_MAX). value: 6 + BLE_MESH_ADV: + description: > + Advertiser mode + value: 1 + + BLE_MESH_ADV_LEGACY: + description: > + Use legacy advertising commands for mesh sending. Legacy + advertising is significantly slower than the extended advertising, but + is supported by all controllers. + value: 1 + restrictions: + - "BLE_MESH_ADV if 0" + - "!BLE_MESH_ADV_EXT" + + BLE_MESH_ADV_EXT: + description: > + Use extended advertising commands for operating the advertiser. + Extended advertising is faster and uses less memory than legacy + advertising, but isn't supported by all controllers. + value: 0 + restrictions: + - "BLE_MESH_ADV if 0" + - "!BLE_MESH_ADV_LEGACY" + - "BLE_EXT_ADV" + + BLE_MESH_DEBUG_USE_ID_ADDR: + description: > + Use ID address for mesh advertisements, use random address otherwise. + value: 0 + BLE_MESH_ADV_STACK_SIZE: description: > Mesh advertiser thread stack size. @@ -196,6 +286,11 @@ syscfg.defs: absolutely necessary value: 768 + BLE_MESH_IV_UPDATE_SEQ_LIMIT: + description: > + This option specifies the sequence number value to start iv update. + value: 0x800000 + BLE_MESH_IVU_DIVIDER: description: > When the IV Update state enters Normal operation or IV Update @@ -601,16 +696,22 @@ syscfg.defs: BLE_MESH_RPL_STORE_TIMEOUT: description: > - This value defines in seconds how soon the RPL gets written to - persistent storage after a change occurs. If the node receives - messages frequently it may make sense to have this set to a - large value, whereas if the RPL gets updated infrequently a - value as low as 0 (write immediately) may make sense. Note that - if the node operates a security sensitive use case, and there's - a risk of sudden power loss, it may be a security vulnerability - to set this value to anything else than 0 (a power loss before - writing to storage exposes the node to potential message - replay attacks). + Minimum interval after which unsaved RPL entries are updated in storage + + This value defines in seconds how soon unsaved RPL entries + gets written to the persistent storage. Setting this value + to a large number may lead to security vulnerabilities if a node + gets powered off before the timer is fired. When flash is used + as the persistent storage setting this value to a low number + may wear out flash sooner or later. However, if the RPL gets + updated infrequently a value as low as 0 (write immediately) + may make sense. Setting this value to -1 will disable this timer. + In this case, a user is responsible to store pending RPL entries + using @ref bt_mesh_rpl_pending_store. In the mean time, when + IV Index is updated, the outdated RPL entries will still be + stored by @ref BT_MESH_STORE_TIMEOUT. Finding the right balance + between this timeout and calling @ref bt_mesh_rpl_pending_store + may reduce a risk of security vulnerability and flash wear out. value: 5 BLE_MESH_DEVICE_NAME: @@ -876,6 +977,10 @@ syscfg.vals.BLE_MESH_GATT_PROXY: syscfg.vals.BLE_MESH_PB_GATT: BLE_MESH_PROXY: 1 BLE_MESH_PROV: 1 + BLE_MESH_PROXY_MSG_LEN: 66 syscfg.vals.BLE_MESH_PB_ADV: BLE_MESH_PROV: 1 + +syscfg.vals.'BLE_MESH_GATT_PROXY && !BLE_MESH_PB_GATT': + BLE_MESH_PROXY_MSG_LEN: 33 diff --git a/nimble/host/pkg.yml b/nimble/host/pkg.yml index a063a0b636..b4df8f8712 100644 --- a/nimble/host/pkg.yml +++ b/nimble/host/pkg.yml @@ -30,6 +30,10 @@ pkg.deps: - "@apache-mynewt-core/sys/log/modlog" - "@apache-mynewt-core/util/mem" - nimble + - nimble/transport + +pkg.deps.BLE_AUDIO: + - nimble/host/audio pkg.deps.BLE_SM_LEGACY: - "@apache-mynewt-core/crypto/tinycrypt" @@ -37,19 +41,16 @@ pkg.deps.BLE_SM_LEGACY: pkg.deps.BLE_SM_SC: - "@apache-mynewt-core/crypto/tinycrypt" -pkg.deps.BLE_MONITOR_RTT: - - "@apache-mynewt-core/hw/drivers/rtt" - pkg.deps.BLE_MESH: - nimble/host/mesh +pkg.deps.BLE_EATT_CHAN_NUM: + - nimble/host/services/gatt + pkg.req_apis: - ble_transport - console - stats -pkg.init: - ble_hs_init: 'MYNEWT_VAL(BLE_HS_SYSINIT_STAGE)' - pkg.down.BLE_HS_STOP_ON_SHUTDOWN: ble_hs_shutdown: 200 diff --git a/nimble/host/pts/README.txt b/nimble/host/pts/README.txt deleted file mode 100644 index bb03b18caf..0000000000 --- a/nimble/host/pts/README.txt +++ /dev/null @@ -1,8 +0,0 @@ -This folder contains qualification tests results against BT SIG Profile Test -Suite. - -pts-FOO.txt files contain result for specific profiles or protocols. This -includes PTS version, test date, enabled tests, results etc. - -In addition to tests results 'tpg' folder constains Test Plang Generator -configuration files that can be imported by PTS for tests configuration. diff --git a/nimble/host/pts/pts-gap.txt b/nimble/host/pts/pts-gap.txt deleted file mode 100644 index 29ed2446ea..0000000000 --- a/nimble/host/pts/pts-gap.txt +++ /dev/null @@ -1,367 +0,0 @@ -PTS test results for GAP - -PTS version: 7.5.0 -Tested: 27-Sept-2019 - -Results: -PASS test passed -FAIL test failed -INC test is inconclusive -N/A test is disabled due to PICS setup - -------------------------------------------------------------------------------- -Test Name Result Notes -------------------------------------------------------------------------------- - -GAP/BROB/BCST/BV-01-C PASS advertise-configure legacy=1 connectable=0 scannable=0 -GAP/BROB/BCST/BV-02-C PASS advertise-configure legacy=1 connectable=0 scannable=0 - -GAP/BROB/BCST/BV-03-C PASS set irk= e.g: 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:11 - Note: in PTS IXIT please set: - TSPX_iut_device_IRK_for_resolvable_privacy_address_generation_procedure=11000000000000000000000000000000 - set advertise-set-adv-data name= flags=4 - advertise-configure connectable=0 scannable=0 own_addr_type=rpa_pub -GAP/BROB/BCST/BV-04-C PASS TSPX_advertising_data=07086E696D626C65 - advertise-set-adv-data name=nimble - set addr_type=random addr=01:3e:56:f7:46:21 - advertise-configure connectable=0 scannable=0 own_addr_type=random -GAP/BROB/BCST/BV-05-C N/A -GAP/BROB/OBSV/BV-01-C PASS scan passive -GAP/BROB/OBSV/BV-02-C PASS scan -GAP/BROB/OBSV/BV-03-C PASS scan -GAP/BROB/OBSV/BV-04-C PASS connect peer_addr= - security-set-data bonding=1 - security-pair conn= - - -GAP/BROB/OBSV/BV-05-C PASS scan own_addr_type=rpa_pub -GAP/BROB/OBSV/BV-06-C PASS scan own_addr_type=rpa_pub -------------------------------------------------------------------------------- - -GAP/DISC/NONM/BV-01-C PASS advertise-configure connectable=0 legacy=1 adverdise=non -GAP/DISC/NONM/BV-02-C PASS advertise-configure connectable=0 - -GAP/DISC/LIMM/BV-01-C N/A -GAP/DISC/LIMM/BV-02-C N/A -GAP/DISC/LIMM/BV-03-C PASS advertise-configure legacy=1 connectable=0 - advertise-set-adv-data flags=5 - advertise-start duration= e.g.3000 -GAP/DISC/LIMM/BV-04-C PASS advertise-configure legacy=1 connectable=0 - advertise-set-adv-data flags=5 - advertising-start duration= -GAP/DISC/GENM/BV-01-C N/A -GAP/DISC/GENM/BV-02-C N/A -GAP/DISC/GENM/BV-03-C PASS advertise-configure legacy=1 connectable=0 - advertise-set-adv-data flags=6 - advertise-start -GAP/DISC/GENM/BV-04-C PASS advertise-configure legacy=1 connectable=0 - advertise-set-adv-data flags=6 - advertising-start - -GAP/DISC/LIMP/BV-01-C PASS scan limited=1 nodups=1 -GAP/DISC/LIMP/BV-02-C PASS scan limited=1 nodups=1 -GAP/DISC/LIMP/BV-03-C PASS scan limited=1 nodups=1 -GAP/DISC/LIMP/BV-04-C PASS scan limited=1 nodups=1 -GAP/DISC/LIMP/BV-05-C PASS scan limited=1 nodups=1 - -GAP/DISC/GENP/BV-01-C PASS scan nodups=1 -GAP/DISC/GENP/BV-02-C PASS scan nodups=1 -GAP/DISC/GENP/BV-03-C PASS scan nodups=1 - -GAP/DISC/GENP/BV-04-C PASS scan nodups=1 - -GAP/DISC/GENP/BV-05-C PASS scan nodups=1 - -GAP/DISC/RPA/BV-01-C N/A scan nodups=1 -------------------------------------------------------------------------------- - -GAP/IDLE/GIN/BV-01-C N/A -GAP/IDLE/GIN/BV-02-C N/A -GAP/IDLE/NAMP/BV-01-C PASS advertise-configure connectable=1 legacy=1 - advertising-start - gatt-discover-full conn= - gatt-show - - gatt-read conn= uuid=0x2a00 start= end= - disconnect conn= -GAP/IDLE/NAMP/BV-02-C PASS - advertise-configure connectable=1 legacy=1 - advertising-start -GAP/IDLE/DED/BV-01-C N/A -GAP/IDLE/DED/BV-02-C N/A -------------------------------------------------------------------------------- - -GAP/CONN/NCON/BV-01-C PASS advertise-configure connectable=0 legacy=1 - advertising-start -GAP/CONN/NCON/BV-02-C PASS advertise-configure connectable=0 legacy=1 - advertise-set-adv-data flags=6 - advertise-start -GAP/CONN/NCON/BV-03-C PASS advertise-configure connectable=0 legacy=1 - advertise-set-adv-data flags=5 - advertise-start - -GAP/CONN/DCON/BV-01-C PASS advertise-configure connectable=0 directed=1 peer_addr= - advertise-start -GAP/CONN/DCON/BV-02-C N/A -GAP/CONN/DCON/BV-03-C N/A - -GAP/CONN/UCON/BV-01-C PASS advertise-configure connectable=1 legacy=1 - advertise-set-adv-data flags=4 - advertise-start -GAP/CONN/UCON/BV-02_C PASS advertise-configure connectable=1 legacy=1 - advertise-set-adv-data flags=5 - advertise-start -GAP/CONN/UCON/BV-03_C PASS adbertise-configure connectable=1 legacy=1 - advertise-set-adv-data flags=6 -GAP/CONN/UCON/BV-04_C N/A -GAP/CONN/UCON/BV-05_C N/A -GAP/CONN/UCON/BV-06_C N/A - -GAP/CONN/ACEP/BV-01-C PASS white-list addr_type=public addr= - connect - disconnect conn= -GAP/CONN/ACEP/BV-02-C N/A - -GAP/CONN/GCEP/BV-01-C PASS connect peer_addr= - disconnect conn= -GAP/CONN/GCEP/BV-02-C PASS connect peer_addr= -GAP/CONN/GCEP/BV-03-C PASS set irk= - connect peer_addr= own_addr_type=rpa_pub - security-set-data bonding=1 our_key_dist=7 their_key_dist=7 - security-pair conn= - connect peer_addr= - disconnect conn=1 -GAP/CONN/GCEP/BV-04-C N/A -GAP/CONN/SCEP/BV-01-C PASS white-list addr_type=public addr= - connect - disconnect conn= -GAP/CONN/SCEP/BV-02-C INC -GAP/CONN/DCEP/BV-01-C PASS connect peer_addr= - disconnect conn= -GAP/CONN/DCEP/BV-02-C INC -GAP/CONN/DCEP/BV-03-C PASS connect peer_addr= - disconnect conn= -GAP/CONN/DCEP/BV-04-C PASS connect peer_addr= - disconnect conn= - -GAP/CONN/CPUP/BV-01-C PASS advertise-start - conn-update-params conn= -GAP/CONN/CPUP/BV-02-C PASS advertise-start - conn-update-params conn= -GAP/CONN/CPUP/BV-03-C PASS advertise-start - conn-update-params conn= -GAP/CONN/CPUP/BV-04-C PASS connect peer_addr= - disconnect conn= -GAP/CONN/CPUP/BV-05-C PASS connect peer_addr= - disconnect conn= -GAP/CONN/CPUP/BV-06-C PASS conect peer_addr= - conn-update-params conn= eg.latency=20 - disconnect conn= -GAP/CONN/CPUP/BV-08-C PASS advertise-configure legacy=1 connectable=1 - advertise-set-data name= - advertise-start - -GAP/CONN/TERM/BV-01-C PASS connect peer_addr= - disconnect conn= -GAP/CONN/PRDA/BV-01-C N/A -GAP/CONN/PRDA/BV-02-C N/A -------------------------------------------------------------------------------- -GAP/BOND/NBON/BV-01-C PASS security-set-data bonding=0 - connect peer_addr= - - connect peer_addr= - -GAP/BOND/NBON/BV-02-C PASS security-set-data bonding=0 - connect peer_addr= - security-pair conn= - - connect peer_addr= - security-pair conn= - -GAP/BOND/NBON/BV-03-C PASS security-set-data bonding=0 - advertise-configure legacy=1 connectable=1 - advertise-set-data name= - advertise-start - - -GAP/BOND/BON/BV-01-C PASS security-set-data bonding=1 sc=1 our_key_dist=7 their_key_dist=7 - advertise-configure legacy=1 connectable=1 - advertise-start - security-start conn= - - advertise-start - -GAP/BOND/BON/BV-02-C PASS security-set-data bonding=1 - connect peer_addr= - security-pair conn= - - connect peer_addr= - seccurity-pair conn= - -GAP/BOND/BON/BV-03-C PASS security-set-sm-data bonding=1 our_key_dist=7 their_key_dist=7 - advertise-configure legacy=1 connectable=1 - advertise-start - - advertise-start - -GAP/BOND/BON/BV-04-C PASS security-set-data bonding=1 - connect-peer_addr= - disconnect conn= - connect peer_addr= - security-pair conn= - disconnect conn= -------------------------------------------------------------------------------- - -GAP/SEC/AUT/BV-11-C PASS security-set-data io_capabilities=1 sc=1 - advertise-configure legacy=1 connectable=1 - advertising-start - Note: in PTS enter handle for characteristics - value which requires encryption for read (gatt-show-local) - auth-passkey conn= action=3 key=123456 - Note: enter '123456' passkey in PTS -GAP/SEC/AUT/BV-12-C PASS security-set-data io_capabilities=1 bonding=1 mitm_flag=1 sc=1 our_key_dist=7 their_key_dist=7 - connect peer_addr= - gatt-show-local - Note: in PTS enter handle for characteristics - value which requires encryption for read - auth-passkey conn= action=3 key=123456 - Note: enter '123456' passkey in PTS -GAP/SEC/AUT/BV-13-C PASS Note: in PTS confirm that IUT supports GATT Server - security-set-data io_capabilities=1 bonding=1 mitm_flag=1 sc=1 our_key_dist=7 their_key_dist=7 - connect peer_addr= - gatt-show-local - Note: in PTS enter handle for characteristics - value which requires authenticated pairing for read - auth-passkey conn= action=3 key=123456 - Note: enter '123456' passkey in PTS -GAP/SEC/AUT/BV-14-C PASS security-set-data io_capabilities=1 - advertise-configure legacy=1 connectable=1 - advertise-start - gatt-show-local - Note: in PTS enter handle for characteristics - value which requires authenticated pairing for read - auth-passkey conn= action=3 key=123456 - Note: enter '123456' passkey in PTS -GAP/SEC/AUT/BV-15-C N/A security-set-data bonding=1 io_capabilities=4 mitm_flag=1 sc=1 our_key_dist=7 their_key_dist=7 - advertise-configure legacy=1 connectable=1 - advertise-start - auth-passkey conn= action=2 key= - advertise-start - gatt-show-local - Note: in PTS enter handle for characteristics - value which requires authenticated pairing for read -GAP/SEC/AUT/BV-16-C N/A security-set-data io_capabilities=1 bonding=1 mitm_flag=1 sc=1 our_key_dist=7 their_key_dist=7 - connect peer_addr= - auth-passkey conn= action=3 key=123456 - Note: enter '123456' passkey in PTS - connect peer_addr= - gatt-show-local - Note: in PTS enter handle for characteristics - value which requires authenticated pairing for read -GAP/SEC/AUT/BV-17-C N/A -GAP/SEC/AUT/BV-18-C N/A -GAP/SEC/AUT/BV-19-C N/A -GAP/SEC/AUT/BV-20-C N/A -GAP/SEC/AUT/BV-21-C N/A -GAP/SEC/AUT/BV-22-C N/A -GAP/SEC/AUT/BV-23-C N/A -GAP/SEC/AUT/BV-24-C N/A - -GAP/SEC/CSIGN/BV-01-C N/A -GAP/SEC/CSIGN/BV-02-C N/A - -GAP/SEC/CSIGN/BI-01-C N/A -GAP/SEC/CSIGN/BI-02-C N/A -GAP/SEC/CSIGN/BI-03-C N/A -GAP/SEC/CSIGN/BI-04-C N/A -------------------------------------------------------------------------------- - -GAP/PRIV/CONN/BV-01-C N/A -GAP/PRIV/CONN/BV-02-C N/A -GAP/PRIV/CONN/BV-03-C N/A -GAP/PRIV/CONN/BV-04-C INC -GAP/PRIV/CONN/BV-05-C N/A -GAP/PRIV/CONN/BV-06-C N/A -GAP/PRIV/CONN/BV-07-C N/A -GAP/PRIV/CONN/BV-08-C N/A -GAP/PRIV/CONN/BV-09-C N/A -GAP/PRIV/CONN/BV-10-C N/A -GAP/PRIV/CONN/BV-11-C N/A -------------------------------------------------------------------------------- - -GAP/ADV/BV-01-C PASS advertise-set-adv_data uuid16=0x1802 - advertise-start - advertise-stop -GAP/ADV/BV-02-C PASS advertise-set-adv_data name= - advertise-start - advertise-stop -GAP/ADV/BV-03-C PASS advertise-set-adv_data flags=6 - advertise-start - advertise-stop -GAP/ADV/BV-04-C PASS advertise-set-adv_data mfg_data=ff:ff - advertise-start - advertise-stop -GAP/ADV/BV-05-C PASS advertise-set-adv_data tx_pwr_lvl=10 - advertise-start - advertise-stop -GAP/ADV/BV-08-C N/A -GAP/ADV/BV-09-C N/A -GAP/ADV/BV-10-C PASS advetrise-set-adv_data service_data_uuid16=18:02:ff:ff - advertise-start - advertise-stop -GAP/ADV/BV-11-C PASS advertise-set -dv_data appearance=12 - advertise-start - advertise-stop -GAP/ADV/BV-12-C N/A -GAP/ADV/BV-13-C N/A -GAP/ADV/BV-14-C N/A -GAP/ADV/BV-15-C N/A -GAP/ADV/BV-16-C N/A -GAP/ADV/BV-17-C PASS In PTS: TSPX_URI= - set-adv-data uri= - advertise-start - advertise-stop -------------------------------------------------------------------------------- - -GAP/GAT/BV-01-C PASS - advertising-start - - connect peer_addr= -GAP/GAT/BV-02-C N/A -GAP/GAT/BV-03-C N/A -GAP/GAT/BV-04-C PASS advertise-configure connectable=1 legacy=1 - advertise-start -GAP/GAT/BV-05-C N/A -GAP/GAT/BV-06-C N/A -GAP/GAT/BV-07-C N/A -GAP/GAT/BV-08-C N/A ----------------------------------------------------------------------------- - -GAP/DM/NCON/BV-01-C N/A -GAP/DM/CON/BV-01-C N/A -GAP/DM/NBON/BV-01-C N/A -GAP/DM/BON/BV-01-C N/A -GAP/DM/GIN/BV-01-C N/A -GAP/DM/LIN/BV-01-C N/A -GAP/DM/NAD/BV-01-C N/A -GAP/DM/NAD/BV-02-C N/A -GAP/DM/LEP/BV-01-C N/A -GAP/DM/LEP/BV-02-C N/A -GAP/DM/LEP/BV-04-C N/A -GAP/DM/LEP/BV-05-C N/A -GAP/DM/LEP/BV-06-C N/A -GAP/DM/LEP/BV-07-C N/A -GAP/DM/LEP/BV-08-C N/A -GAP/DM/LEP/BV-09-C N/A -GAP/DM/LEP/BV-10-C N/A -GAP/DM/LEP/BV-11-C N/A -------------------------------------------------------------------------------- - -GAP/MOD/NDIS/BV-01-C N/A -GAP/MOD/LDIS/BV-01-C N/A -GAP/MOD/LDIS/BV-02-C N/A -GAP/MOD/LDIS/BV-03-C N/A -GAP/MOD/GDIS/BV-01-C N/A -GAP/MOD/GDIS/BV-02-C N/A -GAP/MOD/NCON/BV-01-C N/A -GAP/MOD/CON/BV-01-C N/A \ No newline at end of file diff --git a/nimble/host/pts/pts-gatt.txt b/nimble/host/pts/pts-gatt.txt deleted file mode 100644 index 74c0a2e016..0000000000 --- a/nimble/host/pts/pts-gatt.txt +++ /dev/null @@ -1,508 +0,0 @@ -PTS test results for GATT - -PTS version: 7.5.0 -Tested: 27-Sept-2019 - -Results: -PASS test passed -FAIL test failed -INC test is inconclusive -N/A test is disabled due to PICS setup - -------------------------------------------------------------------------------- -Test Name Result Notes -------------------------------------------------------------------------------- -GATT/CL/GAC/BV-01-C PASS connect peer_addr= - gatt-exchanche-mtu conn= - gatt-write conn= long=1 attr= value= - disconnect conn= -------------------------------------------------------------------------------- - -GATT/CL/GAD/BV-01-C PASS connect peer_addr= - gatt-discover-service conn= - gatt-show - - disconnect conn= - -GATT/CL/GAD/BV-02-C PASS connect peer_addr= - gatt-discover-service conn= uuid= - gatt-show - - disconnect conn= - -GATT/CL/GAD/BV-03-C PASS connect peer_addr= - gatt-find-included-services conn= start=1 end=0xffff - - disconnect conn= - -GATT/CL/GAD/BV-04-C PASS connect peer_addr= - gatt-discover-service conn= uuid= - gatt-discover-characteristic conn= start= end= - gatt-show - - disconnect conn= - -GATT/CL/GAD/BV-05-C PASS connect peer_addr= - gatt-discover-service conn= - gatt-discover-characteristic conn= uuid= start= end= - gatt-show - - disconnect conn= - -GATT/CL/GAD/BV-06-C PASS connect peer_addr= - gatt-discover-service conn= - gatt-discover-characteristic conn= start= end= - gatt-discover-descriptor conn= start= end= - - disconnect conn= - -GATT/CL/GAD/BV-07-C N/A -GATT/CL/GAD/BV-08-C N/A -------------------------------------------------------------------------------- - -GATT/CL/GAR/BV-01-C PASS connect peer_addr= - gatt-read conn= attr= - - disconnect conn= -GATT/CL/GAR/BI-01-C PASS connect peer_addr= - gatt-read conn= attr= - - disconnect conn= -GATT/CL/GAR/BI-02-C PASS connect peer_addr= - gatt-read conn= attr= - - disconnect conn= -GATT/CL/GAR/BI-03-C N/A - -GATT/CL/GAR/BI-04-C PASS connect peer_addr= - gatt-read conn= attr= - disconnect conn= - -GATT/CL/GAR/BI-05-C PASS connect peer_addr= - gatt-read conn= attr= - - disconnect conn= -GATT/CL/GAR/BV-03-C PASS connect peer_addr= - gatt-read conn= uuid= start=1 end=0xffff - - - disconnect conn= -GATT/CL/GAR/BI-06-C PASS connect peer_addr= - gatt-read conn= uuid= start= end= - disconnect conn= - -GATT/CL/GAR/BI-07-C PASS connect peer_addr= - gatt-read conn= uuid= start= end= - disconnect conn= - -GATT/CL/GAR/BI-09-C N/A -GATT/CL/GAR/BI-10-C PASS connect peer_addr= - gatt-read conn= uuid= start= end= - disconnect conn= - -GATT/CL/GAR/BI-11-C PASS connect perr_addr= - gatt-read conn= start= end= - disconnect conn= - -GATT/CL/GAR/BV-04-C PASS connect peer_addr= - gatt-read conn= long=1 attr= - - - disconnect conn= -GATT/CL/GAR/BI-12-C PASS connect peer_addr= - gatt-read conn= long=1 attr= - - disconnect conn= -GATT/CL/GAR/BI-13-C PASS connect peer_addr= - gatt-read conn= long=1 attr= offset= - - disconnect conn= -GATT/CL/GAR/BI-14-C PASS connect peer_addr= - gatt-read conn= long=1 attr= - disconnect conn= - -GATT/CL/GAR/BI-15-C N/A - -GATT/CL/GAR/BI-16-C PASS connect peer_addr= - gatt-read conn= long=1 attr= - disconnect conn= - -GATT/CL/GAR/BI-17-C PASS connect peer_addr= - gatt-read conn= long=1 attr= - - disconnect conn= -GATT/CL/GAR/BV-05-C PASS connect peer_addr= - gatt-read conn= attr= attr= - disconnect conn= -GATT/CL/GAR/BI-18-C PASS connect peer_addr= - gatt-read conn= attr= attr= - - disconnect conn= -GATT/CL/GAR/BI-19-C PASS connect peer_addr= - gatt-read conn= attr= attr= - disconnect conn= - -GATT/CL/GAR/BI-20-C N/A - -GATT/CL/GAR/BI-21-C PASS connect peer_addr= - gatt-read conn= attr= attr= - disconnect conn= - -GATT/CL/GAR/BI-22-C PASS connect peer_addr= - gatt-read conn= attr= attr= - - disconnect conn= -GATT/CL/GAR/BV-06-C PASS connect peer_addr= - gatt-read conn= attr= - - disconnect conn= -GATT/CL/GAR/BV-07-C PASS connect peer_addr= - gatt-read conn= long=1 attr= - - - disconnect conn= -GATT/CL/GAR/BI-34-C N/A -GATT/CL/GAR/BI-35-C PASS connect peer_addr= - gatt-read conn= long=1 attr= - - disconnect conn= -------------------------------------------------------------------------------- - -GATT/CL/GAW/BV-01-C PASS connect peer_addr= - gatt-write no_rsp=1 conn= attr= value= - disconnect conn= -GATT/CL/GAW/BV-02-C N/A - -GATT/CL/GAW/BV-03-C PASS connect peer_addr= - gatt-write conn= attr= value= - disconnect conn= -GATT/CL/GAW/BI-02-C PASS connect peer_addr= - gatt-write conn= attr= value= - disconnect conn= -GATT/CL/GAW/BI-03-C PASS connect peer_addr= - gatt-write conn= attr= value= - disconnect conn= -GATT/CL/GAW/BI-04-C N/A - -GATT/CL/GAW/BI-05-C PASS connect peer_addr= - gatt-write conn= attr= value= - disconnect conn= -GATT/CL/GAW/BI-06-C PASS connect peer_addr= - gatt-write conn= attr= value= - disconnect conn= -GATT/CL/GAW/BV-05-C PASS connect peer_addr= - gatt-write long=1 conn= attr= value= - disconnect conn= -GATT/CL/GAW/BI-07-C PASS connect peer_addr= - gatt-write long=1 conn= attr= value= - disocnnect conn= -GATT/CL/GAW/BI-08-C PASS connect peer_addr= - gatt-write long=1 conn= attr= value= - diconnect conn= -GATT/CL/GAW/BI-09-C PASS connect peer_addr= - gatt-write long=1 conn= attr= value= offset= - diconnect conn=1 -GATT/CL/GAW/BI-11-C N/A - -GATT/CL/GAW/BI-12-C PASS connect peer_addr= - gatt-write long=1 conn= attr= value= - disconnect conn= -GATT/CL/GAW/BI-13-C PASS connect peer_addr= - gatt-write long=1 conn= attr= value= - diconnect conn= -GATT/CL/GAW/BV-06-C PASS connect peer_addr= - gatt-write long=1 conn= attr= value= - -GAAT/CL/GAW/BV-08-C PASS connect peer_addr= - gat-write conn= attr= value= - -GATT/CL/GAW/BV-09-C PASS connect peer_addr= - gatt-write long=1 conn= attr= value= - -GATT/CL/GAW/BI-32-C PASS connect peer_addr= - gatt-write conn= attr= value= attr= value= - disconnect conn= -GATT/CL/GAW/BI-33-C PASS connect peer_addr= - gatt-write conn= attr= value= - disconnect conn= -GATT/CL/GAW/BI-34-C PASS connect peer_addr= - gatt-write long=1 conn= attr= value= - disconnect conn= - -------------------------------------------------------------------------------- - -GATT/CL/GAN/BV-01-C PASS connect peer_addr= - gatt-write conn= attr= value=01:00 - Note: verify that the notification was received - disconnect conn= -------------------------------------------------------------------------------- - -GATT/CL/GAI/BV-01-C PASS connect peer_addr= - gatt-write conn= attr= value=01:00 - Note: verify that the notification was received - disconnect conn= -------------------------------------------------------------------------------- - -GATT/CL/GAS/BV-01-C PASS connect peer_addr= - disconnect conn= -------------------------------------------------------------------------------- - -GATT/CL/GAT/BV-01-C PASS connect peer_addr= - gatt-read conn= attr= -GATT/CL/GAT/BV-02-C PASS connect peer_addr= - gatt-write conn= attr= value= -------------------------------------------------------------------------------- - -GATT/CL/GPA/BV-01-C N/A -GATT/CL/GPA/BV-02-C N/A -GATT/CL/GPA/BV-03-C N/A -GATT/CL/GPA/BV-04-C N/A -GATT/CL/GPA/BV-05-C N/A -GATT/CL/GPA/BV-06-C N/A -GATT/CL/GPA/BV-07-C N/A -GATT/CL/GPA/BV-08-C N/A -GATT/CL/GPA/BV-11-C N/A -GATT/CL/GPA/BV-12-C N/A -------------------------------------------------------------------------------- - -GATT/SR/GAC/BV-01-C PASS set mtu=25 - advertise-configure connectable=1 legacy=1 - advertise-start - advertise-start -------------------------------------------------------------------------------- - -GATT/SR/GAD/BV-01-C PASS advertise-configure connectable=1 legacy=1 - advertise-start - gatt-show-local - -GATT/SR/GAD/BV-02-C PASS advertise-configure connectable=1 legacy=1 - advertise-start - gatt-show-local - -GATT/SR/GAD/BV-03-C PASS advertise-configure connectable=1 legacy=1 - advertise-start - gatt-show-local - -GATT/SR/GAD/BV-04-C PASS advertise-configure connectable=1 legacy=1 - advertise-start - -GATT/SR/GAD/BV-05-C PASS advertise-configure connectable=1 legacy=1 - advertise-start -GATT/SR/GAD/BV-06-C PASS advertise-configure connectable=1 legacy=1 - advertise-start -GATT/SR/GAD/BV-07-C N/A -GATT/SR/GAD/BV-08-C N/A -------------------------------------------------------------------------------- - -GATT/SR/GAR/BV-01-C PASS advertise-configure connectable=1 legacy=1 - advertise-start -GATT/SR/GAR/BI-01-C PASS advertise-configure connectable=1 legacy=1 - advertise-start -GATT/SR/GAR/BI-02-C PASS advertise-configure connectable=1 legacy=1 - advertise-start - -GATT/SR/GAR/BI-03-C N/A -GATT/SR/GAR/BI-04-C PASS advertise-configure connectable=1 legacy=1 - advertise-start -GATT/SR/GAR/BI-05-C PASS advertise-configure connectable=1 legacy=1 - advertise-start -GATT/SR/GAR/BV-03-C PASS advertise-configure connectable=1 legacy=1 - advertise-start -GATT/SR/GAR/BI-06-C PASS advertise-configure connectable=1 legacy=1 - advertise-start - gatt-show-local - - -GATT/SR/GAR/BI-07-C PASS advertise-configure connectable=1 legacy=1 - advertise-start - -GATT/SR/GAR/BI-08-C PASS advertise-configure connectable=1 legacy=1 - advertise-start -GATT/SR/GAR/BI-09-C N/A -GATT/SR/GAR/BI-10-C PASS advertise-configure connectable=1 legacy=1 - advertise-start -GATT/SR/GAR/BI-11-C PASS advertise-configure connectable=1 legacy=1 - advertise-start - -GATT/SR/GAR/BV-04-C PASS advertise-configure connectable=1 legacy=1 - advertise-start -GATT/SR/GAR/BI-12-C PASS advertise-configure connectable=1 legacy=1 - advertise-start - -GATT/SR/GAR/BI-13-C PASS advertise-configure connectable=1 legacy=1 - advertise-start -GATT/SR/GAR/BI-14-C PASS advertise-configure connectable=1 legacy=1 - advertise-start - -GATT/SR/GAR/BI-15-C N/A -GATT/SR/GAR/BI-16-C PASS advertise-configure connectable=1 legacy=1 - advertise-start -GATT/SR/GAR/BI-17-C PASS advertise-configure connectable=1 legacy=1 - advertise-start -GATT/SR/GAR/BV-05-C PASS advertise-configure connectable=1 legacy=1 - advertise-start -GATT/SR/GAR/BI-18-C PASS advertise-configure connectable=1 legacy=1 - advertise-start - -GATT/SR/GAR/BI-19-C PASS advertise-configure connectable=1 legacy=1 - advertise-start - -GATT/SR/GAR/BI-20-C N/A -GATT/SR/GAR/BI-21-C PASS advertise-configure connectable=1 legacy=1 - advertise-start -GATT/SR/GAR/BI-22-C PASS advertise-configure connectable=1 legacy=1 - advertise-startt -GATT/SR/GAR/BV-06-C PASS advertise-configure connectable=1 legacy=1 - advertise-start -GATT/SR/GAR/BI-23-C N/A -GATT/SR/GAR/BI-24-C N/A -GATT/SR/GAR/BI-25-C N/A -GATT/SR/GAR/BI-26-C N/A -GATT/SR/GAR/BI-27-C N/A -GATT/SR/GAR/BV-07-C PASS advertise-configure connectable=1 legacy=1 - advertise-start -GATT/SR/GAR/BV-08-C PASS advertise-configure connectable=1 legacy=1 - advertise-start -GATT/SR/GAR/BI-28-C N/A -GATT/SR/GAR/BI-29-C N/A -GATT/SR/GAR/BI-30-C N/A -GATT/SR/GAR/BI-31-C N/A -GATT/SR/GAR/BI-32-C N/A -GATT/SR/GAR/BI-33-C N/A -GATT/SR/GAR/BI-34-C N/A -GATT/SR/GAR/BI-35-C N/A -------------------------------------------------------------------------------- - -GATT/SR/GAW/BV-01-C PASS advertise-configure connectable=1 legacy=1 - advertise-start -GATT/SR/GAW/BV-02-C N/A -GATT/SR/GAW/BI-01-C N/A -GATT/SR/GAW/BV-03-C PASS advertise-configure connectable=1 legacy=1 - advertise-start -GATT/SR/GAW/BI-02-C PASS advertise-configure connectable=1 legacy=1 - advertise-start - -GATT/SR/GAW/BI-03-C PASS advertise-configure connectable=1 legacy=1 - advertise-start -GATT/SR/GAW/BI-04-C N/A -GATT/SR/GAW/BI-05-C PASS advertise-configure connectable=1 legacy=1 - advertise-start -GATT/SR/GAW/BI-06-C PASS advertise-configure connectable=1 legacy=1 - advertise-start -GATT/SR/GAW/BV-05-C PASS advertise-configure connectable=1 legacy=1 - advertise-start -GATT/SR/GAW/BI-07-C PASS advertise-configure connectable=1 legacy=1 - advertise-start - -GATT/SR/GAW/BI-08-C PASS advertise-configure connectable=1 legacy=1 - advertise-start - -GATT/SR/GAW/BI-09-C PASS advertise-configure connectable=1 legacy=1 - advertise-start -GATT/SR/GAW/BI-11-C N/A -GATT/SR/GAW/BI-12-C PASS advertise-configure connectable=1 legacy=1 - advertise-start -GATT/SR/GAW/BI-13-C PASS advertise-configure connectable=1 legacy=1 - advertise-start -GATT/SR/GAW/BV-06-C PASS advertise-configure connectable=1 legacy=1 - advertise-start -GATT/SR/GAW/BV-10-C PASS advertise-configure connectable=1 legacy=1 - advertise-start -GATT/SR/GAW/BI-14-C PASS advertise-configure connectable=1 legacy=1 - advertise-start - -GATT/SR/GAW/BI-15-C PASS advertise-configure connectable=1 legacy=1 - advertise-start - -GATT/SR/GAW/BI-17-C N/A -GATT/SR/GAW/BI-18-C PASS advertise-configure connectable=1 legacy=1 - advertise-start -GATT/SR/GAW/BI-19-C PASS advertise-configure connectable=1 legacy=1 - advertise-start -GATT/SR/GAW/BV-11-C PASS advertise-configure connectable=1 legacy=1 - advertise-start -GATT/SR/GAW/BV-07-C PASS advertise-configure connectable=1 legacy=1 - advertise-start -GATT/SR/GAW/BV-08-C PASS advertise-configure connectable=1 legacy=1 - advertise-start -GATT/SR/GAW/BI-20-C PASS advertise-configure connectable=1 legacy=1 - advertise-start - -GATT/SR/GAW/BI-21-C PASS advertise-configure connectable=1 legacy=1 - advertise-start - -GATT/SR/GAW/BI-22-C N/A -GATT/SR/GAW/BI-23-C PASS advertise-configure connectable=1 legacy=1 - advertise-start -GATT/SR/GAW/BI-24-C PASS advertise-configure connectable=1 legacy=1 - advertise-start -GATT/SR/GAW/BV-09-C PASS advertise-configure connectable=1 legacy=1q - advertise-start -GATT/SR/GAW/BI-25-C PASS advertise-configure connectable=1 legacy=1 - advertise-start - -GATT/SR/GAW/BI-26-C PASS advertise-configure connectable=1 legacy=1 - advertise-start - -GATT/SR/GAW/BI-27-C PASS advertise-configure connectable=1 legacy=1 - advertise-start -GATT/SR/GAW/BI-29-C N/A -GATT/SR/GAW/BI-30-C PASS advertise-configure connectable=1 legacy=1 - advertise-start -GATT/SR/GAW/BI-31-C PASS advertise-configure connectable=1 legacy=1 - advertise-start -GATT/SR/GAW/BI-32-C PASS advertise-configure connectable=1 legacy=1 - advertise-start -GATT/SR/GAW/BI-33-C PASS advertise-configure connectable=1 legacy=1 - advertise-start -GATT/SR/GAW/BI-34-C PASS advertise-configure connectable=1 legacy=1 - advertise-start -GATT/SR/GAW/BI-35-C PASS advertise-configure connectable=1 legacy=1 - advertise-start ------------------------------------------------------------------------------- - -GATT/SR/GAN/BV-01-C PASS advertise-configure connectable=1 legacy=1 - advertise-start - gatt-notify attr= ------------------------------------------------------------------------------- - -GATT/SR/GAI/BV-01-C PASS advertise-configure connectable=1 legacy=1 - advertise-start - gatt-notify attr= -------------------------------------------------------------------------------- - -GATT/SR/GAS/BV-01-C PASS Note: set TSPX_security_enabled to TRUE - security-set-data bonding=1 our_key_dist=7 their_key_dist=7 - advertise-configure connectable=1 legacy=1 - advertise-start - - gatt-service-changed start=1 end=0xffff - advertise-start - security-start conn= -------------------------------------------------------------------------------- - -GATT/SR/GAT/BV-01-C PASS advertise-start - gatt-notify attr=0x0008 ------------------------------------------------------------------------------- - -GATT/SR/GPA/BV-01-C N/A -GATT/SR/GPA/BV-02-C N/A -GATT/SR/GPA/BV-03-C N/A -GATT/SR/GPA/BV-04-C N/A -GATT/SR/GPA/BV-05-C N/A -GATT/SR/GPA/BV-06-C N/A -GATT/SR/GPA/BV-07-C N/A -GATT/SR/GPA/BV-08-C N/A -GATT/SR/GPA/BV-11-C N/A -GATT/SR/GPA/BV-12-C N/A -------------------------------------------------------------------------------- - -GATT/SR/UNS/BI-01-C PASS advertise-configure connectable=1 legacy=1 - advertise-start -GATT/SR/UNS/BI-02-C PASS advertise-configure connectable=1 legacy=1 - advertise-start - --------------------------------------------------------------------------------- - -GATT/SR/GPM/BV-01-C N/A - diff --git a/nimble/host/pts/pts-l2cap.txt b/nimble/host/pts/pts-l2cap.txt deleted file mode 100644 index c09add9168..0000000000 --- a/nimble/host/pts/pts-l2cap.txt +++ /dev/null @@ -1,304 +0,0 @@ -PTS test results for L2CAP - -PTS version: 7.5.0 -Tested: 07-Oct-2019 - -syscfg.vals: - BLE_EXT_ADV: 1 - BLE_PUBLIC_DEV_ADDR: "((uint8_t[6]){0x01, 0xff, 0xff, 0xc0, 0xde, 0xc0})" - BLE_SM_LEGACY: 1 - BLE_SM_SC: 1 - BLE_L2CAP_COC_MAX_NUM: 5 - BLE_SVC_GAP_PPCP_MIN_CONN_INTERVAL: 9 - BLE_SVC_GAP_PPCP_MAX_CONN_INTERVAL: 30 - BLE_SVC_GAP_PPCP_SUPERVISION_TMO: 2000 - CONSOLE_HISTORY_SIZE: 10 - -Results: -PASS test passed -FAIL test failed -INC test is inconclusive -N/A test is disabled due to PICS setup - -------------------------------------------------------------------------------- -Test Name Result Notes -------------------------------------------------------------------------------- - -L2CAP/COS/CED/BV-01-C N/A -L2CAP/COS/CED/BV-03-C N/A -L2CAP/COS/CED/BV-04-C N/A -L2CAP/COS/CED/BV-05-C N/A -L2CAP/COS/CED/BV-07-C N/A -L2CAP/COS/CED/BV-08-C N/A -L2CAP/COS/CED/BV-09-C N/A -L2CAP/COS/CED/BV-10-C N/A -L2CAP/COS/CED/BV-11-C N/A -L2CAP/COS/CED/BI-01-C N/A -------------------------------------------------------------------------------- - -L2CAP/COS/CFD/BV-01-C N/A -L2CAP/COS/CFD/BV-02-C N/A -L2CAP/COS/CFD/BV-03-C N/A -L2CAP/COS/CFD/BV-08-C N/A -L2CAP/COS/CFD/BV-09-C N/A -L2CAP/COS/CFD/BV-10-C N/A -L2CAP/COS/CFD/BV-11-C N/A -L2CAP/COS/CFD/BV-12-C N/A -L2CAP/COS/CFD/BV-13-C N/A -------------------------------------------------------------------------------- - -L2CAP/COS/IEX/BV-01-C N/A -L2CAP/COS/IEX/BV-02-C N/A -------------------------------------------------------------------------------- - -L2CAP/COS/ECH/BV-01-C N/A -L2CAP/COS/ECH/BV-02-C N/A -------------------------------------------------------------------------------- - -L2CAP/COS/CFC/BV-01-C PASS advertise-configure connectable=1 legacy=1 - advertise-set-adv-data flags=6 - l2cap-create-server psm= - advertise-start - l2cap-send conn= idx=0 bytes=15 - -L2CAP/COS/CFC/BV-02-C PASS advertise-configure connectable=1 legacy=1 - advertise-set-adv-data flags=6 - l2cap-create-server psm= - advertise-start - l2cap-send conn= idx=0 bytes=15 - -L2CAP/COS/CFC/BV-03-C PASS NOTE: #define BTSHELL_COC_MTU = 512 - advertise-configure connectable=1 legacy=1 - l2cap-create-server psm= - advertise-start -L2CAP/COS/CFC/BV-04-C PASS advertise-configure connectable=1 legacy=1 - l2cap-create-server psm= - advertise-start -L2CAP/COS/CFC/BV-05-C PASS advertise-configure connectable=1 legacy=1 - l2cap-create-server psm= - advertise-start - l2cap-connect conn= psm= - l2cap-connect conn= psm=<2nd psm> -------------------------------------------------------------------------------- - -L2CAP/CLS/CLR/BV-01-C N/A -------------------------------------------------------------------------------- - -L2CAP/CLS/UCD/BV-01-C N/A -L2CAP/CLS/UCD/BV-02-C N/A -L2CAP/CLS/UCD/BV-03-C N/A -------------------------------------------------------------------------------- - -L2CAP/EXF/BV-01-C N/A -L2CAP/EXF/BV-02-C N/A -L2CAP/EXF/BV-03-C N/A -L2CAP/EXF/BV-04-C N/A -L2CAP/EXF/BV-05-C N/A -L2CAP/EXF/BV-06-C N/A -------------------------------------------------------------------------------- - -L2CAP/CMC/BV-01-C N/A -L2CAP/CMC/BV-02-C N/A -L2CAP/CMC/BV-03-C N/A -L2CAP/CMC/BV-04-C N/A -L2CAP/CMC/BV-05-C N/A -L2CAP/CMC/BV-06-C N/A -L2CAP/CMC/BV-07-C N/A -L2CAP/CMC/BV-08-C N/A -L2CAP/CMC/BV-09-C N/A -L2CAP/CMC/BV-10-C N/A -L2CAP/CMC/BV-11-C N/A -L2CAP/CMC/BV-12-C N/A -L2CAP/CMC/BV-13-C N/A -L2CAP/CMC/BV-14-C N/A -L2CAP/CMC/BV-15-C N/A -L2CAP/CMC/BI-01-C N/A -L2CAP/CMC/BI-02-C N/A -L2CAP/CMC/BI-03-C N/A -L2CAP/CMC/BI-04-C N/A -L2CAP/CMC/BI-05-C N/A -L2CAP/CMC/BI-06-C N/A -------------------------------------------------------------------------------- - -L2CAP/FOC/BV-01-C N/A -L2CAP/FOC/BV-02-C N/A -L2CAP/FOC/BV-03-C N/A -------------------------------------------------------------------------------- - -L2CAP/OFS/BV-01-C N/A -L2CAP/OFS/BV-02-C N/A -L2CAP/OFS/BV-03-C N/A -L2CAP/OFS/BV-04-C N/A -L2CAP/OFS/BV-05-C N/A -L2CAP/OFS/BV-06-C N/A -L2CAP/OFS/BV-07-C N/A -L2CAP/OFS/BV-08-C N/A -------------------------------------------------------------------------------- - -L2CAP/ERM/BV-01-C N/A -L2CAP/ERM/BV-02-C N/A -L2CAP/ERM/BV-03-C N/A -L2CAP/ERM/BV-05-C N/A -L2CAP/ERM/BV-06-C N/A -L2CAP/ERM/BV-07-C N/A -L2CAP/ERM/BV-08-C N/A -L2CAP/ERM/BV-09-C N/A -L2CAP/ERM/BV-10-C N/A -L2CAP/ERM/BV-11-C N/A -L2CAP/ERM/BV-12-C N/A -L2CAP/ERM/BV-13-C N/A -L2CAP/ERM/BV-14-C N/A -L2CAP/ERM/BV-15-C N/A -L2CAP/ERM/BV-16-C N/A -L2CAP/ERM/BV-17-C N/A -L2CAP/ERM/BV-18-C N/A -L2CAP/ERM/BV-19-C N/A -L2CAP/ERM/BV-20-C N/A -L2CAP/ERM/BV-21-C N/A -L2CAP/ERM/BV-22-C N/A -L2CAP/ERM/BV-23-C N/A -L2CAP/ERM/BI-01-C N/A -L2CAP/ERM/BI-02-C N/A -L2CAP/ERM/BI-03-C N/A -L2CAP/ERM/BI-04-C N/A -L2CAP/ERM/BI-05-C N/A -------------------------------------------------------------------------------- - -L2CAP/STM/BV-01-C N/A -L2CAP/STM/BV-02-C N/A -L2CAP/STM/BV-03-C N/A -L2CAP/STM/BV-11-C N/A -L2CAP/STM/BV-12-C N/A -L2CAP/STM/BV-13-C N/A -------------------------------------------------------------------------------- - -L2CAP/FIX/BV-01-C N/A -L2CAP/FIX/BV-02-C N/A -------------------------------------------------------------------------------- - -L2CAP/EWC/BV-01-C N/A -L2CAP/EWC/BV-02-C N/A -L2CAP/EWC/BV-03-C N/A -------------------------------------------------------------------------------- - -L2CAP/LSC/BV-01-C N/A -L2CAP/LSC/BV-02-C N/A -L2CAP/LSC/BV-03-C N/A -L2CAP/LSC/BI-04-C N/A -L2CAP/LSC/BI-05-C N/A -L2CAP/LSC/BV-06-C N/A -L2CAP/LSC/BV-07-C N/A -L2CAP/LSC/BV-08-C N/A -L2CAP/LSC/BV-09-C N/A -L2CAP/LSC/BI-10-C N/A -L2CAP/LSC/BI-11-C N/A -L2CAP/LSC/BV-12-C N/A -------------------------------------------------------------------------------- - -L2CAP/CCH/BV-01-C N/A -L2CAP/CCH/BV-02-C N/A -L2CAP/CCH/BV-03-C N/A -L2CAP/CCH/BV-04-C N/A -------------------------------------------------------------------------------- - -L2CAP/ECF/BV-01-C N/A -L2CAP/ECF/BV-02-C N/A -L2CAP/ECF/BV-03-C N/A -L2CAP/ECF/BV-04-C N/A -L2CAP/ECF/BV-05-C N/A -L2CAP/ECF/BV-06-C N/A -L2CAP/ECF/BV-07-C N/A -L2CAP/ECF/BV-08-C N/A -------------------------------------------------------------------------------- - -L2CAP/LE/CPU/BV-01-C PASS advertise-configure connectable=1 legacy=1 - advertise-set-adv-data flags=6 - advertise-start - l2cap-update conn= -L2CAP/LE/CPU/BV-02-C PASS connect peer_addr= - disconnect conn= -L2CAP/LE/CPU/BI-01-C PASS connect peer_addr= - disconnect conn= -L2CAP/LE/CPU/BI-02-C PASS advertise-configure connectable=1 legacy=1 - advertise-set-adv-data flags=6 - advertise-start -------------------------------------------------------------------------------- - -L2CAP/LE/REJ/BI-01-C PASS advertise-configure connectable=1 legacy=1 - advertise-set-adv-data flags=6 - advertise-start -L2CAP/LE/REJ/BI-02-C PASS advertise-configure connectable=1 legacy=1 - advertise-set-adv-data flags=6 - advertise-start - disconnect conn= -------------------------------------------------------------------------------- - -L2CAP/LE/CFC/BV-01-C PASS advertise-configure connectable=1 legacy=1 - advertise-set-adv-data flags=6 - advertise-start -L2CAP/LE/CFC/BV-02-C PASS advertise-configure connectable=1 legacy=1 - advertise-set-adv-data flags=6 - advertise-start - l2cap-connect conn= psm=90 -L2CAP/LE/CFC/BV-03-C PASS advertise-configure connectable=1 legacy=1 - advertise-set-adv-data flags=6 - l2cap-create-server psm= - advertise-start - l2cap-send conn= idx=0 bytes=15 - -L2CAP/LE/CFC/BV-04-C PASS advertise-configure connectable=1 legacy=1 - advertise-set-adv-data flags=6 - advertise-start - l2cap-connect conn= psm= -L2CAP/LE/CFC/BV-05-C PASS advertise-configure connectable=1 legacy=1 - advertise-set-adv-data flags=6 - advertise-start -L2CAP/LE/CFC/BV-06-C PASS advertise-configure connectable=1 legacy=1 - advertise-set-adv-data flags=6 - l2cap-create-server psm= - advertise-start - l2cap-send conn= idx=0 bytes=15 -L2CAP/LE/CFC/BV-07-C PASS advertise-configure connectable=1 legacy=1 - advertise-set-adv-data flags=6 - l2cap-create-server psm= - advertise-start -L2CAP/LE/CFC/BI-01-C PASS advertise-configure connectable=1 legacy=1 - l2cap-create-server psm= - advertise-start -L2CAP/LE/CFC/BV-08-C PASS advertise-configure connectable=1 legacy=1 - advertise-set-adv-data flags=6 - l2cap-create-server psm= - advertise-start - l2cap-disconnect conn= idx=0 -L2CAP/LE/CFC/BV-09-C PASS advertise-configure connectable=1 legacy=1 - advertise-set-adv-data flags=6 - l2cap-create-server psm= - advertise-start -L2CAP/LE/CFC/BV-16-C PASS advertise-configure connectable=1 legacy=1 - advertise-set-adv-data flags=6 - advertise-start - l2cap-connect conn= psm=90 -L2CAP/LE/CFC/BV-17-C N/A -L2CAP/LE/CFC/BV-18-C PASS advertise-configure connectable=1 legacy=1 - advertise-set-adv-data flags=6 - advertise-start - l2cap-connect conn= psm=90 -L2CAP/LE/CFC/BV-19-C PASS NOTE: TSPC_L2CAP_3_16 (multiple channel support) must be checked - advertise-configure connectable=1 legacy=1 - advertise-set-adv-data flags=6 - advertise-start - l2cap-connect conn= psm=90 -L2CAP/LE/CFC/BV-20-C PASS NOTE: TSPC_L2CAP_3_16 (multiple channel support) must be checked - advertise-configure connectable=1 legacy=1 - l2cap-create-server psm= - advertise-start -L2CAP/LE/CFC/BV-21-C PASS advertise-configure connectable=1 legacy=1 - advertise-set-adv-data flags=6 - advertise-start - l2cap-connect conn= psm=90 -------------------------------------------------------------------------------- - -L2CAP/LE/CID/BV-01-C N/A -L2CAP/LE/CID/BV-02-C N/A -------------------------------------------------------------------------------- - diff --git a/nimble/host/pts/pts-sm.txt b/nimble/host/pts/pts-sm.txt deleted file mode 100644 index ac26db712e..0000000000 --- a/nimble/host/pts/pts-sm.txt +++ /dev/null @@ -1,310 +0,0 @@ -PTS test results for SM - -PTS version: 7.5.0 -Tested: 07-Oct-2019 - -syscfg.vals: - BLE_EXT_ADV: 1 - BLE_PUBLIC_DEV_ADDR: "((uint8_t[6]){0x01, 0xff, 0xff, 0xc0, 0xde, 0xc0})" - BLE_SM_LEGACY: 1 - BLE_SM_SC: 1 - BLE_L2CAP_COC_MAX_NUM: 5 - BLE_SVC_GAP_PPCP_MIN_CONN_INTERVAL: 9 - BLE_SVC_GAP_PPCP_MAX_CONN_INTERVAL: 30 - BLE_SVC_GAP_PPCP_SUPERVISION_TMO: 2000 - CONSOLE_HISTORY_SIZE: 10 - -Results: -PASS test passed -FAIL test failed -INC test is inconclusive -N/A test is disabled due to PICS setup -NONE test result is none - -------------------------------------------------------------------------------- -Test Name Result Notes -------------------------------------------------------------------------------- - -SM/MAS/PROT/BV-01-C PASS connect peer_addr= - security-set-data bonding=1 sc=1 our_key_dist=7 their_key_dist=7 - security-pair conn= -------------------------------------------------------------------------------- - -SM/MAS/JW/BV-01-C N/A -SM/MAS/JW/BV-05-C PASS connect peer_addr= - security-pair conn= - disconnect conn= - -SM/MAS/JW/BI-01-C PASS connect peer_addr= - security-pair conn= -SM/MAS/JW/BI-04-C PASS connect peer_addr= - security-set-data bonding=1 sc=1 - security-pair conn= -------------------------------------------------------------------------------- - -SM/MAS/PKE/BV-01-C PASS security-set-data io_capabilities=1 - connect peer_addr= - b sec pair conn= - b passkey conn= action=3 key=123456 - Note: enter '123456' passkey in PTS -SM/MAS/PKE/BV-04-C PASS security-set-data bonding=1 oob_flag=0 - connect peer_addr= - security-pair conn= - disconnect conn= -SM/MAS/PKE/BI-01-C PASS ecurity-set-data io_capabilities=1 oob_flag=0 - connect peer_addr= - security-pair conn= - auth-passkey conn= action=3 key=123456 - Note: enter invalid passkey -SM/MAS/PKE/BI-02-C PASS security-set-data io_capabilities=1 oob_flag=0 - connect peer_addr= - security-pair conn= - auth-passkey conn= action=3 key=123456 - Note: enter '123456' passkey in PTS -------------------------------------------------------------------------------- - -SM/MAS/OOB/BV-01-C N/A -SM/MAS/OOB/BV-03-C N/A -SM/MAS/OOB/BV-05-C PASS security-set-data io_capabilities=1 oob_flag=0 - connect-peer_addr= - security-pair conn= - auth-passkey conn= action=3 key=123456 - Note: enter '123456' passkey in PTS - disconnect conn=1 -SM/MAS/OOB/BV-07-C PASS ecurity-set-data io_capabilities=1 oob_flag=0 - connect-peer_addr= - security-pair conn= - disconnect conn=1 -SM/MAS/OOB/BV-09-C N/A -SM/MAS/OOB/BI-01-C N/A -------------------------------------------------------------------------------- - -SM/MAS/EKS/BV-01-C PASS connect peer_addr= - security-pair conn= - disconnect conn=1 -SM/MAS/EKS/BI-01-C PASS connect peer_addr= - security-pair conn= - disconnect conn=1 -------------------------------------------------------------------------------- - -SM/MAS/SIGN/BV-01-C N/A -SM/MAS/SIGN/BV-03-C N/A -SM/MAS/SIGN/BI-01-C N/A -------------------------------------------------------------------------------- - -SM/MAS/KDU/BV-04-C PASS security-set-data our_key_dist=4 - connect peer_addr= - security-pair conn= - disconnect conn=1 -SM/MAS/KDU/BV-05-C PASS security-set-data our_key_dist=2 - connect peer_addr= - security-pair conn= - disconnect conn=1 -SM/MAS/KDU/BV-06-C PASS security-set-data our_key_dist=1 - connect peer_addr= - security-pair conn= - disconnect conn=1 -SM/MAS/KDU/BV-10-C PASS security-set-data our_key_dist=2 sc=1 - connect peer_addr= - security-pair conn= - disconnect conn=1 -SM/MAS/KDU/BV-11-C PASS security-set-data our_key_dist=2 sc=1 - connect peer_addr= - security-pair conn= - disconnect conn=1 -SM/MAS/KDU/BI-01-C PASS connect peer_addr= - disconnect conn=1 - reset device - - -------------------------------------------------------------------------------- - -SM/MAS/SIP/BV-02-C PASS security-set-data io_capabilities=4 - connect peer_addr= - disconnect conn=1 -------------------------------------------------------------------------------- -SM/MAS/SCJW/BV-01-C PASS security-set-data sc=1 - connect peer_addr= - security-pair conn= - disconnect conn=1 -SM/MAS/SCJW/BV-04-C PASS security-set-data sc=1 io_capabilities=1 our_key_dist=1 - connect peer_addr= - security-pair conn= - disconnect conn=1 -SM/MAS/SCJW/BI-01-C PASS security-set-data sc=1 io_capabilities=4 - connect peer_addr= - security-pair conn= - disconnect conn=1 - - -------------------------------------------------------------------------------- - -SM/MAS/SCPK/BV-01-C PASS security-set-data sc=1 io_capabilities=2 - connect peer_addr= - security-pair conn= - auth_passkey conn=1 action=2 key=123456 - Note: enter '123456' passkey in PTS - disconnect conn=1 -SM/MAS/SCPK/BV-04-C PASS security-set-data io_capabilities=4 oob_flag=0 our_key_dist=1 their_key_dist=1 - connect peer_addr= - security-pair conn= - auth_passkey conn=1 action=2 key=123456 - Note: enter '123456' passkey in PTS - disconnect conn=1 -SM/MAS/SCPK/BI-01-C PASS security-set-data io_capabilities=4 oob_flag=0 sc=1 - connect peer_addr= - security-pair conn= - disconnect conn=1 - - auth_passkey conn=1 action=2 key=123456 - Note: enter '123456' passkey in PTS - disconnect conn=1 -SM/MAS/SCPK/BI-02-C PASS security-set-data io_capabilities=2 oob_flag=0 bonding=1 sc=1 - connect peer_addr= - security-pair conn= - auth_passkey conn=1 action=2 key=123456 - Note: enter '123456' passkey in PTS - disconnect conn=1 -------------------------------------------------------------------------------- - -SM/MAS/SCOB/BV-01-C N/A -SM/MAS/SCOB/BI-04-C N/A -SM/MAS/SCOB/BV-01-C N/A -SM/MAS/SCOB/BI-04-C N/A -------------------------------------------------------------------------------- - -SM/MAS/SCCT/BV-01-C N/A -SM/MAS/SCCT/BV-03-C N/A -SM/MAS/SCCT/BV-05-C N/A -SM/MAS/SCCT/BV-07-C N/A -SM/MAS/SCCT/BV-09-C N/A -------------------------------------------------------------------------------- - -SM/SLA/PROT/BV-02-C PASS advertise-configure connectable=1 legacy=1 - advertise-start - -------------------------------------------------------------------------------- - -SM/MAS/JW/BV-02-C PASS advertise-configure connectable=1 legacy=1 - advertise-start -SM/SLA/JW/BI-02-C PASS advertise-configure connectable=1 legacy=1 - advertise-start -SM/SLA/JW/BI-03-C PASS advertise-configure connectable=1 legacy=1 - advertise-start -------------------------------------------------------------------------------- - -SM/SLA/PKE/BV-02-C PASS security-set-data io_capabilities=4 - advertise-configure connectable=1 legacy=1 - advertise-start - auth-passkey conn= action=2 key= - -SM/SLA/PKE/BV-05-C PASS security-set-data io_capabilities=4 - advertise-configure connectable=1 legacy=1 - advertise-start -SM/SLA/PKE/BI-03-C PASS security-set-data io_capabilities=4 - advertise-configure connectable=1 legacy=1 - advertise-start - auth-passkey conn= action=3 key=123456 - Note: enter invalid passkey -------------------------------------------------------------------------------- - -SM/SLA/OOB/BV-02-C N/A -SM/SLA/OOB/BV-04-C N/A -SM/SLA/OOB/BV-06-C PASS security-set-data io_capabilities=1 - advertise-configure connectable=1 legacy=1 - advertise-start - auth-passkey conn= action=3 key= -SM/SLA/OOB/BV-08-C PASS advertise-configure connectable=1 legacy=1 - advertise-start -SM/SLA/OOB/BV-10-C N/A -SM/SLA/OOB/BI-02-C N/A -------------------------------------------------------------------------------- - -SM/SLA/EKS/BV-02-C PASS advertise-configure connectable=1 legacy=1 - advertise-start -SM/SLA/EKS/BI-02-C PASS advertise-configure connectable=1 legacy=1 - advertise-start -------------------------------------------------------------------------------- - -SM/SLA/KDU/BV-01-C PASS security-set-data io_capabilities=1 - advertise-configure connectable=1 legacy=1 - advertise-start -SM/SLA/KDU/BV-02-C PASS security-set-data io_capabilities=2 - advertise-configure connectable=1 legacy=1 - advertise-start -SM/SLA/KDU/BV-03-C PASS security-set-data io_capabilities=4 - advertise-configure connectable=1 legacy=1 - advertise-start -SM/SLA/KDU/BV-07-C PASS security-set-data our_key_dist=1 bonding=1 - advertise-configure connectable=1 legacy=1 - advertise-start -SM/SLA/KDU/BV-08-C PASS security-set-data our_key_dist=2 sc=1 - advertise-configure connectable=1 legacy=1 - advertise-start -SM/SLA/KDU/BV-09-C PASS security-set-data our_key_dist=4 bonding=0 - advertise-configure connectable=1 legacy=1 - advertise-start -SM/SLA/KDU/BI-01-C PASS advertise-configure connectable=1 legacy=1 - security-set-data sc=1 - advertise-start - - -------------------------------------------------------------------------------- - -SM/SLA/SIP/BV-01-C PASS security-set-data io_capabilities=4 - advertise-configure connectable=1 legacy=1 - advertise-start - security-start conn= -------------------------------------------------------------------------------- - -SM/SLA/SIE/BV-01-C PASS security-set-data io_capabilities=3 bonding=1 our_key_dist=1 their_key_dist=1 - advertise-configure connectable=1 legacy=1 - advertise-start - advertise-start - security-start conn= -------------------------------------------------------------------------------- - -SM/SLA/SCJW/BV-02-C PASS security-set-data io_capabilities=4 oob_flag=0 bonding=0 mitm_flag=0 sc=1 our_key_dist=1 - advertise-configure connectable=1 legacy=1 - advertise-start -SM/SLA/SCJW/BV-03-C PASS security-set-data io_capabilities=1 our_key_dist=1 oob_flag=0 - advertise-configure connectable=1 legacy=1 - advertise-start -SM/SLA/SCJW/BI-02-C PASS security-set-data io_capabilities=1 oob_flag=0 bonding=1 sc=1 - advertise-configure connectable=1 legacy=1 - advertise-start -------------------------------------------------------------------------------- - -SM/SLA/SCPK/BV-02-C PASS security-set-data io_capabilities=1 oob_flag=0 sc=1 - advertise-configure connectable=1 legacy=1 - advertise-start - auth-passkey conn=1 action=4 key=186900 yesno=yy -SM/SLA/SCPK/BV-03-C PASS security-set-data io_capabilities=2 oob_flag=0 our_key_dist=1 their_key_dist=1 sc=1 - advertise-configure connectable=1 legacy=1 - advertise-start - auth-passkey conn=1 action=2 key=123456 - Note: enter '123456' passkey in PTS -SM/SLA/SCPK/BI-03-C PASS security-set-data io_capabilities=2 oob_flag=0 sc=1 - advertise-configure connectable=1 legacy=1 - advertise-start - auth-passkey conn=1 action=2 key=123456 oob= - Note: enter '123456' passkey in PTS -SM/SLA/SCPK/BI-04-C PASS security-set-data io_capabilities=2 oob_flag=0 mitm_flag=1 sc=1 - advertise-configure connectable=1 legacy=1 - advertise-start - - auth-passkey conn=1 action=2 key=123456 - Note: enter '123456' passkey in PTS -------------------------------------------------------------------------------- - -SM/SLA/SCOB/BV-02-C N/A -SM/SLA/SCOB/BI-03-C N/A -SM/SLA/SCOB/BV-02-C N/A -SM/SLA/SCOB/BI-03-C N/A -------------------------------------------------------------------------------- - -SM/SLA/SCCT/BV-02-C N/A -SM/SLA/SCCT/BV-04-C N/A -SM/SLA/SCCT/BV-06-C N/A -SM/SLA/SCCT/BV-08-C N/A -SM/SLA/SCCT/BV-10-C N/A \ No newline at end of file diff --git a/nimble/host/pts/tpg/94654-20170317-085122560.tpg b/nimble/host/pts/tpg/94654-20170317-085122560.tpg deleted file mode 100644 index f5bb0ce99c..0000000000 --- a/nimble/host/pts/tpg/94654-20170317-085122560.tpg +++ /dev/null @@ -1,1026 +0,0 @@ - -M'&/JP\$+#X83?)"[ M2E=\N*7*U 5)JSKT(5#=>@^/#]IP*[GTZ0%0]$F(/$ -MEK[V7>349??;!JZJNFZ CK=QGD^FOYV^FU>"DK<@0U*##HV\H9&_%["5IK@1 -MA9F,FJO2P^3:4_]04%-0T%9=^XCMWKF"L$[)%)G>_I 0Q?@:H)&1HX)7VY&. -M3 *!JH;^YUJ1[_*7JN2'Z5^*0I&NP+[LAE:>S92BP^T:3+B>IKFJJ8A,4Y^L -MUX+P_C'Z#VN20)A!ANN2@J#!AYY4"KQ\5):1]+[B\TN+BI"AB8NJH ,NZ(() -MG>K?^A\-B,<@/IVC+$#XFXJ<65V*OE'"L]7*OEJ*C]CS^."A/) (K_@0 -ME"&)D)^IP]?+')Q(%NM&7:VL@*6#D!-TU,7.WG SERP(@*R+DH"MPH;@X:Y) -M]X6NG8^EC)N?AH+3[\3SG''R3(?WRGF0NZ#,_4%*E)&>&9R)5[F0OM$A0Y.; -MA8R7%EGBS&\IDPYNR%4ZV$FK^(F[P B/[TU86=H%S^ -MH[H^EYQB:MZ)A:2@IV)4O=//SXNP#%F]5N&<3KZL>(#6'H"D4\DST(O!(![@ -MUYZX#+:1G:V5BE&TGHK]+;@:^JF;;2-&@WD;Z8I9*SB5D+7 &/J8NI6GYGMDGK2(U+_)K!,I$6Q4R% -MAIE9AK#]!JAFCWWD:A8K.9O/I(;D(F2G*6A0YUCMIOQ5M*VD#1: -MG9^)MMZ GIK7,^R0^M"/\%^_B9Y7TLQ/^N?S1 DEF 6XUJU"V_3_U\44H9.; -M6C/PV(36QT(9B9^.C)*YUP?BN>#F%4ST/JM>\*Y;K)J:S+4[O%?G[S[L"^FPVC9/W+).O23U=;?;2EV+G5"5%KG(EED8SLB#Q["2.9YW6IB4DKT QL7P\,%# -MAY^ (+Y+V8GD:B'!S H%G*;=[-\ -M 0+QQ3;G\H21FY_P4-)38+ =K,/38[24B[6W\(N-L/(9[/_LY.X/OLZ%S;A> -MO0TN'._"@/.)DDZ*AGY.V1XW%G7:O+R67U"C@:L%+T\24!11KH^]@[UR\Y\T -M'G.5D/)=H)R"J6R470%+AO24DHF5L -2OV(60>3Z]/#0\HE4<(V%GXBM% 0- -M3X-@G;H%E[2$DL$P-?W&"JI0-EV0AUP(\>] XIW!BI6DO7I9T33VE._FJ(*_ -MKQ6$@E,QFO?! P_#OYFAJ_:"JEF6?]O2PM3:)3"+BYBAK :/H:SLBX.NPOA_3S>U9*&PG[SAU:$=KQR\M>?\!X3 -MZYZ?J;\8N0V1]JOBJ@3;9=L01YQ<:%>>U)-!GAL!T^"]VF8KB/^$EH.ENI:4 -M[(80V,)1T>^'[@;!KIZ5T4.RQW)2M,X;#;8LTO_GV8V[OD6F@JNK JO G$2Q -MH(=0E:GW!3:0E_/T4ZF!M!D-F1F7NI*^QP;A%%V8M*U:R59]QE^+$NONY](% -M28E"K!J#K5N5E8#B_OU9L819J(CL]20ZBF"L4*4D#JV,*& -MYJV<6(JKEZZ4+^NI?%8D<$.P^*4 Z#=7K>XM. -MU3'S/BX/AP [V4*K!EY0C-/CE//ME"./3?_H5OQM$R!7NN&@21#()=Q)MEIG -MU_Y)N7IZ .'V51 ]]L:;LEZ+DI"H^K R=CO:@D2&#^H,PQ!"EDZ>@'"*JK)I -MM9<-XF7"=^(HC+:D156UME\ U?+P=G >A(^3=EW1ZB[7^C_1CZ&R#Y!"F:FH -MHO_0SL+1D%1$55K!?)*MLC?(]!3G_A,(AXY&\M.G+@>5;>6Z]?^Z&KBV:9N< -MBRWP0KI!\#7P]MOC;Y)<5(NN%8*2GEL9'\7/SMD 1Q6PCZ]6;0T*&KK)-^4N -M-OV!3U6TE8(,B;9"K*0WH=?J*<_9J=-(NK)0LY:FO5R)P'*3V.;%;^Z6() 2 -MWEB>F*H-#0RERD0TG[]6I4)#T_26M/[GQ8V5MO]RIY&RN%W_S1G/L829DMR2 -M]('/K/92XJKUML7OR!,>P)J*"H>&-Q0-\]("+'L^-EO>=(036Y>P%.:V&"8V-7ZT139&:(YNN@Z VJQCV=M VOMJ:E/XOE(L[GZ4;QT"H -M$!AY7Y>2^:N K"-$'B0L[FEJN#[Q19:D[2;=9F*>)!$@X/4']#" -M!1&2G)8;"$M&=?M B=+DQ^YQ"-!FB)9'T\^32NDK[68N]-J[6Y^IR:Z(A[.. -M6RG95?0:6^K'2FAK[7\O>>+_9#G(I4O*2=3,_<+@R)UM-9DW*NL+I?DJA^ -M:X8+&-[1=O9MX:R#BIVVVL*?&,-#U928LBR6DI:OR/OQV_;Z"H13GEZ <)J[ -M^8(-)]\+U9V24@V?@HK_A'3=YS&MN]3U&:<&)%JJPHZ6H4 --!,T\L,(ICBY -M$XOXI)]-\^"U_CHZ!52.^"'OK$V=K;>;@,34R_HCW U3FB1#KKV/@Z#_S.'% -M9M 26;U3E76LAFN3DZG5@QO8R.G+!?N(V9N<2;,*E9E2@K&$0L$X+707X.^\ -MT*.^GE""6H$?\19Z=D.11X"6D]CR\RWCD_%?L8JF/FV$&X]!:4**[ -MIJ&85T .P5K[]>8?Q92+TN#S6X[[MHCH"/&KV'J%?' -MDXN2D@L"PEG3X\S?#I9!&(61@+:/6K0YEXK-.ODV/_?'<;&3^)J!2E##A^,3 -M^E;>K7N=]K<"P^$PWC05A%.T7+ 72YJ2?GKS[_#*?9/+D5I=DGF1MKNMU-:; -MTA'SN[>Q@KJ'7 >7QXCJY?#F JZBH%J*TH7WD[S#-.W&]"["KX^N/$.2E8- -M\'OI3>S9)=OP3U7$O"FNK.\J5(+0IC!.XWY;M$\. -M=$Z/KD^-C/1_0?_L_+W"8^N=B7="A8V64I)?G0DOR_KWS/WPQFUSE4C6DDBH -MPJ(PFL.YN.[W]D+^>+I&EEF\EPW'VQA<& I.AD"V5P+ .6_&1:%>-O&=E8%* -M4Z0_F\3GXHI]D-*1FG<:^(&&FQ$__=_Z\-!-I[N#]"^O-VP$ U1GN0\!K]*A/C9:4F99SFM+[ -M[/?CV\*/O(Z#ME:'OC&&?BVA3B31],CN[TF*EE6"FYY(_IXY];+QIY%OQ/?P -MO'*3\1.ABJKLSL+ 7[&CG)>!3%[%>BSWMCX#>%VV+I"SC'*XM%O%*Q$\F$3R -MFPZ16JEA@IM"\L/P^B,0TK:X6KG'%9"W[*C0N>76+Q%7H<_>PHYZHI3A)I%T -M'CJE1J;\5+\;VP%IFYWG(<')6(D;XR:/K)56#*O 5YC#VK;WD_H'2JC>IQI2 -M#Q)4X? :TPVM[5T "L<4HRZ>IZZGK_N#H)Z#!2#PQ>W&P5H#TE6?DII]0?_U -M&*Q64E:.A]I>Y.KMN_K%\W60 9M4G7>#89>?AQ=WP<6$M/BPF(@#DXY8H>HV -M_98"]E%UHB\\ASAPD.K1\^:UE\.K'Z!]6YL*DABNQ='FFM8U\J>$N;^)5E:; -M)HY7P\"EFN02YN[;E$Z.O[U&K 1"I3*7,,8PB6.?)NNE%"<+^?)R\BZB9Z6IC<;N)4W -MEY_GY\JLE%.13J-^"6Q2BLC7\M ,DGJQ)(E!VJ2>JL$T&>X]XL(MD$C9 KM8 -M%Y>>1_Z3H)?PNK"UEQY;MXY:G%GHQVX4[8_K5(P&CO(G'D&LVCKQRXG#YNWUT]23B'FSNANK -M@Z20C[BBQL4UU=+ND/(1D56Y OC->0^5A'RAD:0)&OZ$T.+\%E=K2E)F21L'SG5?CVIO&C8Z+K@7F\3[O\+J% -MK ,6OHYV"U3WZ=%^O_I*[+2LOFNZ'JB&3Z[%X$%9K\/(9II5A+\>CLV44)DG -MY"7V/;KFB)A=4].7@ZASJ'":Q?OL=UEIJBM)BH:'DOQRDJGTL!*[0>HY??Y= -MFH1(OYRWAUJ2T4S+"ZR@FZZRN4&HP\;T]IH2Q9F!DZV225N_C9);$_T!Y9J6 -MB?F&05X*DJ"#A3HS)L?'&@E>::Z$F&OD%;D[>K$/HNT2&C7!VF$ _$SYEG(;VM@7+&[?+^VI-.F;>X -M4$N*I)"B-MC^$ ;YV2@#T;JXA(JZ$ N3WQ-JL"%2M&J##F86WT/BL'P -MY.VZ(+&==J "\H:'QX.LP/#E[>8/BUZF'QI-5Y"0G*"V[S?D9O%'18Y.OQY. -MBN.WELSHV]K#\>(NUEP8;K>_4;:W^HE8]=?]M-" G)V?4[6AJYZ2EEO(SYH. -MTTO,P0*3G@V)GMG/YD6U,L<2Y XGUX) -M5_*33$# Y3?& [B;I:JP:89:E>KG^_6:7=8*G*!8[&^$;(Z@1KQ02XQR>D^[0?W8I/O-HL#UDI)0DZAU -MB0)0^(Z7S,)\T"?Z U#6N@25I]B*U0;.UH2"=%]>6:ZX\2'U/M(5U716I!UU -MAU>VX _/V?RJT)V2DA"&F9I3<(VJ\_9U\.#3L9.F9)JHII.?H+_E_M'N.AC' -MLJ26B+DMEGL&T.?A\O3"2VZZG P?TXM@[/:MS>W.P<\+W$D$U;_/>$NY>I>X -M@7(U+^;^3T^$B;-_E[M7GA&.60E*V?<3XZ;8V;L]]0J6EIF<%& -J5L2]SOF -M)..<4(JK6EB.FR?/*Y/*3^&/#W\G-)F'B? -M_I^'2E1MGHKG[)A4BPP,6SO'#EU2L@8-FX'XNKJJMD?P]A#56)N3GJ:]0(]# -MKQOCD)&4K4(9#][#/G_6O= #>+!255^7FJLR<%C8RX_1K[:$A7N@B;OC]X-8 -MD<#T'M<6O7NCD]Z'?G!;B/,JPSIMY8V7L!]:YYA>@(CT]#ETYC7;3**MC$LL -MGITZ!Y[MV@],Q_+DGQ6>J,^3K(EMA+=-(OW7L//1@8:QI5G:JH(>;!2"QRXJ -M+R[F!=L=DUCVD5J60+I_Q%R+1_*UQG;UV46@EY],D=";@:GC\)J8F)M;W8R; -M*.+3[O8_Q?!5A-&;R((_DEJ? LG"R$Q\%E20$:^YD96)27[S\]/WG8,";9:< -MB\;UOXW--C77[].KC!/_VJ;VMZ.4P+KM^M R]8]67@PGA[R'HA)=V0W=!13! -MY%:R5&I>GJT_;)R Q5/7[);$"[J:>U7SEY&\5B95RW<.4*_2T\;"V(-3OI]Y -M\@__\X:4/1J3QT3^-=.JL]O[I3=Q1GB=J]ISE]AB"MH2U.UFE?U7^,8K))8C=:WBEBA$ISUM_JO# !"7X>:K!ML#X,"_.J= -MG!R4+TY!FAEF5YO2PO$U[*- [4:L7U8]CA>_O)CFP<7;TQ"2IKGZN5>GGPAS -M.;5>5A ;3I:$O*=[#2@N0NZU'H$O7!BZB==5R7@K:4D->IP,'V\CHW@)Z40(>&U;>7 -M1P/+%KBF6Y]?D)!6\L'U->V;]1S=])[\45:#HI67Q LF:<'M@% 1!+V?BN4)3P"-F-18@GM^ -MB*CJ)3+6X,]04)Y;!?R;@V&PFM7.UT&$4!&III5*O9)WV=L2=^YN&LJ[%^V> -M^8,L'!J(D2(FN_1!#SIX%YN/5E^Q;BS"YO_$/\M-5H2=KYR&T+"@GN#,(?G! -M#\A+NYR\%)V%/7N.>R3Q[._&\]JK7Y"+2Y>*JA>IIZE)7I@*XWH6T32[6]6: -MDE";E_',D)?HU"T:YM[A4""1K*)S\ED S^+T6 O:>(>5&_W',OEWT#[C78"> -M&9/2N;T(C;VI#ML)O9.24?.8_!ULCY#%%\3&^]DT8IN UZJHKOWRJB$S^58O -MVTM:L8-\#__SHTK3:?&_L/#V[).5W*:>.9*3O%L"P*T-[H-"IR>MSFR?C*V, -M7@BBPF?DU' *@?*UWU>:HT);D=H.\9>.2TT$P_?4:TX,\+NFJZ@";%6XXS;N -M\O"]VI6&I%N&,+:S)2L3YC&CGJ]R")Y[PR@P[;/_R7I0,$)*=0Y7SNZ"6D_%]Q="M%!&:FJS7 -MEMDR]?W +_V8I>";BHB]UK.,S/(QE??CBZ9@20F__):6I('^/,;W]=B/6Y^, -M@IA>B[!3FPDMXWV\C 9CG6)O96G H-MEHO!3L#FE)82CY>(F8FACI^'F^\P\%K0YJ>( -ML\Z3DHZWO$DPP>+ TPT@28J,F+R&64#!QNR0/]!8CU::O8^>O6>AH$+!S/[- -MY]/4CY#_N8\NCTN@6[?1:OF6]?7%!U>?7UKPC5)"XY*;\,82 ^\%R\-)ZJR9 -M7UK0FZJFL%>MTR9W-<75I9A0@EOP6)^=4-4#Y@^CDZTT45I;R?XY9__P Y!2 -M7D2 ,)(7HJ8:T<,*_863^XETD)J;8I92Y_(E]B_3U(>2X)WV2]:"AIS''MS^ -M-/*(EZQ:@^W7PK6*(.)9Y/8PXI:"! Z?BZMI1I;91/[)R.7"MNN:D Q'^KU<\5$<:<8!WC4$,SLT-V_Z M$U=GJ"^3D?;FF.T@2?V -M/K0[HE"0G'@_UI2;]]COX1F<%%&5CISZ>\3'Y-_Z-/.JEI.MH-,7JJ9VE_%= -M,@YVK@V2V6]?*7-+JUMJ/6I"5IY^5"W.R$^'S^486[]%* -MKI$C6Z9.F*)@GKB'B %&2#&U3&8K:U9&J81DY*05ADDPG'6X$8+D/:8<+Z) -MN-DM1\'<6@O>?07UF%C),M,P]/X*^GR3AU99G .AEBG-[=NPF9+?A(Q=2]N$ -M3Y\"DKTZQN49B(YX&HF'3K:*FG,;O3KG\ZU6A/.I@RV&4(KP^C<\^\>E#*1% -MZ!F/CKJYCIO#QX&,RV;0CZ)=J :>#8N")MLI<]7V+._BGI)]FQ>WD5H(:))7 -M8*(+U0L(Y^-8N0X9$+RF0*I?K,Y7S=0YU/Y$\3CVHKREH,*!P0,*T;BFHXV. -M7;B-1='8T/OGR+F6O@Z65ZFWJ'^;052%R)&@$5_ 9[CIPQ1=7FHV9>NE*HH6="LC/ -M2-'6V$:D7!^]AX]O>HW]\3@9I^;U\Z:8G)M7LHJ*T'"@4L$-^E[3AL[ \8K= -MN;>LF@^KLZF0>MCPEI/0N\=:=C>(EEU*5N4,HN"4G(H=I8D2C -MMJ"?DX&;MP6R*N#-PW:/]WPO6PQ)%,%VJ:ZJ. -MJ*"2@0+#]^_N]@^JAX:?0J:-O'&1SE>@COOE".;#]^9)FKGW"?9##K:3L'JL -M].TPY]##+%);A/H'0EL'W(\0CY&TMU"G^KG"XG3:M";)+'G_E:!=@JNX7)F) -M3T4QOG0#F*7WDZED%C="PC/[_?%4KH^64UAKV%*U0=G'[/04B:N2N,F+GIA& -MB97"X^[TU_971:1]B:=6N)U&NMCPSXOY#\[9O:.=@$,.0:B25[L'/O;%TE+/ -M2:H9@YY7C2QT08^0S2VJQ\<*U4?B/]2=I5NEKPN2\+:+(O+'-^X^YWF@DYN/ -MHKR7)KXL-1;176O#6D!?FKJN&QW^?C\J;DNQV -MBZ'6$*'/'ACJTYYK!F]%LOM)X9&@F;F0,'![/]D:.- -M6@C^ N/$\2PMFL.8!!'UEA&8GN2FGL'#0<05D)X=FJ*[F(&6]PWST-7$\+2K -MCJ2=>EE?E=*\Z?IMU#)+2IK* IQMAX!:O\JJ=<3\]M"+1I'JJYZ]"*2:G5C< -MR*5C0/&/5I")E(RNJ_B5VLT^.6(ZED^'NX]3G_(MC'NZMIG,S_C5_2?9HM&> -MG'BS>O!FBY.LEYW6(OR_.$QA8H!T494B8K,]'35DI1& -MN@@1A)^2_@VAI9E2XLL05! 4W9(U69*P7E+1\/3[E]+@FX6AL]>-#8*!O**Z -M/:S$SS^ZQ!JKC87[B[@)X_R@QOP%N?>IO(*&A<\1LYLA#$S[(<=1CO8-K8,: -M;(J0]XCG'_F@8L2:HKQ]V7J<9T*4:%9;04[J"^.+T<, @5^[HIX7N[N4N_!V -MQ-[O$/_D<)R"D+VDR9Z7 -: AA"$B"R5G9A+!_#@_%;F3PJ<4XZ0E5>KL!(J -M],+:DH_"0]^D=((*H)I?V.@U;<9ET8%0HI>H@Y1T YCU_F?P\@-)L)!6UDM. -M#XLMI\ 3]]HP U[WA)Q/.$'/*%"!]]3!:I[U!@<2^@J$F V0ED19VOXSUN;V -MXKBMJWZLEAN:6*P6F<+"R ,/Q^'W2(C2"4N:$+N"@[B0F_+;Y28:,L"\H)I? -M]ET;B_7,YQVOL91TGE%:FU+K^>YOUE.?D_ %LY/^FTQ3FLW_J39\\EX4S**Z -MF:(&]MGKP/?5Q=C*G*B76&C=IEL:HL(NFB?AJ51RJQKO5C!)O '7T_?@[\*B -MCKR<0UQOBV"F \OL?)D/Y1:#Q/W.@]X.O9)7B4B0+MYR=1DYL)P\??[<[2 -MRU*47U>'#*6@O&5B$?I\V+^3H%=:4K9:GX0!5CCZ\_X/:S9<@:^&5I-PM_O9 -MBERO2_; 1PY?A(,/AJMKG?DG,?]^U"?3XY)5$*S/BOF!IC.XR,C0(J+DR\"< -MQ[(UDU>'AZGX(%:7YSYCYN;>SQ"0B]TV 8NHP0[ \_&6(ATF79>O 3#SKL9O -MSYJ;M/$>]UG^L%Y;&?KS')ZQMJ^FM)):AD87"JOC+/H+,D>4$9J?DUW&4HHG -MX#3:-\F-J0>LSC -ME\";IG1["//YML:23[M=KU5ZSN\6"&6VLR$,Z O'!\S9$"*V>YL C:J=K^=5G>?]\E6\S!0\Y2?DEV" PDYEM?E]CS]_#7391&JIG+ -M4E^5'<<4+3+N;O*.@ER>%(V^@I./NHG$Q,S5P/!'M]P=B_^!;SA63Q+K^3OE -MO\\^EIT?2I:/&DFF#[C!#,"G^\_^Q39JNERS6Y:;@Y^QAE>9__B;_=IK49CS -MK821OX*1 O;1F)&1O7*0F%# T^3"=L"C'8@)M8:S4M/&>YK:R0_!CIB;E7*@ -MJ;:ZD'L(U#EZ1L,1F2:@2UJ-6$WPC$CJ_3KURHN_AJNL1Y)&$HSRPM2ZUBS' -M#I2(3L=:;XUFXC -M.HNR(@->1T^:D(JBY_62- -#6C@!EIM/E:6*23IM?]>20:D&#>F,AI2[#$9^ -MZ,_@^,4#X ]V48P6EX\8H 9:Q_1#-/+N#P*-A8**1D">5BF&@0D"B<\##JW9 -M-=BN!+M65;CYDJ&.ET<^*$X.>LK.*'ZBB+2#*T(95U%2=#(&:@+*@>_,T.?;0(+!+%$&;K&J/CY#* -MHM+QTI(/1_ [O9Q(A)):NL#$^1)GYL6,GK&,5H>/:Q!>6SV/2725PU=[ U>MOEX]2N/^BCG(,M%:DSM'B^X);Q]:]F"RRDI>KL()C -MIE<#,KVWF^XB_[*7KH+QKE?E:X-ACY:1]+ZW6+/9(L7G[+_S"K*FG,>\G'*6 -M<#G'W<>05).VA)^%KE."EACQ/N;UQ"?;O5^P"5@;OY!35='"=O746TJ5E+%3 -MA_;F(" 6>WO#^1'T'((FMD6&\.WL_3B..1& -MQU:MGF&KFDM\3[*GR3+G\!K!8)9F*9F3?9J;O_&S[.6UQ -?5X> C-N>HJV. -M6/' I0"3T>96:O[58O*>HJEN5I)[!OD:2=N G'!!>=(*9KXW5Z0,0CM!SE4^9OI,*]\,Z -M=&?/AG&4G?69 %>QM_O7'JO;K?R^O:;97JFL'?L-T.$_^B+P2:>&.1/95X>B -MH%GT./;BZ9?;OV-D<)]E#M3YRU$YBY61 -M[$^.F)BAI(MQU/4WY_32HH^[VJ/; -MJ:-R_Z4 1;EVI#V&6.S_92M2&V;I'9*R-S!T,;VTYU>K,1)EI];N$>3))'5 -M$!3[\+TLFW*6I:B<0:.20N?B3@\K!F6OT^L/J8B#MX]+>,2/./%T.ZN -M6*1Q'I&^FL?<]M"?H)1WMH&:OUG^_)?F]<"=@#9>II%+^JRFOL46PY;^O<&- -M3I>;O6I:&_<3[=+FPQ"#A$KXEDN;E_&*&SIU^C7/$[:&>YPG)GH.EQEO,Y,$?POKPG-9QO(Z)UXNHPMKC -MK***N194FK<"Z#/ZW^;;K8N7K/>7XKM^^?F -MWB$269JXK1.14E;Q <#^9I+2:U*,AE^;FY)7@L?:PM,>^FS2O_"8A)^^/KF0 -M4AE#1<_(]=5T3(Y_KY2O60O(M%^9M-D2)U*!-/;RT)+C-?(;L9%2L-*;AS^4 -M=8?:P_E[YA6;=+3_$BC=C8#J31.19G#028S_OXY"N%RHI)0+0MZ7XMAS=_\^L;%;Q)( -M>IRG5Y>5O@3CDS[F/I""D%6*CMR52JSUEMD<1OT5V1Q&O[F4:7Z6BZ#RDM/B -M\3;RU\"2GBB3K%YOMYJLGI_-5@OO^0C$4D-7!@T8CUEI.#DT_>BKQ,\.S2 -MNCO6B;JMA>]R:X*J6DT(S\O3]L\1S[11J!:+X8-@1/W3\O/0+OK7 QZ>H9*$ -MSJFGH*>=#5?HP$:CY_]@JA,C992@Y>MV_#PY_ EVU06<+E?E8)3!WVE -M *W3H-"F2KI;9]'YOU -MQOH*UJM.1D.)C01P2.B-_M?FY<,^AFA0JZL&MJ<4<<34T#?6(QE2VFCOAFZ -ML(W]+?H,[UR@Y)>$C8J_FXNGP9I(TQ;WT[ L#Y&8G-JJI(B>T^!6^-'"49\K -MS(KE18J5D2$#CH,(LF!=PU'>U,+:]<-4$YN\D@$"EPS*T[65B8N4AAFJ&1?K -M[)?RP@MY]I:MCZ% DJ&,DJ?)SM*%G(.;F@*^5L)?U^5[T2?&SU1*G^V;@X>] -MU9;%P7)C>CHE2)9!NP&'6YO3*O$S_6XU^O+"A'Y 0JI;:4765Q',R0\' U6' -MEH6437W%1J"6K0=I[7OW]L-*CH2*WE(+F?&H5E*:[M *^(?1Q0B+5)Z@G!:[ -MNH)@7%^A4!6^)B+G** +E-")N9K+!M+DK_K+W7!0@H_G]C3P\K(%_Y&>L?+% -M4[T-NH+EZ440G)12*QH9FIJ5CK<5\O?W\\#)CY:A^U.-J%"EC,#Z-MSR6(>6 -MI:U6RUJ2 X_ UM$F-/?SAQZ,+>^S6@R#J&$;)APO!9DNOKW"?CJNJ6[JEW>CY^77P, "X49I;IZ"3BL#% -M)O11HDN$Q*5:K\+2K?#&QMM<5(.8LB&V2X9PJ2G_ZU&?H(&>GY._@J)/F8+ -M[3HW\N"ZC\&8\8]=OX.^(>'%GJ:A0!DC\^8WU\-71CC825X! -M*J8 D,3J>,7NSMQ)C\Z,'+X50)0WBN^+G*(DJ5VW@H/!V2.)CG 8"L0#T^P,:N+ -MAZ17B<"KM=8N*(G7H/NN37^"7Z#8\<,Z,'K*@XY=X(M22T>26K:CP-7?WI,8 -MBS>L'&FH;4\FLM-,WC?$/!?S!UAVDK86KU>#D*:QR,=J]+,)4PI(6"ZZ1\YFZ2(NHJ' -MF).=8Y>:R.+:P8^;D;ZPD5)W!8RXT/;Q)O;U0ZE>.%S]]!NI^Z&]DRQ -M=IJZBH&B#(W)@@7+QJY;ZT.[MZE;"*)=7Z+CUDNM(N?^P-3BA" 6NQITMBT* -MBO"+_B*0'8R'G'O@]O3N>OKS3$G2^0^(NE<#GGK#S\M02D/Q_W:4RGNBMXG! -M,C#V[%#EPY1F0UKKGJ;?3B7W]?0UD6-WIJN;AQ[%F*7A]#Z:\._5BY><3*O[ -MG3NMEDL- <;HR\?PEH!<5,3RGK^UH(M13\M"4&KJ8@I[[\6/!\^0GF%O[MH.2 -MB+WPLL#W]_4P-!L:D$Q=NX=6!KM!T=XY.G#OVIF:K(V#!ZD9N%K#PQWDR-[% -MY ^F#$SLM[MJN%ZHP4/TYA8P6LB_EK*"?E*:"^@PEV36 G4*_[GW-8 -MCY."H[G4^$BKB, -M5P#4V=/E[E.#>'M56@"Y5X*J@7(/PTF<6 -M[N6FC NQN/>0^9[$PJ75WJ6>65J=BA$A:[E3T/W%6EB G9>5JECAC%?!_0]) -M\* ZA9:AFD*!GYO8\O;V<]K0FI:4B*NY5I1'C%#V=3:V Y*[DML*N)>4DVH( -M].W&-,;PCU8)[9J%Z[BAUBW*S.L%3R+8EW:=C$M5A)"I^I[ NN$0XOK'S;^+ -MH:HFYJNQPEK#$L9)Q*OL!P\VAK);4*Z@K_;1H8X?<,/3.C_@(X1V?H>ZD+J3 -ME2IA^,:IRG\JP'GK;:Y!"#7FQ LY/=EEZ64O(]W^62SX^V>&W/ -M6XV I%^IX,:)R4]#FF,?J8Q##:4T1.FJW"+);'V]R*D$:K -MNJ:6\)<(D_GWQ'XBIIKBB1:=.O(0JJC$)-_V9D^GED3EC(9?3<"0O]G_J,D5 -M6]8I1@^-AYB.B[F0?77^"$HT<:+_=&' -M?@Y+G['&GXD*F<'W]<8*O)""B1X'DIO"_]J9S-02F[>BFA#C\O,_[N;)7[R2 -M'02(GHJFE[K(P_#=J$B;JZ8E>_M,%_T16_#"?O(FL1(FT<%+)S=;+(=B63WN.CXF:F;F0 -M5HL2N^3F)?S(DP>$IK>WDI8@99^;Q>QYT\'_C<\":7^9PRF6NX)0A* )\<#W -M1G'. -M03CN]L8W\X=>7#VO5:UOS .:S-P.S>O'X@J&1-1&CI2;,/#ZS/8M[AW^!Z], -M%5,;\JZV7B , QD(J,>*K#?><\)*;DI 4NO?B>>#WV]5-ED914*'Z -M"\SNP_91D]&-IEU:D\/6N-65_L\=O88?4]2:7;"0EW$'04F9D,I$IYTJ6_AV -M@PW &4?ORV2-6BR:DJJ*IM*IX=0LWI)/ Y*DDHI8BEN53?$Q_Q8N5\6LFE&Z -MAUH%4T9-S2' ZP#2AM"?SYV?BPMEGN%T3S%JO%I>IMHO: -MPX'$V'S)\]P;FK2%EZ9-ED.@6EOB]C]^W_Y!=8F*CO67OG/A(],5K]A*5))3 -M7X.)*B#N0!*+,!S;G*1QEY*CW#U)_X+<&-"6/(ZE_X%[EIW2T?ST=\/+A_PU -MU_N(OH^E;,&X93+0(PN4H9U!FWQVD4QEXY;5YO*!E[I0"9S^H2C!I9+2S(TI -MZ_'+KH2LOX:/O*J4$%/Q,><:WC7' SA0BKHW[KN"#):=T5[!XNH-S:[8D5Z% -M0YN60IBBK8^;I?;DQ=3OHZV6&'B:HJN=$_ZC&;&:4?R7^).1PI(L_>;$*5BQ -MF_"%\5J7::6^@7SQPIQ1HIZ.B/);\HZ9#/#@^A^GUKB'PI] CXN?ATX(PM5& -M-_.Y3A 76X?XU9>7T,'E+9HD"I]4#X'IEXWMQ89]PLP!Q5U%V[NPF!6-/D[- -MJ >8S9(Y,#J[Y6&(3-> GDN;FJP/N>+B"-[1W*7;=(AKLJOI9WJ/7_ -M[3?N%\^>E*>KFDB#D2W4RN"5D'Z,FM"9T,%^P<7$/E,?EEY>FA&(NN&V6Q3# -MP-NX64[FD0H/D^=?PS]!"AFJ/J-M2EE.X4.)LM!7#6Z:ZCZF0K%;7 -M:M+"+5/U]]57''F5BQ>=2[I^KRB**P_CQ]SNM%H-F1:EH(@WJT+P)NX6[/61 -M?:T1 "*"BX)IA*O P_H!Z^A= ]1(F@L@VD:K@@2!AIK'PD7[U]/CM=PCE=*7 -M I<9QO,54R@DBCB1Y'E^4]D'? WJ>9=IJF -MM9TKE^/N-_*;HI.@4H&/N)9)E$/S^,9V!]E08%&SBKW.G^_%T,5_\L/V@U1Z -M:FU&:VF@I+_3^-:OWO/9GU>6KHJ=CQJV_XE2\?F:U\8GXYK.OZARJH)0K Z> -MZ1@M]/Q_S.,3RYZ?MT*ZJ)J2IG")\Y \]O8T 4>\0I66D*B!P4TCT9GX4I". -M49H)V.+T_Y VP)2QDX^6<9Y0DHR=V>?/^:PCE%L0\:GY1!^# L#35A?BLDJ, -M-E/9NI)4'[R-ZM,7N]6? NC_6ZM.)J"_\.@1-_!NYHU/F=6;6%6[(Y>3R_[) -M+0L32@R&6KA#7 5*I%I!*/B3N]KMTXN.6P";CD&:0&RRN^S\V,;("A^CX:N- -MGH&*6H;^D('^7UDQ^4;%Q-NZ2%^6AE*?^L+_#[8&B9:[$'<*N -M_I &V5;(&=.9LI>3KZ4?\304]B>*ICWNOL:N@Y*GK5B,#H3! +0Y39Q.29H; -MBZ&7U^[U'"W>!M#+J#V74Z(;&%.@5OT! -M]"5N1B;BG*!QL3)S@8G#6L,:1Z&+C573EINHXFSWP-> K)*7D:9=2XM@!JC3 -M%P+ESI3T!O9\BIBF6@/-_NUN\"71BPY$]IZ-TA11J!":_)8UVU*^)I>2DP^/ -MH(^-*;SL[; #2869B$6'G;ESFHKPU FM!L/EA7>_P#F:P8^X%?DAXFSZQ>_U -MJ0Z(EKBZ@4NAH%>3".SIALF):P-"H[ROMUIR ZX?DG>"C>K6Q_ILP-_\N@Z% -MI8*ZS=G1UEP1LG:U\*F*S?G&YM(OVKI=MJM[MXG[>)>"T<\@M'Q6DY^46?#Q -M((*HP78W=C?/X$K=Z8/\CH7<%:C%(#/']L6Y>^Y\4&>KT]M26)\S6 -MCXP_+>^M+*:? ^K/$,%8\,*T18^+?HNK@IVZV6@5)\?@((QQ"0($FO -M5H-9D\W^->;U^]5<=O.=1HJ*F*@, _#,UU&_MI&;<'%7F+A>J]4R?; _HMP/ -MI&)"D[J&P%75PN+_[]+6D[7SDU:M59*:O\?$/T;Z)B:.FE2,EXALDRQ4N]C -MUH55#V OCE@4AIP/2*/;_V$0U/Y YL5*F];95Y"]G+.REILBABFBZ?G-PYV( -MK+V F):;7K>@7@O!8D:R[M)GO)*TG(^8BJU!!-O@4/9R_I90UD,G,_,_]^Y& -MD<@+E7+0@=V$A:_K+2\;D=Q4F170BA>[L%GPZGG;[@*6OP>,2*A*A+7>B 'Q -M^,?0 \]6H"J1BIH<0X[T^C:U[/7#1:1VR>/_G;O$G?_(B$]:Z\76B9Q*G$>& -MNY"[IH-U<'FTPD3.ZT>LH-&PQ[I3K(VWP>KZ"L>M_//3D7+57YY>F)HVIE6K -M0O#4]C3EX71TI%$&H[(MD-;;V+FXWE^PT5(ID/INVC)6H*V(?[M6FIF2N!XK -MQ8DI:-B:RI,\;%E_*''8!=5NN2 -M&O\!Q\ W/L>OSHO]D.V-3KZG,/ S"0[>H\OE$%Z?AYR'K$R#,[!XD>G5-#IF -MSQ":A0B,=>J6,[JCF0-*_/4H M_RP9%'C<.,I$:P0OA0BP*D]?XZ.Z:7\!*? -M4@F;JT+OPOR0D+"YMY&L>M?_[,>L=J*P")Z?=H&IDZ8U^^/%X4C\5J*HMG>H -M6*V,347V7)?_YU"=5G*9M@E_EY"\X4'Y.F[78H>0^HAM&J>#+S7!^",7D"\#!VQI)S@^EEUH4FX6'MP$4$SH>E\*[EI674G*XDY8L -M%YT(Q='2QBGJ#U&Z])]>L\:JG+ZLAIOS-CD^-# #F$&P'J" JYN'+0&P.G(* -MFUI94ZCQU/GPX"^#]YA?G/J")PM?G/:]^?9IHY*5^FNE5.&C[K! -MP'U2RR+8XQ:4Z)RR%-BDD%$H\O;%Y?8 JS*=TKF5Y[H>H$8 \0X$2OC+ .76 -MDJZONUKZ2]Q:;81XB>+%0/OR<:Z4AE$2U]J]\*W1BH9)B?T:6)>"Y_OU]?H^ -MUY>A@IU?DI)8ECV[S>L'29&PD)U:HP.;:/:= 7YS?C3OUKM/L%U2'0Y6(0K8 -MP!'D]^>;H&R:ELM?A(- 09^L\C 0VT,0C(KM7^2Y089+]/KNR.=:V$V41DJK -M3;ZYJI29\RO1]K*T0J^>'4#7GXV2DX"&F6<'[,7JK[);=EUV=V&D -MD^C' +)<"%^9#KU#N)*$2-$^9/8^)I!"C$!^F@ZY&-1?00JBWZ-7?GP.V0I%:0AJWP\HG ]#;Z]!): -MGK2'[:_8;-]L]X+8W.'JI\$)AI_>X%Z>K:JYL(,*]^W$V_7PS9*57ZI64)R^ -M,_6N]0+ITOZ'XL$QG8@>M7GTBU9&B*6S8*K&QM#GY7J+H)6F4I/SS,M2X?V( -M.H6UTT#S"1[4QCI]PP0R6_R>5UZXY9Q*]R+2U86BNE6,D8G#>*3]X\+Q_^X% -M$D+R(%/QQKA3GTP PC7V']*)5[.^FH*L3Z&< >+VT/;%B,>-G)Q/CHF-D(V_ -MP/S$S5S VZ_:F$B'TA[J[!?_$_?]PNXTSXJ,51]^!A-RE'(0<.W-Q!;.R\/" -MU$;:!:&7HHU>D\&:NP#S[S8R/>:X@Y^\E%BZGLD-HQ)0E).TP%R6"N?P-9WV -M\@%=D9J-=I*KEY;<7TC/ZH6%G!.,L)":FS > O?R)?;GVLIH]:.#FBV*\+%- -MK3+%DL8!0(>@&];FTX)2E@V6Q-;VE@.6FK:$H'(54W'&MB7D%0: -MZ9R!.L"F"QD2T]?0]"6O"(4UJ@^/0Z1%E9=Q&"A.TLI"6\!+7<6CFG^(D]ZY -MCM+!,>SNOA037(JD?50#O%DMPUNT#(*:$9_53KU%D&;BE:W/79F)K9V$@KBQ -MI)C([VO*=8F6E)H)7JB@A:M(^=DUK\/\3\3$F+N*GX!S'Z7VE1KSVYJ7I B" -M T2$,Z !WD&O]):BB7*$GIZZ#+K&FO?11>WJW=$9BJ7]BD,]ELJYCI*B\Z'Z -ME^7 IU(P0T>K!8ASI_SV8G0;I_+9)BP2!YCP -MD9":$0.(PRK#"9I4@!^.F8+3#70Y,#SZ2KIP6OBU]XB#:;>#!\U%/"^B I2B -M7+*]0):3V?+')G;%&HN%D+U:B(>:DT_9DO4[_ .&FGJ"FI/ZII68U\*L[B[O -MX8=%G[Y4OXNM1C>9)\P$S4OKG!>.E$0\OX22EK*0T.JPD3]?+V+G&X0_>=7IERJ,'?S^"5 -MB!X=A)D%)4M!-3K:.V6Q$)BN @_9SFB[1D/%P,F_:G8J;KYYWJYO1+L_6AZ&V!9."O$-SZ_7& -ML#)"A+&BKYW7?JB3GX]PW=#B7IQ2O( WUYE(LI+AZ\;^==D(JI;AUP(GEGI? -MJ-GT-3>2YTM0^)-[NUPR]I7LZF-F.D:G@Q8NK(*8J\^DO9+,U:L?)O+6NU^6 -MC(<854> #'K!WB[Z-"[BO9B>@SN$DUJFLD2J]_P*)T;2R?;)TH>8@(&0@WI* -M29* S93'5?_T6ZW<5(W?\JN7$8;NX8BV/JE679IXS3)4_<#VCK^D4GR/B8*= -MI9""Y,.EU%^ ]JV. JJJJEY102O?$,7IUCF.N+.^BIB2_[Z'_K;'YHJ=O_A6 -MN9*6=]"\R/'Y;AO$TS\4>DQ9C8U&L#JK@LK\R43S$\] %F@7NKR=0X:SQ\(P -MD#?%K[J<>(%:IXM>"Z&6JZH #J^#NT]2_B)8% -M==SZ@L9?NO>[U>;6Q=2 EZ&ZNH:'GE%, NHU\)X(Y]*2-PF*]EJ11>7R=3?5 -M\,-OE[V=EJYAB6"DN2S*CL%&U1Q?IX?!C*P-2Z&5_\%ZM-;EYD$9N/R1C%R3 -MJYF3IK;8POS1!@J+S_9C?+V;@9N2J'.20YT@YL;V?O8BF+96&9I=&G\55PMF -MA(B3D)>8J[,-]#UT']?.NJ**1[:*LOZT1X,!6<#6C)!>1*0=RD%@FO_:^^;G -M]<+VS="MLO*OCOH I:/R,1?N0XJRI$E+GIZ5FX##/GGVX-#'3X:$/(FLSH>Y -MDC_+ 8Z3SLNV382'BKM,2;MSCE^-<>'BF^?CU>"T#B; -MDL&DD,JS].[2YB&T4G);AAR#J4WCBT6828H%D$JH?W&6],?W]@N>B9.1-X"" -MD+0V4LD#KL#^$ JLH_T;F6RV0N*:]71FKO!GGJ K7$*3IA6DQ]Y6DM?50J:6 -M>]ZM6EZ:G&N4)T=^$ %JKA 10+7ER/YJR\AKFB5P'" -M]II0K *3WDVSK)2IC(.AAIW9Z'HA@X7^P)F3GJM;J ^;_%*DGJT!$'&6^C6% -ME'04J=ZS_ZC@S/"3VHO[KYN(^9[2U/74NM!'^*/2A-I7@EZ"IGOA^0[=WZ8Q -MK=ZQ0EVAI9_A(KG /J"?GIVMOIB S@-8XC,VFN8*KYH$B[F$ -M@MATJ:>HV-7KURX2_J+42\AY\MNPGKN*N).W3<;!;_/WPHFQFGW4L7Z7PJM; -M3Q+8[!;!S[S -M[?8%-HB/D%J#CY00N(6@X!$W]>]+592I5HB'GZ-8$_XU%CI_P,T>?YB7L@EH -MJ W6R0_NVO3U&<*6A[_75>V+HI>;\_[U\#9&X(B^G:""=M#>TJ $6(T-RXJJ -MR\%!F*O^F5&[OD&80LIV8E]3#Y].1D$&M5:?^LT?J -M)SK%L]JNAE^0LA=[NTV&DL<,RM:\T%.-4%RSJ7A'JJC!M?3'RQ.+5J!7";BK -MOI,\P7+U]/?+B\:@@)Q''J23C.6S]2_N]N4>M;S,3YR$@SBRB,'5Q(3U ,&) -MEE^!EYY+4,9^@(CT]V;U]@.M7HUSB)^*LE'!IIW0PO@G RP_(D72$I:N7F1FQH8Z):?[YU#K^ -M IQ3T[E&43.1PHL'T[CP6AZ 0O:0\,;%0KOV HB((927D7RMPMN2Q://M'HV -M%+BD01H]MI8.P?OMQCX#YDJ6K*JHN5^>=X^%*FRR[\5#5B1:NJC\OO4*67OQ -M1Y)RH)Z@1\"&FYZHS%*:]]W/R-_Q,)?R.M2_'8F-+)!8R)O$U_HFVUF.L??9 -M_NM#F9#W^(E&:N7&>M[G5D<$^WM^5A**"I2-F.$PQJ_^%=*L4Y_[5O2^0O+[ -M!V94PS(S8/K:C79DGJJ3J(^5K=KSRRB_\#V-.77W@5M1ICUEH2=*HJHC_J@R@A% -M2%&M\N)M7X6+6(_/?$*B]X+K:J:VML0:^I"PGI(0FH/ JL58?8B7G195+ZK- -M\>W@^CWCE;P1\5>PFJO@IEL#*V?;D9/47T:=EE= 5%W9TMU<$Z;V6- A@IJ" -MDA7RBG$R_336B,. 8)*#V1N&!:P!PO3ZU?(2O[Z<5\KX[5,ACIW*S=?Y7=J8 -MBQ>,[ZD5CHJH3ZK1,\3S\% #1])&9SXIUW3,ZA+W]CXP)52\VJN5 -MB/;SP%.+!=T#286<-E4]B;F)1O"/I_0M/C_#";J&)*FR"+6@(*?E>=-P5L.* -MI[F*_D"6EJ*4V//D\#;_\HR&5^#/Q$$)Z/?3.:JLA(*V,I"*@ZQ=U\,Z,2[M -MVJ:<$%).IO";LL?\RN"%HZ(=18"[@=J2Q)7P1>54MHJVAB":G_I:"PSM#]&* -MG%&[]J>2F:R.2UO^$78OTK@/AY/#>@*2%;J]Y?F5(."@BPX@>HH[+":BE=K@ -M.;0VYO5FGAI,9KB) ZP]JT7.%2CO@]1&MEV 'Q6,B,*Z_P+FE_OR) <-A?M* -MV@Q;DXI&%:O9!, E+@K* P*;>E"2C%O/JDHIFH$A_F3$Q;_&E+#+L:60K'D9 -M*\_D7HBB]7"A?(K7%[SRQ^Q+<;"3^3!;>@\AEI,;#\7P7[!+G7:;0G]LGJN1 -M^I>OP,5<2;9P HB*C]1!3=#RQ>P0 ,MUDD":0W[P@Z'!<>TF[F7+KZ)059]% -MG*DAFYL*W LA%L4^( -M)LH(#HG("H?=@:R>F4""N+>31-+LUA#MY5!85%&02(H#P<*O\9F+H=26F8(" -M\O+Y]BZET=>0E%VTUUA:H/*6VP,*V%2;WI&5V('_0*:JX1*=[Y9B^ K7D%B6 -MJ)H&5:GPT#"0.H"=0*9>D(MR&_.\\L)%-N[MSXT$""J&ADE+,II7 ,[[!*7: -M\LRWF@9/K;FG.;(O*1+EQG;@P6FJCIE*A8V\0::'FT$#JA?1CBLNVKL._55: -MGFJ GI/0>/';N47D8-'5M(J=!=&V?\W9PM.=AK*[U9""K\UB;/3 +\*$6!'\ -MFD&"KKFD5LT% -)_D)@&MA2OQ@*ZD$>7B89-TJR:&QD.?Q'+RO&'=':-B7V%7KI7 -MFR?3[\06/MNYFM"#.)^1B98PFO\E!^[A+@O$]WQ"KHF? B>+J8+#E)[,TOG -M=9/!6 &25I"Q7/T91,'!A;!;N9!;BG+8\_/V0C$^8 ;JV6YO8\G[2/?[!BIB= -M2)J<:ZF7[(Y[P\:IP\S-Z\,!ZHNQBI[&"8RAIE*^Y[CY;CYRCTI1@JR7@+XI -MP8VB]EJ+AJVR1/JW#;;'-]KURX>E^85:5YY8P!:74,M3580 DY\WE5>)<%:_ -M()Y=GNV"UEJ08X-;C9A:N(1(Z]$>)@'/6XB:W$B,L[&, >HYD!#DP5>5K*&I -MFX5JHYY[",0&VM[ FX6D#$&)5YR+$;N8@[&7+]8[PH=]MU$:=&>Z7C1:G2?+ -MZ:\*S^_OX$B5K94<6J]<-( 6 L>K[/00[,56 ";4J"^J\3,X0A4"G9=CG"_ -M@ZE8W78@+L??\%3TDI*:5S*T00+YT=:=HJ*579FKEJ 7M\ -MRM&KGG:EI9(!JR('J\>V.=Y4K<]+E_:?7%7"D[>HDOD+S]C7!LL0\P&(JYRQ -M^E92J+)CH C8\C%_QBX(G$A3\;*!7EK PJ'D+H9^6;"(^D'AWO:B,/K@M+:> -MCUH509.0?ZMBSZ?$6%R:?H^7NAZKMZT4].;>)-KE -MQ8JGJ8W9B(V0Q:H JD5$QA_/3([$%%2M@9*L) -3)@9N0 -MFECQ,?7OT/W"DU71$I.:NUP+L]:7TPV!ZL'+BPOQJX7=FI:T1ZJ4@-Y7:1OG -M\# 663R"DYU0=;J=QX]S/9 (,G7 <7F[<2HVYG9OZKKVH%[P2Y97H'!"YPRC -MV%P001;^O>$&YIIZ9P4#)!=70V8^#C$&NB*R'HY36QV'LU=WWT]*< -MK8>NGJG8^>&GBQC=G)'#K]^NV%N8&;::E::"GI&.>L'JXS?MP-"^$(N5CE%2 -MJ-'#H+&^<(I;@A%_C>?4UMOMU\>?LE1Q=I.NUZ1.*Q/.K_A=N%I_CI6)J4.< -MB/$J9:#G ZS3\T0N4:5^\5E_%7N -M29. DTR0>\35Z_K%!<@/GDQ%S*_%7J"@%^%ITQ8F[N-0LKV@EH^(V)"3E$"M -M"JP+XP''QT/O#G^?2OZ-FI[H!AW9$A'WOE0/+D:QG5?36D/%70/)O8A>K9Q1 -M6:[C*]#PYCY1F%":4;Y5>Y=@FXMQ:H];A\B"4+11G%U!EX'%-O4R/O#82)HP -MG5.]^(6%Q<+P[/(L&U-:D$M^:I:7HI0E.F5MD\;+9J.>6$.>[,?LFJO-SBS/ -M ^'' =\GD%^>7=6ZQ+MZBZ& 4L?V -M/,;2YF".O9^5^C58_H4*[MR0&?J/MX>?^P5 Y.)#\@?%DXN$II*OJ/BV4-C# -MP=)>@J)%&Y+ZJJQ:4?*K\^8UIO&K6CB_%Y&^I:-,0_1TT.WU4J9H0UZ3WY:3 -M;<3IV.S [\.ZH+B8Z:R]DZ6.N(NGSHDD\>9LWYJ 3RBOKTQ:6(KZUJ(P9 J3 -ME'];@?"C@[BH#GL!'<#!X>N@*_9C1I<75\?HC%.RM;O#/YW4T^R@G!N0B3*= -M6%=QXT_#_(*!G1ZTDKM8GA4^)? *_!&@DK+[3^CRE93F6UF:J)<9KOA3GT#3_I&:]Y3NGU". -M1==>0)BL!:[9S?O,U]+0AY>42(*%C8Q-JK -MX2S%YO71$:=2#OI="ZG>BIS0I:>30/(G$&_F*-85D)WUM9J#26_"XM>2/[R: -MD1^?P_.C=9*SPTRPBHTE_5F788Z)UP_*R# 448R5D).:LGY"Y/OU+F[NT>N/ -MJ!T#N890DIA+$N,_Y!NBE ?FU+"U6>D[O"XB(I1=;%3EZT,XPNWL9Z[4L.J]\S7UQ+$.X=] -MG!>^E:4;J,0G@=*NP-&=M;2-5;>V_Z:BCNTSU]3Z&MR.IGFNS!,J-J-$P>0Q -M^_Z3&Y>M@HA)JX23+\36X2;Z]_"NEEB(BQZA2H::/^G]S,KG(=1LC$2_E+B4 -MD*W;K=DW]-;']O-MA?N?JD1+G':3@%;8PM##XOE8[]9OB)BCC%^:GHI!D(K! -M.^?%[\)RV8:>D(V1<@-0R0+:_-0&U)I35@''(\3F$"_;JHAP6)^1"8-B=_F- -M6J,2!;:@NS>AG)UFE@,-^_G\E^_)F Y'UN,:_586&[F.(3TV? -MES_%EC4@-! /.O2IA9V;C8LD#K?HR*S/\?+ "[N,C$Z25)UR>IC!P-CV\'78 -MBI@EZ, 6,+U/O8R)TRD -MGX2/-YWHNZ:=4\PLWXKBT8F7O$ /KY43:+23@-[%;^Y:6H"6]K[3ODMR7D&F -M&\&H"NZA38[#R)E648B9EIVN%ZB/C\'^Q_)SY_$ND*![CX-<6RS/!4*>UIZ% -ME:">GIB3E-9_QHOY?J^!WVZ -MGC""J!C8EE]%A>/%_[;;B5YL6)N'FY92@*CQN7?Z\D;7%Y =HOX B,;/K^T -MU (!\P/.MA7L5?KLN*Q5NLCYYIY +87"EZNPV[:);NAN@SY<#PBT[[=:!4!6AO(81VBG'#O$V>I&QD8Y16H/PX.%%U[;7 -M][:^!9JCG(J@7XK'')/F5=#0"521JENHL%[''O4N5M#P.H[@$I:#]&J;JFE9OQ#M8#].$23WYX5&^> -MO^BLD@O,LNS3[]9W3_Z?2YN>6?ZZJ!8I6:9YQ0ZFJ0[<$TR,L9^2D7):;"13 -M25#VE_ON\)6)H(D0BJF3 M2CPH0+DZMR18*)]W#FEO7MT4J!@964(JJ=^8^X -MH)IZ?C^1,KJS)["6;&NW/XO;:T*^0GF"?K&&3LI1:PN2UE]8R -MTIV-K5Z7MZTKMC'46MGZ$-7)0JO6\IM:F3BIQKBJ=/OV3\'BE/X^U-N<"%ZW -M2OA45R==D(#T"Z(Q%CN6 -MN99V0]FR=J_M\UP FB9:FKJ'O8M H/Z=]<+%480V+WJ-FI"0[,%I]K/T=>., -MDM_HEWQ9B3JZ#4T%_(XA!3 7LIJ!C+CAJ+@&J8WJD1)21:<(N]4BD):*GD*$ -M>X,!SY#?P1;2P].#4JMRG(Z+C+^YG]E(\NT>D"W;3"&2A(8)D__RQ0/(BG61 -MFU^7&9C@\_CR\'"KW[:3A(13L[JEMGK,@]K$FEF4N;I14?JDGGU$\/D^>]?+ -MJH^VNPQM?X8?)N=^126O@-#62'^+GYA6LT_9=!$^-G[UO7()G(*.7NJL5IK! -M#HPMKL/1[HX%O!R2+8JL$%L#U//V;:Q+O08K5II6BOZB1I 7VLY-]P'GKN#0 -M*9)1,K:.4MNV+ Z6Q2OT\&80V_VCLEZUB)ROB-W2X89SN'M0$:NS&S/M]^?T -M+Y63@YU?@5B*JEVKV/]'7%&\4KU66JH#JA>#I^O6L/330$\5L=.,P[6D2I^D -M\.5F?L*8]K&XOD:'EO/L$NOVUM;LSHZ0?KV$F+R3,L) @MP &G4%0X^:1:B/ -MG\T+ME92P>/Q-L8V08N'](N,^EJJE*9SBR"L0O? #T\*X$-2MYM\=B^R0GCW -MO5#S\=1P,.6LH]0;6Z"KJ4T7HP!,G8FH4JFZ -M@D"6%Y.;DHCR/J)OP./'I:.8FHJ.F_<-\,+U'<8"K8_&FY:' -M4HZ#.HUR5VXR!/@%KJ7YY?TZR&0L7S[N8Z -MW?# '/C']ND_^G4(Q13K?F_DE>'2E:LIYD8P>W5K,0E=-!; -ML;N0GIK+QJ,VA'8"AK>:JE,BEO'F0_OG!_&FL82PG)NVGX+-!_48G';_B5N@ -MNGNJ?YO!>]'O]@,PB]N@ UIOBI;S3!L;\77ZP+L&()?(27)66IH!8?;&EM/* -MAX:L1*NN7IF[C;\2W8#B7L\9OX1QG$-2@*Z1TJO2\C3V$MI)BH91=9XF&QIT -M$%.7S*SX$]S6JX\4POI"7@6^<8*XQWG#'+V@ -M"G%:H5I]'C+J:.J^5BL_U%/?@W\5MAZ(3DY+_AG*J ^O%M]7B"QV3NIV^EZF.H9Z* -MU:G4UJ3K8;NZFJA"B)?-@Y[72/*]4E03T)E*?55:WHJV4GF?@P%"S-=-P]H@ -MF8BN!3*IMXF[D+AT4<<6QR[>4"E_]H*QD(*ZGT<74MA0-/*%3EW#OP'@-9W% -M[<*JE(*%I?2[G[C.5]?OQ1B&N &%7%%:$W %JQ,BR'/:AEY;)!O,3D9!PC*!4@E*%TB=OEKX77%W"O9*RNXNL -MWH':C,[*F$.2NW8"B=^039U2XC\4$/&02I )J_R"F$X*KL3B-\1U\UJ I),P -M/ZY;E4W#%[7_W9>!J[.:C$^5OU,2=/_-3(XNH<5$#(ZIE,V&F4UJAE+7(E3G -M]?_+O9_;BHX&8HFC@!(-]>C\T0'9"AL1IH>-F9:.1UZ)QEN;!2HG\!+^Q9&] -MGE_279I7H6M:X$6(D;"0B*Z7 )KXMG_6 IJ@%)5:H7HZLG(=)4;:G/K4$OO. -M 4)#>E"7&+34^M+8\+BGQ +3PI*.$HY;\O,N.B_:G+B;BF*OM?J'X?(YEY?N -M"X,4G,FYNF%(N#:>H:14 DJ(R(>F6@&"GD"+.'*H\-'M%I9WR)F'AWZ#D$T7 -MMF+0&^+8[/3>%NO#"9"5D?::L&N"FZQ: M'Q^>#R$,-YD:&M4L7ZE_%&VS10 -MH8N>W/21M]-VQ9>UM>/\4DH%#8JK@X1.60=+!THOG/ZTDJ/8OZ);@<<>,.^: -MX]*1L*0;@ZN'GDBDA?#Q[C/3CUIXG7F[5:*SED/[L7?E]--7!86J;Z@%4L.@ -MB<%(WE^BJM1O1%B(0IV^V, =@N$T-O[VUX_MEBZ9%Y:M&!I,5=T"S,!"G$G1 -M\/ 2K$6+3X/MJEN@=[W!\GSB,O 'E)"@#Y!9UZCQQR_RA%Q3V98@OZ\8\>3D -M\) +CY*+KO90J).FIZ_'_<>P3*._GY7#K(*LMYO3,_]5L!KUBT+&$XCCGE"% -M1 SC[/;EYPBF8D*RNMV^BQY"PI4E__YU1Q#:;$Z.2+N#I;[BU]1X!T*TCKR' -MX(NZO6NCEE?-Z]3\VO7S3861F,O4C?N_K,2[I]WX$JS4H,5@31R%EZK2Z,H7 -MDY./TIZ3%COFXPBRD'U0EY"_ Q4 PE 6"D7>E5.]Q\&_U>; Q^CMH[[HIR3 -MJ9J?T<[*])1"E%B6N)X3;9"K43+ETMQ%MN<0,+?<2QAZ7Z" _^SP\@^!IX)? -M*I]E,"U64$ ,CI7)MK"8ZK)E -M5<*OCX\NO5"KMAN*4*N/^*/=R@% OS)X^U3GX".^CB6>J.%^O#J[._>=NJ5 -MG;.=VY"6'O+^X]RLMO1'\J**@M?J1?_ZE8_>&$2MM?=3G89UMT=LJ]*)EA)? -MAA*;@JSWFO<3T7WWQ<92M*F:^XJ&7)+ X^I#M<9#D_!JKQ/'?::@G^&6[700 -M%.*O%X67OQ^KO3@GJ5G=W(YG"N OMX6 O)>!AJR?G?,6'T77_]M)+)"3B[*3 -M-HNPT)LG2-)![ @#P_ !7,2PJ99)4Z+F!H#-Y.TFQ\#;7XNCCUI8D[J- Z;# -MO;83CQN0BIC9XZ42QN?#4%B^&[6EMDNP\(+E5_,0';!+O/J7_'^(4+OEZO$N -M[\4V;49&PZI*C%Z3'ZOK[1HV\XD.NDBKDI^FD(C-_^[ZQ_1.@I67K\LHKKJL -M<$L(JBP+Y/$::XR/E+U?G8MFMA$)$+7P+9XIII)&PY:7NZF7H+: P8I: ^SB -MR^,".Y(I4UR"0_JB8!6NR>/%Q>WV#_RED:Z.L+N7K0[ X+I=@$4"LKG](OXP -M]#3%A5QV<9&F77NHJY[["R3O";@2BZN,L9J;)EI#663U]]+ P"L6H)B6GPCW -MLXS:VL7EK@.+7ZA_DH"NEG\%]^K9U_;RRHUZ5;_/F$N[8EN!B4RMAX2GT9\ -MGD2)6BVZD*:+030QY;(ZYQL,K*-8RGN]FCROVX\\FIG-*_9H2=NPW$ -M??;[M/-#7XZ3BO7/0\NX5)N-'=/'UZ_KQ?:&AIZ:G)7'5O^@VGCI_L5O@?V-^^P1P]>^IVL0]8/GX"A-Y75 -MT& FOJ.07$S(;8MXA9<)+-3.(>#:1590C%5:0+MX]GK!LCGPU_)&TY^%BUFC -MIU^2(9Y]"8[+X=K=Y\#FC_.1=Y["NY'2>:!7V.)!\N_VQ[^CFHW>0JJ= OS. -M\GZ)DYVUH5[RI7KL]\74"KF3MENF=SI^N9*]9?GSR(29T;N7U(NX@IRHX39S -MY="+6I.[D8#V1OA;FV0#%C7%]^.O3FJ[6X>'D)#MB<;3/\601\F:^*RCE)ZO -M:9VI&P_\0ES#R8^4^D#FG8U/H82=0_0TW_;6(T=2U5-:I9&II[I%@L<."Z3L -M^LS/&,==OI,2VA"\5K2[GIFA]>P2VH>,49*%\%V[]M*#]='0DCZ1UXD:>5G" -M%1_&$ ^0(%0;6IVL7Y#0?_#90+C]B?!1C#U8BI664R/R-Q 7DU*;6G"H^^J$ -MNE\-P]/E+,7##IN3ETFHKY.# />>_16N%?5E<+KL%JV)8J"7@NG\P.3#PYF, -MG9YDKJZ DJWWD^3J-9?<_]JHQKD2O(>/7A8LI[?JB/OTJ@W[\=:[MZZ@NB93 -MJ[B 7I>BT.Z6>_3S4+944)2*JA=GZ4=1M!)(GOVPJM<(T.4V+!_;7:#?GU07 -MFLBQAM^I#0,P<:6CR()=>K^0E'OMY#74+L7@S89A][J13G^C/?#PV?+UVY*= -MK%=7FP:,6Y7PTY:^>C?0K72/E+E[OH:XCY+RE9W.UL\23Y95C)J_H*J@FHO1 -MP/<2]]!#.WR6DZ^=V/E#R)RB&E%6H:Z;1<8S;L+'PT1&GER2UT.;+!>*R^L)TII" -M]@2PP9:6K/H+P12TQ00[#RIB\G5]8=HG"=$16EPS^M<60%O.Z<$@]5C";@R%? -MP<.YH!YQO%"KJ(G"7)66E@5Z4X>=#A"+K:.0?]'7<,F$UE"[&Z%V2?&,70TQ -M\3?<\/:.D^V"]I.VI@L,&>/%L.V*N*:X75.-!XZ3G C#]S_UPL,75E6$KU^- -MQK!WRUD$),@+T32#\EY*@X9!27GR4J#>^31NY,B+>@U0@Y"3").IFM+W_^X* -M^ASXE1"2^IV?^Z:KNG*@1%WQP?CT%O3%1;.+D=*1]MOG U4*-)2SW;:1FYL5 -M(G,6]O9CO(.PO9:7VX.FG_=!SR=AF+12O9;QOC_B6I[!Z?'T;]-8CZ80@Y)' -MLEJ2I=#V-)HZSXB7EKB"4W^.F8_8U!DUY!3S:8"\A[R:.)*6A@#!_.W.+]CT -MKXV%J*Z:E1.X&I?7(\3 U9)EAUR8@H!TBPA^D"!S -W('/C5 4,UA[Z-L+*V -M"7[^B+)=\O1YTGXPRPJBOXS\6)./0/D/4GA0GXZ2<9(; >)1)!;$$TR;T F2 -ME9.?J/*7F:GJQ%^AFO%UB5R;;'V_HSXNG:;%"DN]P)N6CYR7DHS"T^W"NO6+ -MDI&=JX]65I5J&M;'+]/ $XZ6F$R/GXV8H+6;P1S.[L[7T(G7JDR#F(V(S9J= -MPQ/%\O2Z][B.7;^L=8-X"&VVE_#*! K5S<[%2:,>_9%:UKE:GZ!TDL'JE>XV -MQ>L,G!F>Q)6ZY=J45@!1IA>+@7IR4\,K[P0% -MH))=CKU6FJ"06W%WQ? VPL#M<"Q#G,N+I$N>S?O9]/O/A].BF9P)AEJA0%D4 -M\W?F9>>\E?F 2[N4BK&5F0KY[.Z!'[UKNJZ64N-D_W-+WY!5GM9V9 -M6H_M&K:XE(NAWOA3S=4OR=6.LA6?TY"JJE+VCZKRO\4@<#8"K%B249H=KE;S -MU\?@68+:ET22R/;%(=4V%M8KKHH>7(;9?+Z05ZK#WL<]J)S+E-!]5[\AE?,, -MZBWV_L\4D)20&[:#1YX2UA'PET8]CZN5H+] DIY;DT3-_CCNL/I#%Z!<;:Z& -MZ4>1DJL2U(;7"?C2 -M"_C\J]C82-QTF_Y2XIX)S!J1!>A%P/8L6_QUHKE6L)H9 -M\=/6FI_&YS>=FX6PG9[#N86]=^G%$ZA1GEV5^KN_M!I*P<+C(]?.U%N-K)O# -M@UJ&]^3"]Z,0I@JO%^2;J)L>3:>OF?(W8_KWP1^VAFKD6NKMD9N >0QY/YV^9.E**VDPF2>?07K,%45@G[D+.>JQK^V^ %W!!17HO87\/")-+OP@%$E@'8 -MD+NL<^*7@TSO!=;PF9.0_J*\6H@:6)'!T_)WCN9ID*Q#6^UXEJ:%R>ID]D3" -MB5N!LH.;7H*RO%GF[,6U[>=-I[Y47I>]IWF@@ W1Q6 R$B+N>/)MFEK;1\>;$+_;S.)YY -M7RB2B+Z*I)N;14W%]MP$P<\6FZN;58O[Z(.+D9"Y*3YU(#?"[H664)&>\*J2 -MQ]3%, Q %IDE]Q.2R. L^O??D*_[PIOPD7J;H->_0(_#RY"$$ZV6D1RS)H7+ -MP?/FT)SO4&N5H'V#KQAVDVK'UAG5^L/ID#F-7+]%]I*J!_+L[_;6\Y:VO.R9 -MG;W+('*"P43=V-W W$F?JI86AY6XQEWZP33U+BRVT,KSFZ>3IHF"4L&R%_'* -M @^JW0P+&(>ZK55V]I*^<0U^Z&?F! MIZ%8.QC\A=Q%G".;IHJ( -M6/+^=*XGQ@:><%9\D%U>K6S0]PM[A3.UEEN.H)&7LTB>6\?RU:_U]5"CE&." -MJ(.?D)*?[<'5+OQSP7+DDQZ-CA8>H"T_MS>S]?&)5I0*OKR%JKB:/2<:_Z_F -MVV.O%IIMK7^MJSB6NL4;[/ PUL,=3=E7"E6]=I&@L('U5L##3,7MXM!;OYR* -MO$20F**-MGK1P?S%L/3%7["T5(V1 9C@QH[6G( 4NU^16%O%-!; /O+6E)Q -M'16Q&[VD3D, J>+@&+!*#YYQY):C%I#V7PL!?GHS\J00H>M2HB06QI219*:P7'X -M]9:6=ZZ9AY2:M:I[ ^DC":I8&]BP)U.+P6NTQ[;OU5RJ&3OC:2II>I)S^3C'.M>!8Q#6HD:AO>HQSOFOL(P6J]& -M!9-8NJ>;G[F6LJ#$T,,$RLP#'>JRA5%ZG(>)ENQ'@Z?!\;WZPAJJE"&OHXN\ -M0R7+0L.LF9.$E]N8F<5PQS+Z[<5=H_1-4A26^9&46,U6VV/Z.@J[A?% ?R"6 -MW1LR,_8VP]F3G[I[B8N?GJ=,0/;UT.#32/>SVY['7?>C $RV7O>+EE95DR* -MIXB^B^@7BM$ #LPBV=Q4L+I/UYB-NHB06PF2.?0F-N*JA(5SNXR-=\9QHDL0 -M@BG'S" 3H;2BUIU36\Q/&A*L$E_!*!W0]_X Q(B:K)8+?[L"CQ,<++">JZ>2 -M@YG+\C_B/.Q%F!:BC5Z(D[F67Y]-#U,3L9.0JWN8J?-@%XB-]M7P)A/R#9N& -MFQF9K%#?O-':;R(WYT]&<-*:DQY=WQ12ZO30%_?JEH^>7+_<3HNX59T#($ . -MW*?DOIKX'H^^U0;,6MOG$O%WY!K"N9;=5;>7BWN!J96RH,_XH^:H^\#\K[V] -M7ZG/BJFV; 73!7+%%\;LR,?4@(>GD7N#PJ/3"8>\BZ]&EY8"U?#M]G8O]X:@ -M]@6:4I.=N' =R:V768IQBY\2"+I(P)K_3=/Y\A8"PX\$;;>^1X2:@8S),\4T -MHV5%DV[C)":B87^SZ;;W8F2O(2^AZ4' -MAO +TNG%_A OVHV6/)#VD&"6H;.UB=FN"&'IS=L%]*V$E=B\IKBNP8&0>,,9 -MU/RZ8 5Z@*.%C@E"B,?[QP&:7+9B,AJ-%V?;LG^#/ PV2G7R-1[3( -M[-%IE77<$,^"FCQ)C9Y+:>R/MP5,ZJCA3_9/3;^,!+NM0I!5D/%K]?JV?]F# -MOY&8K)_+"8F,1EK-K_JOP$CDZO)ME[U>B:>-%D.YAXC'%$;&T#>9D9.*GJ77 -M@HK9%0/CW:(R>W)#EIG)$L;VYJ[1NER?NY;=5JK %9K!"U"24%147+8+F@.5 -MC[GQ=M7G^J4 '0_#W5N8N'*73-C^-Y;Z$P>7K!U!NYV0P4RJX/3R<];3[K2> -M#9N.'4=F<+K8[OJ,]M=<9/JJ5%3-U9J,DEL9\?;%\N^2NYA5BTH635.29%H! -MT(P8!Q[%PJM/$R[0PEYYEAV2!UF?YC2#P/YVFA +$FUZ -MN:J*6]>0EXK'(&SP\G.8G;B9<;J,ME6N&?KY,E R#J*5FFQ%C9N+XZ>K94AN -MS@[8]8>Z3^_CDI2+:9Z:X//6YI8_PP-/ELB,](:IUI/V^,C^:$>!K\7N\$== -MW)&NMH,7RB95TTCSV-:@Q=NV4Y:;GO=(5X'Y3Q&Z&))PEYB>N(X -M5%:>];?06I!$O\/KV-F$%E^%I'*(CHQ$6RO"P3ID\]!(D[A;F;V>ODL-U?'E -M]+_ONW:KDII&NK.9@%DR=Q3&&B*[7Y^\"4?/T;BZVLKZS_Q#"T&<^IJ*C):7 -M4H&V6*#JQI#N\@K-_*^52I)8W@@2?;K)U$FGS,76IG8^=NT7_;PG(V13D+8]&\VQG[K5!B0GO6PN(JJ6AL1 -M+O,!NG8@G1I;5ET@FH'G%C<]YL"P!U:2J?Q+DG>UK!/E$V<3V_ $)#E"$[MQ.?X0]:T2::X@1*L!H+;WBS_MWY//' BVK8,;NOO:59S)).RV\!KND$*"J.NNGM% :9_W-NWOXS]W -MFH /&XRHC:776LX [^JJT[Z&A+WC'I4'*'IRP/+^Y&&!2?E9*>D_G/^PE?\>**@)"_M8B"?WN5J*3$/27"+["[ -MEK:]@8=.L).<22(\Q_X#AUN6?IH0A;*3#,KJ%K?VIL=K5=KL7X8-1R.G@//H -MSZ(&XN/OCZ^NBZV4H( 6TYT%5QL#V)0^%0Z)7E\#.M7_P+N. -MFE0>KYZG2HVRC],"CP,06 /".[2GEAUH-@/LZ!$Z-G'&6I;YJ4 /=::?/-GR -M8S?@\TM&H!^[AU.4@X^A.\SN"M/3O5OP;9V& -MGHMZEK=)0<;Z-_#"C7N>^JKPYYFB8/:+R,( Y*K]RL"YNJB4@WF>1X*VL9"_ -M$V@Y9N7@<*^0EYN/^IFK <\E2'R8HY%6DJF"\=[99.[V UZ 7YU?D8#2LAN] -MPLO%XI;XI![UT/R#D$X3\NO],]0EM;B?DEDKZ)>?E0Q1GCSZU\N2E+F2D&:' -MA9E Y-9M?O;Z0VZ6D>@/G>E(QG:?Q\S Q@?"D9^0$:J&GYR#J9J# _OO[<#R -M&KF'JUM:>KM:GD"05^/"# ?ITL<'' ]WG)-:!ZV?WGF?G0/:Q=96%-M07!I5 -M1AVV*.*?U/;5@Q"?G&!7N8E^MY>4V-8]U_8FNUI&GP*/*Y21;DT2%2WWY<]# -M6ZJZA[_=#6@V@>3WI8 78^)T_*L%9K![I=4HY3 $R;=80!6UWZ9"YDIB0IC(,(ZVUF<_+ -MS P>W\.]A96\3XR.A:F $*[@EG;'K[I:[9B-O<^G 6+IBV(OV@V5*+=(V.; \'SQ@:UWD0)[>(R#V4 U/#_2PZ^@89^:457&"\XB -MTL7VQ]CI7X.96H#>)DKI\3;UE^X^T(FCA(A&FZ^-YDZ7Q50DX]_U$8L4+;V? -M5H'C)/93$I8V]^7Z4.<8B9DIE8U:GGJ.B]%]&?\_KD%\^:5(IQVA>#@:RE -M^.D7&L15B+>;4AB<'4.^6>/0%/*RHA_13<,;V ]6H=:8BS?S)E04HX23UER$"OP;.+?VY1<;U+Z#TH=:01I#=!Y[0-03[BZ0 -MV8:4[)*NJU^'BTI9$YW$,%M"HX2!.X?R?=.*H30NYD;ZP[JF4$P6_82+(K8? -MQWQ S_8.X<:5EE6/$FW8AH2[\3X\QC)[\)"^/I,7I&NIFK)ZF2W]Q/;8_ K! -MUI-3AP&V]$J^)B060PSC_6;DUD5&G$N'AH=)NM++H\/>D%Z,HY$8_\+;W18V -M1_?<$]F]1XB3VN& ER4<\M+>]EI$O[#WN,9/BUB2\\;_PQ2'D'236N\&I9*- -MQ2GU->7%2J2DGI^2J)H?/LSQ[/8T):B+4L6^;[A-NW.[^]'4_-@FPM!>M?R\ -M3XV,AX(.DL3S[;I%OEB#5ER N)>HCE>0=KTAR.F/J,)8 - Y>HRPK(8ZJJ*Q -MC$B%/C,T\!:E?).R57)2JAW YL+CCZ99KI80@[CQP<;NXM/%5?"P7PZA')*@ -M5'W;RQ""M=#!E]6EF]BLI%V8D_40_<]A[59B6W?/1J>2BA%Q]KOZB.LGIGVV -MFZQRGTG0Z^TZEG!Q;J2^1KZ_E(JXI%/JB/WXPY'2EX(%G8F3G5-LAI^2L_;^ -M5^_#IQ>9VTP&4JN3I9 !U\VH%,7"#X\QNUX50*F:HIQ9K!W7 3O\EA?UIIQP -M4:T 2:H]PPM%X;B4]@:F6X/_"7 9[/J0(1S4&JRGHIQZH-^=)^*F\!6&D9:? -MD99.P%8#2/3TTO?8X:UP1E.Q7DD"KK)6*V,[-SG;Q'"T"A8I.DKV"I/+8VSNU%^^2$U%XD0/\7DN7 -MDF*EVL+]RJ?H$\#GR*J*'Z62>@]^0F!: P50+,+7L!OWU/*QP'.[D\EJRS20 -M!!XKG;&[K8#R53+F.D+00+.;7*48N62_^L"*XN):I9:1-X>)F6V44Z/9[6[F -MVS&/4$R"L=L^1%2LFIL*V\0YB@DZVEDMOFM.WV=D*3J*\5@J22F8*1CGCC+>KDZ=U' -M:L@15;BSUHQOJ*&@DHK9XF;6]E/E#;1+J9;4FEW"_Z/2=! !K9Y4FHM:\_?0 -M+-;1O9/R+I>BFXCKCA<(SL#9A*3&"492V;^Y@)N$X[,^+?#8B/K[OQ^*C982 -ME-CC_[?R0[Q[HNC!=,/7X/?C;YI01$,2A9*IEJO-#'K8W"<4G)"M -MC:(_AH[WBQ\7FQ\(!BU0(*^ -ME/"?QW_/&'RF2YR.TX*]899:V5/$D.:ORYU/DXB/AQ>22Y7,]#<7[_&G$JP" -MJ*BNI*%M\\3&K[K^4ZV0$8RBF#BI=/.+V?W,U\?NU$.3JF2+KXD/K Z3TSHE -MNKH?SY"8GK&O_[J#BZJ. ('X^<,'^_\/W*EW^Y*)IDM2N*1>D]"0U/[F-I,% -MB8NTC9*KJP.O4]P:H;.'7_*"G:5KQ.W&^^4<7%*$E9.>NJ >J,+O]YRTB=ZM -M$(GY@S.:G2B08]OL4KSMFJV;*HM.-8642/*1O"X#$5!-FW^]#MVS:L7V]/?P -M9\6#2<4# -MG:!;FZ2)?Y?1$!5ME]/:AE&@10.7>H"H=%KS+LM06'7:488T]IZ-EZB1%#7F -M-B.P@U>@O;*"E91^AL>^Q930VY".E9:+DH>%V8@7L]5&]BXA'UN8:.^2H5M# -MDC[J[-@.)";(CYZ4E-:?E(NVG:V ^G7G[E(2NMA=GP./J7NCDG*=Q,H.]2HJ -MF_72:FWLI8#"7_XP#;&VMY:^I64<8.) 5\"L*^4GE^&71N3\RHE -M?(X#T0/'% J(M%O_B?Q];8Y)S3_Y5/9:XF?6:*BJAU;> -MBI1:P^7Z^DE>ZT\Q^!O#+$K]6 -M7,:?'"LFJ9?:P-03QO9ORPU6FU^:MY_V2,Q4B\3^Y,2MRP8#$[J?E7]<58\3 -MN[CSJ.34;91VM<+=H%&TEB5;@Z+"V[9\$%.'=;R[@Z#"+1:0]^]46%H4MAV< -M.I&@20FL\1*0H;*56Y.\TVQ:FQCB.,3 UQ"K=&2_]D.^SD=J!^CNK?I"HU[L -M2*J.CD#70-/JT)3_[_"[5X^\1IAKJZ&;@R??UD[""\)K5=>43YR!9J.FC0SR -MX1_PU,>'5IN(ED^^D-YPOY+2U<@75@K%]1RXKE[S7@6[BY@F<-MMGF_B6L3) -M?HF>7(:=J@/M"R\V1Y/^1KYPK%;2\.7WP-9SC:(2GZ 56XJMII['UV;!Q89R -MD:.*^OZ0A9/:L;;P].#:A[>DMU*9N ^+'@L^<._MPS]48)U867)7DKW!Z]7O -MM9?*KX^-C8F\JVJBI'LE*%>"WZ, 3(^$C9M7GVJP3Y_!'G-@$I#KGIY?HYZU -MJ=F3[ ^:\OS[[LI*[LOPK9X%"/B;CQCR+$2-4\/A;L VY9GYWD5V4IB-$0_" -MXYGVMMVEH9B?X6HF_N;V6U6P&9Z:%1JZX'7_36D!TGJ!VD:F65"3.X[=Q30W -M^_#%&%*V>8]7AP>WTH3-*,$F/\_(I&!:JKJ2,@.\$93Y;_KT#[G4NF0,\KT3 -M.;^:I\#4H@H/$)Z.3%6*GLTZP\Y*YW[A\,+>&UN+G[,HC+J6"L&=M_$'K@M& -M#02KRFJ;G=NN7KM;H8&7DP3^.:XV/\#1M!A%1[6*^<'6PK)=@Z:OEAW\ Q?: -M.38;[F=1H%[[LY$9VH"GEP,.SQ*L5+0ISYU>_K1: L$^&3_@%="-1H/[?HO> -ME9>ET;'T[O6BJ)W"=IF;FJ2)2-+T[L+$,\;NAM6-B9>4BKHUEQG:@ P=HM 4 -MIEKHZ5*+8[".32BS]/3P-"N CX7!7@:[N_Y$M%T3%.#JRB*@<1")%EN#FI^' -MFA>Z4']!ZFSV(/(#?)G6D;97DYM"W?6'UN3A)W* -MZN7^!>+ OX8#OSIK1=&ZIBMUMQ7JTQ)QE?ZP,#L_O;N -M)40<2D2Z49H"TL2EPYS0FIZ.@*J2P3[\T/I%]Y"@D8VV5YJ[>E:RTPU0T800 -M5IM:45I=;*)7YQ03__(3XIVWDIJKNWQSL3K9]&% >_.'5B69FKV8E+"_S2+Y -M;.(N R2VF:>>G$5*LY6:\P0,:M?#'(N5CYQNVXF[A)^JZ233U[WN(VK?C5M# -MCKBWB+&.4H$/R_=Z! %0M,L]O:*ZEIC27F)^6\'CYL9EU^>8S[L%45EZ=7@B>F*6^B\E_(LB&T9X<^E2"6JQ.LL7J -MK,8?]M*3H&P#BXU>&XJ\[<'5(##S4)83@MN3D@QWA*%!E/_%^L"CLMP9C)(, -MOVQZ6L+ _'XI.4FEZ5RH9=3N3WC>$Z)Q(E]:BC4["@F[9-FX)XCH,'!,A= -M7LOJ%>"KKHE*F9I+3J&CT)FJ_N5ZTCO"KI6+^UPW2'K1+<[;G))V>Z1 EY?! -MD]-T/_ KG)V4K[912GN@4$F3AZ#;G/92/*8=*'F@59WCE&WR.LK=D*)MDY:3 -MDEI[C #1L3?EVIND@JJYA]9,D>IE:.S2>L#3UI:5C"*8GX/@D(O-W^BH0 /= -MF8"\'FU8B:V1]YT#'O__K]H%2).9L=J06+Y#NKH/0?[!X=7\$\?3ZI^5RQHF -M[?:+DYI!P\/G/C[E\8QT6AT$>7Q:U0SWV)!1B?[RB?NK\SIF]9?\C[V<@9&D -MPH""RK[9VN+9R8>06YLD$9S>N(YQ03+36D+0\+ORIIJ"ZI*/EVP9ZC-EX-*" -M\K@8_&^4A%D, SOM[I1V KF?O$!6AH]-J%>7)\HJS>I/0NM?K8ZI -M)2/QM#6UAPM/AK;VI)&^/J:/B<#?[$<-V^G3RBNFFG=#]'+'O% -M?IN9%IX@E%KRULOCU"C/HM([CO]U>J!#4E;Q@)C%^>;$%,73^HF4\:)TJA;0 -MR_,"OMR41II(T'\!/C\TUA##E%"!WO97FIUYEOL0RQ?0E)B;E5^Q&IBG4*<9 ?2 -MK(# IHB:B!A7P,]3HY.&C9F-CY.XAI$%U!D^;A+(B).IE5Y2JI)0.)JY QN: -M8?Q\V\ZT2YZ? 9[UZTH2H)*7*)[1K_;V&XX0VZ\0D9.7\>_0D)!#H8>%DW)[ -MT?!Y/N9MPKR!BZ]&21*70:*:S5VKY;Q1DM%?G5S;:X29P/;#.C7U] M>N:EZ -MF)I?H^[)\?3B>IO-):N96XJX:F%J>G<&M1EY_@3OGQF(VX)K_G2%:=H4\4,@L!JU'I($40+'5%O?S -MG79FKTO+DG>5EAKT%_> 1&6GEA O8>[N.RFW:LFY)2OKFPPD7]U. 4]F9"4)Q3DXFE\9:8 -M\P_C1!264YR3MUA#S3/%+K RHQ!&@YG22)./;':I"WL+YG2#G_R6D=R?D?>2 -MP??L]9>GXFVFH9L>6P>V18SSY].7]\N[D.:95^J+@I%&#?[U/OOFVXF;G$&? -M$E6_H_+[(0HD_\K/ [LF^81&AZU&H$^7T,3UE>;ZY5*($9E\H(*ZM+&F^_?M -MSL\(5L/:R:]&>*>.$@**EFRVER+6;_#TQ Z?W%:?@H4:6L#YPL*-@*"'IE%; -MJ/?&^3HT,D#^D8I96J-^F6+ -MFZJJCJ".2.KS[C?&C86(&K.9NE(!*-+-W _B -MHLF_%GC@O_VNAI(7O1#@V7NZ],N'2(^ E@:]KIZF58-)3='#U<34U0GG\K>^ -MDZ7+FEIXC+;E>O7^9CKRG*/RGW"W<\+9RW,0A(:2A9+TFZK9\E5O]_90U9!6 -MOW"#CYJ@^X$IZ='(BI22U/HU'*NYEGUG\\;\/J+0:YJX,IN2AY7SF-K2<);7 -MRZVFP;^*0W>R7M0MU\4G[_ CBQI03BQH-*S@">OH.N%ZOS -MI9< P\3[[N;W1K9[5T(0AKQ2>Z1:\M? =5Z:\E6#TL;%;N;/-D.VQ$M:;Y.VLIP(]\4P^J-=M+ 9K$=7T)Z> -M6RIL]]0P&P]PF8CM6X;KD%6#&6K8!J80ME2GO;Y5$D6=H#6"\?XXU^[_]IB. -MOQ"3CXE*F^)>?U'?R\\4Y>90(N! -MJH<# -S1EO&5\+V?LMF0;._2%$^\EH0=E:27WV" 6L',QM)>B%>=^K"3O[.% -M^L$4GQ(FA;R=%!8;DB\/FH,-P?G%\D/O4Z"AF9R)59YRC!#JX<7'[]574E1* -MI(J'B+GT?MM<' W*]MP/D#ZAHTRORY!?@\,Z$.06VO.KEE&0F+N&F]Y@1E<# -MJM'C7-]")IQ3BYT0J R^FO;AI9OR\?:BGN7OFH)2732'>AMRJ^- >DF:!?:' -M6(KR]K[OUM?U=YA?D*)2WIMD!@O-'L[PNA9#BU>2\8N0)E?'UL7EUA+_3605XM/IKB^2)X6D(G3/OC&^_;5SYY>BK^=GLOX7E,L_-A( -MS^*6GU9?E8U604+H-D+E?NS\]^?%O[7$AUN/D4^+H'NJF0[(H0'!S4#&B_[? -M$((,NYHR<9_1 L#U-?X_UUV DD'G' -M]O"9EFA7*%N83;6.VO+E_O7"P6O6JHH)F(Z->(X8S=_@U\K3"ZU]C!^6QEWK -MAI!0S69EGFWPHHM2G)=7I*U\H:S6")&CZ!\%UMPAN^\@B+JTU=P+&LECZO<)>+DL$3[>8:^]DUEG.1C**"FT.UJ0TB -MD1"*H\F38VE -MTEORSQ'P6E9031"7LY$'._$@=93'6EP;KYJ=T+F0)ZD#Q.;<,%V+O873LJB@ -MFY-SJ]3?UL+"1X^AJ*J[E%)*B,GJ9?7PXL=:,'VXAQI$LY_)-\=PQ?!SETVX -M#+[&#H>-EKL3V@H"2M/\GU"6N+L7C4-Y\ZKQ8MF64$6BPJB$GJF66IB+N:6H -MQ5[84Z#+7L+8ZL^\BON6./^:+%_941(\Q-HOPQC3LX2?D5N)(PL'" 1P"AR' -MN+R]96H\QC VTIR3FZT025J];).ZQU=:T9P05DF.%?*_N8^K IYX__Y/<$ZF -MN8U64,Y;GS_%P^7V+ME#I9&/VHL/E9CO@V+VNYZB]TOVD(^_6F] -MG56HIJN6I"0647%D__02[]-<0!2M4+-*.P>"]4NN>Y11AIGXF<6I3?F,%'0-R$@Y95D$>I@I.:7P4J-/8GHYS I")2JX*N=!.?R^ M -M._OBB_!&JJ@-&!1#G-JJU.?^-<4+CM6F0PQO:+&WJ<'-B@/)OEKYLA7NM -M"Z"%W<#RL3;TY$#KQY&3EYY(@K/$EGKE)E&&_ ?.]U62F(T%K)>/N%K$#Y<) -MY-C:Q<7"A$2CA9.72JE5PRC(C9R*K9K;EBN,W^/2\#X'A%"?E[255X,UEJB@ -MIRMTG_!3AHV5%XMFCY?5M-%R,_?QD(YYL)!3+J !;_+2\3>0RXKWH-.KOZJ0 -MT0WG$9V:ME %GW90E&SRO4*RWAWD_M1>IO&SHPZ>U8.HBYZ GIUQ(''@-A;8 -MC[J8L)R:2():>AZ](O_:%(?"I-#Z.9W^E7.ZKIK2PZ#;46OL]IKEX712BI#W -M@)R*VNL/\%A#ODMTD5X2X=[Q9OIN$/24<962BI&+AGY(\>'YDD*4PH^/ -MNKY.J%VOH_J Q=S4_D8AP82$F9YCBFM2EKY8T_#SDO8G]]FOOJ6ZFMLJ2(&U -MM\,&0<'6=]PC4E[2.YJWC(=2DKI4FJ/7[?:4TM,QMJ* -MHG&L7_'6,S8W[\&7M!Z']@"6MV!P>LT7(1FO@[.6I+R+BL97FH?T[>?_PQ.Z -MCX&/6B:ZI'+!P^KD]F7;XYY%V*AK6%I5@=%^^>)T)8&#\$S5E*V/.L.4^5C( -M5,+=R+!BQKV E?WM1Z 25TSJ$48UG\:;A*M[OZ:36 J1UAK'PD1WK:KJXO&3 -M5YZW6?Y/7O1J]XG1,:/3P#9PK )T_YDH'$QO7A_HFV_:8=MM#"#9"H\&:\FL\0!Y20FP)-KD!3'@' -M9QS&TPJ6.YUZOIAT4JS9T>7&.L"BOT>N0$D5ZT$Y@(,IS?W^R@/&0Q8&K$F> -M36U@6A" P96FL/KO@UY]5U9'DUF ?9)+:)1X7_%VDO2#5@=BZ^%P)B@M!9W -M\?/Y.F?0PHA0E%F^68(!\<[)6;V#GHZVI5^-I.H8_\9URI!0>G']G)Q^I-93 -M)]\%@*V)@\Z]]*^"@ 690?(M\"? UJN6DYV(3PVRDZ?QP=4N5J.(E[)]JBV3 -ME@-6"<0Y),?WVT]5G>VS [L[S]E;PE9:-$DRGHHY7\<)D[C8Z -M\4Z^1)\L4XB(GB:&T]KOX$\J*@# Q@V;AP"Z\$*?BLF&FL?S_>XR;L%_L%N% -M0%>6F-K>PO"YB9(KCZ-;JZ#B=/ P%H%R: -ME[:Z7\TBY?0R\,6#]I.;JB:65]M4HO.=TC_+K87TGY:3F >>ZL7 W-9R/\"& -MGDP\#-:!HV9P4MC]^DP Y32"G)!%B:^[2V!0>,GVP3WT_\J3._U>FY!#=HN@ -M6KMQ" 76P, 1SM*Y/JLA4E93>::0MI,1,=_&1E;"SLF4CHXA&GLD_P*!B8)0 -M?I6GN@/3_N^?@IJ$T2OW-/3F!UZ,FI1+'[\O.9H9TP %Q\I#XYR@G*6I -M6HT=.*:=PV+C-C 6\(J/<"H#WXD>XE4B#\[M"H8&E -MNJG ]1YN/ML:LY.4I%5: N#6V3!7D#0,E]&"@Z#RDQ8R]AM4"+25C@BZ66)T -M^DBVBS!0"<&6/3/EKQF'E*))LYNJ7Z>)PO)E[G?3"W+&E_I" -MKE6*CZS">+YV>_%ICII 3K96BVP"D]&L!(_& T 76K!$'\;ANJRZ\\U^,]6] -MQ9M:F([&_'"+EE1H7YO-2LG3^,/(@)"&K*Z@FEN_&Y_&7%W%]$7DQO;8O=!6 -MKOJ0G*K"[*"(K)P6.4^1*Z\BDH.4 -MDYHJ\L@)RP%&U-LXJ(?%E5P%DQ;T>DZ[YQ+&Q;O&PU@1AA^6E9A*\03:T)!0 -MHDL'E)*:S?O5_X:P@8/H+-W*[8>* -MO8F\F7JWD&NKL997O\#A]6S0^J,DE6L=XW'Q?0/\9._DE&QB1G6-] T -MQ@%=E*.QQ?F^$Y/^2I;>9_3"=VTE$\<;NQ=Q!#L&ZJH=?VEN/ -MTOY$\.X%:Q>3@K:XVZ7:@)F1E,?&]ZZ>\(V439X,DK)?^.MV4^// 0-L]-G_M2@IJ-"%J CKZ [MC#QLT/QQ_DY"MX"D -M)%%QP/3L+L CG;VBD9"PFITEP\K0,8F2K773NAMB\BT:,- ++%.TF[#W0%ML -M5 . YU/3GKP*VW2%JH*MMMTEN^UO]D\02H6KGKZ3A_>9O(73]O_ZY1-?I:E_ -MDXQ42TW9YO7^-Y>K2;2>+4FTE*K1^_:= -MTO6:ZIX$@IHZAY?RP,R?T0+,SY/O*@L(3XBU&W:_AUP&)J)RTV'0U^; )?22 -M%EU&4)99P-WS\:B$H[7;@WGS)]/1Y_07VZV*6;U45UY?*8Z:]PE%2:X*KR7OM-O0JU9U%LAN6@MR@DJP!^_'^4.-/?J&="D*=\HBJ1?''\#9Z -M\HZRFJ^'=_(ZPH*8<)5>AX\H -ME*2/@NTHZ>,C@P4'$DB7E0&[M@-#B^VGD0C#[J#@]8%0$(&[EZ"9@P%/HU&( -M5D&K@)*Z?0OO=EPJ'R].\D*"=$A$6FZ&.GLCS[,;V -M=M*O1:2+GIM25K%,6? 55/K.J8>ADQ^3!A/^H,R4)^_ZQ=..E9R5A4^^BT:@ -MFPK@U)A=;QX95L[_8EG9:>A8>)BYL(ZP44#Z:1])"*D8]A]/W5 -MFL2GKX">6W>BB(GH!9G2[L<6#YN1E+?$CDF&VOTGX/3&^EK=IWVX'_JJCXZ@ -MB?5\*VR@+NFF+F-K8+:M82(7[> M:Y*A3GUQ-_7VWVFEIZ B,&? -M;%Z_07SOUH_PH]'V$WR=$9 #K/OM9?K/XX>:D$J#JJRR!TIST<77PHOCHJ8O -MNE&5I+=, 3YYY\0Z$4*W_8VYA;MKH)03&,^,3<_B_$S&6HIOGE^-8;H+"?+M -ME_HV15">F5:#H%O\^7UZ.Z -MO#9$E%22B/+_VK2H&%H&DI6*P^23Y=6V18*5DE;VAG264O*'KT%^+1N':Q;I? -MNN:/U*BX7Q]Y6SQP3AZVCUO^'&Y20\)?UZFWEPL#Q^8@+N5(R_BB9@U/8 -M>9Q4?867FG[(WK6Z9CK'C%P!K;:@DL,YLE?9YZKZK:"+K-^=F:ZLFJ[1.9,N -M\,*XGQ8PDY.#&(ZPC-/ T1O4 -V:P?U**T9.FX ,TKFW_.93[Z:,.$*2/)D@ -M6J[##:Q4YMOQ@Z2]@$^3SU*( "TG/B7^IO)#BZZ0HIN.BYO4N\":U,[;XLK& -MUL/<0-^="H)>BY::2+>ZV7+P]:_P)8_)@)U4B;^Z\9><@UA_ -MB6RA:_<67Z.-GZ*_>(F=U8*4), O_/?P%6=.G,V7C V2J)7_4L#$R:E#\9^T -M?DS%CHBHJZ7XQ;05QKWN\*&J^QO6$Y*!EZF7K:-OPB]/G_SJU$=^SK> -MT[.2FM'[Y.V4^BN$$%&],J*J6Q5.TO0=EA.IAE*RG>TVE3__K=/P78G/O8D: -M]S!RFU%58S %G/*%59%8$\PPGN<^\7YEV_#+FL&]>^^<=B.EZ?XU=>X%CW"L -MET.G2"!?G_#DU1+0]MM-< YL2Q*-0)&0>T5O_\U/%<.&]]^,5W^!/6:.70$6 -MQ^_FTE#M?9DFD9"0JI>YE]WRSCB9C0_PLTO?P)SKHP@@ML_^SWMN^)6!!1GY"AJI'CO9U'(T#PK=S3 -MF4;7@KUAH(CJZL<0$,7!C;:YJIJO7;!Q1\7$-;_DQHJ:*/NJ.QS5H)G2]GFE -MY!#BF51_G#L83+TAM[;GR$C5U_=XCI!)GDD.BXULEXM(U/-W[Y;;4HA?BUI/ -MB9PRK+(-40V+Q#*O!)&\UB^?V*^"ADM.L(+2H4OQ -MT(P"HYU7@M.;\L*C.N_NVORP5ID$45F8P25*.WD(Z:4'A%@PSZ->_7UZ?XL_Y-M'B!DN4#PM94=DH,M_>87XGF -M+,?NU@5.?9:<\'U6J,!>BUG#QMQ?H90\E;$(@VP 5]*2967E]=&=ID7RF -M5$MH0,#$]'/'DI*X]H.#';)1O:"V\5 UDNZ]&Y>\KY>/JZP:&,*T?%G>/G)K!LX+(_ YUSPH'X\N(KMO!6)9M -MGO)*3E,BDC[&)&;/4=A6A10)@ZODV=CX_9(B'YN5JHKRPC5M[_Y0N(NCA5H) -M\C&CIJW7QO+"FI19K(^ASEVTAD+8H9;UT-'&F\:KJ]@0TM10K$6C]1 ?T6>R -M;%\*FX>/DT 1'K3NUL;E8Q"]B@V'[1LAVD$)"@ 6!-K(AY;0/)RX9:MLEY_- -M]-$P]B?;[YQY?H.62*BPI(^:P*I2*M$.2?. NYZ<@U9 FI&2H(_-Q^NN[O;^ -MRY!6K.18**7H:Z#Q+RC -MG_F<69ZY0 _#R//F]\6K$HF/D[J2CPA7@HA8T]76U\J[TBP?LI&H=8FO\.'D -M]^SZ)KM/C> ]<@%3EI(70.W>"N;"Q!22N)P4JX"3N*0^P-;U1L:N0ZB&F?#8 -MC[N6)NR<0LW]J8JHC8J:%^+5@M&C\S?O]'51H%I&FO"+F]D= -M$_6X0GY=D%F"6\-R-?+FQ8^=G*2M,(M""V/7FR+V -M-,6:_ZK^>6IMV_OUHK -MAK&2TT$/ZLCF5SF5=GF4N:C,ZI!T@N+DQS"^,E6_%?&UEC!B@')P3H+9#LCW -M6LC?&4"+3[=>J?J#FJ)LEI['\#7P;C;2EYRRD9HQEX+Q2O72?IB6G(Q0F8*C -M,A/P]/( J(.*O)^8B+MIH(+S[84<+_)X6U8(O\.CUE<@\OGW^LBUJ/:D6_'/ -MG[>3O<+V'>0^Q1*2(_*;N(:&G[ZA0/U]_?ONNQ*0+]Z:JXNML B@Z ?H!LN( -MJ:><@(SZ3IUSEI]!-^<;[O[#:9O=DIO6CU86@))?\?[KYNO(@&_5ARP1D7Q^ -MRISSD86:P/C&NB7D\_2)EM64>KFY@,+:X+PV4;BD=Y?;)_;S-OWPSZQ6RAF> -M5WFY0]HXRP.NN'JCF)TSE5JIQHR#X1 \]C!7-8U6:9J;HU):GTJ@QL%]XB5& -M_8R)K@_7L%.-US_NI]8VPI:6OHV]AXV3X%NZVJK4SXH"TKL5K]2)N)5'ME>= -MPO1%)'_^"KNRK4.)H$U2LF.?B6Y1%#9/;G?&)X-2N,_!6DEO,>0+QLS8R_\+^7-N]?;$*W2*$77##\1@J -M@8&;=Z>06^R"0^#1\;?_T^ 2I&P)2CBJ.J%,R/&VUO("BZ>D0WJA%);U9%+_ -MQ>;\QO.&E!BHETV.JR10\P/^#,%+43VILDF.HWN^BZQ6BQ?6]_;ZUO#K+ASS -MB;J-J9G!CIW)HAQ?(M_!0N&"GM\+GI)#5X.B-YCQOCE"_\8C68 6G8ZRB:CC -M52G0/AP+A;"0G/?EP>?6_/IS+!:)KL*7NAEF0#O SN=45""6G0ZALD#CEE/) -M%#3O]_'3DX!I@U&#OX1WG.S3P20ZP)*7H!.HK[.<%;C:GCSO_G/S ]91G\FH -M0;ML(%?-R@\:QHK0EUX1CXN+C:]F_XJ#%L7^P&Z(AU97]Y>>J)^F\+Y[2._D -M0]31 G$(N9/]&H!^F8A8L%.KP/XS.OXZY1J1^["0E*H+@O_STLQ0 Y$WEUJ> -M\JOLGN64X[Q<@;6>4*^+S');(-L'W*Y;^Y"0DU:"J::9XT(W\,+CP^<7J8BO -M@T:2D9H$P?COQNNFGY.#6AV2$HL:VI?V^A)'X3T:'$_M1HL.H8Y;%^0)_^?B -MXH./E$1>4X",V3;%=J+: -MDY>V5S9;K@Y3K,#0[])OUE.-O97MOU^)BL:$5_$*'N/' ,B4M%14G_8@CY:. -M4Q$V-7OE^EJYAY"UJ:>]=A*[LX.E!EC/S\@LSO&KJ)[SL?62B?*2AYK#*A7N -MTE?U?G >5:#1]I\%Z8'(#Y."T2 PO(#(T\"VKNB5Y+0L;/O]O-29YHJTI9+C%^5ZB#"/-#^R4:")9?ZJKX5HX!, -MH?37^BY/G19>FF2N()MMAL*IR$VHWO,<3I:L3;D&[U-F=K;A,A#OYF6A@Y+Y -MFP+R@7N*:80?AP)*S,\*5,J#JIN,B*FFDII3Q+!WPSKD]N7N\)J3E(MR@,.K -M$7\5V*YR7@Z:\-B6\^GJJDJ&"':%6;%SO%]L7_\,N&G:.>]XJ:,J16T*XV;).IO7\'T3)V^(:M?8[1YRL -MJR22D?0N=>M%EHN+Q -M4].#G@9@KYJ(G:P&EW'V-.+'^O/*EM%:T+Z?RJ'YDAOWB*ZG1) OTN6C2O&; -MC'^/ I!ACA+1X_?UTM.%4));FU:E3$/EUX-AD)#0^Q(3U@W',;\5L+O VI ? -MG+18F*DXA /'_,\+L+!3JX19J%OD$%W-,!&7]:L<&;V$@JGIE;K;X$F>EWK$ -MVP^>>8-3NHN=I5;EL";WYMK#UU^,; >]C4UCOG?HU"D9Q5LREIN?S R7N4TY -MI9,%,\3V5A &DH^,VX.5AIX&:;>0D0*LU\>-QL661T^-DT.=JH!*IEZ:PI#E -MEM>:P7^(0%U.2H*X[1G/\Y0+GBV7E192UZO\^O/N"YIQB\5&M+9;XM:M\1O/ -M'(6V,@2GDIZZH+>"QSO7+/J^/>"T>(JNCDB\ -MCZ5*X;6:Q_4>1T[_#QO"C_!6 -ME\4B-.X[RW#GIG1= X:MCHM/A^ 3];9PCJ7L0QB37Y33Z*USESO[^]B/4*Q( -MZ9N;CX7<\7$/VMT6P\F/W+F:2_I-K::"@,SD^?ODTH_HEJRS>O>'4[8%MZV@ -M_H1QR\_$CL&'GYV0J;6)3A& EYKG_O/D]NW%A$B(J5J1'*GKWZ<07)7[D1QS -M29+ ]G&6/I/+?(N3L0^=_)*4$-L(SP]D.)Q?A5>2FH%AI)<94;7FU@+(4H^@ -M5T.[#Z971@TPY^__SI*,H(M3@HCPA83 T_;2,!0!G)99KY:HJYUCAJ[#5I1\ -MK*4(OW2:1YFXC(:*5[_HU#WMM=;S0K95LUO5COI*;+9#$-@ X_]BRR>T4U>; -M1Q&0II821I.;)Z%%'"@%*^R6))6PYN_A"MY^@NVJ_08HFF&8R]GI]!1D^7P,#.;<\HYH] '8B/7LVK -M8$1;F9KL\C?Z3XJ2A7=U[6LR3C$]MY"PYH0>0F+?XRC -M3<#^;>[P9AJ)5 9-@IRE( !D,STJ>@(YJ75YHNKG[FM'S[/3P,@-) -MOME;5J1(G[N OXF% ONCRX_"CKR!E'V%J//GDY3!EY[-,A9G_:*3_>(DXLH -MAX#;:&SN,O<84)6 FM.I=HR5JL'B_/+D]5*VDIJYNPI&DHW17\=V=C[15W:( -MO#^&#HZXCDC-#?^O#=/27B_'RI6MPPI&NH.QEIJ* -M\,9" 5+,Q]K)F7@YFI9:+?R?H)^-I.(]%>[WCSV T;$Z,9:9!=SE$)B2$ECW -MD1J0P])O^[;$PKP*7H22H)NM0I/=*,-*_)"[FJF5]UH>IHY33>)6_;XK.X*C -MK;BS@OI&=8X TB&6VD^[GD&7^CV8SZ:M]-XNQ?Y@PVR6GZJ\VH]=H+79V\[* -MS0;2RK^RNHRL^Z6BK!X;K7*YQ].ZX^>!&)7O1KSG<;POB.\B()UL'2^6]+*V?*4D9.%4%37@<'F[,)O[\.. -M\(.;EG>"@SF7MJ7)V1 .B+*MFB%<@TR^B,/3D3!4TM!'Q[*=%\<(C[<&X./U -M^I;6DIV%@MJ2UH9(K:'P_ZEYX%EY_ -MU-SN>O+:])R$FP!QB8/1^87 A(A?FU2C?%+"PCCR$.6CNHBSK5H$KH/!WD'9 -M(P/R7"2&B38128FR]YK,\_E %^5)IX_#FKB-?I91@:+D%6[WU4_2;).L;Y^7 -MVK[-UM5VFL8;KJ2. 8FOKI,$L(K)5EP; L7REH_PK+V>1-*[EBG)$N\5R+E9:*T->.QAJ5L*5TRJO$O 6X4^0 -ME)2'7EZ;I8"!TJ * ]G?*\B>0M(- -M6MF1FM+ ?,?3[N*1EI"$AXF#@6P-FU/4\QF?O!&%CE5*6J2'@QDYV?_04-O) -M7Z 6N;C7E_4 diff --git a/nimble/host/pts/tpg/94654-20170317-085441153.pts b/nimble/host/pts/tpg/94654-20170317-085441153.pts deleted file mode 100644 index 92507b139c..0000000000 --- a/nimble/host/pts/tpg/94654-20170317-085441153.pts +++ /dev/null @@ -1,289 +0,0 @@ - -94654mynewt-Updated - - - L2CAP - 0
2
- 1
3
- 1
4
- 1
5
- 1
6
- 2
40
- 2
41
- 2
42
- 2
43
- 2
45
- 2
46
- 2
47
- 3
1
- 3
12
- 3
16
-
- - GAP - 0
2
- 0a
4
- 10
1
- 12
1
- 13
1
- 13
2
- 14
1
- 15
1
- 16
1
- 18
1
- 18
2
- 19
1
- 19
2
- 19
3
- 20
1
- 20
2
- 20
3
- 20
4
- 20A
1
- 20A
10
- 20A
11
- 20A
12
- 20A
13
- 20A
14
- 20A
15
- 20A
16
- 20A
17
- 20A
2
- 20A
3
- 20A
4
- 20A
5
- 20A
7
- 20A
8
- 20A
9
- 21
1
- 21
2
- 21
3
- 21
4
- 21
5
- 21
6
- 21
7
- 21
8
- 21
9
- 22
1
- 22
2
- 22
3
- 22
4
- 23
1
- 23
2
- 23
3
- 23
4
- 23
5
- 24
1
- 24
2
- 24
3
- 24
4
- 25
1
- 25
2
- 25
3
- 25
4
- 25
7
- 25
8
- 25
9
- 26
1
- 26
2
- 26
3
- 26
4
- 27
1
- 27
2
- 28
1
- 28
2
- 29
1
- 29
2
- 29
3
- 29
4
- 30
1
- 30
2
- 31
1
- 31
2
- 31
3
- 31
4
- 31
5
- 31
6
- 31
7
- 31
8
- 31
9
- 32
1
- 32
2
- 32
3
- 33
1
- 33
2
- 33
3
- 33
4
- 33
5
- 33
6
- 34
1
- 34
2
- 34
3
- 35
1
- 35
2
- 35
3
- 35
4
- 35
5
- 35
7
- 35
8
- 35
9
- 37
1
- 37
2
- 37
3
- 5
1
- 5
2
- 5
3
- 5
4
- 6
1
- 7
1
- 7
2
- 8
1
- 8
2
- 8a
3
- 9
1
-
- - SUM ICS - - - PROD - - - GATT - 1
1
- 1
2
- 2
2
- 3
1
- 3
10
- 3
11
- 3
12
- 3
14
- 3
15
- 3
16
- 3
17
- 3
18
- 3
19
- 3
2
- 3
20
- 3
21
- 3
22
- 3
23
- 3
3
- 3
4
- 3
5
- 3
6
- 3
7
- 3
8
- 3
9
- 4
1
- 4
10
- 4
11
- 4
12
- 4
14
- 4
15
- 4
16
- 4
17
- 4
18
- 4
19
- 4
2
- 4
20
- 4
21
- 4
22
- 4
23
- 4
3
- 4
4
- 4
5
- 4
6
- 4
7
- 4
8
- 4
9
- 7
2
- 7
3
- 7
4
-
- - ATT - 1
1
- 1
2
- 2
2
- 3
1
- 3
10
- 3
11
- 3
12
- 3
13
- 3
14
- 3
15
- 3
16
- 3
17
- 3
18
- 3
19
- 3
2
- 3
20
- 3
22
- 3
23
- 3
24
- 3
25
- 3
26
- 3
27
- 3
28
- 3
29
- 3
3
- 3
4
- 3
5
- 3
6
- 3
7
- 3
8
- 3
9
- 4
1
- 4
10
- 4
11
- 4
12
- 4
13
- 4
14
- 4
15
- 4
16
- 4
17
- 4
18
- 4
19
- 4
2
- 4
20
- 4
22
- 4
23
- 4
24
- 4
25
- 4
26
- 4
27
- 4
28
- 4
29
- 4
3
- 4
4
- 4
5
- 4
6
- 4
7
- 4
8
- 4
9
- 5
2
- 5
3
- 5
4
-
- - SM - 1
1
- 1
2
- 2
1
- 2
2
- 2
3
- 2
5
- 3
1
- 4
1
- 4
2
- 5
1
- 5
2
- 5
3
- 5
4
- 7
1
- 7
2
- 7
3
-
-
-
diff --git a/nimble/host/services/ans/src/ble_svc_ans.c b/nimble/host/services/ans/src/ble_svc_ans.c index 5b64f18c44..edaf7f3c12 100644 --- a/nimble/host/services/ans/src/ble_svc_ans.c +++ b/nimble/host/services/ans/src/ble_svc_ans.c @@ -390,7 +390,7 @@ ble_svc_ans_new_alert_notify(uint8_t cat_id, const char * info_str) memcpy(&ble_svc_ans_new_alert_val[2], info_str, info_str_len); } } - return ble_gattc_notify(ble_svc_ans_conn_handle, + return ble_gatts_notify(ble_svc_ans_conn_handle, ble_svc_ans_new_alert_val_handle); } @@ -407,7 +407,7 @@ ble_svc_ans_unr_alert_notify(uint8_t cat_id) { ble_svc_ans_unr_alert_stat[0] = cat_id; ble_svc_ans_unr_alert_stat[1] = ble_svc_ans_unr_alert_cnt[cat_id]; - return ble_gattc_notify(ble_svc_ans_conn_handle, + return ble_gatts_notify(ble_svc_ans_conn_handle, ble_svc_ans_unr_alert_val_handle); } @@ -457,6 +457,7 @@ ble_svc_ans_init(void) rc = ble_gatts_add_svcs(ble_svc_ans_defs); SYSINIT_PANIC_ASSERT(rc == 0); + (void)rc; ble_svc_ans_new_alert_cat = MYNEWT_VAL(BLE_SVC_ANS_NEW_ALERT_CAT); ble_svc_ans_unr_alert_cat = MYNEWT_VAL(BLE_SVC_ANS_UNR_ALERT_CAT); diff --git a/nimble/host/services/bas/src/ble_svc_bas.c b/nimble/host/services/bas/src/ble_svc_bas.c index 631519cf9d..b49eb862e2 100644 --- a/nimble/host/services/bas/src/ble_svc_bas.c +++ b/nimble/host/services/bas/src/ble_svc_bas.c @@ -32,7 +32,7 @@ static uint16_t ble_svc_bas_battery_handle; #endif /* Battery level */ -uint8_t ble_svc_bas_battery_level; +static uint8_t ble_svc_bas_battery_level; /* Access function */ static int @@ -98,9 +98,9 @@ ble_svc_bas_access(uint16_t conn_handle, uint16_t attr_handle, int ble_svc_bas_battery_level_set(uint8_t level) { if (level > 100) - level = 100; + level = 100; if (ble_svc_bas_battery_level != level) { - ble_svc_bas_battery_level = level; + ble_svc_bas_battery_level = level; #if MYNEWT_VAL(BLE_SVC_BAS_BATTERY_LEVEL_NOTIFY_ENABLE) > 0 ble_gatts_chr_updated(ble_svc_bas_battery_handle); #endif @@ -119,6 +119,8 @@ ble_svc_bas_init(void) /* Ensure this function only gets called by sysinit. */ SYSINIT_ASSERT_ACTIVE(); + ble_svc_bas_battery_level = 0; + rc = ble_gatts_count_cfg(ble_svc_bas_defs); SYSINIT_PANIC_ASSERT(rc == 0); diff --git a/nimble/host/services/bleuart/src/bleuart.c b/nimble/host/services/bleuart/src/bleuart.c index 1585635286..5703224509 100644 --- a/nimble/host/services/bleuart/src/bleuart.c +++ b/nimble/host/services/bleuart/src/bleuart.c @@ -165,7 +165,7 @@ bleuart_uart_read(void) if (!om) { return; } - ble_gattc_notify_custom(g_console_conn_handle, + ble_gatts_notify_custom(g_console_conn_handle, g_bleuart_attr_read_handle, om); off = 0; break; diff --git a/nimble/host/services/gatt/include/services/gatt/ble_svc_gatt.h b/nimble/host/services/gatt/include/services/gatt/ble_svc_gatt.h index 06c44784af..eefd412f57 100644 --- a/nimble/host/services/gatt/include/services/gatt/ble_svc_gatt.h +++ b/nimble/host/services/gatt/include/services/gatt/ble_svc_gatt.h @@ -28,8 +28,11 @@ extern "C" { struct ble_hs_cfg; -#define BLE_SVC_GATT_CHR_SERVICE_CHANGED_UUID16 0x2a05 +#define BLE_SVC_GATT_CHR_SERVICE_CHANGED_UUID16 0x2a05 +#define BLE_SVC_GATT_CHR_SERVER_SUPPORTED_FEAT_UUID16 0x2b3a +#define BLE_SVC_GATT_CHR_CLIENT_SUPPORTED_FEAT_UUID16 0x2b29 +uint8_t ble_svc_gatt_get_local_cl_supported_feat(void); void ble_svc_gatt_changed(uint16_t start_handle, uint16_t end_handle); void ble_svc_gatt_init(void); diff --git a/nimble/host/services/gatt/src/ble_svc_gatt.c b/nimble/host/services/gatt/src/ble_svc_gatt.c index 78b4a0683c..331d6bedd8 100644 --- a/nimble/host/services/gatt/src/ble_svc_gatt.c +++ b/nimble/host/services/gatt/src/ble_svc_gatt.c @@ -22,28 +22,61 @@ #include "sysinit/sysinit.h" #include "host/ble_hs.h" #include "services/gatt/ble_svc_gatt.h" +#include "../src/ble_gatt_priv.h" static uint16_t ble_svc_gatt_changed_val_handle; static uint16_t ble_svc_gatt_start_handle; static uint16_t ble_svc_gatt_end_handle; +/* Server supported features */ +#define BLE_SVC_GATT_SRV_SUP_FEAT_EATT_BIT (0x00) + +/* Client supported features */ +#define BLE_SVC_GATT_CLI_SUP_FEAT_ROBUST_CATCHING_BIT (0x00) +#define BLE_SVC_GATT_CLI_SUP_FEAT_EATT_BIT (0x01) +#define BLE_SVC_GATT_CLI_SUP_FEAT_MULT_NTF_BIT (0x02) + +static uint8_t ble_svc_gatt_local_srv_sup_feat = 0; +static uint8_t ble_svc_gatt_local_cl_sup_feat = 0; + static int ble_svc_gatt_access(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg); +static int +ble_svc_gatt_srv_sup_feat_access(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, void *arg); + +static int +ble_svc_gatt_cl_sup_feat_access(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, void *arg); + static const struct ble_gatt_svc_def ble_svc_gatt_defs[] = { { /*** Service: GATT */ .type = BLE_GATT_SVC_TYPE_PRIMARY, .uuid = BLE_UUID16_DECLARE(BLE_GATT_SVC_UUID16), - .characteristics = (struct ble_gatt_chr_def[]) { { - .uuid = BLE_UUID16_DECLARE(BLE_SVC_GATT_CHR_SERVICE_CHANGED_UUID16), - .access_cb = ble_svc_gatt_access, - .val_handle = &ble_svc_gatt_changed_val_handle, - .flags = BLE_GATT_CHR_F_INDICATE, - }, { - 0, /* No more characteristics in this service. */ - } }, + .characteristics = (struct ble_gatt_chr_def[]) { + { + .uuid = BLE_UUID16_DECLARE(BLE_SVC_GATT_CHR_SERVICE_CHANGED_UUID16), + .access_cb = ble_svc_gatt_access, + .val_handle = &ble_svc_gatt_changed_val_handle, + .flags = BLE_GATT_CHR_F_INDICATE, + }, + { + .uuid = BLE_UUID16_DECLARE(BLE_SVC_GATT_CHR_SERVER_SUPPORTED_FEAT_UUID16), + .access_cb = ble_svc_gatt_srv_sup_feat_access, + .flags = BLE_GATT_CHR_F_READ, + }, + { + .uuid = BLE_UUID16_DECLARE(BLE_SVC_GATT_CHR_CLIENT_SUPPORTED_FEAT_UUID16), + .access_cb = ble_svc_gatt_cl_sup_feat_access, + .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE, + }, + { + 0, /* No more characteristics in this service. */ + } + }, }, { @@ -51,6 +84,44 @@ static const struct ble_gatt_svc_def ble_svc_gatt_defs[] = { }, }; +static int +ble_svc_gatt_srv_sup_feat_access(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, void *arg) +{ + if (ctxt->op != BLE_GATT_ACCESS_OP_READ_CHR) { + return BLE_ATT_ERR_WRITE_NOT_PERMITTED; + } + + os_mbuf_append(ctxt->om, &ble_svc_gatt_local_srv_sup_feat, sizeof(ble_svc_gatt_local_srv_sup_feat)); + + return 0; +} + +static int +ble_svc_gatt_cl_sup_feat_access(uint16_t conn_handle, uint16_t attr_handle, + struct ble_gatt_access_ctxt *ctxt, void *arg) +{ + uint8_t supported_feat; + int rc; + + if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) { + rc = ble_gatts_peer_cl_sup_feat_get(conn_handle, &supported_feat, 1); + if (rc != 0) { + return BLE_ATT_ERR_UNLIKELY; + } + os_mbuf_append(ctxt->om, &supported_feat, sizeof(supported_feat)); + return 0; + } + if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) { + rc = ble_gatts_peer_cl_sup_feat_update(conn_handle, ctxt->om); + if (rc != 0) { + return rc; + } + } + + return 0; +} + static int ble_svc_gatt_access(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg) @@ -77,6 +148,12 @@ ble_svc_gatt_access(uint16_t conn_handle, uint16_t attr_handle, return 0; } +uint8_t +ble_svc_gatt_get_local_cl_supported_feat(void) +{ + return ble_svc_gatt_local_cl_sup_feat; +} + /** * Indicates a change in attribute assignment to all subscribed peers. * Unconnected bonded peers receive an indication when they next connect. @@ -105,4 +182,16 @@ ble_svc_gatt_init(void) rc = ble_gatts_add_svcs(ble_svc_gatt_defs); SYSINIT_PANIC_ASSERT(rc == 0); + + if (MYNEWT_VAL(BLE_EATT_CHAN_NUM) > 0) { + ble_svc_gatt_local_srv_sup_feat |= (1 << BLE_SVC_GATT_SRV_SUP_FEAT_EATT_BIT); + } + + if (MYNEWT_VAL(BLE_EATT_CHAN_NUM) > 0) { + ble_svc_gatt_local_cl_sup_feat |= (1 << BLE_SVC_GATT_CLI_SUP_FEAT_EATT_BIT); + } + + if (MYNEWT_VAL(BLE_ATT_SVR_NOTIFY_MULTI) > 0) { + ble_svc_gatt_local_cl_sup_feat |= (1 << BLE_SVC_GATT_CLI_SUP_FEAT_MULT_NTF_BIT); + } } diff --git a/nimble/host/src/ble_att.c b/nimble/host/src/ble_att.c index 8aab7f9190..8bde29b2ac 100644 --- a/nimble/host/src/ble_att.c +++ b/nimble/host/src/ble_att.c @@ -20,12 +20,22 @@ #include #include #include "ble_hs_priv.h" +#include "host/ble_att.h" #if NIMBLE_BLE_CONNECT + +#ifndef min +#define min(a, b) ((a) < (b) ? (a) : (b)) +#endif + +#ifndef max +#define max(a, b) ((a) > (b) ? (a) : (b)) +#endif + static uint16_t ble_att_preferred_mtu_val; /** Dispatch table for incoming ATT requests. Sorted by op code. */ -typedef int ble_att_rx_fn(uint16_t conn_handle, struct os_mbuf **om); +typedef int ble_att_rx_fn(uint16_t conn_handle, uint16_t cid, struct os_mbuf **om); struct ble_att_rx_dispatch_entry { uint8_t bde_op; ble_att_rx_fn *bde_fn; @@ -59,6 +69,9 @@ static const struct ble_att_rx_dispatch_entry ble_att_rx_dispatch[] = { { BLE_ATT_OP_NOTIFY_REQ, ble_att_svr_rx_notify }, { BLE_ATT_OP_INDICATE_REQ, ble_att_svr_rx_indicate }, { BLE_ATT_OP_INDICATE_RSP, ble_att_clt_rx_indicate }, + { BLE_ATT_OP_READ_MULT_VAR_REQ, ble_att_svr_rx_read_mult_var }, + { BLE_ATT_OP_READ_MULT_VAR_RSP, ble_att_clt_rx_read_mult_var }, + { BLE_ATT_OP_NOTIFY_MULTI_REQ, ble_att_svr_rx_notify_multi}, { BLE_ATT_OP_WRITE_CMD, ble_att_svr_rx_write_no_rsp }, }; @@ -127,7 +140,7 @@ static const struct ble_att_rx_dispatch_entry * ble_att_rx_dispatch_entry_find(uint8_t op) { const struct ble_att_rx_dispatch_entry *entry; - int i; + unsigned int i; for (i = 0; i < BLE_ATT_RX_DISPATCH_SZ; i++) { entry = ble_att_rx_dispatch + i; @@ -144,13 +157,20 @@ ble_att_rx_dispatch_entry_find(uint8_t op) } int -ble_att_conn_chan_find(uint16_t conn_handle, struct ble_hs_conn **out_conn, +ble_att_conn_chan_find(uint16_t conn_handle, uint16_t cid, struct ble_hs_conn **out_conn, struct ble_l2cap_chan **out_chan) { - return ble_hs_misc_conn_chan_find(conn_handle, BLE_L2CAP_CID_ATT, + return ble_hs_misc_conn_chan_find(conn_handle, cid, out_conn, out_chan); } +int +ble_att_conn_chan_find_by_psm(uint16_t conn_handle, uint16_t psm, struct ble_hs_conn **out_conn, + struct ble_l2cap_chan **out_chan) +{ + return ble_hs_misc_conn_chan_find(conn_handle, psm, out_conn, out_chan); +} + void ble_att_inc_tx_stat(uint8_t att_op) { @@ -400,7 +420,7 @@ ble_att_truncate_to_mtu(const struct ble_l2cap_chan *att_chan, } uint16_t -ble_att_mtu(uint16_t conn_handle) +ble_att_mtu_by_cid(uint16_t conn_handle, uint16_t cid) { struct ble_l2cap_chan *chan; struct ble_hs_conn *conn; @@ -409,7 +429,7 @@ ble_att_mtu(uint16_t conn_handle) ble_hs_lock(); - rc = ble_att_conn_chan_find(conn_handle, &conn, &chan); + rc = ble_att_conn_chan_find(conn_handle, cid, &conn, &chan); if (rc == 0) { mtu = ble_att_chan_mtu(chan); } else { @@ -421,6 +441,12 @@ ble_att_mtu(uint16_t conn_handle) return mtu; } +uint16_t +ble_att_mtu(uint16_t conn_handle) +{ + return ble_att_mtu_by_cid(conn_handle, BLE_L2CAP_CID_ATT); +} + void ble_att_set_peer_mtu(struct ble_l2cap_chan *chan, uint16_t peer_mtu) { @@ -436,6 +462,16 @@ ble_att_chan_mtu(const struct ble_l2cap_chan *chan) { uint16_t mtu; +#if MYNEWT_VAL(BLE_EATT_CHAN_NUM) > 0 + if (chan->psm == BLE_EATT_PSM) { + /* The ATT_MTU for the Enhanced ATT bearer shall be set to the minimum of the + * MTU field values of the two devices. Reference: + * Core v5.0, Vol 6, Part B, section 1.3.2.1 + */ + return min(chan->coc_tx.mtu, chan->coc_rx.mtu); + } +#endif + /* If either side has not exchanged MTU size, use the default. Otherwise, * use the lesser of the two exchanged values. */ @@ -454,7 +490,7 @@ ble_att_chan_mtu(const struct ble_l2cap_chan *chan) static void ble_att_rx_handle_unknown_request(uint8_t op, uint16_t conn_handle, - struct os_mbuf **om) + uint16_t cid, struct os_mbuf **om) { /* If this is command (bit6 is set to 1), do nothing */ if (op & 0x40) { @@ -462,27 +498,38 @@ ble_att_rx_handle_unknown_request(uint8_t op, uint16_t conn_handle, } os_mbuf_adj(*om, OS_MBUF_PKTLEN(*om)); - ble_att_svr_tx_error_rsp(conn_handle, *om, op, 0, + ble_att_svr_tx_error_rsp(conn_handle, cid, *om, op, 0, BLE_ATT_ERR_REQ_NOT_SUPPORTED); *om = NULL; } +static void +ble_att_send_outstanding_after_response(uint16_t conn_handle) +{ + struct ble_hs_conn *conn; + struct ble_l2cap_chan *chan; + int rc; + + ble_hs_lock(); + rc = ble_hs_misc_conn_chan_find_reqd(conn_handle, BLE_L2CAP_CID_ATT, &conn, + &chan); + if (rc) { + ble_hs_unlock(); + return; + } + conn->client_att_busy = false; + ble_att_tx_with_conn(conn, chan, NULL); + ble_hs_unlock(); +} + static int -ble_att_rx(struct ble_l2cap_chan *chan) +ble_att_rx_extended(uint16_t conn_handle, uint16_t cid, struct os_mbuf **om) { const struct ble_att_rx_dispatch_entry *entry; uint8_t op; - uint16_t conn_handle; - struct os_mbuf **om; int rc; - conn_handle = ble_l2cap_get_conn_handle(chan); - if (conn_handle == BLE_HS_CONN_HANDLE_NONE) { - return BLE_HS_ENOTCONN; - } - - om = &chan->rx_buf; BLE_HS_DBG_ASSERT(*om != NULL); rc = os_mbuf_copydata(*om, 0, 1, &op); @@ -490,9 +537,13 @@ ble_att_rx(struct ble_l2cap_chan *chan) return BLE_HS_EMSGSIZE; } + if (cid == BLE_L2CAP_CID_ATT && ble_att_is_response_op(op)) { + ble_att_send_outstanding_after_response(conn_handle); + } + entry = ble_att_rx_dispatch_entry_find(op); if (entry == NULL) { - ble_att_rx_handle_unknown_request(op, conn_handle, om); + ble_att_rx_handle_unknown_request(op, conn_handle, cid, om); return BLE_HS_ENOTSUP; } @@ -501,10 +552,10 @@ ble_att_rx(struct ble_l2cap_chan *chan) /* Strip L2CAP ATT header from the front of the mbuf. */ os_mbuf_adj(*om, 1); - rc = entry->bde_fn(conn_handle, om); + rc = entry->bde_fn(conn_handle, cid, om); if (rc != 0) { if (rc == BLE_HS_ENOTSUP) { - ble_att_rx_handle_unknown_request(op, conn_handle, om); + ble_att_rx_handle_unknown_request(op, conn_handle, cid, om); } return rc; } @@ -512,6 +563,19 @@ ble_att_rx(struct ble_l2cap_chan *chan) return 0; } +static int +ble_att_rx(struct ble_l2cap_chan *chan, struct os_mbuf **om) +{ + uint16_t conn_handle; + + conn_handle = ble_l2cap_get_conn_handle(chan); + if (conn_handle == BLE_HS_CONN_HANDLE_NONE) { + return BLE_HS_ENOTCONN; + } + + return ble_att_rx_extended(conn_handle, chan->scid, om); +} + uint16_t ble_att_preferred_mtu(void) { @@ -572,6 +636,102 @@ ble_att_create_chan(uint16_t conn_handle) return chan; } +bool +ble_eatt_supported_req(uint8_t opcode) +{ + switch (opcode) { + /* EATT does not support MTU request, + * but we must handle this request with proper error response. + */ + case BLE_ATT_OP_MTU_REQ: + case BLE_ATT_OP_WRITE_CMD: + case BLE_ATT_OP_FIND_INFO_REQ: + case BLE_ATT_OP_FIND_TYPE_VALUE_REQ: + case BLE_ATT_OP_READ_TYPE_REQ: + case BLE_ATT_OP_READ_REQ: + case BLE_ATT_OP_READ_BLOB_REQ: + case BLE_ATT_OP_READ_MULT_REQ: + case BLE_ATT_OP_READ_GROUP_TYPE_REQ: + case BLE_ATT_OP_WRITE_REQ: + case BLE_ATT_OP_PREP_WRITE_REQ: + case BLE_ATT_OP_EXEC_WRITE_REQ: + case BLE_ATT_OP_INDICATE_REQ: + case BLE_ATT_OP_READ_MULT_VAR_REQ: + case BLE_ATT_OP_NOTIFY_MULTI_REQ: + return true; + } + return false; +} + +bool +ble_eatt_supported_rsp(uint8_t opcode) +{ + switch (opcode) { + case BLE_ATT_OP_ERROR_RSP: + case BLE_ATT_OP_FIND_INFO_RSP: + case BLE_ATT_OP_FIND_TYPE_VALUE_RSP: + case BLE_ATT_OP_READ_TYPE_RSP: + case BLE_ATT_OP_INDICATE_RSP: + case BLE_ATT_OP_READ_RSP: + case BLE_ATT_OP_READ_BLOB_RSP: + case BLE_ATT_OP_READ_MULT_RSP: + case BLE_ATT_OP_READ_GROUP_TYPE_RSP: + case BLE_ATT_OP_WRITE_RSP: + case BLE_ATT_OP_PREP_WRITE_RSP: + case BLE_ATT_OP_EXEC_WRITE_RSP: + case BLE_ATT_OP_READ_MULT_VAR_RSP: + return true; + } + return false; +} + +bool +ble_att_is_request_op(uint8_t opcode) +{ + switch (opcode) { + case BLE_ATT_OP_MTU_REQ: + case BLE_ATT_OP_FIND_INFO_REQ: + case BLE_ATT_OP_FIND_TYPE_VALUE_REQ: + case BLE_ATT_OP_READ_TYPE_REQ: + case BLE_ATT_OP_READ_REQ: + case BLE_ATT_OP_READ_BLOB_REQ: + case BLE_ATT_OP_READ_MULT_REQ: + case BLE_ATT_OP_READ_GROUP_TYPE_REQ: + case BLE_ATT_OP_WRITE_REQ: + case BLE_ATT_OP_PREP_WRITE_REQ: + case BLE_ATT_OP_EXEC_WRITE_REQ: + case BLE_ATT_OP_INDICATE_REQ: + case BLE_ATT_OP_READ_MULT_VAR_REQ: + case BLE_ATT_OP_NOTIFY_MULTI_REQ: + return true; + } + return false; +} + +bool +ble_att_is_response_op(uint8_t opcode) +{ + switch (opcode) { + case BLE_ATT_OP_MTU_RSP: + case BLE_ATT_OP_ERROR_RSP: + case BLE_ATT_OP_FIND_INFO_RSP: + case BLE_ATT_OP_FIND_TYPE_VALUE_RSP: + case BLE_ATT_OP_READ_TYPE_RSP: + case BLE_ATT_OP_INDICATE_RSP: + case BLE_ATT_OP_READ_RSP: + case BLE_ATT_OP_READ_BLOB_RSP: + case BLE_ATT_OP_READ_MULT_RSP: + case BLE_ATT_OP_READ_GROUP_TYPE_RSP: + case BLE_ATT_OP_WRITE_RSP: + case BLE_ATT_OP_PREP_WRITE_RSP: + case BLE_ATT_OP_EXEC_WRITE_RSP: + case BLE_ATT_OP_READ_MULT_VAR_RSP: + return true; + } + + return false; +} + int ble_att_init(void) { @@ -586,6 +746,8 @@ ble_att_init(void) return BLE_HS_EOS; } + ble_eatt_init(ble_att_rx_extended); + return 0; } diff --git a/nimble/host/src/ble_att_clt.c b/nimble/host/src/ble_att_clt.c index 1a76297518..2b60f8b533 100644 --- a/nimble/host/src/ble_att_clt.c +++ b/nimble/host/src/ble_att_clt.c @@ -32,7 +32,7 @@ *****************************************************************************/ int -ble_att_clt_rx_error(uint16_t conn_handle, struct os_mbuf **rxom) +ble_att_clt_rx_error(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rxom) { struct ble_att_error_rsp *rsp; int rc; @@ -44,7 +44,7 @@ ble_att_clt_rx_error(uint16_t conn_handle, struct os_mbuf **rxom) rsp = (struct ble_att_error_rsp *)(*rxom)->om_data; - ble_gattc_rx_err(conn_handle, le16toh(rsp->baep_handle), + ble_gattc_rx_err(conn_handle, cid, le16toh(rsp->baep_handle), le16toh(rsp->baep_error_code)); return 0; @@ -69,7 +69,7 @@ ble_att_clt_tx_mtu(uint16_t conn_handle, uint16_t mtu) ble_hs_lock(); - rc = ble_att_conn_chan_find(conn_handle, &conn, &chan); + rc = ble_att_conn_chan_find(conn_handle, BLE_L2CAP_CID_ATT, &conn, &chan); if (rc != 0) { rc = BLE_HS_ENOTCONN; } else if (chan->flags & BLE_L2CAP_CHAN_F_TXED_MTU) { @@ -90,14 +90,14 @@ ble_att_clt_tx_mtu(uint16_t conn_handle, uint16_t mtu) req->bamc_mtu = htole16(mtu); - rc = ble_att_tx(conn_handle, txom); + rc = ble_att_tx(conn_handle, BLE_L2CAP_CID_ATT, txom); if (rc != 0) { return rc; } ble_hs_lock(); - rc = ble_att_conn_chan_find(conn_handle, &conn, &chan); + rc = ble_att_conn_chan_find(conn_handle, BLE_L2CAP_CID_ATT, &conn, &chan); if (rc == 0) { chan->flags |= BLE_L2CAP_CHAN_F_TXED_MTU; } @@ -108,7 +108,7 @@ ble_att_clt_tx_mtu(uint16_t conn_handle, uint16_t mtu) } int -ble_att_clt_rx_mtu(uint16_t conn_handle, struct os_mbuf **rxom) +ble_att_clt_rx_mtu(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rxom) { struct ble_att_mtu_cmd *cmd; struct ble_l2cap_chan *chan; @@ -117,13 +117,20 @@ ble_att_clt_rx_mtu(uint16_t conn_handle, struct os_mbuf **rxom) mtu = 0; +#if MYNEWT_VAL(BLE_EATT_CHAN_NUM) > 0 + if (cid != BLE_L2CAP_CID_ATT) { + /*FIXME reject ?*/ + assert(0); + } +#endif + rc = ble_hs_mbuf_pullup_base(rxom, sizeof(*cmd)); if (rc == 0) { cmd = (struct ble_att_mtu_cmd *)(*rxom)->om_data; ble_hs_lock(); - rc = ble_att_conn_chan_find(conn_handle, NULL, &chan); + rc = ble_att_conn_chan_find(conn_handle, cid, NULL, &chan); if (rc == 0) { ble_att_set_peer_mtu(chan, le16toh(cmd->bamc_mtu)); mtu = ble_att_chan_mtu(chan); @@ -136,7 +143,7 @@ ble_att_clt_rx_mtu(uint16_t conn_handle, struct os_mbuf **rxom) } } - ble_gattc_rx_mtu(conn_handle, rc, mtu); + ble_gattc_rx_mtu(conn_handle, BLE_L2CAP_CID_ATT, rc, mtu); return rc; } @@ -145,7 +152,7 @@ ble_att_clt_rx_mtu(uint16_t conn_handle, struct os_mbuf **rxom) *****************************************************************************/ int -ble_att_clt_tx_find_info(uint16_t conn_handle, uint16_t start_handle, +ble_att_clt_tx_find_info(uint16_t conn_handle, uint16_t cid, uint16_t start_handle, uint16_t end_handle) { #if !NIMBLE_BLE_ATT_CLT_FIND_INFO @@ -167,7 +174,7 @@ ble_att_clt_tx_find_info(uint16_t conn_handle, uint16_t start_handle, req->bafq_start_handle = htole16(start_handle); req->bafq_end_handle = htole16(end_handle); - return ble_att_tx(conn_handle, txom); + return ble_att_tx(conn_handle, cid, txom); } static int @@ -222,7 +229,7 @@ ble_att_clt_parse_find_info_entry(struct os_mbuf **rxom, uint8_t rsp_format, } int -ble_att_clt_rx_find_info(uint16_t conn_handle, struct os_mbuf **om) +ble_att_clt_rx_find_info(uint16_t conn_handle, uint16_t cid, struct os_mbuf **om) { #if !NIMBLE_BLE_ATT_CLT_FIND_INFO return BLE_HS_ENOTSUP; @@ -249,14 +256,14 @@ ble_att_clt_rx_find_info(uint16_t conn_handle, struct os_mbuf **om) } /* Hand find-info entry to GATT. */ - ble_gattc_rx_find_info_idata(conn_handle, &idata); + ble_gattc_rx_find_info_idata(conn_handle, cid, &idata); } rc = 0; done: /* Notify GATT that response processing is done. */ - ble_gattc_rx_find_info_complete(conn_handle, rc); + ble_gattc_rx_find_info_complete(conn_handle, cid, rc); return rc; } @@ -269,8 +276,9 @@ ble_att_clt_rx_find_info(uint16_t conn_handle, struct os_mbuf **om) * anyway */ int -ble_att_clt_tx_find_type_value(uint16_t conn_handle, uint16_t start_handle, - uint16_t end_handle, uint16_t attribute_type, +ble_att_clt_tx_find_type_value(uint16_t conn_handle, uint16_t cid, + uint16_t start_handle, uint16_t end_handle, + uint16_t attribute_type, const void *attribute_value, int value_len) { #if !NIMBLE_BLE_ATT_CLT_FIND_TYPE @@ -295,7 +303,7 @@ ble_att_clt_tx_find_type_value(uint16_t conn_handle, uint16_t start_handle, req->bavq_attr_type = htole16(attribute_type); memcpy(req->bavq_value, attribute_value, value_len); - return ble_att_tx(conn_handle, txom); + return ble_att_tx(conn_handle, cid, txom); } static int @@ -321,7 +329,7 @@ ble_att_clt_parse_find_type_value_hinfo( } int -ble_att_clt_rx_find_type_value(uint16_t conn_handle, struct os_mbuf **rxom) +ble_att_clt_rx_find_type_value(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rxom) { #if !NIMBLE_BLE_ATT_CLT_FIND_TYPE return BLE_HS_ENOTSUP; @@ -338,11 +346,11 @@ ble_att_clt_rx_find_type_value(uint16_t conn_handle, struct os_mbuf **rxom) break; } - ble_gattc_rx_find_type_value_hinfo(conn_handle, &hinfo); + ble_gattc_rx_find_type_value_hinfo(conn_handle, cid, &hinfo); } /* Notify GATT client that the full response has been parsed. */ - ble_gattc_rx_find_type_value_complete(conn_handle, rc); + ble_gattc_rx_find_type_value_complete(conn_handle, cid, rc); return 0; } @@ -352,7 +360,7 @@ ble_att_clt_rx_find_type_value(uint16_t conn_handle, struct os_mbuf **rxom) *****************************************************************************/ int -ble_att_clt_tx_read_type(uint16_t conn_handle, uint16_t start_handle, +ble_att_clt_tx_read_type(uint16_t conn_handle, uint16_t cid, uint16_t start_handle, uint16_t end_handle, const ble_uuid_t *uuid) { #if !NIMBLE_BLE_ATT_CLT_READ_TYPE @@ -377,11 +385,11 @@ ble_att_clt_tx_read_type(uint16_t conn_handle, uint16_t start_handle, ble_uuid_flat(uuid, req->uuid); - return ble_att_tx(conn_handle, txom); + return ble_att_tx(conn_handle, cid, txom); } int -ble_att_clt_rx_read_type(uint16_t conn_handle, struct os_mbuf **rxom) +ble_att_clt_rx_read_type(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rxom) { #if !NIMBLE_BLE_ATT_CLT_READ_TYPE return BLE_HS_ENOTSUP; @@ -423,13 +431,13 @@ ble_att_clt_rx_read_type(uint16_t conn_handle, struct os_mbuf **rxom) adata.value_len = data_len - sizeof(*data); adata.value = data->value; - ble_gattc_rx_read_type_adata(conn_handle, &adata); + ble_gattc_rx_read_type_adata(conn_handle, cid, &adata); os_mbuf_adj(*rxom, data_len); } done: /* Notify GATT that the response is done being parsed. */ - ble_gattc_rx_read_type_complete(conn_handle, rc); + ble_gattc_rx_read_type_complete(conn_handle, cid, rc); return rc; } @@ -439,7 +447,7 @@ ble_att_clt_rx_read_type(uint16_t conn_handle, struct os_mbuf **rxom) *****************************************************************************/ int -ble_att_clt_tx_read(uint16_t conn_handle, uint16_t handle) +ble_att_clt_tx_read(uint16_t conn_handle, uint16_t cid, uint16_t handle) { #if !NIMBLE_BLE_ATT_CLT_READ return BLE_HS_ENOTSUP; @@ -460,7 +468,7 @@ ble_att_clt_tx_read(uint16_t conn_handle, uint16_t handle) req->barq_handle = htole16(handle); - rc = ble_att_tx(conn_handle, txom); + rc = ble_att_tx(conn_handle, cid, txom); if (rc != 0) { return rc; } @@ -469,14 +477,14 @@ ble_att_clt_tx_read(uint16_t conn_handle, uint16_t handle) } int -ble_att_clt_rx_read(uint16_t conn_handle, struct os_mbuf **rxom) +ble_att_clt_rx_read(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rxom) { #if !NIMBLE_BLE_ATT_CLT_READ return BLE_HS_ENOTSUP; #endif /* Pass the Attribute Value field to GATT. */ - ble_gattc_rx_read_rsp(conn_handle, 0, rxom); + ble_gattc_rx_read_rsp(conn_handle, cid, 0, rxom); return 0; } @@ -485,7 +493,7 @@ ble_att_clt_rx_read(uint16_t conn_handle, struct os_mbuf **rxom) *****************************************************************************/ int -ble_att_clt_tx_read_blob(uint16_t conn_handle, uint16_t handle, uint16_t offset) +ble_att_clt_tx_read_blob(uint16_t conn_handle, uint16_t cid, uint16_t handle, uint16_t offset) { #if !NIMBLE_BLE_ATT_CLT_READ_BLOB return BLE_HS_ENOTSUP; @@ -507,7 +515,7 @@ ble_att_clt_tx_read_blob(uint16_t conn_handle, uint16_t handle, uint16_t offset) req->babq_handle = htole16(handle); req->babq_offset = htole16(offset); - rc = ble_att_tx(conn_handle, txom); + rc = ble_att_tx(conn_handle, cid, txom); if (rc != 0) { return rc; } @@ -516,14 +524,14 @@ ble_att_clt_tx_read_blob(uint16_t conn_handle, uint16_t handle, uint16_t offset) } int -ble_att_clt_rx_read_blob(uint16_t conn_handle, struct os_mbuf **rxom) +ble_att_clt_rx_read_blob(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rxom) { #if !NIMBLE_BLE_ATT_CLT_READ_BLOB return BLE_HS_ENOTSUP; #endif /* Pass the Attribute Value field to GATT. */ - ble_gattc_rx_read_blob_rsp(conn_handle, 0, rxom); + ble_gattc_rx_read_blob_rsp(conn_handle, cid, 0, rxom); return 0; } @@ -531,8 +539,8 @@ ble_att_clt_rx_read_blob(uint16_t conn_handle, struct os_mbuf **rxom) * $read multiple * *****************************************************************************/ int -ble_att_clt_tx_read_mult(uint16_t conn_handle, const uint16_t *handles, - int num_handles) +ble_att_clt_tx_read_mult(uint16_t conn_handle, uint16_t cid, const uint16_t *handles, + int num_handles, bool variable) { #if !NIMBLE_BLE_ATT_CLT_READ_MULT return BLE_HS_ENOTSUP; @@ -541,12 +549,15 @@ ble_att_clt_tx_read_mult(uint16_t conn_handle, const uint16_t *handles, struct ble_att_read_mult_req *req; struct os_mbuf *txom; int i; + uint8_t op; if (num_handles < 1) { return BLE_HS_EINVAL; } - req = ble_att_cmd_get(BLE_ATT_OP_READ_MULT_REQ, + op = variable ? BLE_ATT_OP_READ_MULT_VAR_REQ : BLE_ATT_OP_READ_MULT_REQ; + + req = ble_att_cmd_get(op, sizeof(req->handles[0]) * num_handles, &txom); if (req == NULL) { @@ -557,18 +568,30 @@ ble_att_clt_tx_read_mult(uint16_t conn_handle, const uint16_t *handles, req->handles[i] = htole16(handles[i]); } - return ble_att_tx(conn_handle, txom); + return ble_att_tx(conn_handle, cid, txom); } int -ble_att_clt_rx_read_mult(uint16_t conn_handle, struct os_mbuf **rxom) +ble_att_clt_rx_read_mult(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rxom) { #if !NIMBLE_BLE_ATT_CLT_READ_MULT return BLE_HS_ENOTSUP; #endif /* Pass the Attribute Value field to GATT. */ - ble_gattc_rx_read_mult_rsp(conn_handle, 0, rxom); + ble_gattc_rx_read_mult_rsp(conn_handle, cid, 0, rxom, false); + return 0; +} + +int +ble_att_clt_rx_read_mult_var(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rxom) +{ +#if !NIMBLE_BLE_ATT_CLT_READ_MULT_VAR + return BLE_HS_ENOTSUP; +#endif + + /* Pass the Attribute Value field to GATT. */ + ble_gattc_rx_read_mult_rsp(conn_handle, cid, 0, rxom, true); return 0; } @@ -577,7 +600,7 @@ ble_att_clt_rx_read_mult(uint16_t conn_handle, struct os_mbuf **rxom) *****************************************************************************/ int -ble_att_clt_tx_read_group_type(uint16_t conn_handle, +ble_att_clt_tx_read_group_type(uint16_t conn_handle, uint16_t cid, uint16_t start_handle, uint16_t end_handle, const ble_uuid_t *uuid) { @@ -602,7 +625,7 @@ ble_att_clt_tx_read_group_type(uint16_t conn_handle, req->bagq_end_handle = htole16(end_handle); ble_uuid_flat(uuid, req->uuid); - return ble_att_tx(conn_handle, txom); + return ble_att_tx(conn_handle, cid, txom); } static int @@ -630,7 +653,7 @@ ble_att_clt_parse_read_group_type_adata( } int -ble_att_clt_rx_read_group_type(uint16_t conn_handle, struct os_mbuf **rxom) +ble_att_clt_rx_read_group_type(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rxom) { #if !NIMBLE_BLE_ATT_CLT_READ_GROUP_TYPE return BLE_HS_ENOTSUP; @@ -660,13 +683,13 @@ ble_att_clt_rx_read_group_type(uint16_t conn_handle, struct os_mbuf **rxom) goto done; } - ble_gattc_rx_read_group_type_adata(conn_handle, &adata); + ble_gattc_rx_read_group_type_adata(conn_handle, cid, &adata); os_mbuf_adj(*rxom, len); } done: /* Notify GATT that the response is done being parsed. */ - ble_gattc_rx_read_group_type_complete(conn_handle, rc); + ble_gattc_rx_read_group_type_complete(conn_handle, cid, rc); return rc; } @@ -675,7 +698,7 @@ ble_att_clt_rx_read_group_type(uint16_t conn_handle, struct os_mbuf **rxom) *****************************************************************************/ int -ble_att_clt_tx_write_req(uint16_t conn_handle, uint16_t handle, +ble_att_clt_tx_write_req(uint16_t conn_handle, uint16_t cid, uint16_t handle, struct os_mbuf *txom) { #if !NIMBLE_BLE_ATT_CLT_WRITE @@ -694,12 +717,12 @@ ble_att_clt_tx_write_req(uint16_t conn_handle, uint16_t handle, req->bawq_handle = htole16(handle); os_mbuf_concat(txom2, txom); - return ble_att_tx(conn_handle, txom2); + return ble_att_tx(conn_handle, cid, txom2); } int -ble_att_clt_tx_write_cmd(uint16_t conn_handle, uint16_t handle, - struct os_mbuf *txom) +ble_att_clt_tx_write_cmd(uint16_t conn_handle, uint16_t cid, + uint16_t handle, struct os_mbuf *txom) { #if !NIMBLE_BLE_ATT_CLT_WRITE_NO_RSP return BLE_HS_ENOTSUP; @@ -707,6 +730,8 @@ ble_att_clt_tx_write_cmd(uint16_t conn_handle, uint16_t handle, struct ble_att_write_cmd *cmd; struct os_mbuf *txom2; + +#if MYNEWT_VAL(BLE_HS_DEBUG) uint8_t b; int rc; int i; @@ -720,7 +745,7 @@ ble_att_clt_tx_write_cmd(uint16_t conn_handle, uint16_t handle, assert(rc == 0); BLE_HS_LOG(DEBUG, "0x%02x", b); } - +#endif cmd = ble_att_cmd_get(BLE_ATT_OP_WRITE_CMD, sizeof(*cmd), &txom2); if (cmd == NULL) { @@ -731,18 +756,18 @@ ble_att_clt_tx_write_cmd(uint16_t conn_handle, uint16_t handle, cmd->handle = htole16(handle); os_mbuf_concat(txom2, txom); - return ble_att_tx(conn_handle, txom2); + return ble_att_tx(conn_handle, cid, txom2); } int -ble_att_clt_rx_write(uint16_t conn_handle, struct os_mbuf **rxom) +ble_att_clt_rx_write(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rxom) { #if !NIMBLE_BLE_ATT_CLT_WRITE return BLE_HS_ENOTSUP; #endif /* No payload. */ - ble_gattc_rx_write_rsp(conn_handle); + ble_gattc_rx_write_rsp(conn_handle, cid); return 0; } @@ -751,7 +776,7 @@ ble_att_clt_rx_write(uint16_t conn_handle, struct os_mbuf **rxom) *****************************************************************************/ int -ble_att_clt_tx_prep_write(uint16_t conn_handle, uint16_t handle, +ble_att_clt_tx_prep_write(uint16_t conn_handle, uint16_t cid, uint16_t handle, uint16_t offset, struct os_mbuf *txom) { #if !NIMBLE_BLE_ATT_CLT_PREP_WRITE @@ -773,7 +798,7 @@ ble_att_clt_tx_prep_write(uint16_t conn_handle, uint16_t handle, } if (OS_MBUF_PKTLEN(txom) > - ble_att_mtu(conn_handle) - BLE_ATT_PREP_WRITE_CMD_BASE_SZ) { + ble_att_mtu_by_cid(conn_handle, cid) - BLE_ATT_PREP_WRITE_CMD_BASE_SZ) { rc = BLE_HS_EINVAL; goto err; } @@ -788,7 +813,7 @@ ble_att_clt_tx_prep_write(uint16_t conn_handle, uint16_t handle, req->bapc_offset = htole16(offset); os_mbuf_concat(txom2, txom); - return ble_att_tx(conn_handle, txom2); + return ble_att_tx(conn_handle, cid, txom2); err: os_mbuf_free_chain(txom); @@ -796,7 +821,7 @@ ble_att_clt_tx_prep_write(uint16_t conn_handle, uint16_t handle, } int -ble_att_clt_rx_prep_write(uint16_t conn_handle, struct os_mbuf **rxom) +ble_att_clt_rx_prep_write(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rxom) { #if !NIMBLE_BLE_ATT_CLT_PREP_WRITE return BLE_HS_ENOTSUP; @@ -825,7 +850,7 @@ ble_att_clt_rx_prep_write(uint16_t conn_handle, struct os_mbuf **rxom) done: /* Notify GATT client that the full response has been parsed. */ - ble_gattc_rx_prep_write_rsp(conn_handle, rc, handle, offset, rxom); + ble_gattc_rx_prep_write_rsp(conn_handle, cid, rc, handle, offset, rxom); return rc; } @@ -834,7 +859,7 @@ ble_att_clt_rx_prep_write(uint16_t conn_handle, struct os_mbuf **rxom) *****************************************************************************/ int -ble_att_clt_tx_exec_write(uint16_t conn_handle, uint8_t flags) +ble_att_clt_tx_exec_write(uint16_t conn_handle, uint16_t cid, uint8_t flags) { #if !NIMBLE_BLE_ATT_CLT_EXEC_WRITE return BLE_HS_ENOTSUP; @@ -851,7 +876,7 @@ ble_att_clt_tx_exec_write(uint16_t conn_handle, uint8_t flags) req->baeq_flags = flags; - rc = ble_att_tx(conn_handle, txom); + rc = ble_att_tx(conn_handle, cid, txom); if (rc != 0) { return rc; } @@ -860,13 +885,13 @@ ble_att_clt_tx_exec_write(uint16_t conn_handle, uint8_t flags) } int -ble_att_clt_rx_exec_write(uint16_t conn_handle, struct os_mbuf **rxom) +ble_att_clt_rx_exec_write(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rxom) { #if !NIMBLE_BLE_ATT_CLT_EXEC_WRITE return BLE_HS_ENOTSUP; #endif - ble_gattc_rx_exec_write_rsp(conn_handle, 0); + ble_gattc_rx_exec_write_rsp(conn_handle, cid, 0); return 0; } @@ -884,6 +909,7 @@ ble_att_clt_tx_notify(uint16_t conn_handle, uint16_t handle, struct ble_att_notify_req *req; struct os_mbuf *txom2; + uint16_t cid; int rc; if (handle == 0) { @@ -900,7 +926,10 @@ ble_att_clt_tx_notify(uint16_t conn_handle, uint16_t handle, req->banq_handle = htole16(handle); os_mbuf_concat(txom2, txom); - return ble_att_tx(conn_handle, txom2); + cid = ble_eatt_get_available_chan_cid(conn_handle, BLE_GATT_OP_DUMMY); + rc = ble_att_tx(conn_handle, cid, txom2); + ble_eatt_release_chan(conn_handle, BLE_GATT_OP_DUMMY); + return rc; err: os_mbuf_free_chain(txom); @@ -912,8 +941,8 @@ ble_att_clt_tx_notify(uint16_t conn_handle, uint16_t handle, *****************************************************************************/ int -ble_att_clt_tx_indicate(uint16_t conn_handle, uint16_t handle, - struct os_mbuf *txom) +ble_att_clt_tx_indicate(uint16_t conn_handle, uint16_t cid, + uint16_t handle, struct os_mbuf *txom) { #if !NIMBLE_BLE_ATT_CLT_INDICATE return BLE_HS_ENOTSUP; @@ -937,7 +966,7 @@ ble_att_clt_tx_indicate(uint16_t conn_handle, uint16_t handle, req->baiq_handle = htole16(handle); os_mbuf_concat(txom2, txom); - return ble_att_tx(conn_handle, txom2); + return ble_att_tx(conn_handle, cid, txom2); err: os_mbuf_free_chain(txom); @@ -945,15 +974,47 @@ ble_att_clt_tx_indicate(uint16_t conn_handle, uint16_t handle, } int -ble_att_clt_rx_indicate(uint16_t conn_handle, struct os_mbuf **rxom) +ble_att_clt_rx_indicate(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rxom) { #if !NIMBLE_BLE_ATT_CLT_INDICATE return BLE_HS_ENOTSUP; #endif /* No payload. */ - ble_gattc_rx_indicate_rsp(conn_handle); + ble_gatts_rx_indicate_rsp(conn_handle, cid); return 0; } #endif + +/***************************************************************************** + * $multiple handle value notification * + *****************************************************************************/ + +int +ble_att_clt_tx_notify_mult(uint16_t conn_handle, struct os_mbuf *txom) +{ +#if !NIMBLE_BLE_ATT_CLT_NOTIFY_MULT + return BLE_HS_ENOTSUP; +#endif + + struct os_mbuf *txom2; + uint16_t cid; + int rc; + + if (ble_att_cmd_get(BLE_ATT_OP_NOTIFY_MULTI_REQ, 0, &txom2) == NULL) { + rc = BLE_HS_ENOMEM; + goto err; + } + + os_mbuf_concat(txom2, txom); + + cid = ble_eatt_get_available_chan_cid(conn_handle, BLE_GATT_OP_DUMMY); + rc = ble_att_tx(conn_handle, cid, txom2); + if (cid != BLE_L2CAP_CID_ATT) { + ble_eatt_release_chan(conn_handle, BLE_GATT_OP_DUMMY); + } + +err: + return rc; +} diff --git a/nimble/host/src/ble_att_cmd.c b/nimble/host/src/ble_att_cmd.c index e7192351c5..4760ff60da 100644 --- a/nimble/host/src/ble_att_cmd.c +++ b/nimble/host/src/ble_att_cmd.c @@ -17,6 +17,10 @@ * under the License. */ +#include +#define BLE_NPL_LOG_MODULE BLE_EATT_LOG +#include + #include #include #include "os/os.h" @@ -24,7 +28,6 @@ #include "ble_hs_priv.h" #include "host/ble_att.h" #include "host/ble_uuid.h" -#include "ble_hs_priv.h" #if NIMBLE_BLE_CONNECT void * @@ -56,28 +59,68 @@ ble_att_cmd_get(uint8_t opcode, size_t len, struct os_mbuf **txom) } int -ble_att_tx(uint16_t conn_handle, struct os_mbuf *txom) +ble_att_tx_with_conn(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan, struct os_mbuf *txom) { - struct ble_l2cap_chan *chan; - struct ble_hs_conn *conn; int rc; + struct os_mbuf_pkthdr *omp; + + if (!txom) { + if (conn->client_att_busy) { + return 0; + } + omp = STAILQ_FIRST(&conn->att_tx_q); + if (omp == NULL) { + BLE_EATT_LOG_ERROR("%s: wakeup but nothing in the queue\n", __func__); + return 0; + } + STAILQ_REMOVE_HEAD(&conn->att_tx_q, omp_next); + txom = OS_MBUF_PKTHDR_TO_MBUF(omp); + BLE_EATT_LOG_DEBUG("%s: wakeup will send %p\n", __func__, txom); + } BLE_HS_DBG_ASSERT_EVAL(txom->om_len >= 1); + + if (ble_att_is_request_op(txom->om_data[0])) { + if (conn->client_att_busy) { + BLE_EATT_LOG_DEBUG("ATT Queue %p, client busy %d\n", txom, conn->client_att_busy); + STAILQ_INSERT_TAIL(&conn->att_tx_q, OS_MBUF_PKTHDR(txom), omp_next); + return 0; + } + conn->client_att_busy = true; + } + ble_att_inc_tx_stat(txom->om_data[0]); - ble_hs_lock(); + ble_att_truncate_to_mtu(chan, txom); + rc = ble_l2cap_tx(conn, chan, txom); + assert(rc == 0); + return rc; +} +int +ble_att_tx(uint16_t conn_handle, uint16_t cid, struct os_mbuf *txom) +{ + struct ble_l2cap_chan *chan; + struct ble_hs_conn *conn; + int rc; + +#if MYNEWT_VAL(BLE_EATT_CHAN_NUM) > 0 + if (cid != BLE_L2CAP_CID_ATT) { + return ble_eatt_tx(conn_handle, cid, txom); + } +#endif + + ble_hs_lock(); rc = ble_hs_misc_conn_chan_find_reqd(conn_handle, BLE_L2CAP_CID_ATT, &conn, &chan); if (rc != 0) { + ble_hs_unlock(); os_mbuf_free_chain(txom); - } else { - ble_att_truncate_to_mtu(chan, txom); - rc = ble_l2cap_tx(conn, chan, txom); + return rc; } + rc = ble_att_tx_with_conn(conn, chan, txom); ble_hs_unlock(); - return rc; } diff --git a/nimble/host/src/ble_att_cmd_priv.h b/nimble/host/src/ble_att_cmd_priv.h index 70f33260a7..ab407ca9a2 100644 --- a/nimble/host/src/ble_att_cmd_priv.h +++ b/nimble/host/src/ble_att_cmd_priv.h @@ -309,6 +309,20 @@ struct ble_att_exec_write_req { */ #define BLE_ATT_EXEC_WRITE_RSP_SZ 1 +/** + * | Parameter | Size (octets) | + * +-----------------------------------------------+-------------------+ + * | Attribute Opcode | 1 | + * | Attribute Handle Length Value Tuple List | 8 to (ATT_MTU-1) | + */ +#define BLE_ATT_NOTIFY_MULTI_REQ_BASE_SZ 9 + +struct ble_att_tuple_list { + uint16_t handle; + uint16_t value_len; + uint8_t data[0]; +} __attribute__((packed)); + /** * | Parameter | Size (octets) | * +------------------------------------+-------------------+ @@ -440,8 +454,16 @@ void ble_att_indicate_rsp_write(void *payload, int len); void *ble_att_cmd_prepare(uint8_t opcode, size_t len, struct os_mbuf *txom); void *ble_att_cmd_get(uint8_t opcode, size_t len, struct os_mbuf **txom); -int ble_att_tx(uint16_t conn_handle, struct os_mbuf *txom); - +int ble_att_tx(uint16_t conn_handle, uint16_t cid, struct os_mbuf *txom); + +struct ble_l2cap_chan; +struct ble_hs_conn; +int ble_att_tx_with_conn(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan, + struct os_mbuf *txom); +bool ble_att_is_response_op(uint8_t opcode); +bool ble_att_is_request_op(uint8_t opcode); +bool ble_eatt_supported_req(uint8_t opcode); +bool ble_eatt_supported_rsp(uint8_t opcode); #ifdef __cplusplus } #endif diff --git a/nimble/host/src/ble_att_priv.h b/nimble/host/src/ble_att_priv.h index a2a9f9797b..2bc3da361b 100644 --- a/nimble/host/src/ble_att_priv.h +++ b/nimble/host/src/ble_att_priv.h @@ -161,13 +161,15 @@ SLIST_HEAD(ble_att_clt_entry_list, ble_att_clt_entry); /*** @gen */ struct ble_l2cap_chan *ble_att_create_chan(uint16_t conn_handle); -int ble_att_conn_chan_find(uint16_t conn_handle, struct ble_hs_conn **out_conn, +int ble_att_conn_chan_find(uint16_t conn_handle, uint16_t cid, + struct ble_hs_conn **out_conn, struct ble_l2cap_chan **out_chan); void ble_att_inc_tx_stat(uint8_t att_op); void ble_att_truncate_to_mtu(const struct ble_l2cap_chan *att_chan, struct os_mbuf *txom); void ble_att_set_peer_mtu(struct ble_l2cap_chan *chan, uint16_t peer_mtu); uint16_t ble_att_chan_mtu(const struct ble_l2cap_chan *chan); +uint16_t ble_att_mtu_by_cid(uint16_t conn_handle, uint16_t cid); int ble_att_init(void); /*** @svr */ @@ -179,33 +181,37 @@ ble_att_svr_find_by_uuid(struct ble_att_svr_entry *start_at, const ble_uuid_t *uuid, uint16_t end_handle); uint16_t ble_att_svr_prev_handle(void); -int ble_att_svr_rx_mtu(uint16_t conn_handle, struct os_mbuf **rxom); +int ble_att_svr_rx_mtu(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rxom); struct ble_att_svr_entry *ble_att_svr_find_by_handle(uint16_t handle_id); int32_t ble_att_svr_ticks_until_tmo(const struct ble_att_svr_conn *svr, ble_npl_time_t now); -int ble_att_svr_rx_find_info(uint16_t conn_handle, struct os_mbuf **rxom); -int ble_att_svr_rx_find_type_value(uint16_t conn_handle, +int ble_att_svr_rx_find_info(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rxom); +int ble_att_svr_rx_find_type_value(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rxom); -int ble_att_svr_rx_read_type(uint16_t conn_handle, +int ble_att_svr_rx_read_type(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rxom); -int ble_att_svr_rx_read_group_type(uint16_t conn_handle, +int ble_att_svr_rx_read_group_type(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rxom); -int ble_att_svr_rx_read(uint16_t conn_handle, +int ble_att_svr_rx_read(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rxom); -int ble_att_svr_rx_read_blob(uint16_t conn_handle, +int ble_att_svr_rx_read_blob(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rxom); -int ble_att_svr_rx_read_mult(uint16_t conn_handle, +int ble_att_svr_rx_read_mult(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rxom); -int ble_att_svr_rx_write(uint16_t conn_handle, +int ble_att_svr_rx_read_mult_var(uint16_t conn_handle, uint16_t cid, + struct os_mbuf **rxom); +int ble_att_svr_rx_write(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rxom); -int ble_att_svr_rx_write_no_rsp(uint16_t conn_handle, struct os_mbuf **rxom); -int ble_att_svr_rx_prep_write(uint16_t conn_handle, +int ble_att_svr_rx_write_no_rsp(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rxom); +int ble_att_svr_rx_prep_write(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rxom); -int ble_att_svr_rx_exec_write(uint16_t conn_handle, +int ble_att_svr_rx_exec_write(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rxom); -int ble_att_svr_rx_notify(uint16_t conn_handle, +int ble_att_svr_rx_notify(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rxom); -int ble_att_svr_rx_indicate(uint16_t conn_handle, +int ble_att_svr_rx_notify_multi(uint16_t conn_handle, uint16_t cid, + struct os_mbuf **rxom); +int ble_att_svr_rx_indicate(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rxom); void ble_att_svr_prep_clear(struct ble_att_prep_entry_list *prep_list); int ble_att_svr_read_handle(uint16_t conn_handle, uint16_t attr_handle, @@ -217,7 +223,7 @@ int ble_att_svr_init(void); void ble_att_svr_hide_range(uint16_t start_handle, uint16_t end_handle); void ble_att_svr_restore_range(uint16_t start_handle, uint16_t end_handle); -int ble_att_svr_tx_error_rsp(uint16_t conn_handle, struct os_mbuf *txom, +int ble_att_svr_tx_error_rsp(uint16_t conn_handle, uint16_t cid, struct os_mbuf *txom, uint8_t req_op, uint16_t handle, uint8_t error_code); /*** $clt */ @@ -250,48 +256,53 @@ struct ble_att_read_group_type_adata { uint8_t *value; }; -int ble_att_clt_rx_error(uint16_t conn_handle, struct os_mbuf **rxom); +int ble_att_clt_rx_error(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rxom); int ble_att_clt_tx_mtu(uint16_t conn_handle, uint16_t mtu); -int ble_att_clt_rx_mtu(uint16_t conn_handle, struct os_mbuf **rxom); -int ble_att_clt_tx_read(uint16_t conn_handle, uint16_t handle); -int ble_att_clt_rx_read(uint16_t conn_handle, struct os_mbuf **rxom); -int ble_att_clt_tx_read_blob(uint16_t conn_handle, uint16_t handle, +int ble_att_clt_rx_mtu(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rxom); +int ble_att_clt_tx_read(uint16_t conn_handle, uint16_t cid, uint16_t handle); +int ble_att_clt_rx_read(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rxom); +int ble_att_clt_tx_read_blob(uint16_t conn_handle, uint16_t cid, uint16_t handle, uint16_t offset); -int ble_att_clt_rx_read_blob(uint16_t conn_handle, struct os_mbuf **rxom); -int ble_att_clt_tx_read_mult(uint16_t conn_handle, - const uint16_t *handles, int num_handles); -int ble_att_clt_rx_read_mult(uint16_t conn_handle, struct os_mbuf **rxom); -int ble_att_clt_tx_read_type(uint16_t conn_handle, uint16_t start_handle, +int ble_att_clt_rx_read_blob(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rxom); +int ble_att_clt_tx_read_mult(uint16_t conn_handle, uint16_t cid, + const uint16_t *handles, int num_handles, bool variable); +int ble_att_clt_rx_read_mult(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rxom); +int ble_att_clt_rx_read_mult_var(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rxom); +int ble_att_clt_tx_read_type(uint16_t conn_handle, uint16_t cid, uint16_t start_handle, uint16_t end_handle, const ble_uuid_t *uuid); -int ble_att_clt_rx_read_type(uint16_t conn_handle, struct os_mbuf **rxom); -int ble_att_clt_tx_read_group_type(uint16_t conn_handle, +int ble_att_clt_rx_read_type(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rxom); +int ble_att_clt_tx_read_group_type(uint16_t conn_handle, uint16_t cid, uint16_t start_handle, uint16_t end_handle, const ble_uuid_t *uuid128); -int ble_att_clt_rx_read_group_type(uint16_t conn_handle, +int ble_att_clt_rx_read_group_type(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rxom); -int ble_att_clt_tx_find_info(uint16_t conn_handle, uint16_t start_handle, +int ble_att_clt_tx_find_info(uint16_t conn_handle, uint16_t cid, uint16_t start_handle, uint16_t end_handle); -int ble_att_clt_rx_find_info(uint16_t conn_handle, struct os_mbuf **rxom); -int ble_att_clt_tx_find_type_value(uint16_t conn_handle, uint16_t start_handle, +int ble_att_clt_rx_find_info(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rxom); +int ble_att_clt_tx_find_type_value(uint16_t conn_handle, uint16_t cid, uint16_t start_handle, uint16_t end_handle, uint16_t attribute_type, const void *attribute_value, int value_len); -int ble_att_clt_rx_find_type_value(uint16_t conn_handle, +int ble_att_clt_rx_find_type_value(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rxom); -int ble_att_clt_tx_write_req(uint16_t conn_handle, uint16_t handle, - struct os_mbuf *txom); -int ble_att_clt_tx_write_cmd(uint16_t conn_handle, uint16_t handle, - struct os_mbuf *txom); -int ble_att_clt_tx_prep_write(uint16_t conn_handle, uint16_t handle, - uint16_t offset, struct os_mbuf *txom); -int ble_att_clt_rx_prep_write(uint16_t conn_handle, struct os_mbuf **rxom); -int ble_att_clt_tx_exec_write(uint16_t conn_handle, uint8_t flags); -int ble_att_clt_rx_exec_write(uint16_t conn_handle, struct os_mbuf **rxom); -int ble_att_clt_rx_write(uint16_t conn_handle, struct os_mbuf **rxom); +int ble_att_clt_tx_write_req(uint16_t conn_handle, uint16_t cid, + uint16_t handle, struct os_mbuf *txom); +int ble_att_clt_tx_write_cmd(uint16_t conn_handle, uint16_t cid, + uint16_t handle, struct os_mbuf *txom); +int ble_att_clt_tx_prep_write(uint16_t conn_handle, uint16_t cid, + uint16_t handle, uint16_t offset, + struct os_mbuf *txom); +int ble_att_clt_rx_prep_write(uint16_t conn_handle, uint16_t cid, + struct os_mbuf **rxom); +int ble_att_clt_tx_exec_write(uint16_t conn_handle, uint16_t cid, + uint8_t flags); +int ble_att_clt_rx_exec_write(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rxom); +int ble_att_clt_rx_write(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rxom); int ble_att_clt_tx_notify(uint16_t conn_handle, uint16_t handle, struct os_mbuf *txom); -int ble_att_clt_tx_indicate(uint16_t conn_handle, uint16_t handle, - struct os_mbuf *txom); -int ble_att_clt_rx_indicate(uint16_t conn_handle, struct os_mbuf **rxom); +int ble_att_clt_tx_indicate(uint16_t conn_handle, uint16_t cid, + uint16_t handle, struct os_mbuf *txom); +int ble_att_clt_rx_indicate(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rxom); +int ble_att_clt_tx_notify_mult(uint16_t conn_handle, struct os_mbuf *txom); #ifdef __cplusplus } diff --git a/nimble/host/src/ble_att_svr.c b/nimble/host/src/ble_att_svr.c index 4fdf27e843..8fdf0e8457 100644 --- a/nimble/host/src/ble_att_svr.c +++ b/nimble/host/src/ble_att_svr.c @@ -21,6 +21,7 @@ #include #include #include "os/os.h" +#include "host/ble_att.h" #include "nimble/ble.h" #include "host/ble_uuid.h" #include "ble_hs_priv.h" @@ -30,7 +31,7 @@ * ATT server - Attribute Protocol * * Notes on buffer reuse: - * Most request handlers reuse the request buffer for the reponse. This is + * Most request handlers reuse the request buffer for the response. This is * done to prevent out-of-memory conditions. However, there are two handlers * which do not reuse the request buffer: * 1. Write request. @@ -288,12 +289,18 @@ ble_att_svr_check_perms(uint16_t conn_handle, int is_read, * require it on level 4 */ if (MYNEWT_VAL(BLE_SM_SC_ONLY)) { - if (sec_state.key_size != 16 || - !sec_state.authenticated || + if (!sec_state.authenticated || !sec_state.encrypted) { - return BLE_ATT_ERR_INSUFFICIENT_KEY_SZ; + *out_att_err = BLE_ATT_ERR_INSUFFICIENT_AUTHEN; + return BLE_HS_ATT_ERR(*out_att_err); + } else if (sec_state.authenticated && + sec_state.encrypted && + sec_state.key_size != 16) { + *out_att_err = BLE_ATT_ERR_INSUFFICIENT_KEY_SZ; + return BLE_HS_ATT_ERR(*out_att_err); } } + if ((enc || authen) && !sec_state.encrypted) { ble_hs_lock(); conn = ble_hs_conn_find(conn_handle); @@ -571,7 +578,7 @@ ble_att_svr_write_handle(uint16_t conn_handle, uint16_t attr_handle, } int -ble_att_svr_tx_error_rsp(uint16_t conn_handle, struct os_mbuf *txom, +ble_att_svr_tx_error_rsp(uint16_t conn_handle, uint16_t cid, struct os_mbuf *txom, uint8_t req_op, uint16_t handle, uint8_t error_code) { struct ble_att_error_rsp *rsp; @@ -588,7 +595,7 @@ ble_att_svr_tx_error_rsp(uint16_t conn_handle, struct os_mbuf *txom, rsp->baep_handle = htole16(handle); rsp->baep_error_code = error_code; - return ble_att_tx(conn_handle, txom); + return ble_att_tx(conn_handle, cid, txom); } /** @@ -615,13 +622,12 @@ ble_att_svr_tx_error_rsp(uint16_t conn_handle, struct os_mbuf *txom, * field. */ static int -ble_att_svr_tx_rsp(uint16_t conn_handle, int hs_status, struct os_mbuf *om, +ble_att_svr_tx_rsp(uint16_t conn_handle, uint16_t cid, int hs_status, struct os_mbuf *om, uint8_t att_op, uint8_t err_status, uint16_t err_handle) { struct ble_l2cap_chan *chan; struct ble_hs_conn *conn; int do_tx; - int rc; if (hs_status != 0 && err_status == 0) { /* Processing failed, but err_status of 0 means don't send error. */ @@ -631,28 +637,33 @@ ble_att_svr_tx_rsp(uint16_t conn_handle, int hs_status, struct os_mbuf *om, } if (do_tx) { - ble_hs_lock(); + if (hs_status == 0) { + ble_hs_lock(); + conn = ble_hs_conn_find(conn_handle); + if (conn == NULL) { + hs_status = BLE_HS_ENOTCONN; + ble_hs_unlock(); + goto done; + } - rc = ble_att_conn_chan_find(conn_handle, &conn, &chan); - if (rc != 0) { - /* No longer connected. */ - hs_status = rc; - } else { - if (hs_status == 0) { - BLE_HS_DBG_ASSERT(om != NULL); + chan = ble_hs_conn_chan_find_by_scid(conn, cid); + if (chan == NULL) { + hs_status = BLE_HS_ENOENT; + ble_hs_unlock(); + goto done; + } - ble_att_inc_tx_stat(om->om_data[0]); - ble_att_truncate_to_mtu(chan, om); - hs_status = ble_l2cap_tx(conn, chan, om); - om = NULL; - if (hs_status != 0) { - err_status = BLE_ATT_ERR_UNLIKELY; - } - } - } + ble_att_truncate_to_mtu(chan, om); + ble_hs_unlock(); - ble_hs_unlock(); + hs_status = ble_att_tx(conn_handle, cid, om); + om = NULL; + if (hs_status) { + err_status = BLE_ATT_ERR_UNLIKELY; + } + } +done: if (hs_status != 0) { STATS_INC(ble_att_stats, error_rsp_tx); @@ -663,7 +674,7 @@ ble_att_svr_tx_rsp(uint16_t conn_handle, int hs_status, struct os_mbuf *om, os_mbuf_adj(om, OS_MBUF_PKTLEN(om)); } if (om != NULL) { - ble_att_svr_tx_error_rsp(conn_handle, om, att_op, + ble_att_svr_tx_error_rsp(conn_handle, cid, om, att_op, err_handle, err_status); om = NULL; } @@ -690,7 +701,7 @@ ble_att_svr_build_mtu_rsp(uint16_t conn_handle, struct os_mbuf **rxom, txom = NULL; ble_hs_lock(); - rc = ble_att_conn_chan_find(conn_handle, NULL, &chan); + rc = ble_att_conn_chan_find(conn_handle, BLE_L2CAP_CID_ATT, NULL, &chan); if (rc == 0) { mtu = chan->my_mtu; } @@ -722,7 +733,7 @@ ble_att_svr_build_mtu_rsp(uint16_t conn_handle, struct os_mbuf **rxom, } int -ble_att_svr_rx_mtu(uint16_t conn_handle, struct os_mbuf **rxom) +ble_att_svr_rx_mtu(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rxom) { struct ble_att_mtu_cmd *cmd; struct ble_l2cap_chan *chan; @@ -735,6 +746,11 @@ ble_att_svr_rx_mtu(uint16_t conn_handle, struct os_mbuf **rxom) txom = NULL; mtu = 0; + if (cid != BLE_L2CAP_CID_ATT) { + /* This operation is not supported over enhanced ATT bearer */ + return BLE_HS_ENOTSUP; + } + rc = ble_att_svr_pullup_req_base(rxom, sizeof(*cmd), &att_err); if (rc != 0) { goto done; @@ -752,12 +768,12 @@ ble_att_svr_rx_mtu(uint16_t conn_handle, struct os_mbuf **rxom) rc = 0; done: - rc = ble_att_svr_tx_rsp(conn_handle, rc, txom, BLE_ATT_OP_MTU_REQ, + rc = ble_att_svr_tx_rsp(conn_handle, BLE_L2CAP_CID_ATT, rc, txom, BLE_ATT_OP_MTU_REQ, att_err, 0); if (rc == 0) { ble_hs_lock(); - rc = ble_att_conn_chan_find(conn_handle, &conn, &chan); + rc = ble_att_conn_chan_find(conn_handle, BLE_L2CAP_CID_ATT, &conn, &chan); if (rc == 0) { ble_att_set_peer_mtu(chan, mtu); chan->flags |= BLE_L2CAP_CHAN_F_TXED_MTU; @@ -856,7 +872,7 @@ ble_att_svr_fill_info(uint16_t start_handle, uint16_t end_handle, } static int -ble_att_svr_build_find_info_rsp(uint16_t conn_handle, +ble_att_svr_build_find_info_rsp(uint16_t conn_handle, uint16_t cid, uint16_t start_handle, uint16_t end_handle, struct os_mbuf **rxom, struct os_mbuf **out_txom, @@ -885,7 +901,7 @@ ble_att_svr_build_find_info_rsp(uint16_t conn_handle, /* Write the variable length Information Data field, populating the format * field as appropriate. */ - mtu = ble_att_mtu(conn_handle); + mtu = ble_att_mtu_by_cid(conn_handle, cid); rc = ble_att_svr_fill_info(start_handle, end_handle, txom, mtu, &rsp->bafp_format); if (rc != 0) { @@ -902,7 +918,7 @@ ble_att_svr_build_find_info_rsp(uint16_t conn_handle, } int -ble_att_svr_rx_find_info(uint16_t conn_handle, struct os_mbuf **rxom) +ble_att_svr_rx_find_info(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rxom) { #if !MYNEWT_VAL(BLE_ATT_SVR_FIND_INFO) return BLE_HS_ENOTSUP; @@ -939,7 +955,7 @@ ble_att_svr_rx_find_info(uint16_t conn_handle, struct os_mbuf **rxom) goto done; } - rc = ble_att_svr_build_find_info_rsp(conn_handle, + rc = ble_att_svr_build_find_info_rsp(conn_handle, cid, start_handle, end_handle, rxom, &txom, &att_err); if (rc != 0) { @@ -950,7 +966,7 @@ ble_att_svr_rx_find_info(uint16_t conn_handle, struct os_mbuf **rxom) rc = 0; done: - rc = ble_att_svr_tx_rsp(conn_handle, rc, txom, BLE_ATT_OP_FIND_INFO_REQ, + rc = ble_att_svr_tx_rsp(conn_handle, cid, rc, txom, BLE_ATT_OP_FIND_INFO_REQ, att_err, err_handle); return rc; } @@ -1165,7 +1181,7 @@ ble_att_svr_fill_type_value(uint16_t conn_handle, } static int -ble_att_svr_build_find_type_value_rsp(uint16_t conn_handle, +ble_att_svr_build_find_type_value_rsp(uint16_t conn_handle, uint16_t cid, uint16_t start_handle, uint16_t end_handle, ble_uuid16_t attr_type, @@ -1192,7 +1208,7 @@ ble_att_svr_build_find_type_value_rsp(uint16_t conn_handle, } /* Write the variable length Information Data field. */ - mtu = ble_att_mtu(conn_handle); + mtu = ble_att_mtu_by_cid(conn_handle, cid); rc = ble_att_svr_fill_type_value(conn_handle, start_handle, end_handle, attr_type, *rxom, txom, mtu, @@ -1209,7 +1225,7 @@ ble_att_svr_build_find_type_value_rsp(uint16_t conn_handle, } int -ble_att_svr_rx_find_type_value(uint16_t conn_handle, struct os_mbuf **rxom) +ble_att_svr_rx_find_type_value(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rxom) { #if !MYNEWT_VAL(BLE_ATT_SVR_FIND_TYPE) return BLE_HS_ENOTSUP; @@ -1247,7 +1263,7 @@ ble_att_svr_rx_find_type_value(uint16_t conn_handle, struct os_mbuf **rxom) rc = BLE_HS_EBADDATA; goto done; } - rc = ble_att_svr_build_find_type_value_rsp(conn_handle, start_handle, + rc = ble_att_svr_build_find_type_value_rsp(conn_handle, cid, start_handle, end_handle, attr_type, rxom, &txom, &att_err); if (rc != 0) { @@ -1258,14 +1274,14 @@ ble_att_svr_rx_find_type_value(uint16_t conn_handle, struct os_mbuf **rxom) rc = 0; done: - rc = ble_att_svr_tx_rsp(conn_handle, rc, txom, + rc = ble_att_svr_tx_rsp(conn_handle, cid, rc, txom, BLE_ATT_OP_FIND_TYPE_VALUE_REQ, att_err, err_handle); return rc; } static int -ble_att_svr_build_read_type_rsp(uint16_t conn_handle, +ble_att_svr_build_read_type_rsp(uint16_t conn_handle, uint16_t cid, uint16_t start_handle, uint16_t end_handle, const ble_uuid_t *uuid, struct os_mbuf **rxom, @@ -1296,7 +1312,7 @@ ble_att_svr_build_read_type_rsp(uint16_t conn_handle, *rxom = NULL; os_mbuf_adj(txom, OS_MBUF_PKTLEN(txom)); - /* Allocate space for the respose base, but don't fill in the fields. They + /* Allocate space for the response base, but don't fill in the fields. They * get filled in at the end, when we know the value of the length field. */ @@ -1308,7 +1324,7 @@ ble_att_svr_build_read_type_rsp(uint16_t conn_handle, goto done; } - mtu = ble_att_mtu(conn_handle); + mtu = ble_att_mtu_by_cid(conn_handle, cid); /* Find all matching attributes, writing a record for each. */ entry = NULL; @@ -1380,7 +1396,7 @@ ble_att_svr_build_read_type_rsp(uint16_t conn_handle, } int -ble_att_svr_rx_read_type(uint16_t conn_handle, struct os_mbuf **rxom) +ble_att_svr_rx_read_type(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rxom) { #if !MYNEWT_VAL(BLE_ATT_SVR_READ_TYPE) return BLE_HS_ENOTSUP; @@ -1432,7 +1448,7 @@ ble_att_svr_rx_read_type(uint16_t conn_handle, struct os_mbuf **rxom) goto done; } - rc = ble_att_svr_build_read_type_rsp(conn_handle, start_handle, end_handle, + rc = ble_att_svr_build_read_type_rsp(conn_handle, cid, start_handle, end_handle, &uuid.u, rxom, &txom, &att_err, &err_handle); if (rc != 0) { @@ -1442,13 +1458,13 @@ ble_att_svr_rx_read_type(uint16_t conn_handle, struct os_mbuf **rxom) rc = 0; done: - rc = ble_att_svr_tx_rsp(conn_handle, rc, txom, BLE_ATT_OP_READ_TYPE_REQ, + rc = ble_att_svr_tx_rsp(conn_handle, cid, rc, txom, BLE_ATT_OP_READ_TYPE_REQ, att_err, err_handle); return rc; } int -ble_att_svr_rx_read(uint16_t conn_handle, struct os_mbuf **rxom) +ble_att_svr_rx_read(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rxom) { #if !MYNEWT_VAL(BLE_ATT_SVR_READ) return BLE_HS_ENOTSUP; @@ -1491,13 +1507,13 @@ ble_att_svr_rx_read(uint16_t conn_handle, struct os_mbuf **rxom) } done: - rc = ble_att_svr_tx_rsp(conn_handle, rc, txom, BLE_ATT_OP_READ_REQ, + rc = ble_att_svr_tx_rsp(conn_handle, cid, rc, txom, BLE_ATT_OP_READ_REQ, att_err, err_handle); return rc; } int -ble_att_svr_rx_read_blob(uint16_t conn_handle, struct os_mbuf **rxom) +ble_att_svr_rx_read_blob(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rxom) { #if !MYNEWT_VAL(BLE_ATT_SVR_READ_BLOB) return BLE_HS_ENOTSUP; @@ -1544,13 +1560,13 @@ ble_att_svr_rx_read_blob(uint16_t conn_handle, struct os_mbuf **rxom) rc = 0; done: - rc = ble_att_svr_tx_rsp(conn_handle, rc, txom, BLE_ATT_OP_READ_BLOB_REQ, + rc = ble_att_svr_tx_rsp(conn_handle, cid, rc, txom, BLE_ATT_OP_READ_BLOB_REQ, att_err, err_handle); return rc; } static int -ble_att_svr_build_read_mult_rsp(uint16_t conn_handle, +ble_att_svr_build_read_mult_rsp(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rxom, struct os_mbuf **out_txom, uint8_t *att_err, @@ -1561,7 +1577,7 @@ ble_att_svr_build_read_mult_rsp(uint16_t conn_handle, uint16_t mtu; int rc; - mtu = ble_att_mtu(conn_handle); + mtu = ble_att_mtu_by_cid(conn_handle, cid); rc = ble_att_svr_pkt(rxom, &txom, att_err); if (rc != 0) { @@ -1611,7 +1627,7 @@ ble_att_svr_build_read_mult_rsp(uint16_t conn_handle, } int -ble_att_svr_rx_read_mult(uint16_t conn_handle, struct os_mbuf **rxom) +ble_att_svr_rx_read_mult(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rxom) { #if !MYNEWT_VAL(BLE_ATT_SVR_READ_MULT) return BLE_HS_ENOTSUP; @@ -1627,10 +1643,117 @@ ble_att_svr_rx_read_mult(uint16_t conn_handle, struct os_mbuf **rxom) err_handle = 0; att_err = 0; - rc = ble_att_svr_build_read_mult_rsp(conn_handle, rxom, &txom, &att_err, + rc = ble_att_svr_build_read_mult_rsp(conn_handle, cid, rxom, &txom, &att_err, + &err_handle); + + return ble_att_svr_tx_rsp(conn_handle, cid, rc, txom, BLE_ATT_OP_READ_MULT_REQ, + att_err, err_handle); +} + +static int +ble_att_svr_build_read_mult_rsp_var(uint16_t conn_handle, uint16_t cid, + struct os_mbuf **rxom, + struct os_mbuf **out_txom, + uint8_t *att_err, + uint16_t *err_handle) +{ + struct os_mbuf *txom; + uint16_t handle; + uint16_t mtu; + uint16_t tuple_len; + struct os_mbuf *tmp = NULL; + int rc; + + mtu = ble_att_mtu_by_cid(conn_handle, cid); + + rc = ble_att_svr_pkt(rxom, &txom, att_err); + if (rc != 0) { + *err_handle = 0; + goto done; + } + + if (ble_att_cmd_prepare(BLE_ATT_OP_READ_MULT_VAR_RSP, 0, txom) == NULL) { + *att_err = BLE_ATT_ERR_INSUFFICIENT_RES; + *err_handle = 0; + rc = BLE_HS_ENOMEM; + goto done; + } + + tmp = os_msys_get_pkthdr(2, 0); + + /* Iterate through requested handles, reading the corresponding attribute + * for each. Stop when there are no more handles to process, or the + * response is full. + */ + while (OS_MBUF_PKTLEN(*rxom) >= 2 && OS_MBUF_PKTLEN(txom) < mtu) { + /* Ensure the full 16-bit handle is contiguous at the start of the + * mbuf. + */ + rc = ble_att_svr_pullup_req_base(rxom, 2, att_err); + if (rc != 0) { + *err_handle = 0; + goto done; + } + + /* Extract the 16-bit handle and strip it from the front of the + * mbuf. + */ + handle = get_le16((*rxom)->om_data); + os_mbuf_adj(*rxom, 2); + + rc = ble_att_svr_read_handle(conn_handle, handle, 0, tmp, att_err); + if (rc != 0) { + *err_handle = handle; + goto done; + } + tuple_len = OS_MBUF_PKTLEN(tmp); + rc = os_mbuf_append(txom, &tuple_len, sizeof(tuple_len)); + if (rc != 0) { + *err_handle = handle; + goto done; + } + if (tuple_len != 0) { + rc = os_mbuf_appendfrom(txom, tmp, 0, tuple_len); + if (rc != 0) { + *err_handle = handle; + goto done; + } + os_mbuf_adj(tmp, tuple_len); + } + } + rc = 0; + +done: + + if (tmp) { + os_mbuf_free_chain(tmp); + } + *out_txom = txom; + return rc; +} + +int +ble_att_svr_rx_read_mult_var(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rxom) +{ +#if (!MYNEWT_VAL(BLE_ATT_SVR_READ_MULT) || (MYNEWT_VAL(BLE_VERSION) < 52)) + return BLE_HS_ENOTSUP; +#endif + + struct os_mbuf *txom; + uint16_t err_handle; + uint8_t att_err; + int rc; + + /* Initialize some values in case of early error. */ + txom = NULL; + err_handle = 0; + att_err = 0; + + rc = ble_att_svr_build_read_mult_rsp_var(conn_handle, cid, rxom, &txom, &att_err, &err_handle); - return ble_att_svr_tx_rsp(conn_handle, rc, txom, BLE_ATT_OP_READ_MULT_REQ, + return ble_att_svr_tx_rsp(conn_handle, cid, rc, txom, + BLE_ATT_OP_READ_MULT_VAR_REQ, att_err, err_handle); } @@ -1698,7 +1821,7 @@ ble_att_svr_read_group_type_entry_write(struct os_mbuf *om, uint16_t mtu, * @return 0 on success; BLE_HS error code on failure. */ static int -ble_att_svr_build_read_group_type_rsp(uint16_t conn_handle, +ble_att_svr_build_read_group_type_rsp(uint16_t conn_handle, uint16_t cid, uint16_t start_handle, uint16_t end_handle, const ble_uuid_t *group_uuid, @@ -1718,11 +1841,14 @@ ble_att_svr_build_read_group_type_rsp(uint16_t conn_handle, /* Silence warnings. */ end_group_handle = 0; + start_group_handle = 0; + + entry = NULL; *att_err = 0; *err_handle = start_handle; - mtu = ble_att_mtu(conn_handle); + mtu = ble_att_mtu_by_cid(conn_handle, cid); /* Just reuse the request buffer for the response. */ txom = *rxom; @@ -1738,7 +1864,6 @@ ble_att_svr_build_read_group_type_rsp(uint16_t conn_handle, goto done; } - start_group_handle = 0; rsp->bagp_length = 0; STAILQ_FOREACH(entry, &ble_att_svr_list, ha_next) { if (entry->ha_handle_id < start_handle) { @@ -1865,7 +1990,7 @@ ble_att_svr_build_read_group_type_rsp(uint16_t conn_handle, } int -ble_att_svr_rx_read_group_type(uint16_t conn_handle, struct os_mbuf **rxom) +ble_att_svr_rx_read_group_type(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rxom) { #if !MYNEWT_VAL(BLE_ATT_SVR_READ_GROUP_TYPE) return BLE_HS_ENOTSUP; @@ -1925,9 +2050,10 @@ ble_att_svr_rx_read_group_type(uint16_t conn_handle, struct os_mbuf **rxom) goto done; } - rc = ble_att_svr_build_read_group_type_rsp(conn_handle, start_handle, - end_handle, &uuid.u, - rxom, &txom, &att_err, + rc = ble_att_svr_build_read_group_type_rsp(conn_handle, cid, + start_handle, end_handle, + &uuid.u, rxom, + &txom, &att_err, &err_handle); if (rc != 0) { goto done; @@ -1936,7 +2062,7 @@ ble_att_svr_rx_read_group_type(uint16_t conn_handle, struct os_mbuf **rxom) rc = 0; done: - rc = ble_att_svr_tx_rsp(conn_handle, rc, txom, + rc = ble_att_svr_tx_rsp(conn_handle, cid, rc, txom, BLE_ATT_OP_READ_GROUP_TYPE_REQ, att_err, err_handle); return rc; @@ -1971,7 +2097,7 @@ ble_att_svr_build_write_rsp(struct os_mbuf **rxom, struct os_mbuf **out_txom, } int -ble_att_svr_rx_write(uint16_t conn_handle, struct os_mbuf **rxom) +ble_att_svr_rx_write(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rxom) { #if !MYNEWT_VAL(BLE_ATT_SVR_WRITE) return BLE_HS_ENOTSUP; @@ -2016,13 +2142,13 @@ ble_att_svr_rx_write(uint16_t conn_handle, struct os_mbuf **rxom) rc = 0; done: - rc = ble_att_svr_tx_rsp(conn_handle, rc, txom, BLE_ATT_OP_WRITE_REQ, + rc = ble_att_svr_tx_rsp(conn_handle, cid, rc, txom, BLE_ATT_OP_WRITE_REQ, att_err, handle); return rc; } int -ble_att_svr_rx_write_no_rsp(uint16_t conn_handle, struct os_mbuf **rxom) +ble_att_svr_rx_write_no_rsp(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rxom) { #if !MYNEWT_VAL(BLE_ATT_SVR_WRITE_NO_RSP) return BLE_HS_ENOTSUP; @@ -2299,7 +2425,8 @@ ble_att_svr_insert_prep_entry(uint16_t conn_handle, #if BLE_HS_ATT_SVR_QUEUED_WRITE_TMO != 0 conn->bhc_att_svr.basc_prep_timeout_at = - ble_npl_time_get() + BLE_HS_ATT_SVR_QUEUED_WRITE_TMO; + ble_npl_time_get() + + ble_npl_time_ms_to_ticks32(BLE_HS_ATT_SVR_QUEUED_WRITE_TMO); ble_hs_timer_resched(); #endif @@ -2308,7 +2435,7 @@ ble_att_svr_insert_prep_entry(uint16_t conn_handle, } int -ble_att_svr_rx_prep_write(uint16_t conn_handle, struct os_mbuf **rxom) +ble_att_svr_rx_prep_write(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rxom) { #if !MYNEWT_VAL(BLE_ATT_SVR_QUEUED_WRITE) return BLE_HS_ENOTSUP; @@ -2383,13 +2510,13 @@ ble_att_svr_rx_prep_write(uint16_t conn_handle, struct os_mbuf **rxom) rc = 0; done: - rc = ble_att_svr_tx_rsp(conn_handle, rc, txom, BLE_ATT_OP_PREP_WRITE_REQ, + rc = ble_att_svr_tx_rsp(conn_handle, cid, rc, txom, BLE_ATT_OP_PREP_WRITE_REQ, att_err, err_handle); return rc; } int -ble_att_svr_rx_exec_write(uint16_t conn_handle, struct os_mbuf **rxom) +ble_att_svr_rx_exec_write(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rxom) { #if !MYNEWT_VAL(BLE_ATT_SVR_QUEUED_WRITE) return BLE_HS_ENOTSUP; @@ -2458,19 +2585,20 @@ ble_att_svr_rx_exec_write(uint16_t conn_handle, struct os_mbuf **rxom) ble_att_svr_prep_clear(&prep_list); } - rc = ble_att_svr_tx_rsp(conn_handle, rc, txom, BLE_ATT_OP_EXEC_WRITE_REQ, + rc = ble_att_svr_tx_rsp(conn_handle, cid, rc, txom, BLE_ATT_OP_EXEC_WRITE_REQ, att_err, err_handle); return rc; } int -ble_att_svr_rx_notify(uint16_t conn_handle, struct os_mbuf **rxom) +ble_att_svr_rx_notify(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rxom) { #if !MYNEWT_VAL(BLE_ATT_SVR_NOTIFY) return BLE_HS_ENOTSUP; #endif struct ble_att_notify_req *req; + struct ble_gap_sec_state sec_state; uint16_t handle; int rc; @@ -2487,6 +2615,15 @@ ble_att_svr_rx_notify(uint16_t conn_handle, struct os_mbuf **rxom) return BLE_HS_EBADDATA; } + ble_att_svr_get_sec_state(conn_handle, &sec_state); + + /* All indications shall be confirmed, but only these with required + * security established shall be pass to application + */ + if (MYNEWT_VAL(BLE_SM_LVL) >= 2 && !sec_state.encrypted) { + return 0; + } + /* Strip the request base from the front of the mbuf. */ os_mbuf_adj(*rxom, sizeof(*req)); @@ -2496,6 +2633,67 @@ ble_att_svr_rx_notify(uint16_t conn_handle, struct os_mbuf **rxom) return 0; } +int +ble_att_svr_rx_notify_multi(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rxom) +{ +#if !MYNEWT_VAL(BLE_ATT_SVR_NOTIFY_MULTI) + return BLE_HS_ENOTSUP; +#endif + + struct ble_att_tuple_list *req; + uint16_t handle; + int rc = 0; + uint16_t pkt_len; + struct os_mbuf *tmp; + uint16_t attr_len; + + pkt_len = OS_MBUF_PKTLEN(*rxom); + while (pkt_len > 0) { + rc = ble_att_svr_pullup_req_base(rxom, sizeof(struct ble_att_tuple_list), NULL); + if (rc != 0) { + return BLE_HS_ENOMEM; + } + + req = (struct ble_att_tuple_list *)(*rxom)->om_data; + + handle = le16toh(req->handle); + attr_len = le16toh(req->value_len); + + os_mbuf_adj(*rxom, 4); + + if (attr_len > BLE_ATT_ATTR_MAX_LEN) { + BLE_HS_LOG_ERROR("attr length (%d) > max (%d)", + attr_len, BLE_ATT_ATTR_MAX_LEN); + rc = BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN; + goto done; + } + + tmp = os_msys_get_pkthdr(attr_len, 0); + if (!tmp) { + BLE_HS_LOG_ERROR("not enough resources, aborting"); + rc = BLE_ATT_ERR_INSUFFICIENT_RES; + goto done; + } + + rc = os_mbuf_appendfrom(tmp, *rxom, 0, attr_len); + if (rc) { + BLE_HS_LOG_ERROR("not enough resources, aborting"); + rc = BLE_ATT_ERR_INSUFFICIENT_RES; + goto done; + } + + ble_gap_notify_rx_event(conn_handle, handle, tmp, 0); + + os_mbuf_adj(*rxom, attr_len); + pkt_len = OS_MBUF_PKTLEN(*rxom); + } +done: + os_mbuf_free_chain(*rxom); + *rxom = NULL; + + return rc; +} + /** * @return 0 on success; nonzero on failure. */ @@ -2529,13 +2727,14 @@ ble_att_svr_build_indicate_rsp(struct os_mbuf **rxom, } int -ble_att_svr_rx_indicate(uint16_t conn_handle, struct os_mbuf **rxom) +ble_att_svr_rx_indicate(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rxom) { #if !MYNEWT_VAL(BLE_ATT_SVR_INDICATE) return BLE_HS_ENOTSUP; #endif struct ble_att_indicate_req *req; + struct ble_gap_sec_state sec_state; struct os_mbuf *txom; uint16_t handle; uint8_t att_err; @@ -2568,6 +2767,15 @@ ble_att_svr_rx_indicate(uint16_t conn_handle, struct os_mbuf **rxom) goto done; } + ble_att_svr_get_sec_state(conn_handle, &sec_state); + + /* All indications shall be confirmed, but only these with required + * security established shall be pass to application + */ + if (MYNEWT_VAL(BLE_SM_LVL) >= 2 && !sec_state.encrypted) { + goto done; + } + /* Strip the request base from the front of the mbuf. */ os_mbuf_adj(*rxom, sizeof(*req)); @@ -2577,7 +2785,7 @@ ble_att_svr_rx_indicate(uint16_t conn_handle, struct os_mbuf **rxom) rc = 0; done: - rc = ble_att_svr_tx_rsp(conn_handle, rc, txom, BLE_ATT_OP_INDICATE_REQ, + rc = ble_att_svr_tx_rsp(conn_handle, cid, rc, txom, BLE_ATT_OP_INDICATE_REQ, att_err, handle); return rc; } @@ -2671,6 +2879,8 @@ ble_att_svr_reset(void) ble_att_svr_entry_free(entry); } + ble_att_svr_id = 0; + /* Note: prep entries do not get freed here because it is assumed there are * no established connections. */ diff --git a/nimble/controller/test/src/ble_ll_csa2_test.h b/nimble/host/src/ble_audio_codec_priv.h similarity index 85% rename from nimble/controller/test/src/ble_ll_csa2_test.h rename to nimble/host/src/ble_audio_codec_priv.h index 5bcc142bb3..64e999efeb 100644 --- a/nimble/controller/test/src/ble_ll_csa2_test.h +++ b/nimble/host/src/ble_audio_codec_priv.h @@ -17,11 +17,9 @@ * under the License. */ -#ifndef H_BLE_LL_CSA2_TEST_ -#define H_BLE_LL_CSA2_TEST_ +#ifndef H_BLE_AUDIO_CODEC_PRIV_ +#define H_BLE_AUDIO_CODEC_PRIV_ -#include "testutil/testutil.h" +int ble_audio_codec_init(void); -TEST_SUITE_DECL(ble_ll_csa2_test_suite); - -#endif +#endif /* H_BLE_AUDIO_CODEC_PRIV_ */ diff --git a/nimble/host/src/ble_cs.c b/nimble/host/src/ble_cs.c new file mode 100644 index 0000000000..cef622206b --- /dev/null +++ b/nimble/host/src/ble_cs.c @@ -0,0 +1,731 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include "syscfg/syscfg.h" +#include "ble_hs_mbuf_priv.h" + +#if MYNEWT_VAL(BLE_CHANNEL_SOUNDING) + +#include "os/os_mbuf.h" +#include "host/ble_hs_log.h" +#include "host/ble_hs.h" +#include "host/ble_cs.h" +#include "nimble/hci_common.h" +#include "sys/queue.h" +#include "ble_hs_hci_priv.h" + +struct ble_cs_rd_rem_supp_cap_cp { + uint16_t conn_handle; +} __attribute__((packed)); + +struct ble_cs_wr_cached_rem_supp_cap_cp { + uint16_t conn_handle; + uint8_t num_config_supported; + uint16_t max_consecutive_procedures_supported; + uint8_t num_antennas_supported; + uint8_t max_antenna_paths_supported; + uint8_t roles_supported; + uint8_t optional_modes_supported; + uint8_t rtt_capability; + uint8_t rtt_aa_only_n; + uint8_t rtt_sounding_n; + uint8_t rtt_random_payload_n; + uint16_t optional_nadm_sounding_capability; + uint16_t optional_nadm_random_capability; + uint8_t optional_cs_sync_phys_supported; + uint16_t optional_subfeatures_supported; + uint16_t optional_t_ip1_times_supported; + uint16_t optional_t_ip2_times_supported; + uint16_t optional_t_fcs_times_supported; + uint16_t optional_t_pm_times_supported; + uint8_t t_sw_time_supported; +} __attribute__((packed)); +struct ble_cs_wr_cached_rem_supp_cap_rp { + uint16_t conn_handle; +} __attribute__((packed)); + +struct ble_cs_sec_enable_cp { + uint16_t conn_handle; +} __attribute__((packed)); + +struct ble_cs_set_def_settings_cp { + uint16_t conn_handle; + uint8_t role_enable; + uint8_t cs_sync_antenna_selection; + uint8_t max_tx_power; +} __attribute__((packed)); +struct ble_cs_set_def_settings_rp { + uint16_t conn_handle; +} __attribute__((packed)); + +struct ble_cs_rd_rem_fae_cp { + uint16_t conn_handle; +} __attribute__((packed)); + +struct ble_cs_wr_cached_rem_fae_cp { + uint16_t conn_handle; + uint8_t remote_fae_table[72]; +} __attribute__((packed)); +struct ble_cs_wr_cached_rem_fae_rp { + uint16_t conn_handle; +} __attribute__((packed)); + +struct ble_cs_create_config_cp { + uint16_t conn_handle; + uint8_t config_id; + /* If the config should be created on the remote controller too */ + uint8_t create_context; + /* The main mode to be used in the CS procedures */ + uint8_t main_mode_type; + /* The sub mode to be used in the CS procedures */ + uint8_t sub_mode_type; + /* Minimum/maximum number of CS main mode steps to be executed before + * a submode step. + */ + uint8_t min_main_mode_steps; + uint8_t max_main_mode_steps; + /* The number of main mode steps taken from the end of the last + * CS subevent to be repeated at the beginning of the current CS subevent + * directly after the last mode 0 step of that event + */ + uint8_t main_mode_repetition; + uint8_t mode_0_steps; + uint8_t role; + uint8_t rtt_type; + uint8_t cs_sync_phy; + uint8_t channel_map[10]; + uint8_t channel_map_repetition; + uint8_t channel_selection_type; + uint8_t ch3c_shape; + uint8_t ch3c_jump; + uint8_t companion_signal_enable; +} __attribute__((packed)); + +struct ble_cs_remove_config_cp { + uint16_t conn_handle; + uint8_t config_id; +} __attribute__((packed)); + +struct ble_cs_set_chan_class_cp { + uint8_t channel_classification[10]; +} __attribute__((packed)); + +struct ble_cs_set_proc_params_cp { + uint16_t conn_handle; + uint8_t config_id; + /* The maximum duration of each CS procedure (time = N × 0.625 ms) */ + uint16_t max_procedure_len; + /* The minimum and maximum number of connection events between + * consecutive CS procedures. Ignored if only one CS procedure. */ + uint16_t min_procedure_interval; + uint16_t max_procedure_interval; + /* The maximum number of consecutive CS procedures to be scheduled */ + uint16_t max_procedure_count; + /* Minimum/maximum suggested durations for each CS subevent in microseconds. + * Only 3 bytes meaningful. */ + uint32_t min_subevent_len; + uint32_t max_subevent_len; + /* Antenna Configuration Index (ACI) for swithing during phase measuement */ + uint8_t tone_antenna_config_selection; + /* The remote device’s Tx PHY. A 4 bits bitmap. */ + uint8_t phy; + /* How many more or fewer of transmit power levels should the remote device’s + * Tx PHY use during the CS tones and RTT transmission */ + uint8_t tx_power_delta; + /* Preferred peer-ordered antenna elements to be used by the peer for + * the selected antenna configuration (ACI). A 4 bits bitmap. */ + uint8_t preferred_peer_antenna; + /* SNR Output Index (SOI) for SNR control adjustment. */ + uint8_t snr_control_initiator; + uint8_t snr_control_reflector; +} __attribute__((packed)); +struct ble_cs_set_proc_params_rp { + uint16_t conn_handle; +} __attribute__((packed)); + +struct ble_cs_proc_enable_cp { + uint16_t conn_handle; + uint8_t config_id; + uint8_t enable; +} __attribute__((packed)); + +struct ble_cs_state { + uint8_t op; + ble_cs_event_fn *cb; + void *cb_arg; +}; + +static struct ble_cs_state cs_state; + +static int +ble_cs_call_event_cb(struct ble_cs_event *event) +{ + int rc; + + if (cs_state.cb != NULL) { + rc = cs_state.cb(event, cs_state.cb_arg); + } else { + rc = 0; + } + + return rc; +} + +static void +ble_cs_call_procedure_complete_cb(uint16_t conn_handle, uint8_t status) +{ + struct ble_cs_event event; + + memset(&event, 0, sizeof event); + event.type = BLE_CS_EVENT_CS_PROCEDURE_COMPLETE; + event.procedure_complete.conn_handle = conn_handle; + event.procedure_complete.status = status; + ble_cs_call_event_cb(&event); +} + +static int +ble_cs_rd_loc_supp_cap(void) +{ + int rc; + struct ble_hci_le_cs_rd_loc_supp_cap_rp rp; + + rc = ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_CS_RD_LOC_SUPP_CAP), + NULL, 0, &rp, sizeof(rp)); + + rp.max_consecutive_procedures_supported = le16toh(rp.max_consecutive_procedures_supported); + rp.optional_nadm_sounding_capability = le16toh(rp.optional_nadm_sounding_capability); + rp.optional_nadm_random_capability = le16toh(rp.optional_nadm_random_capability); + rp.optional_subfeatures_supported = le16toh(rp.optional_subfeatures_supported); + rp.optional_t_ip1_times_supported = le16toh(rp.optional_t_ip1_times_supported); + rp.optional_t_ip2_times_supported = le16toh(rp.optional_t_ip2_times_supported); + rp.optional_t_fcs_times_supported = le16toh(rp.optional_t_fcs_times_supported); + rp.optional_t_pm_times_supported = le16toh(rp.optional_t_pm_times_supported); + (void) rp; + + return rc; +} + +static int +ble_cs_rd_rem_supp_cap(const struct ble_cs_rd_rem_supp_cap_cp *cmd) +{ + struct ble_hci_le_cs_rd_rem_supp_cap_cp cp; + + cp.conn_handle = htole16(cmd->conn_handle); + + return ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_CS_RD_REM_SUPP_CAP), + &cp, sizeof(cp), NULL, 0); +} + +static int +ble_cs_wr_cached_rem_supp_cap(const struct ble_cs_wr_cached_rem_supp_cap_cp *cmd, + struct ble_cs_wr_cached_rem_supp_cap_rp *rsp) +{ + struct ble_hci_le_cs_wr_cached_rem_supp_cap_cp cp; + struct ble_hci_le_cs_wr_cached_rem_supp_cap_rp rp; + int rc; + + cp.conn_handle = htole16(cmd->conn_handle); + cp.num_config_supported = cmd->num_config_supported; + cp.max_consecutive_procedures_supported = htole16(cmd->max_consecutive_procedures_supported); + cp.num_antennas_supported = cmd->num_antennas_supported; + cp.max_antenna_paths_supported = cmd->max_antenna_paths_supported; + cp.roles_supported = cmd->roles_supported; + cp.optional_modes_supported = cmd->optional_modes_supported; + cp.rtt_capability = cmd->rtt_capability; + cp.rtt_aa_only_n = cmd->rtt_aa_only_n; + cp.rtt_sounding_n = cmd->rtt_sounding_n; + cp.rtt_random_payload_n = cmd->rtt_random_payload_n; + cp.optional_nadm_sounding_capability = htole16(cmd->optional_nadm_sounding_capability); + cp.optional_nadm_random_capability = htole16(cmd->optional_nadm_random_capability); + cp.optional_cs_sync_phys_supported = cmd->optional_cs_sync_phys_supported; + cp.optional_subfeatures_supported = htole16(cmd->optional_subfeatures_supported); + cp.optional_t_ip1_times_supported = htole16(cmd->optional_t_ip1_times_supported); + cp.optional_t_ip2_times_supported = htole16(cmd->optional_t_ip2_times_supported); + cp.optional_t_fcs_times_supported = htole16(cmd->optional_t_fcs_times_supported); + cp.optional_t_pm_times_supported = htole16(cmd->optional_t_pm_times_supported); + cp.t_sw_time_supported = cmd->t_sw_time_supported; + + rc = ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_CS_WR_CACHED_REM_SUPP_CAP), + &cp, sizeof(cp), &rp, sizeof(rp)); + + rsp->conn_handle = le16toh(rp.conn_handle); + + return rc; +} + +static int +ble_cs_sec_enable(const struct ble_cs_sec_enable_cp *cmd) +{ + struct ble_hci_le_cs_sec_enable_cp cp; + + cp.conn_handle = htole16(cmd->conn_handle); + + return ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_CS_SEC_ENABLE), + &cp, sizeof(cp), NULL, 0); +} + +static int +ble_cs_set_def_settings(const struct ble_cs_set_def_settings_cp *cmd, + struct ble_cs_set_def_settings_rp *rsp) +{ + struct ble_hci_le_cs_set_def_settings_cp cp; + struct ble_hci_le_cs_set_def_settings_rp rp; + int rc; + + cp.conn_handle = htole16(cmd->conn_handle); + cp.role_enable = cmd->role_enable; + cp.cs_sync_antenna_selection = cmd->cs_sync_antenna_selection; + cp.max_tx_power = cmd->max_tx_power; + + rc = ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_CS_SET_DEF_SETTINGS), + &cp, sizeof(cp), &rp, sizeof(rp)); + + rsp->conn_handle = le16toh(rp.conn_handle); + + return rc; +} + +static int +ble_cs_rd_rem_fae(const struct ble_cs_rd_rem_fae_cp *cmd) +{ + struct ble_hci_le_cs_rd_rem_fae_cp cp; + + cp.conn_handle = htole16(cmd->conn_handle); + + return ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_CS_RD_REM_FAE), + &cp, sizeof(cp), NULL, 0); +} + +static int +ble_cs_wr_cached_rem_fae(const struct ble_cs_wr_cached_rem_fae_cp *cmd, + struct ble_cs_wr_cached_rem_fae_rp *rsp) +{ + struct ble_hci_le_cs_wr_cached_rem_fae_cp cp; + struct ble_hci_le_cs_wr_cached_rem_fae_rp rp; + int rc; + + cp.conn_handle = htole16(cmd->conn_handle); + memcpy(cp.remote_fae_table, cmd->remote_fae_table, 72); + + rc = ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_CS_WR_CACHED_REM_FAE), + &cp, sizeof(cp), &rp, sizeof(rp)); + + rsp->conn_handle = le16toh(rp.conn_handle); + + return rc; +} + +static int +ble_cs_create_config(const struct ble_cs_create_config_cp *cmd) +{ + struct ble_hci_le_cs_create_config_cp cp; + + cp.conn_handle = htole16(cmd->conn_handle); + cp.config_id = cmd->config_id; + cp.create_context = cmd->create_context; + cp.main_mode_type = cmd->main_mode_type; + cp.sub_mode_type = cmd->sub_mode_type; + cp.min_main_mode_steps = cmd->min_main_mode_steps; + cp.max_main_mode_steps = cmd->max_main_mode_steps; + cp.main_mode_repetition = cmd->main_mode_repetition; + cp.mode_0_steps = cmd->mode_0_steps; + cp.role = cmd->role; + cp.rtt_type = cmd->rtt_type; + cp.cs_sync_phy = cmd->cs_sync_phy; + memcpy(cp.channel_map, cmd->channel_map, 10); + cp.channel_map_repetition = cmd->channel_map_repetition; + cp.channel_selection_type = cmd->channel_selection_type; + cp.ch3c_shape = cmd->ch3c_shape; + cp.ch3c_jump = cmd->ch3c_jump; + cp.companion_signal_enable = cmd->companion_signal_enable; + + return ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_CS_CREATE_CONFIG), + &cp, sizeof(cp), NULL, 0); +} + +static int +ble_cs_remove_config(const struct ble_cs_remove_config_cp *cmd) +{ + struct ble_hci_le_cs_remove_config_cp cp; + + cp.conn_handle = htole16(cmd->conn_handle); + cp.config_id = cmd->config_id; + + return ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_CS_REMOVE_CONFIG), + &cp, sizeof(cp), NULL, 0); +} + +static int +ble_cs_set_chan_class(const struct ble_cs_set_chan_class_cp *cmd) +{ + struct ble_hci_le_cs_set_chan_class_cp cp; + int rc; + + memcpy(cp.channel_classification, cmd->channel_classification, 10); + + rc = ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_CS_SET_CHAN_CLASS), + &cp, sizeof(cp), NULL, 0); + + return rc; +} + +static int +ble_cs_set_proc_params(const struct ble_cs_set_proc_params_cp *cmd, + struct ble_cs_set_proc_params_rp *rsp) +{ + struct ble_hci_le_cs_set_proc_params_cp cp; + struct ble_hci_le_cs_set_proc_params_rp rp; + int rc; + + cp.conn_handle = htole16(cmd->conn_handle); + cp.config_id = cmd->config_id; + cp.max_procedure_len = htole16(cmd->max_procedure_len); + cp.min_procedure_interval = htole16(cmd->min_procedure_interval); + cp.max_procedure_interval = htole16(cmd->max_procedure_interval); + cp.max_procedure_count = htole16(cmd->max_procedure_count); + put_le24(cp.min_subevent_len, cmd->min_subevent_len); + put_le24(cp.max_subevent_len, cmd->max_subevent_len); + cp.tone_antenna_config_selection = cmd->tone_antenna_config_selection; + cp.phy = cmd->phy; + cp.tx_power_delta = cmd->tx_power_delta; + cp.preferred_peer_antenna = cmd->preferred_peer_antenna; + cp.snr_control_initiator = cmd->snr_control_initiator; + cp.snr_control_reflector = cmd->snr_control_reflector; + + rc = ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_CS_SET_PROC_PARAMS), + &cp, sizeof(cp), &rp, sizeof(rp)); + + rsp->conn_handle = le16toh(rp.conn_handle); + + return rc; +} + +static int +ble_cs_proc_enable(const struct ble_cs_proc_enable_cp *cmd) +{ + struct ble_hci_le_cs_proc_enable_cp cp; + + cp.conn_handle = htole16(cmd->conn_handle); + cp.config_id = cmd->config_id; + cp.enable = cmd->enable; + + return ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_CS_PROC_ENABLE), + &cp, sizeof(cp), NULL, 0); +} + +int +ble_hs_hci_evt_le_cs_rd_rem_supp_cap_complete(uint8_t subevent, const void *data, + unsigned int len) +{ + int rc; + const struct ble_hci_ev_le_subev_cs_rd_rem_supp_cap_complete *ev = data; + struct ble_cs_set_def_settings_cp set_cmd; + struct ble_cs_set_def_settings_rp set_rsp; + struct ble_cs_rd_rem_fae_cp fae_cmd; + + if (len != sizeof(*ev) || ev->status) { + return BLE_HS_ECONTROLLER; + } + + BLE_HS_LOG(DEBUG, "CS capabilities exchanged"); + + /* TODO: Save the remote capabilities somewhere */ + + set_cmd.conn_handle = le16toh(ev->conn_handle); + /* Only initiator role is enabled */ + set_cmd.role_enable = 0x01; + /* Use antenna with ID 0x01 */ + set_cmd.cs_sync_antenna_selection = 0x01; + /* Set max TX power to the max supported */ + set_cmd.max_tx_power = 0x7F; + + rc = ble_cs_set_def_settings(&set_cmd, &set_rsp); + if (rc) { + BLE_HS_LOG(DEBUG, "Failed to set the default CS settings, err %dt", rc); + + return rc; + } + + /* Read the mode 0 Frequency Actuation Error table */ + fae_cmd.conn_handle = le16toh(ev->conn_handle); + rc = ble_cs_rd_rem_fae(&fae_cmd); + if (rc) { + BLE_HS_LOG(DEBUG, "Failed to read FAE table"); + } + + return rc; +} + +int +ble_hs_hci_evt_le_cs_rd_rem_fae_complete(uint8_t subevent, const void *data, + unsigned int len) +{ + const struct ble_hci_ev_le_subev_cs_rd_rem_fae_complete *ev = data; + struct ble_cs_create_config_cp cmd; + int rc; + + if (len != sizeof(*ev) || ev->status) { + return BLE_HS_ECONTROLLER; + } + + cmd.conn_handle = le16toh(ev->conn_handle); + /* The config will use ID 0x00 */ + cmd.config_id = 0x00; + /* Create the config on the remote controller too */ + cmd.create_context = 0x01; + /* Measure phase rotations in main mode */ + cmd.main_mode_type = 0x01; + /* Do not use sub mode for now. */ + cmd.sub_mode_type = 0xFF; + /* Range from which the number of CS main mode steps to execute + * will be randomly selected. + */ + cmd.min_main_mode_steps = 0x02; + cmd.max_main_mode_steps = 0x06; + /* The number of main mode steps to be repeated at the beginning of + * the current CS, irrespectively if there are some overlapping main + * mode steps from previous CS subevent or not. + */ + cmd.main_mode_repetition = 0x00; + /* Number of CS mode 0 steps to be included at the beginning of + * each CS subevent + */ + cmd.mode_0_steps = 0x03; + /* Take the Initiator role */ + cmd.role = 0x00; + cmd.rtt_type = 0x01; + cmd.cs_sync_phy = 0x01; + memcpy(cmd.channel_map, (uint8_t[10]) {0x0a, 0xfa, 0xcf, 0xac, 0xfa, 0xc0}, 10); + cmd.channel_map_repetition = 0x01; + /* Use Channel Selection Algorithm #3b */ + cmd.channel_selection_type = 0x00; + /* Ignore these as used only with #3c algorithm */ + cmd.ch3c_shape = 0x00; + cmd.ch3c_jump = 0x00; + /* EDLC/ECLD attack protection not supported */ + cmd.companion_signal_enable = 0x00; + + /* Create CS config */ + rc = ble_cs_create_config(&cmd); + if (rc) { + BLE_HS_LOG(DEBUG, "Failed to create CS config"); + } + + return rc; +} + +int +ble_hs_hci_evt_le_cs_sec_enable_complete(uint8_t subevent, const void *data, + unsigned int len) +{ + int rc; + struct ble_cs_set_proc_params_cp cmd; + struct ble_cs_set_proc_params_rp rsp; + struct ble_cs_proc_enable_cp enable_cmd; + const struct ble_hci_ev_le_subev_cs_sec_enable_complete *ev = data; + + if (len != sizeof(*ev)) { + BLE_HS_LOG(DEBUG, "Failed to enable CS security"); + + return BLE_HS_ECONTROLLER; + } + + BLE_HS_LOG(DEBUG, "CS setup phase completed"); + + cmd.conn_handle = le16toh(ev->conn_handle); + cmd.config_id = 0x00; + /* The maximum duration of each CS procedure (time = N × 0.625 ms) */ + cmd.max_procedure_len = 8; + /* The maximum number of consecutive CS procedures to be scheduled + * as part of this measurement + */ + cmd.max_procedure_count = 0x0001; + /* The minimum and maximum number of connection events between + * consecutive CS procedures. Ignored if only one CS procedure. + */ + cmd.min_procedure_interval = 0x0000; + cmd.max_procedure_interval = 0x0000; + /* Minimum/maximum suggested durations for each CS subevent in microseconds. + * 1250us and 5000us selected. + */ + cmd.min_subevent_len = 1250; + cmd.max_subevent_len = 5000; + /* Use ACI 0 as we have only one antenna on each side */ + cmd.tone_antenna_config_selection = 0x00; + /* Use LE 1M PHY for CS procedures */ + cmd.phy = 0x01; + /* Transmit power delta set to 0x80 means Host does not have a recommendation. */ + cmd.tx_power_delta = 0x80; + /* Preferred antenna array elements to use. We have only a single antenna here. */ + cmd.preferred_peer_antenna = 0x01; + /* SNR Output Index (SOI) for SNR control adjustment. 0xFF means SNR control + * is not to be applied. + */ + cmd.snr_control_initiator = 0xff; + cmd.snr_control_reflector = 0xff; + + rc = ble_cs_set_proc_params(&cmd, &rsp); + if (rc) { + BLE_HS_LOG(DEBUG, "Failed to set CS procedure parameters"); + } + + enable_cmd.conn_handle = le16toh(ev->conn_handle); + enable_cmd.config_id = 0x00; + enable_cmd.enable = 0x01; + + rc = ble_cs_proc_enable(&enable_cmd); + if (rc) { + BLE_HS_LOG(DEBUG, "Failed to enable CS procedure"); + } + + return rc; +} + +int +ble_hs_hci_evt_le_cs_config_complete(uint8_t subevent, const void *data, + unsigned int len) +{ + int rc; + const struct ble_hci_ev_le_subev_cs_config_complete *ev = data; + struct ble_cs_sec_enable_cp cmd; + + if (len != sizeof(*ev) || ev->status) { + return BLE_HS_ECONTROLLER; + } + + cmd.conn_handle = le16toh(ev->conn_handle); + + /* Exchange CS security keys */ + rc = ble_cs_sec_enable(&cmd); + if (rc) { + BLE_HS_LOG(DEBUG, "Failed to enable CS security"); + ble_cs_call_procedure_complete_cb(le16toh(ev->conn_handle), ev->status); + } + + return 0; +} + +int +ble_hs_hci_evt_le_cs_proc_enable_complete(uint8_t subevent, const void *data, + unsigned int len) +{ + const struct ble_hci_ev_le_subev_cs_proc_enable_complete *ev = data; + + if (len != sizeof(*ev) || ev->status) { + return BLE_HS_ECONTROLLER; + } + + return 0; +} + +int +ble_hs_hci_evt_le_cs_subevent_result(uint8_t subevent, const void *data, + unsigned int len) +{ + const struct ble_hci_ev_le_subev_cs_subevent_result *ev = data; + + if (len != sizeof(*ev)) { + return BLE_HS_ECONTROLLER; + } + + return 0; +} + +int +ble_hs_hci_evt_le_cs_subevent_result_continue(uint8_t subevent, const void *data, + unsigned int len) +{ + const struct ble_hci_ev_le_subev_cs_subevent_result_continue *ev = data; + + if (len != sizeof(*ev)) { + return BLE_HS_ECONTROLLER; + } + + return 0; +} + +int +ble_hs_hci_evt_le_cs_test_end_complete(uint8_t subevent, const void *data, + unsigned int len) +{ + const struct ble_hci_ev_le_subev_cs_test_end_complete *ev = data; + + if (len != sizeof(*ev)) { + return BLE_HS_ECONTROLLER; + } + + return 0; +} + +int +ble_cs_initiator_procedure_start(const struct ble_cs_initiator_procedure_start_params *params) +{ + struct ble_hci_le_cs_rd_loc_supp_cap_rp rsp; + struct ble_cs_rd_rem_supp_cap_cp cmd; + int rc; + + /* Channel Sounding setup phase: + * 1. Set local default CS settings + * 2. Exchange CS capabilities with the remote + * 3. Read or write the mode 0 Frequency Actuation Error table + * 4. Create CS configurations + * 5. Start the CS Security Start procedure + */ + + cs_state.cb = params->cb; + cs_state.cb_arg = params->cb_arg; + + cmd.conn_handle = params->conn_handle; + rc = ble_cs_rd_rem_supp_cap(&cmd); + if (rc) { + BLE_HS_LOG(DEBUG, "Failed to read local supported CS capabilities," + "err %dt", rc); + } + + return rc; +} + +int +ble_cs_initiator_procedure_terminate(uint16_t conn_handle) +{ + return 0; +} + +int +ble_cs_reflector_setup(struct ble_cs_reflector_setup_params *params) +{ + cs_state.cb = params->cb; + cs_state.cb_arg = params->cb_arg; + + return 0; +} +#endif diff --git a/nimble/host/src/ble_cs_priv.h b/nimble/host/src/ble_cs_priv.h new file mode 100644 index 0000000000..f02565852d --- /dev/null +++ b/nimble/host/src/ble_cs_priv.h @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_BLE_CS_PRIV_ +#define H_BLE_CS_PRIV_ + +int ble_hs_hci_evt_le_cs_rd_rem_supp_cap_complete(uint8_t subevent, const void *data, unsigned int len); +int ble_hs_hci_evt_le_cs_rd_rem_fae_complete(uint8_t subevent, const void *data, unsigned int len); +int ble_hs_hci_evt_le_cs_sec_enable_complete(uint8_t subevent, const void *data, unsigned int len); +int ble_hs_hci_evt_le_cs_config_complete(uint8_t subevent, const void *data, unsigned int len); +int ble_hs_hci_evt_le_cs_proc_enable_complete(uint8_t subevent, const void *data, unsigned int len); +int ble_hs_hci_evt_le_cs_subevent_result(uint8_t subevent, const void *data, unsigned int len); +int ble_hs_hci_evt_le_cs_subevent_result_continue(uint8_t subevent, const void *data, unsigned int len); +int ble_hs_hci_evt_le_cs_test_end_complete(uint8_t subevent, const void *data, unsigned int len); +#endif diff --git a/nimble/host/src/ble_dtm.c b/nimble/host/src/ble_dtm.c new file mode 100644 index 0000000000..d88bee2702 --- /dev/null +++ b/nimble/host/src/ble_dtm.c @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#include "ble_hs_hci_priv.h" + +int +ble_dtm_rx_start(const struct ble_dtm_rx_params *params) +{ + struct ble_hci_le_rx_test_v2_cp cmd; + + cmd.rx_chan = params->channel; + cmd.phy = params->phy; + cmd.index = params->modulation_index; + + return ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_RX_TEST_V2), + &cmd, sizeof(cmd), NULL, 0); +} + +int +ble_dtm_tx_start(const struct ble_dtm_tx_params *params) +{ + struct ble_hci_le_tx_test_v2_cp cmd; + + cmd.tx_chan = params->channel; + cmd.test_data_len = params->test_data_len; + cmd.payload = params->payload; + cmd.phy = params->phy; + + return ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_TX_TEST_V2), + &cmd, sizeof(cmd), NULL, 0); +} + +int +ble_dtm_stop(uint16_t *num_packets) +{ + struct ble_hci_le_test_end_rp rsp; + int rc; + + rc = ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_TEST_END), + NULL, 0, &rsp, sizeof(rsp)); + + if (rc) { + *num_packets = 0; + } else { + *num_packets = le16toh(rsp.num_packets); + } + + return rc; +} diff --git a/nimble/host/src/ble_eatt.c b/nimble/host/src/ble_eatt.c new file mode 100644 index 0000000000..047a087641 --- /dev/null +++ b/nimble/host/src/ble_eatt.c @@ -0,0 +1,561 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "syscfg/syscfg.h" +#define BLE_NPL_LOG_MODULE BLE_EATT_LOG +#include + +#if MYNEWT_VAL(BLE_EATT_CHAN_NUM) > 0 + +#include "os/mynewt.h" +#include "mem/mem.h" +#include "host/ble_hs_log.h" +#include "ble_att_cmd_priv.h" +#include "ble_hs_priv.h" +#include "ble_l2cap_priv.h" +#include "ble_eatt_priv.h" +#include "services/gatt/ble_svc_gatt.h" + +struct ble_eatt { + SLIST_ENTRY(ble_eatt) next; + uint16_t conn_handle; + struct ble_l2cap_chan *chan; + uint8_t client_op; + + /* Packet transmit queue */ + STAILQ_HEAD(, os_mbuf_pkthdr) eatt_tx_q; + + struct ble_npl_event setup_ev; + struct ble_npl_event wakeup_ev; +}; + +SLIST_HEAD(ble_eatt_list, ble_eatt); + +static struct ble_eatt_list g_ble_eatt_list; +static ble_eatt_att_rx_fn ble_eatt_att_rx_cb; + +#define BLE_EATT_DATABUF_SIZE ( \ + MYNEWT_VAL(BLE_EATT_MTU) + \ + 2 + \ + sizeof (struct os_mbuf_pkthdr) + \ + sizeof (struct os_mbuf)) + +#define BLE_EATT_MEMBLOCK_SIZE \ + (OS_ALIGN(BLE_EATT_DATABUF_SIZE, 4)) + +#define BLE_EATT_MEMPOOL_SIZE \ + OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_EATT_CHAN_NUM) + 1, BLE_EATT_MEMBLOCK_SIZE) +static os_membuf_t ble_eatt_conn_mem[ + OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_EATT_CHAN_NUM), + sizeof(struct ble_eatt)) +]; +static struct os_mempool ble_eatt_conn_pool; +static os_membuf_t ble_eatt_sdu_coc_mem[BLE_EATT_MEMPOOL_SIZE]; +struct os_mbuf_pool ble_eatt_sdu_os_mbuf_pool; +static struct os_mempool ble_eatt_sdu_mbuf_mempool; + +static struct ble_gap_event_listener ble_eatt_listener; + +static struct ble_npl_event g_read_sup_cl_feat_ev; + +static void ble_eatt_setup_cb(struct ble_npl_event *ev); +static void ble_eatt_start(uint16_t conn_handle); + +static struct ble_eatt * +ble_eatt_find_not_busy(uint16_t conn_handle) +{ + struct ble_eatt *eatt; + + SLIST_FOREACH(eatt, &g_ble_eatt_list, next) { + if ((eatt->conn_handle == conn_handle) && !eatt->client_op) { + return eatt; + } + } + + return NULL; +} + +static struct ble_eatt * +ble_eatt_find_by_conn_handle(uint16_t conn_handle) +{ + struct ble_eatt *eatt; + + SLIST_FOREACH(eatt, &g_ble_eatt_list, next) { + if (eatt->conn_handle == conn_handle) { + return eatt; + } + } + + return NULL; +} + +static struct ble_eatt * +ble_eatt_find_by_conn_handle_and_busy_op(uint16_t conn_handle, uint8_t op) +{ + struct ble_eatt *eatt; + + SLIST_FOREACH(eatt, &g_ble_eatt_list, next) { + if (eatt->conn_handle == conn_handle && eatt->client_op == op) { + return eatt; + } + } + + return NULL; +} + +static struct ble_eatt * +ble_eatt_find(uint16_t conn_handle, uint16_t cid) +{ + struct ble_eatt *eatt; + + SLIST_FOREACH(eatt, &g_ble_eatt_list, next) { + if ((eatt->conn_handle == conn_handle) && + (eatt->chan) && + (eatt->chan->scid == cid)) { + return eatt; + } + } + + return NULL; +} + +static int +ble_eatt_prepare_rx_sdu(struct ble_l2cap_chan *chan) +{ + int rc; + struct os_mbuf *om; + + om = os_mbuf_get_pkthdr(&ble_eatt_sdu_os_mbuf_pool, 0); + if (!om) { + BLE_EATT_LOG_ERROR("eatt: no memory for sdu\n"); + return BLE_HS_ENOMEM; + } + + rc = ble_l2cap_recv_ready(chan, om); + if (rc) { + BLE_EATT_LOG_ERROR("eatt: Failed to supply RX SDU conn_handle 0x%04x (status=%d)\n", + chan->conn_handle, rc); + os_mbuf_free_chain(om); + } + + return rc; +} + +static void +ble_eatt_wakeup_cb(struct ble_npl_event *ev) +{ + struct ble_eatt *eatt; + struct os_mbuf *txom; + struct os_mbuf_pkthdr *omp; + struct ble_l2cap_chan_info info; + + eatt = ble_npl_event_get_arg(ev); + assert(eatt); + + omp = STAILQ_FIRST(&eatt->eatt_tx_q); + if (omp != NULL) { + STAILQ_REMOVE_HEAD(&eatt->eatt_tx_q, omp_next); + + txom = OS_MBUF_PKTHDR_TO_MBUF(omp); + ble_l2cap_get_chan_info(eatt->chan, &info); + ble_eatt_tx(eatt->conn_handle, info.dcid, txom); + } +} + +static struct ble_eatt * +ble_eatt_alloc(void) +{ + struct ble_eatt *eatt; + + eatt = os_memblock_get(&ble_eatt_conn_pool); + if (!eatt) { + BLE_EATT_LOG_WARN("eatt: Failed to allocate new eatt context\n"); + return NULL; + } + + SLIST_INSERT_HEAD(&g_ble_eatt_list, eatt, next); + + eatt->conn_handle = BLE_HS_CONN_HANDLE_NONE; + eatt->chan = NULL; + eatt->client_op = 0; + + STAILQ_INIT(&eatt->eatt_tx_q); + ble_npl_event_init(&eatt->setup_ev, ble_eatt_setup_cb, eatt); + ble_npl_event_init(&eatt->wakeup_ev, ble_eatt_wakeup_cb, eatt); + + return eatt; +} + +static void +ble_eatt_free(struct ble_eatt *eatt) +{ + struct os_mbuf_pkthdr *omp; + + while ((omp = STAILQ_FIRST(&eatt->eatt_tx_q)) != NULL) { + STAILQ_REMOVE_HEAD(&eatt->eatt_tx_q, omp_next); + os_mbuf_free_chain(OS_MBUF_PKTHDR_TO_MBUF(omp)); + } + + SLIST_REMOVE(&g_ble_eatt_list, eatt, ble_eatt, next); + os_memblock_put(&ble_eatt_conn_pool, eatt); +} + +static int +ble_eatt_l2cap_event_fn(struct ble_l2cap_event *event, void *arg) +{ + struct ble_eatt *eatt = arg; + struct ble_gap_conn_desc desc; + uint8_t opcode; + int rc; + + switch (event->type) { + case BLE_L2CAP_EVENT_COC_CONNECTED: + BLE_EATT_LOG_DEBUG("eatt: Connected \n"); + if (event->connect.status) { + ble_eatt_free(eatt); + return 0; + } + eatt->chan = event->connect.chan; + break; + case BLE_L2CAP_EVENT_COC_DISCONNECTED: + BLE_EATT_LOG_DEBUG("eatt: Disconnected \n"); + ble_eatt_free(eatt); + break; + case BLE_L2CAP_EVENT_COC_ACCEPT: + BLE_EATT_LOG_DEBUG("eatt: Accept request\n"); + eatt = ble_eatt_find_by_conn_handle(event->accept.conn_handle); + if (eatt) { + /* For now we accept only one additional coc channel per ACL + * TODO: improve it + */ + return BLE_HS_ENOMEM; + } + + eatt = ble_eatt_alloc(); + if (!eatt) { + return BLE_HS_ENOMEM; + } + + eatt->conn_handle = event->accept.conn_handle; + event->accept.chan->cb_arg = eatt; + + rc = ble_eatt_prepare_rx_sdu(event->accept.chan); + if (rc) { + ble_eatt_free(eatt); + return rc; + } + + break; + case BLE_L2CAP_EVENT_COC_TX_UNSTALLED: + ble_npl_eventq_put(ble_hs_evq_get(), &eatt->wakeup_ev); + break; + case BLE_L2CAP_EVENT_COC_DATA_RECEIVED: + assert(eatt->chan == event->receive.chan); + opcode = event->receive.sdu_rx->om_data[0]; + if (ble_eatt_supported_rsp(opcode)) { + ble_npl_eventq_put(ble_hs_evq_get(), &eatt->wakeup_ev); + } else if (!ble_eatt_supported_req(opcode)) { + /* If an ATT PDU is supported on any ATT bearer, then it shall be + * supported on all supported ATT bearers with the following + * exceptions: + * â€ĸ The Exchange MTU sub-procedure shall only be supported on the + * LE Fixed Channel Unenhanced ATT bearer. + * â€ĸ The Signed Write Without Response sub-procedure shall only be + * supported on the LE Fixed Channel Unenhanced ATT bearer. + */ + ble_l2cap_disconnect(eatt->chan); + return BLE_HS_EREJECT; + } + + assert (!ble_gap_conn_find(event->receive.conn_handle, &desc)); + /* As per BLE 5.4 Standard, Vol. 3, Part F, section 5.3.2 + * (ENHANCED ATT BEARER L2CAP INTEROPERABILITY REQUIREMENTS: + * Channel Requirements): + * The channel shall be encrypted. + * + * Disconnect peer with invalid behavior - ATT PDU received before + * encryption. + */ + if (!desc.sec_state.encrypted) { + ble_l2cap_disconnect(eatt->chan); + return BLE_HS_EREJECT; + } + + ble_eatt_att_rx_cb(event->receive.conn_handle, eatt->chan->scid, &event->receive.sdu_rx); + if (event->receive.sdu_rx) { + os_mbuf_free_chain(event->receive.sdu_rx); + event->receive.sdu_rx = NULL; + } + + /* Receiving L2CAP data is no longer possible, terminate connection */ + rc = ble_eatt_prepare_rx_sdu(event->receive.chan); + if (rc) { + ble_l2cap_disconnect(eatt->chan); + return BLE_HS_ENOMEM; + } + break; + default: + break; + } + + return 0; +} + +static void +ble_eatt_setup_cb(struct ble_npl_event *ev) +{ + struct ble_eatt *eatt; + struct os_mbuf *om; + int rc; + + eatt = ble_npl_event_get_arg(ev); + assert(eatt); + + om = os_mbuf_get_pkthdr(&ble_eatt_sdu_os_mbuf_pool, 0); + if (!om) { + ble_eatt_free(eatt); + BLE_EATT_LOG_ERROR("eatt: no memory for sdu\n"); + return; + } + + BLE_EATT_LOG_DEBUG("eatt: connecting eatt on conn_handle 0x%04x\n", eatt->conn_handle); + + rc = ble_l2cap_enhanced_connect(eatt->conn_handle, BLE_EATT_PSM, + MYNEWT_VAL(BLE_EATT_MTU), 1, &om, + ble_eatt_l2cap_event_fn, eatt); + if (rc) { + BLE_EATT_LOG_ERROR("eatt: Failed to connect EATT on conn_handle 0x%04x (status=%d)\n", + eatt->conn_handle, rc); + os_mbuf_free_chain(om); + ble_eatt_free(eatt); + } +} + +static int +ble_gatt_eatt_write_cl_cb(uint16_t conn_handle, + const struct ble_gatt_error *error, + struct ble_gatt_attr *attr, void *arg) +{ + if (error == NULL || (error->status != 0 && error->status != BLE_HS_EDONE)) { + BLE_EATT_LOG_DEBUG("eatt: Cannot write to Client Supported features on peer device\n"); + return 0; + } + + ble_eatt_start(conn_handle); + + return 0; +} + +static int +ble_gatt_eatt_read_cl_uuid_cb(uint16_t conn_handle, + const struct ble_gatt_error *error, + struct ble_gatt_attr *attr, void *arg) +{ + uint8_t client_supported_feat; + int rc; + + if (error == NULL || (error->status != 0 && error->status != BLE_HS_EDONE)) { + BLE_EATT_LOG_DEBUG("eatt: Cannot find Client Supported features on peer device\n"); + return BLE_HS_EDONE; + } + + if (attr == NULL) { + BLE_EATT_LOG_ERROR("eatt: Invalid attribute \n"); + return BLE_HS_EDONE; + } + + if (error->status == 0) { + client_supported_feat = ble_svc_gatt_get_local_cl_supported_feat(); + rc = ble_gattc_write_flat(conn_handle, attr->handle, &client_supported_feat, 1, + ble_gatt_eatt_write_cl_cb, NULL); + BLE_EATT_LOG_DEBUG("eatt: %s , write rc = %d \n", __func__, rc); + assert(rc == 0); + return 0; + } + + return BLE_HS_EDONE; +} + +static void +ble_gatt_eatt_read_cl_uuid(struct ble_npl_event *ev) +{ + uint16_t conn_handle; + + conn_handle = POINTER_TO_UINT(ble_npl_event_get_arg(ev)); + + ble_gattc_read_by_uuid(conn_handle, 1, 0xffff, + BLE_UUID16_DECLARE(BLE_SVC_GATT_CHR_CLIENT_SUPPORTED_FEAT_UUID16), + ble_gatt_eatt_read_cl_uuid_cb, NULL); +} + +static int +ble_eatt_gap_event(struct ble_gap_event *event, void *arg) +{ + struct ble_eatt *eatt; + + switch (event->type) { + case BLE_GAP_EVENT_ENC_CHANGE: + if (event->enc_change.status != 0) { + return 0; + } + + /* don't try to connect if already connected */ + if (ble_eatt_find_by_conn_handle(event->enc_change.conn_handle)) { + return 0; + } + + BLE_EATT_LOG_DEBUG("eatt: Encryption enabled, connecting EATT (conn_handle=0x%04x)\n", + event->enc_change.conn_handle); + + ble_npl_event_set_arg(&g_read_sup_cl_feat_ev, UINT_TO_POINTER(event->enc_change.conn_handle)); + ble_npl_eventq_put(ble_hs_evq_get(), &g_read_sup_cl_feat_ev); + + break; + case BLE_GAP_EVENT_DISCONNECT: + eatt = ble_eatt_find_by_conn_handle(event->disconnect.conn.conn_handle); + assert(eatt == NULL); + break; + default: + break; + } + + return 0; +} + +uint16_t +ble_eatt_get_available_chan_cid(uint16_t conn_handle, uint8_t op) +{ + struct ble_eatt * eatt; + + eatt = ble_eatt_find_not_busy(conn_handle); + if (!eatt) { + return BLE_L2CAP_CID_ATT; + } + + eatt->client_op = op; + + return eatt->chan->scid; +} + +void +ble_eatt_release_chan(uint16_t conn_handle, uint8_t op) +{ + struct ble_eatt * eatt; + + eatt = ble_eatt_find_by_conn_handle_and_busy_op(conn_handle, op); + if (!eatt) { + BLE_EATT_LOG_WARN("ble_eatt_release_chan:" + "EATT not found for conn_handle 0x%04x, operation 0x%02\n", conn_handle, op); + return; + } + + eatt->client_op = 0; +} + +int +ble_eatt_tx(uint16_t conn_handle, uint16_t cid, struct os_mbuf *txom) +{ + struct ble_eatt *eatt; + int rc; + + BLE_EATT_LOG_DEBUG("eatt: %s, size %d ", __func__, OS_MBUF_PKTLEN(txom)); + eatt = ble_eatt_find(conn_handle, cid); + if (!eatt || !eatt->chan) { + BLE_EATT_LOG_ERROR("Eatt not available"); + rc = BLE_HS_ENOENT; + goto error; + } + + rc = ble_l2cap_send(eatt->chan, txom); + if (rc == 0) { + goto done; + } + + if (rc == BLE_HS_ESTALLED) { + BLE_EATT_LOG_DEBUG("ble_eatt_tx: Eatt stalled"); + } else if (rc == BLE_HS_EBUSY) { + BLE_EATT_LOG_DEBUG("ble_eatt_tx: Message queued"); + STAILQ_INSERT_HEAD(&eatt->eatt_tx_q, OS_MBUF_PKTHDR(txom), omp_next); + ble_npl_eventq_put(ble_hs_evq_get(), &eatt->wakeup_ev); + } else { + BLE_EATT_LOG_ERROR("eatt: %s, ERROR %d ", __func__, rc); + assert(0); + } +done: + return 0; + +error: + os_mbuf_free_chain(txom); + + return rc; +} + +static void +ble_eatt_start(uint16_t conn_handle) +{ + struct ble_gap_conn_desc desc; + struct ble_eatt *eatt; + int rc; + + rc = ble_gap_conn_find(conn_handle, &desc); + assert(rc == 0); + if (desc.role != BLE_GAP_ROLE_MASTER) { + /* Let master to create ecoc. + * TODO: Slave could setup after some timeout + */ + return; + } + + eatt = ble_eatt_alloc(); + if (!eatt) { + return; + } + + eatt->conn_handle = conn_handle; + + /* Setup EATT */ + ble_npl_eventq_put(ble_hs_evq_get(), &eatt->setup_ev); +} + +void +ble_eatt_init(ble_eatt_att_rx_fn att_rx_cb) +{ + int rc; + + rc = mem_init_mbuf_pool(ble_eatt_sdu_coc_mem, + &ble_eatt_sdu_mbuf_mempool, + &ble_eatt_sdu_os_mbuf_pool, + MYNEWT_VAL(BLE_EATT_CHAN_NUM) + 1, + BLE_EATT_MEMBLOCK_SIZE, + "ble_eatt_sdu"); + BLE_HS_DBG_ASSERT_EVAL(rc == 0); + + rc = os_mempool_init(&ble_eatt_conn_pool, MYNEWT_VAL(BLE_EATT_CHAN_NUM), + sizeof (struct ble_eatt), + ble_eatt_conn_mem, "ble_eatt_conn_pool"); + BLE_HS_DBG_ASSERT_EVAL(rc == 0); + + ble_gap_event_listener_register(&ble_eatt_listener, ble_eatt_gap_event, NULL); + ble_l2cap_create_server(BLE_EATT_PSM, MYNEWT_VAL(BLE_EATT_MTU), ble_eatt_l2cap_event_fn, NULL); + + ble_npl_event_init(&g_read_sup_cl_feat_ev, ble_gatt_eatt_read_cl_uuid, NULL); + + ble_eatt_att_rx_cb = att_rx_cb; +} +#endif diff --git a/nimble/host/src/ble_eatt_priv.h b/nimble/host/src/ble_eatt_priv.h new file mode 100644 index 0000000000..d3c9877672 --- /dev/null +++ b/nimble/host/src/ble_eatt_priv.h @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "syscfg/syscfg.h" +#include "os/os_mbuf.h" +#include "host/ble_l2cap.h" + +#ifndef BLE_EATT_H_ +#define BLE_EATT_H_ + +typedef int (* ble_eatt_att_rx_fn)(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rx_buf); + +#define BLE_EATT_PSM (0x0027) + +#define BLE_GATT_OP_SERVER 0xF1 +#define BLE_GATT_OP_DUMMY 0xF2 + +#if MYNEWT_VAL(BLE_EATT_CHAN_NUM) > 0 +void ble_eatt_init(ble_eatt_att_rx_fn att_rx_fn); +uint16_t ble_eatt_get_available_chan_cid(uint16_t conn_handle, uint8_t op); +void ble_eatt_release_chan(uint16_t conn_handle, uint8_t op); +int ble_eatt_tx(uint16_t conn_handle, uint16_t cid, struct os_mbuf *txom); +#else +static inline void +ble_eatt_init(ble_eatt_att_rx_fn att_rx_fn) +{ +} + +static inline void +ble_eatt_release_chan(uint16_t conn_handle, uint8_t op) +{ + +} + +static inline uint16_t +ble_eatt_get_available_chan_cid(uint16_t conn_handle, uint8_t op) +{ + return BLE_L2CAP_CID_ATT; +} +#endif +#endif diff --git a/nimble/host/src/ble_gap.c b/nimble/host/src/ble_gap.c index 3125870fa6..4928454d4a 100644 --- a/nimble/host/src/ble_gap.c +++ b/nimble/host/src/ble_gap.c @@ -21,16 +21,29 @@ #include #include #include "nimble/nimble_opt.h" +#include "host/ble_gap.h" #include "host/ble_hs_adv.h" #include "host/ble_hs_hci.h" #include "ble_hs_priv.h" +#include "ble_gap_priv.h" -#if MYNEWT +#ifndef min +#define min(a, b) ((a) < (b) ? (a) : (b)) +#endif + +#ifndef max +#define max(a, b) ((a) > (b) ? (a) : (b)) +#endif + +#ifdef MYNEWT #include "bsp/bsp.h" #else #define bssnz_t #endif +#undef SET_BIT +#define SET_BIT(t, n) (t |= 1UL << (n)) + /** * GAP - Generic Access Profile. * @@ -109,6 +122,10 @@ static const struct ble_gap_conn_params ble_gap_conn_params_dflt = { struct ble_gap_master_state { uint8_t op; +#if MYNEWT_VAL(BLE_EXT_ADV) + /* indicates if discovery was started with legacy API */ + uint8_t legacy_discovery; +#endif uint8_t exp_set:1; ble_npl_time_t exp_os_ticks; @@ -186,6 +203,12 @@ struct ble_gap_slave_state { static bssnz_t struct ble_gap_slave_state ble_gap_slave[BLE_ADV_INSTANCES]; +#if NIMBLE_BLE_ADVERTISE +#if MYNEWT_VAL(BLE_EXT_ADV) +static bool ext_adv_legacy_configured = false; +#endif +#endif + struct ble_gap_update_entry { SLIST_ENTRY(ble_gap_update_entry) next; struct ble_gap_upd_params params; @@ -480,6 +503,10 @@ ble_gap_conn_find_by_addr(const ble_addr_t *addr, #if NIMBLE_BLE_CONNECT struct ble_hs_conn *conn; + if (!ble_hs_is_enabled()) { + return BLE_HS_EDISABLED; + } + ble_hs_lock(); conn = ble_hs_conn_find_by_addr(addr); @@ -499,6 +526,57 @@ ble_gap_conn_find_by_addr(const ble_addr_t *addr, #endif } +int +ble_gap_conn_find_handle_by_addr(const ble_addr_t *addr, uint16_t *out_conn_handle) +{ +#if NIMBLE_BLE_CONNECT + struct ble_hs_conn *conn; + + ble_hs_lock(); + + conn = ble_hs_conn_find_by_addr(addr); + if (conn != NULL) { + *out_conn_handle = conn->bhc_handle; + } else { + *out_conn_handle = BLE_HS_CONN_HANDLE_NONE; + } + + ble_hs_unlock(); + + if (conn == NULL) { + return BLE_HS_ENOTCONN; + } + + return 0; +#else + return BLE_HS_ENOTSUP; +#endif +} + +struct foreach_handle_cb_arg { + ble_gap_conn_foreach_handle_fn *cb; + void *arg; +}; + +static int +ble_gap_conn_foreach_handle_callback(struct ble_hs_conn *conn, void *arg) +{ + struct foreach_handle_cb_arg *cb_arg = (struct foreach_handle_cb_arg *)arg; + + return cb_arg->cb(conn->bhc_handle, cb_arg->arg); +} + +void +ble_gap_conn_foreach_handle(ble_gap_conn_foreach_handle_fn *cb, void *arg) +{ + struct foreach_handle_cb_arg cb_arg = { + .cb = cb, + .arg = arg, + }; + + ble_hs_conn_foreach(ble_gap_conn_foreach_handle_callback, &cb_arg); +} + #if NIMBLE_BLE_CONNECT static int ble_gap_extract_conn_cb(uint16_t conn_handle, @@ -533,6 +611,10 @@ int ble_gap_set_priv_mode(const ble_addr_t *peer_addr, uint8_t priv_mode) { #if NIMBLE_BLE_CONNECT + if (!ble_hs_is_enabled()) { + return BLE_HS_EDISABLED; + } + return ble_hs_pvcy_set_mode(peer_addr, priv_mode); #else return BLE_HS_ENOTSUP; @@ -548,6 +630,10 @@ ble_gap_read_le_phy(uint16_t conn_handle, uint8_t *tx_phy, uint8_t *rx_phy) struct ble_hs_conn *conn; int rc; + if (!ble_hs_is_enabled()) { + return BLE_HS_EDISABLED; + } + ble_hs_lock(); conn = ble_hs_conn_find(conn_handle); ble_hs_unlock(); @@ -596,6 +682,10 @@ ble_gap_set_prefered_default_le_phy(uint8_t tx_phys_mask, uint8_t rx_phys_mask) return BLE_ERR_INV_HCI_CMD_PARMS; } + if (!ble_hs_is_enabled()) { + return BLE_HS_EDISABLED; + } + memset(&cmd, 0, sizeof(cmd)); if (tx_phys_mask == 0) { @@ -626,6 +716,10 @@ ble_gap_set_prefered_le_phy(uint16_t conn_handle, uint8_t tx_phys_mask, struct ble_hci_le_set_phy_cp cmd; struct ble_hs_conn *conn; + if (!ble_hs_is_enabled()) { + return BLE_HS_EDISABLED; + } + ble_hs_lock(); conn = ble_hs_conn_find(conn_handle); ble_hs_unlock(); @@ -896,13 +990,45 @@ ble_gap_disc_report(void *desc) struct ble_gap_event event; memset(&event, 0, sizeof event); + event.type = BLE_GAP_EVENT_DISC; + event.disc = *((struct ble_gap_disc_desc *)desc); + + ble_gap_master_extract_state(&state, 0); + if (ble_gap_has_client(&state)) { + state.cb(&event, state.cb_arg); + } + + ble_gap_event_listener_call(&event); +} + #if MYNEWT_VAL(BLE_EXT_ADV) +static void +ble_gap_ext_disc_report(void *desc) +{ + struct ble_gap_ext_disc_desc *ext_desc = desc; + struct ble_gap_disc_desc legacy_desc; + struct ble_gap_master_state state; + struct ble_gap_event event; + + if (ble_gap_master.legacy_discovery) { + /* ignore non-legacy events */ + if (!(ext_desc->props & BLE_HCI_ADV_LEGACY_MASK)) { + return; + } + + legacy_desc.event_type = ext_desc->legacy_event_type; + legacy_desc.length_data = ext_desc->length_data; + legacy_desc.addr = ext_desc->addr; + legacy_desc.rssi = ext_desc->rssi; + legacy_desc.data = ext_desc->data; + legacy_desc.direct_addr = ext_desc->direct_addr; + ble_gap_disc_report(&legacy_desc); + return; + } + + memset(&event, 0, sizeof event); event.type = BLE_GAP_EVENT_EXT_DISC; event.ext_disc = *((struct ble_gap_ext_disc_desc *)desc); -#else - event.type = BLE_GAP_EVENT_DISC; - event.disc = *((struct ble_gap_disc_desc *)desc); -#endif ble_gap_master_extract_state(&state, 0); if (ble_gap_has_client(&state)) { @@ -911,25 +1037,22 @@ ble_gap_disc_report(void *desc) ble_gap_event_listener_call(&event); } +#endif static void ble_gap_disc_complete(void) { -#if NIMBLE_BLE_CONNECT struct ble_gap_master_state state; -#endif struct ble_gap_event event; memset(&event, 0, sizeof event); event.type = BLE_GAP_EVENT_DISC_COMPLETE; event.disc_complete.reason = 0; -#if NIMBLE_BLE_CONNECT ble_gap_master_extract_state(&state, 1); if (ble_gap_has_client(&state)) { ble_gap_call_event_cb(&event, state.cb, state.cb_arg); } -#endif ble_gap_event_listener_call(&event); } @@ -1115,7 +1238,7 @@ ble_gap_update_failed(uint16_t conn_handle, int status) } #endif -void +static void ble_gap_conn_broken(uint16_t conn_handle, int reason) { #if NIMBLE_BLE_CONNECT @@ -1303,6 +1426,31 @@ ble_gap_adv_active_instance(uint8_t instance) } #endif +#if MYNEWT_VAL(BLE_EXT_ADV) +int ble_gap_ext_adv_active(uint8_t instance) +{ + if (instance >= BLE_ADV_INSTANCES) { + return 0; + } + return ble_gap_adv_active_instance(instance); +} + +int +ble_gap_adv_get_free_instance(uint8_t *out_adv_instance) +{ + uint8_t i; + + for (i = 0; i < BLE_ADV_INSTANCES; i++) { + if (!ble_gap_slave[i].configured) { + *out_adv_instance = i; + return 0; + } + } + + return BLE_HS_ENOENT; +} +#endif + /** * Clears advertisement and discovery state. This function is necessary * when the controller loses its active state (e.g. on stack reset). @@ -1330,6 +1478,8 @@ ble_gap_reset_state(int reason) ble_gap_adv_finished(i, reason, 0, 0); } } + + ext_adv_legacy_configured = false; #else if (ble_gap_adv_active_instance(0)) { /* Indicate to application that advertising has stopped. */ @@ -1453,7 +1603,7 @@ ble_gap_rx_ext_adv_report(struct ble_gap_ext_disc_desc *desc) return; } - ble_gap_disc_report(desc); + ble_gap_ext_disc_report(desc); } #endif @@ -1476,6 +1626,18 @@ ble_gap_rx_adv_set_terminated(const struct ble_hci_ev_le_subev_adv_set_terminate ble_gap_adv_finished(ev->adv_handle, reason, conn_handle, ev->num_events); } +static void +ble_gap_slave_get_cb(uint8_t instance, + ble_gap_event_fn **out_cb, void **out_cb_arg) +{ + ble_hs_lock(); + + *out_cb = ble_gap_slave[instance].cb; + *out_cb_arg = ble_gap_slave[instance].cb_arg; + + ble_hs_unlock(); +} + void ble_gap_rx_scan_req_rcvd(const struct ble_hci_ev_le_subev_scan_req_rcvd *ev) { @@ -1483,7 +1645,7 @@ ble_gap_rx_scan_req_rcvd(const struct ble_hci_ev_le_subev_scan_req_rcvd *ev) ble_gap_event_fn *cb; void *cb_arg; - ble_gap_slave_extract_cb(ev->adv_handle, &cb, &cb_arg); + ble_gap_slave_get_cb(ev->adv_handle, &cb, &cb_arg); if (cb != NULL) { memset(&event, 0, sizeof event); event.type = BLE_GAP_EVENT_SCAN_REQ_RCVD; @@ -1629,6 +1791,46 @@ ble_gap_rx_periodic_adv_sync_lost(const struct ble_hci_ev_le_subev_periodic_adv_ } #endif +#if MYNEWT_VAL(BLE_POWER_CONTROL) +void +ble_gap_rx_le_pathloss_threshold(const struct ble_hci_ev_le_subev_path_loss_threshold *ev) +{ + struct ble_gap_event event; + uint16_t conn_handle = le16toh(ev->conn_handle); + + memset(&event, 0, sizeof event); + + event.type = BLE_GAP_EVENT_PATHLOSS_THRESHOLD; + event.pathloss_threshold.conn_handle = conn_handle; + event.pathloss_threshold.current_path_loss = ev->current_path_loss; + event.pathloss_threshold.zone_entered = ev->zone_entered; + + ble_gap_event_listener_call(&event); + ble_gap_call_conn_event_cb(&event, conn_handle); +} + +void +ble_gap_rx_transmit_power_report(const struct ble_hci_ev_le_subev_transmit_power_report *ev) +{ + struct ble_gap_event event; + uint16_t conn_handle = le16toh(ev->conn_handle); + + memset(&event, 0, sizeof event); + + event.type = BLE_GAP_EVENT_TRANSMIT_POWER; + event.transmit_power.status = ev->status; + event.transmit_power.conn_handle = conn_handle; + event.transmit_power.reason = ev->reason; + event.transmit_power.phy = ev->phy; + event.transmit_power.transmit_power_level = ev->transmit_power_level; + event.transmit_power.transmit_power_level_flag = ev->transmit_power_level_flag; + event.transmit_power.delta = ev->delta; + + ble_gap_event_listener_call(&event); + ble_gap_call_conn_event_cb(&event, conn_handle); +} +#endif + #if MYNEWT_VAL(BLE_PERIODIC_ADV_SYNC_TRANSFER) static int periodic_adv_transfer_disable(uint16_t conn_handle) @@ -1726,6 +1928,47 @@ ble_gap_rx_periodic_adv_sync_transfer(const struct ble_hci_ev_le_subev_periodic_ ble_hs_unlock(); + cb(&event, cb_arg); +} +#endif + +#if MYNEWT_VAL(BLE_PERIODIC_ADV_SYNC_BIGINFO_REPORTS) +void +ble_gap_rx_biginfo_adv_rpt(const struct ble_hci_ev_le_subev_biginfo_adv_report *ev) +{ + struct ble_hs_periodic_sync *psync; + struct ble_gap_event event; + ble_gap_event_fn *cb; + void *cb_arg; + + cb = NULL; + cb_arg = NULL; + + ble_hs_lock(); + psync = ble_hs_periodic_sync_find_by_handle(le16toh(ev->sync_handle)); + if (psync) { + cb = psync->cb; + cb_arg = psync->cb_arg; + } + ble_hs_unlock(); + + memset(&event, 0, sizeof event); + + event.type = BLE_GAP_EVENT_BIGINFO_REPORT; + event.biginfo_report.sync_handle = ev->sync_handle; + event.biginfo_report.bis_cnt = ev->bis_cnt; + event.biginfo_report.nse = ev->nse; + event.biginfo_report.iso_interval = ev->iso_interval; + event.biginfo_report.bn = ev->bn; + event.biginfo_report.pto = ev->pto; + event.biginfo_report.irc = ev->irc; + event.biginfo_report.max_pdu = ev->max_pdu; + event.biginfo_report.sdu_interval = get_le24(&ev->sdu_interval[0]); + event.biginfo_report.max_sdu = ev->max_sdu; + event.biginfo_report.phy = ev->phy; + event.biginfo_report.framing = ev->framing; + event.biginfo_report.encryption = ev->encryption; + ble_gap_event_listener_call(&event); if (cb) { cb(&event, cb_arg); @@ -1733,6 +1976,27 @@ ble_gap_rx_periodic_adv_sync_transfer(const struct ble_hci_ev_le_subev_periodic_ } #endif +#if MYNEWT_VAL(BLE_CONN_SUBRATING) +void +ble_gap_rx_subrate_change(const struct ble_hci_ev_le_subev_subrate_change *ev) +{ + struct ble_gap_event event; + + memset(&event, 0x0, sizeof event); + + event.type = BLE_GAP_EVENT_SUBRATE_CHANGE; + event.subrate_change.status = ev->status; + event.subrate_change.conn_handle = le16toh(ev->conn_handle); + event.subrate_change.subrate_factor = le16toh(ev->subrate_factor); + event.subrate_change.periph_latency = le16toh(ev->periph_latency); + event.subrate_change.cont_num = le16toh(ev->cont_num); + event.subrate_change.supervision_tmo = le16toh(ev->supervision_tmo); + + ble_gap_event_listener_call(&event); + ble_gap_call_conn_event_cb(&event, ev->conn_handle); +} +#endif + #if NIMBLE_BLE_CONNECT static int ble_gap_rd_rem_sup_feat_tx(uint16_t handle) @@ -1829,6 +2093,9 @@ ble_gap_rx_conn_complete(struct ble_gap_conn_complete *evt, uint8_t instance) /* We verified that there is a free connection when the procedure began. */ conn = ble_hs_conn_alloc(evt->connection_handle); BLE_HS_DBG_ASSERT(conn != NULL); + if (conn == NULL) { + return BLE_HS_ENOMEM; + } conn->bhc_itvl = evt->conn_itvl; conn->bhc_latency = evt->conn_latency; @@ -1913,13 +2180,17 @@ ble_gap_rx_l2cap_update_req(uint16_t conn_handle, struct ble_gap_upd_params *params) { #if NIMBLE_BLE_CONNECT + struct ble_gap_upd_params peer_params; struct ble_gap_event event; int rc; + peer_params = *params; + memset(&event, 0, sizeof event); event.type = BLE_GAP_EVENT_L2CAP_UPDATE_REQ; event.conn_update_req.conn_handle = conn_handle; - event.conn_update_req.peer_params = params; + event.conn_update_req.peer_params = &peer_params; + event.conn_update_req.self_params = params; rc = ble_gap_call_conn_event_cb(&event, conn_handle); return rc; @@ -2137,7 +2408,8 @@ ble_gap_wl_tx_add(const ble_addr_t *addr) { struct ble_hci_le_add_whte_list_cp cmd; - if (addr->type > BLE_ADDR_RANDOM) { + if (addr->type > BLE_ADDR_RANDOM && + addr->type != BLE_ADDR_ANONYMOUS) { return BLE_HS_EINVAL; } @@ -2156,6 +2428,23 @@ ble_gap_wl_tx_clear(void) BLE_HCI_OCF_LE_CLEAR_WHITE_LIST), NULL, 0, NULL, 0 ); } + +int +ble_gap_wl_read_size(uint8_t *size) +{ + struct ble_hci_le_rd_white_list_rp rsp; + int rc; + + rc = ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_RD_WHITE_LIST_SIZE), + NULL, 0, &rsp, sizeof(rsp)); + + if (rc == 0) { + *size = rsp.size; + } + + return rc; +} #endif int @@ -2167,11 +2456,16 @@ ble_gap_wl_set(const ble_addr_t *addrs, uint8_t white_list_count) STATS_INC(ble_gap_stats, wl_set); + if (!ble_hs_is_enabled()) { + return BLE_HS_EDISABLED; + } + ble_hs_lock(); for (i = 0; i < white_list_count; i++) { if (addrs[i].type != BLE_ADDR_PUBLIC && - addrs[i].type != BLE_ADDR_RANDOM) { + addrs[i].type != BLE_ADDR_RANDOM && + addrs[i].type != BLE_ADDR_ANONYMOUS) { rc = BLE_HS_EINVAL; goto done; @@ -2268,14 +2562,35 @@ ble_gap_adv_stop_no_lock(void) int ble_gap_adv_stop(void) { -#if NIMBLE_BLE_ADVERTISE && !MYNEWT_VAL(BLE_EXT_ADV) +#if NIMBLE_BLE_ADVERTISE +#if MYNEWT_VAL(BLE_EXT_ADV) + int rc; + + rc = ble_gap_ext_adv_stop(MYNEWT_VAL(BLE_HS_EXT_ADV_LEGACY_INSTANCE)); + if (rc) { + return rc; + } + + rc = ble_gap_ext_adv_remove(MYNEWT_VAL(BLE_HS_EXT_ADV_LEGACY_INSTANCE)); + if (rc) { + return rc; + } + + ext_adv_legacy_configured = false; + return 0; +#else int rc; + if (!ble_hs_is_enabled()) { + return BLE_HS_EDISABLED; + } + ble_hs_lock(); rc = ble_gap_adv_stop_no_lock(); ble_hs_unlock(); return rc; +#endif #else return BLE_HS_ENOTSUP; #endif @@ -2462,35 +2777,102 @@ ble_gap_adv_start(uint8_t own_addr_type, const ble_addr_t *direct_addr, const struct ble_gap_adv_params *adv_params, ble_gap_event_fn *cb, void *cb_arg) { -#if NIMBLE_BLE_ADVERTISE && !MYNEWT_VAL(BLE_EXT_ADV) - uint32_t duration_ticks; +#if NIMBLE_BLE_ADVERTISE +#if MYNEWT_VAL(BLE_EXT_ADV) + struct ble_gap_ext_adv_params ext_params; + int duration; int rc; STATS_INC(ble_gap_stats, adv_start); - ble_hs_lock(); - - rc = ble_gap_adv_validate(own_addr_type, direct_addr, adv_params); - if (rc != 0) { - goto done; + if (!ble_hs_is_enabled()) { + return BLE_HS_EDISABLED; } - if (duration_ms != BLE_HS_FOREVER) { - rc = ble_npl_time_ms_to_ticks(duration_ms, &duration_ticks); - if (rc != 0) { - /* Duration too great. */ - rc = BLE_HS_EINVAL; - goto done; - } - } + memset(&ext_params, 0, sizeof(ext_params)); - if (!ble_hs_is_enabled()) { - rc = BLE_HS_EDISABLED; - goto done; - } + ext_params.own_addr_type = own_addr_type; + ext_params.primary_phy = BLE_HCI_LE_PHY_1M; + ext_params.secondary_phy = BLE_HCI_LE_PHY_1M; + ext_params.tx_power = 127; + ext_params.sid = 0; + ext_params.legacy_pdu = 1; - if (ble_gap_is_preempted()) { - rc = BLE_HS_EPREEMPTED; + switch (adv_params->conn_mode) { + case BLE_GAP_CONN_MODE_NON: + if (adv_params->disc_mode != BLE_GAP_DISC_MODE_NON) { + ext_params.scannable = 1; + } + break; + case BLE_GAP_CONN_MODE_DIR: + if (!direct_addr) { + return BLE_HS_EINVAL; + } + + ext_params.peer = *direct_addr; + ext_params.directed = 1; + if (adv_params->high_duty_cycle) { + ext_params.high_duty_directed = 1; + } + break; + case BLE_GAP_CONN_MODE_UND: + ext_params.connectable = 1; + ext_params.scannable = 1; + break; + default: + return BLE_HS_EINVAL; + } + + ext_params.itvl_min = adv_params->itvl_min; + ext_params.itvl_max = adv_params->itvl_max; + ext_params.channel_map = adv_params->channel_map; + ext_params.filter_policy = adv_params->filter_policy; + ext_params.high_duty_directed = adv_params->high_duty_cycle; + + /* configure legacy instance */ + rc = ble_gap_ext_adv_configure(MYNEWT_VAL(BLE_HS_EXT_ADV_LEGACY_INSTANCE), + &ext_params, NULL, cb, cb_arg); + if (rc) { + return rc; + } + + ext_adv_legacy_configured = true; + + if (duration_ms == BLE_HS_FOREVER) { + duration = 0; + } else { + duration = duration_ms / 10; + } + + return ble_gap_ext_adv_start(MYNEWT_VAL(BLE_HS_EXT_ADV_LEGACY_INSTANCE), duration, 0); +#else + uint32_t duration_ticks; + int rc; + + STATS_INC(ble_gap_stats, adv_start); + + if (!ble_hs_is_enabled()) { + return BLE_HS_EDISABLED; + } + + ble_hs_lock(); + + rc = ble_gap_adv_validate(own_addr_type, direct_addr, adv_params); + if (rc != 0) { + goto done; + } + + if (duration_ms != BLE_HS_FOREVER) { + rc = ble_npl_time_ms_to_ticks(duration_ms, &duration_ticks); + if (rc != 0) { + /* Duration too great. */ + rc = BLE_HS_EINVAL; + goto done; + } + } + + if (ble_gap_is_preempted()) { + rc = BLE_HS_EPREEMPTED; goto done; } @@ -2539,24 +2921,90 @@ ble_gap_adv_start(uint8_t own_addr_type, const ble_addr_t *direct_addr, STATS_INC(ble_gap_stats, adv_start_fail); } return rc; +#endif #else return BLE_HS_ENOTSUP; #endif } +#if NIMBLE_BLE_ADVERTISE +#if MYNEWT_VAL(BLE_EXT_ADV) +static int +ble_gap_ext_adv_legacy_preconfigure(void) +{ + struct ble_gap_ext_adv_params ext_params; + int rc; + + if (ext_adv_legacy_configured) { + return 0; + } + + memset(&ext_params, 0, sizeof(ext_params)); + ext_params.own_addr_type = BLE_ADDR_RANDOM; + ext_params.primary_phy = BLE_HCI_LE_PHY_1M; + ext_params.secondary_phy = BLE_HCI_LE_PHY_1M; + ext_params.tx_power = 127; + ext_params.sid = 0; + ext_params.legacy_pdu = 1; + ext_params.scannable = 1; + ext_params.connectable = 1; + + rc = ble_gap_ext_adv_configure(MYNEWT_VAL(BLE_HS_EXT_ADV_LEGACY_INSTANCE), + &ext_params, NULL, NULL, NULL); + if (rc) { + return rc; + } + + ext_adv_legacy_configured = true; + return 0; +} +#endif +#endif + int ble_gap_adv_set_data(const uint8_t *data, int data_len) { -#if NIMBLE_BLE_ADVERTISE && !MYNEWT_VAL(BLE_EXT_ADV) +#if NIMBLE_BLE_ADVERTISE +#if MYNEWT_VAL(BLE_EXT_ADV) + struct os_mbuf *mbuf; + int rc; + + if (((data == NULL) && (data_len != 0)) || + (data_len > BLE_HCI_MAX_ADV_DATA_LEN)) { + return BLE_HS_EINVAL; + } + + rc = ble_gap_ext_adv_legacy_preconfigure(); + if (rc) { + return rc; + } + + mbuf = os_msys_get_pkthdr(data_len, 0); + if (!mbuf) { + return BLE_HS_ENOMEM; + } + + rc = os_mbuf_append(mbuf, data, data_len); + if (rc) { + os_mbuf_free_chain(mbuf); + return BLE_HS_ENOMEM; + } + + return ble_gap_ext_adv_set_data(MYNEWT_VAL(BLE_HS_EXT_ADV_LEGACY_INSTANCE), mbuf); +#else struct ble_hci_le_set_adv_data_cp cmd; uint16_t opcode; STATS_INC(ble_gap_stats, adv_set_data); + if (!ble_hs_is_enabled()) { + return BLE_HS_EDISABLED; + } + /* Check for valid parameters */ if (((data == NULL) && (data_len != 0)) || (data_len > BLE_HCI_MAX_ADV_DATA_LEN)) { - return BLE_ERR_INV_HCI_CMD_PARMS; + return BLE_HS_EINVAL; } memcpy(cmd.adv_data, data, data_len); @@ -2565,6 +3013,7 @@ ble_gap_adv_set_data(const uint8_t *data, int data_len) opcode = BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_ADV_DATA); return ble_hs_hci_cmd_tx(opcode, &cmd, sizeof(cmd), NULL, 0); +#endif #else return BLE_HS_ENOTSUP; #endif @@ -2573,10 +3022,40 @@ ble_gap_adv_set_data(const uint8_t *data, int data_len) int ble_gap_adv_rsp_set_data(const uint8_t *data, int data_len) { -#if NIMBLE_BLE_ADVERTISE && !MYNEWT_VAL(BLE_EXT_ADV) +#if NIMBLE_BLE_ADVERTISE +#if MYNEWT_VAL(BLE_EXT_ADV) + struct os_mbuf *mbuf; + int rc; + + if (((data == NULL) && (data_len != 0)) || + (data_len > BLE_HCI_MAX_ADV_DATA_LEN)) { + return BLE_HS_EINVAL; + } + + rc = ble_gap_ext_adv_legacy_preconfigure(); + if (rc) { + return rc; + } + + mbuf = os_msys_get_pkthdr(data_len, 0); + if (!mbuf) { + return BLE_HS_ENOMEM; + } + + rc = os_mbuf_append(mbuf, data, data_len); + if (rc) { + os_mbuf_free_chain(mbuf); + return BLE_HS_ENOMEM; + } + + return ble_gap_ext_adv_rsp_set_data(MYNEWT_VAL(BLE_HS_EXT_ADV_LEGACY_INSTANCE), mbuf); +#else struct ble_hci_le_set_scan_rsp_data_cp cmd; uint16_t opcode; + if (!ble_hs_is_enabled()) { + return BLE_HS_EDISABLED; + } /* Check for valid parameters */ if (((data == NULL) && (data_len != 0)) || @@ -2590,6 +3069,7 @@ ble_gap_adv_rsp_set_data(const uint8_t *data, int data_len) opcode = BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_SCAN_RSP_DATA); return ble_hs_hci_cmd_tx(opcode, &cmd, sizeof(cmd), NULL, 0); +#endif #else return BLE_HS_ENOTSUP; #endif @@ -2598,11 +3078,15 @@ ble_gap_adv_rsp_set_data(const uint8_t *data, int data_len) int ble_gap_adv_set_fields(const struct ble_hs_adv_fields *adv_fields) { -#if NIMBLE_BLE_ADVERTISE && !MYNEWT_VAL(BLE_EXT_ADV) +#if NIMBLE_BLE_ADVERTISE uint8_t buf[BLE_HS_ADV_MAX_SZ]; uint8_t buf_sz; int rc; + if (!ble_hs_is_enabled()) { + return BLE_HS_EDISABLED; + } + rc = ble_hs_adv_set_fields(adv_fields, buf, &buf_sz, sizeof buf); if (rc != 0) { return rc; @@ -2622,7 +3106,7 @@ ble_gap_adv_set_fields(const struct ble_hs_adv_fields *adv_fields) int ble_gap_adv_rsp_set_fields(const struct ble_hs_adv_fields *rsp_fields) { -#if NIMBLE_BLE_ADVERTISE && !MYNEWT_VAL(BLE_EXT_ADV) +#if NIMBLE_BLE_ADVERTISE uint8_t buf[BLE_HS_ADV_MAX_SZ]; uint8_t buf_sz; int rc; @@ -2647,7 +3131,7 @@ int ble_gap_adv_active(void) { #if NIMBLE_BLE_ADVERTISE - return ble_gap_adv_active_instance(0); + return ble_gap_adv_active_instance(MYNEWT_VAL(BLE_HS_EXT_ADV_LEGACY_INSTANCE)); #else return 0; #endif @@ -2655,78 +3139,141 @@ ble_gap_adv_active(void) #if MYNEWT_VAL(BLE_EXT_ADV) static int -ble_gap_ext_adv_params_tx(uint8_t instance, - const struct ble_gap_ext_adv_params *params, - int8_t *selected_tx_power) - +ble_gap_set_ext_adv_params(struct ble_hci_le_set_ext_adv_params_cp *cmd, + uint8_t instance, const struct ble_gap_ext_adv_params *params, + int8_t *selected_tx_power) { - struct ble_hci_le_set_ext_adv_params_cp cmd; - struct ble_hci_le_set_ext_adv_params_rp rsp; - int rc; - - memset(&cmd, 0, sizeof(cmd)); - - cmd.adv_handle = instance; + cmd->adv_handle = instance; if (params->connectable) { - cmd.props |= BLE_HCI_LE_SET_EXT_ADV_PROP_CONNECTABLE; + cmd->props |= BLE_HCI_LE_SET_EXT_ADV_PROP_CONNECTABLE; } if (params->scannable) { - cmd.props |= BLE_HCI_LE_SET_EXT_ADV_PROP_SCANNABLE; + cmd->props |= BLE_HCI_LE_SET_EXT_ADV_PROP_SCANNABLE; } if (params->directed) { - cmd.props |= BLE_HCI_LE_SET_EXT_ADV_PROP_DIRECTED; - cmd.peer_addr_type = params->peer.type; - memcpy(cmd.peer_addr, params->peer.val, BLE_DEV_ADDR_LEN); + cmd->props |= BLE_HCI_LE_SET_EXT_ADV_PROP_DIRECTED; + cmd->peer_addr_type = params->peer.type; + memcpy(cmd->peer_addr, params->peer.val, BLE_DEV_ADDR_LEN); } if (params->high_duty_directed) { - cmd.props |= BLE_HCI_LE_SET_EXT_ADV_PROP_HD_DIRECTED; - } - if (params->legacy_pdu) { - cmd.props |= BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY; + cmd->props |= BLE_HCI_LE_SET_EXT_ADV_PROP_HD_DIRECTED; } if (params->anonymous) { - cmd.props |= BLE_HCI_LE_SET_EXT_ADV_PROP_ANON_ADV; + cmd->props |= BLE_HCI_LE_SET_EXT_ADV_PROP_ANON_ADV; } if (params->include_tx_power) { - cmd.props |= BLE_HCI_LE_SET_EXT_ADV_PROP_INC_TX_PWR; + cmd->props |= BLE_HCI_LE_SET_EXT_ADV_PROP_INC_TX_PWR; + } + if (params->legacy_pdu) { + cmd->props |= BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY; + + /* check right away if the applied configuration is valid before handing + * the command to the controller to improve error reporting */ + switch (cmd->props) { + case BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY_IND: + case BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY_LD_DIR: + case BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY_HD_DIR: + case BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY_SCAN: + case BLE_HCI_LE_SET_EXT_ADV_PROP_LEGACY_NONCONN: + break; + default: + return BLE_HS_EINVAL; + } } /* Fill optional fields if application did not specify them. */ if (params->itvl_min == 0 && params->itvl_max == 0) { /* TODO for now limited to legacy values*/ - put_le24(cmd.pri_itvl_min, BLE_GAP_ADV_FAST_INTERVAL1_MIN); - put_le24(cmd.pri_itvl_max, BLE_GAP_ADV_FAST_INTERVAL2_MAX); + put_le24(cmd->pri_itvl_min, BLE_GAP_ADV_FAST_INTERVAL1_MIN); + put_le24(cmd->pri_itvl_max, BLE_GAP_ADV_FAST_INTERVAL2_MAX); } else { - put_le24(cmd.pri_itvl_min, params->itvl_min); - put_le24(cmd.pri_itvl_max, params->itvl_max); + put_le24(cmd->pri_itvl_min, params->itvl_min); + put_le24(cmd->pri_itvl_max, params->itvl_max); } if (params->channel_map == 0) { - cmd.pri_chan_map = BLE_GAP_ADV_DFLT_CHANNEL_MAP; + cmd->pri_chan_map = BLE_GAP_ADV_DFLT_CHANNEL_MAP; } else { - cmd.pri_chan_map = params->channel_map; + cmd->pri_chan_map = params->channel_map; } /* Zero is the default value for filter policy and high duty cycle */ - cmd.filter_policy = params->filter_policy; - cmd.tx_power = params->tx_power; + cmd->filter_policy = params->filter_policy; + cmd->tx_power = params->tx_power; if (params->legacy_pdu) { - cmd.pri_phy = BLE_HCI_LE_PHY_1M; - cmd.sec_phy = BLE_HCI_LE_PHY_1M; + cmd->pri_phy = BLE_HCI_LE_PHY_1M; + cmd->sec_phy = BLE_HCI_LE_PHY_1M; } else { - cmd.pri_phy = params->primary_phy; - cmd.sec_phy = params->secondary_phy; + cmd->pri_phy = params->primary_phy; + cmd->sec_phy = params->secondary_phy; } - cmd.own_addr_type = params->own_addr_type; - cmd.sec_max_skip = 0; - cmd.sid = params->sid; - cmd.scan_req_notif = params->scan_req_notif; + cmd->own_addr_type = params->own_addr_type; + cmd->sec_max_skip = 0; + cmd->sid = params->sid; + cmd->scan_req_notif = params->scan_req_notif; + + return 0; +} + +static int +ble_gap_ext_adv_params_tx_v1(uint8_t instance, + const struct ble_gap_ext_adv_params *params, + int8_t *selected_tx_power) +{ + struct ble_hci_le_set_ext_adv_params_cp cmd; + struct ble_hci_le_set_ext_adv_params_rp rsp; + int rc; + + memset(&cmd, 0, sizeof(cmd)); + + rc = ble_gap_set_ext_adv_params(&cmd, instance, params, selected_tx_power); + + if (rc != 0) { + return rc; + } + + rc = ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_SET_EXT_ADV_PARAM), + &cmd, sizeof(cmd), &rsp, sizeof(rsp)); + + if (rc != 0) { + return rc; + } + + if (selected_tx_power) { + *selected_tx_power = rsp.tx_power; + } + + return 0; + +} + +static int +ble_gap_ext_adv_params_tx_v2(uint8_t instance, + const struct ble_gap_ext_adv_params *params, + int8_t *selected_tx_power) +{ + + struct ble_hci_le_set_ext_adv_params_v2_cp cmd; + struct ble_hci_le_set_ext_adv_params_rp rsp; + int rc; + + memset(&cmd, 0, sizeof(cmd)); + + rc = ble_gap_set_ext_adv_params(&(cmd.params_v1), instance, params, selected_tx_power); + + if (rc != 0) { + return rc; + } + + cmd.pri_phy_opt = params->primary_phy_opt; + cmd.sec_phy_opt = params->secondary_phy_opt; rc = ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE, - BLE_HCI_OCF_LE_SET_EXT_ADV_PARAM), + BLE_HCI_OCF_LE_SET_EXT_ADV_PARAM_V2), &cmd, sizeof(cmd), &rsp, sizeof(rsp)); if (rc != 0) { @@ -2740,6 +3287,32 @@ ble_gap_ext_adv_params_tx(uint8_t instance, return 0; } +static int +ble_gap_ext_adv_params_tx(uint8_t instance, + const struct ble_gap_ext_adv_params *params, + int8_t *selected_tx_power) +{ + struct ble_hs_hci_sup_cmd sup_cmd; + int rc = 0; + + sup_cmd = ble_hs_hci_get_hci_supported_cmd(); + + /* Return Error if phy is non-zero and controller doesn't support V2 */ + if (!((sup_cmd.commands[46] & 0x04) != 0) && + (params->primary_phy_opt || params->secondary_phy_opt)) { + return BLE_HS_EINVAL; + } + + if ((sup_cmd.commands[46] & 0x04) != 0) { + rc = ble_gap_ext_adv_params_tx_v2(instance, params, selected_tx_power); + return rc; + } + + rc = ble_gap_ext_adv_params_tx_v1(instance, params, selected_tx_power); + + return rc; +} + static int ble_gap_ext_adv_params_validate(const struct ble_gap_ext_adv_params *params) { @@ -2798,6 +3371,10 @@ ble_gap_ext_adv_configure(uint8_t instance, return BLE_HS_EINVAL; } + if (!ble_hs_is_enabled()) { + return BLE_HS_EDISABLED; + } + rc = ble_gap_ext_adv_params_validate(params); if (rc) { return rc; @@ -2862,6 +3439,10 @@ ble_gap_ext_adv_set_addr(uint8_t instance, const ble_addr_t *addr) return BLE_HS_EINVAL; } + if (!ble_hs_is_enabled()) { + return BLE_HS_EDISABLED; + } + ble_hs_lock(); rc = ble_gap_ext_adv_set_addr_no_lock(instance, addr->val); ble_hs_unlock(); @@ -2882,6 +3463,10 @@ ble_gap_ext_adv_start(uint8_t instance, int duration, int max_events) return BLE_HS_EINVAL; } + if (!ble_hs_is_enabled()) { + return BLE_HS_EDISABLED; + } + ble_hs_lock(); if (!ble_gap_slave[instance].configured) { ble_hs_unlock(); @@ -3159,6 +3744,11 @@ ble_gap_ext_adv_set_data(uint8_t instance, struct os_mbuf *data) goto done; } + if (!ble_hs_is_enabled()) { + rc = BLE_HS_EDISABLED; + goto done; + } + ble_hs_lock(); rc = ble_gap_ext_adv_set_data_validate(instance, data); if (rc != 0) { @@ -3226,6 +3816,11 @@ ble_gap_ext_adv_rsp_set_data(uint8_t instance, struct os_mbuf *data) goto done; } + if (!ble_hs_is_enabled()) { + rc = BLE_HS_EDISABLED; + goto done; + } + ble_hs_lock(); rc = ble_gap_ext_adv_rsp_set_validate(instance, data); if (rc != 0) { @@ -3254,6 +3849,10 @@ ble_gap_ext_adv_remove(uint8_t instance) return BLE_HS_EINVAL; } + if (!ble_hs_is_enabled()) { + return BLE_HS_EDISABLED; + } + ble_hs_lock(); if (!ble_gap_slave[instance].configured) { ble_hs_unlock(); @@ -3287,13 +3886,17 @@ ble_gap_ext_adv_clear(void) uint8_t instance; uint16_t opcode; + if (!ble_hs_is_enabled()) { + return BLE_HS_EDISABLED; + } + ble_hs_lock(); for (instance = 0; instance < BLE_ADV_INSTANCES; instance++) { /* If there is an active instance or periodic adv instance, * Don't send the command * */ - if ((ble_gap_slave[instance].op == BLE_GAP_OP_S_ADV)) { + if (ble_gap_slave[instance].op == BLE_GAP_OP_S_ADV) { ble_hs_unlock(); return BLE_HS_EBUSY; } @@ -3333,12 +3936,11 @@ ble_gap_periodic_adv_params_tx(uint8_t instance, /* Fill optional fields if application did not specify them. */ if (params->itvl_min == 0 && params->itvl_max == 0) { - /* TODO defines for those */ - cmd.min_itvl = htole16(30 / 1.25); //30 ms - cmd.max_itvl = htole16(60 / 1.25); //150 ms + cmd.min_itvl = BLE_GAP_PERIODIC_ITVL_MS(30); + cmd.max_itvl = BLE_GAP_PERIODIC_ITVL_MS(60); } else { - cmd.min_itvl = htole16( params->itvl_min); + cmd.min_itvl = htole16(params->itvl_min); cmd.max_itvl = htole16(params->itvl_max); } @@ -3380,6 +3982,10 @@ ble_gap_periodic_adv_configure(uint8_t instance, return BLE_HS_EINVAL; } + if (!ble_hs_is_enabled()) { + return BLE_HS_EDISABLED; + } + rc = ble_gap_periodic_adv_params_validate(params); if (rc) { return rc; @@ -3416,7 +4022,7 @@ ble_gap_periodic_adv_configure(uint8_t instance, } int -ble_gap_periodic_adv_start(uint8_t instance) +ble_gap_periodic_adv_start(uint8_t instance, const struct ble_gap_periodic_adv_start_params *params) { struct ble_hci_le_set_periodic_adv_enable_cp cmd; uint16_t opcode; @@ -3426,6 +4032,10 @@ ble_gap_periodic_adv_start(uint8_t instance) return BLE_HS_EINVAL; } + if (!ble_hs_is_enabled()) { + return BLE_HS_EDISABLED; + } + ble_hs_lock(); /* Periodic advertising cannot start unless it is configured before */ @@ -3437,6 +4047,12 @@ ble_gap_periodic_adv_start(uint8_t instance) opcode = BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_PERIODIC_ADV_ENABLE); cmd.enable = 0x01; + +#if MYNEWT_VAL(BLE_VERSION) >= 53 + if (params && params->include_adi) { + SET_BIT(cmd.enable, 1); + } +#endif cmd.adv_handle = instance; rc = ble_hs_hci_cmd_tx(opcode, &cmd, sizeof(cmd), NULL, 0); @@ -3451,6 +4067,27 @@ ble_gap_periodic_adv_start(uint8_t instance) return 0; } +#if MYNEWT_VAL(BLE_VERSION) >= 53 +static int +ble_gap_periodic_adv_update_did(uint8_t instance) +{ + static uint8_t buf[sizeof(struct ble_hci_le_set_periodic_adv_data_cp)]; + struct ble_hci_le_set_periodic_adv_data_cp *cmd = (void *) buf; + uint16_t opcode; + + memset(buf, 0, sizeof(buf)); + + opcode = BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_PERIODIC_ADV_DATA); + + cmd->adv_handle = instance; + cmd->operation = BLE_HCI_LE_SET_DATA_OPER_UNCHANGED; + cmd->adv_data_len = 0; + + return ble_hs_hci_cmd_tx(opcode, cmd, sizeof(*cmd) + cmd->adv_data_len, + NULL, 0); +} +#endif + static int ble_gap_periodic_adv_set(uint8_t instance, struct os_mbuf **data) { @@ -3459,18 +4096,25 @@ ble_gap_periodic_adv_set(uint8_t instance, struct os_mbuf **data) static uint8_t buf[sizeof(struct ble_hci_le_set_periodic_adv_data_cp) + MYNEWT_VAL(BLE_EXT_ADV_MAX_SIZE)]; struct ble_hci_le_set_periodic_adv_data_cp *cmd = (void *) buf; - uint16_t len = OS_MBUF_PKTLEN(*data); + uint16_t len = 0; uint16_t opcode; + if (*data) { + len = OS_MBUF_PKTLEN(*data); + } + opcode = BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_PERIODIC_ADV_DATA); cmd->adv_handle = instance; cmd->operation = BLE_HCI_LE_SET_DATA_OPER_COMPLETE; cmd->adv_data_len = len; - os_mbuf_copydata(*data, 0, len, cmd->adv_data); - os_mbuf_adj(*data, len); - *data = os_mbuf_trim_front(*data); + if (len) { + os_mbuf_copydata(*data, 0, len, cmd->adv_data); + + os_mbuf_adj(*data, len); + *data = os_mbuf_trim_front(*data); + } return ble_hs_hci_cmd_tx(opcode, cmd, sizeof(*cmd) + cmd->adv_data_len, NULL, 0); @@ -3478,11 +4122,15 @@ ble_gap_periodic_adv_set(uint8_t instance, struct os_mbuf **data) static uint8_t buf[sizeof(struct ble_hci_le_set_periodic_adv_data_cp) + BLE_HCI_MAX_PERIODIC_ADV_DATA_LEN]; struct ble_hci_le_set_periodic_adv_data_cp *cmd = (void *) buf; - uint16_t len = OS_MBUF_PKTLEN(*data); + uint16_t len = 0; uint16_t opcode; uint8_t op; int rc; + if (*data) { + len = OS_MBUF_PKTLEN(*data); + } + opcode = BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_PERIODIC_ADV_DATA); cmd->adv_handle = instance; @@ -3490,10 +4138,13 @@ ble_gap_periodic_adv_set(uint8_t instance, struct os_mbuf **data) if (len <= BLE_HCI_MAX_PERIODIC_ADV_DATA_LEN) { cmd->operation = BLE_HCI_LE_SET_DATA_OPER_COMPLETE; cmd->adv_data_len = len; - os_mbuf_copydata(*data, 0, len, cmd->adv_data); - os_mbuf_adj(*data, len); - *data = os_mbuf_trim_front(*data); + if (len) { + os_mbuf_copydata(*data, 0, len, cmd->adv_data); + + os_mbuf_adj(*data, len); + *data = os_mbuf_trim_front(*data); + } return ble_hs_hci_cmd_tx(opcode, cmd, sizeof(*cmd) + cmd->adv_data_len, NULL, 0); @@ -3565,7 +4216,9 @@ ble_gap_periodic_adv_set_data_validate(uint8_t instance, } int -ble_gap_periodic_adv_set_data(uint8_t instance, struct os_mbuf *data) +ble_gap_periodic_adv_set_data(uint8_t instance, + struct os_mbuf *data, + const struct ble_gap_periodic_adv_set_data_params *params) { int rc; if (instance >= BLE_ADV_INSTANCES) { @@ -3573,6 +4226,19 @@ ble_gap_periodic_adv_set_data(uint8_t instance, struct os_mbuf *data) goto done; } + if (!ble_hs_is_enabled()) { + rc = BLE_HS_EDISABLED; + goto done; + } + +#if MYNEWT_VAL(BLE_VERSION) >= 53 + /* update_did and data cannot be set at the same time */ + if (params && params->update_did && data) { + rc = BLE_HS_EINVAL; + goto done; + } +#endif + ble_hs_lock(); rc = ble_gap_periodic_adv_set_data_validate(instance, data); @@ -3581,7 +4247,15 @@ ble_gap_periodic_adv_set_data(uint8_t instance, struct os_mbuf *data) goto done; } +#if MYNEWT_VAL(BLE_VERSION) >= 53 + if (params && params->update_did) { + rc = ble_gap_periodic_adv_update_did(instance); + } else { + rc = ble_gap_periodic_adv_set(instance, &data); + } +#else rc = ble_gap_periodic_adv_set(instance, &data); +#endif ble_hs_unlock(); @@ -3621,6 +4295,10 @@ ble_gap_periodic_adv_stop(uint8_t instance) return BLE_HS_EINVAL; } + if (!ble_hs_is_enabled()) { + return BLE_HS_EDISABLED; + } + ble_hs_lock(); rc = ble_gap_periodic_adv_stop_no_lock(instance); ble_hs_unlock(); @@ -3677,6 +4355,10 @@ ble_gap_periodic_adv_sync_create(const ble_addr_t *addr, uint8_t adv_sid, return BLE_HS_EINVAL; } + if (!ble_hs_is_enabled()) { + return BLE_HS_EDISABLED; + } + ble_hs_lock(); /* No sync can be created if another sync is still pending */ @@ -3710,6 +4392,15 @@ ble_gap_periodic_adv_sync_create(const ble_addr_t *addr, uint8_t adv_sid, memcpy(cmd.peer_addr, BLE_ADDR_ANY->val, BLE_DEV_ADDR_LEN); } +#if MYNEWT_VAL(BLE_VERSION) >= 53 + /* LE Periodic Advertising Create Sync command */ + if (params->reports_disabled) { + SET_BIT(cmd.options, 1); + } + if (params->filter_duplicates) { + SET_BIT(cmd.options, 2); + } +#endif cmd.sid = adv_sid; cmd.skip = params->skip; cmd.sync_timeout = htole16(params->sync_timeout); @@ -3765,6 +4456,10 @@ ble_gap_periodic_adv_sync_terminate(uint16_t sync_handle) uint16_t opcode; int rc; + if (!ble_hs_is_enabled()) { + return BLE_HS_EDISABLED; + } + ble_hs_lock(); if (ble_gap_sync.op == BLE_GAP_OP_SYNC) { @@ -3803,14 +4498,21 @@ ble_gap_periodic_adv_sync_terminate(uint16_t sync_handle) return rc; } #if MYNEWT_VAL(BLE_PERIODIC_ADV_SYNC_TRANSFER) +/* LE Set Periodic Advertising Receive Enable command */ int -ble_gap_periodic_adv_sync_reporting(uint16_t sync_handle, bool enable) +ble_gap_periodic_adv_sync_reporting(uint16_t sync_handle, + bool enable, + const struct ble_gap_periodic_adv_sync_reporting_params *params) { struct ble_hci_le_periodic_adv_receive_enable_cp cmd; struct ble_hs_periodic_sync *psync; uint16_t opcode; int rc; + if (!ble_hs_is_enabled()) { + return BLE_HS_EDISABLED; + } + ble_hs_lock(); if (ble_gap_sync.op == BLE_GAP_OP_SYNC) { @@ -3828,6 +4530,11 @@ ble_gap_periodic_adv_sync_reporting(uint16_t sync_handle, bool enable) cmd.sync_handle = htole16(sync_handle); cmd.enable = enable ? 0x01 : 0x00; +#if MYNEWT_VAL(BLE_VERSION) >= 53 + if (params && params->filter_duplicates) { + SET_BIT(cmd.enable, 1); + } +#endif rc = ble_hs_hci_cmd_tx(opcode, &cmd, sizeof(cmd), NULL, 0); @@ -3847,6 +4554,10 @@ ble_gap_periodic_adv_sync_transfer(uint16_t sync_handle, uint16_t conn_handle, uint16_t opcode; int rc; + if (!ble_hs_is_enabled()) { + return BLE_HS_EDISABLED; + } + ble_hs_lock(); conn = ble_hs_conn_find(conn_handle); @@ -3891,6 +4602,10 @@ ble_gap_periodic_adv_sync_set_info(uint8_t instance, uint16_t conn_handle, return BLE_HS_EINVAL; } + if (!ble_hs_is_enabled()) { + return BLE_HS_EDISABLED; + } + ble_hs_lock(); if (ble_gap_slave[instance].periodic_op != BLE_GAP_OP_S_PERIODIC_ADV) { /* periodic adv not enabled */ @@ -3931,11 +4646,22 @@ periodic_adv_transfer_enable(uint16_t conn_handle, opcode = BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_PERIODIC_ADV_SYNC_TRANSFER_PARAMS); + memset(&cmd, 0, sizeof(cmd)); cmd.conn_handle = htole16(conn_handle); - cmd.sync_cte_type = 0x00; - cmd.mode = params->reports_disabled ? 0x01 : 0x02; - cmd.skip = htole16(params->skip); - cmd.sync_timeout = htole16(params->sync_timeout); + + if (params != NULL) { + cmd.sync_cte_type = 0x00; + cmd.mode = params->reports_disabled ? 0x01 : 0x02; + +#if MYNEWT_VAL(BLE_VERSION) >= 53 + if (!params->reports_disabled && params->filter_duplicates) { + cmd.mode = 0x03; + } +#endif + + cmd.skip = htole16(params->skip); + cmd.sync_timeout = htole16(params->sync_timeout); + } rc = ble_hs_hci_cmd_tx(opcode, &cmd, sizeof(cmd), &rsp, sizeof(rsp)); if (!rc) { @@ -3945,6 +4671,37 @@ periodic_adv_transfer_enable(uint16_t conn_handle, return rc; } +int +periodic_adv_set_default_sync_params(const struct ble_gap_periodic_sync_params *params) +{ + struct ble_hci_le_set_default_periodic_sync_transfer_params_cp cmd; + uint16_t opcode; + + if (!ble_hs_is_enabled()) { + return BLE_HS_EDISABLED; + } + + opcode = BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_DEFAULT_SYNC_TRANSFER_PARAMS); + + memset(&cmd, 0, sizeof(cmd)); + + if (params != NULL) { + cmd.sync_cte_type = 0x00; + cmd.mode = params->reports_disabled ? 0x01 : 0x02; + +#if MYNEWT_VAL(BLE_VERSION) >= 53 + if (!params->reports_disabled && params->filter_duplicates) { + cmd.mode = 0x03; + } +#endif + + cmd.skip = htole16(params->skip); + cmd.sync_timeout = htole16(params->sync_timeout); + } + + return ble_hs_hci_cmd_tx(opcode, &cmd, sizeof(cmd), NULL, 0); +} + int ble_gap_periodic_adv_sync_receive(uint16_t conn_handle, const struct ble_gap_periodic_sync_params *params, @@ -3953,6 +4710,10 @@ ble_gap_periodic_adv_sync_receive(uint16_t conn_handle, struct ble_hs_conn *conn; int rc; + if (!ble_hs_is_enabled()) { + return BLE_HS_EDISABLED; + } + ble_hs_lock(); conn = ble_hs_conn_find(conn_handle); @@ -4013,6 +4774,10 @@ ble_gap_add_dev_to_periodic_adv_list(const ble_addr_t *peer_addr, return BLE_ERR_INV_HCI_CMD_PARMS; } + if (!ble_hs_is_enabled()) { + return BLE_HS_EDISABLED; + } + cmd.peer_addr_type = peer_addr->type; memcpy(cmd.peer_addr, peer_addr->val, BLE_DEV_ADDR_LEN); cmd.sid = adv_sid; @@ -4033,6 +4798,10 @@ ble_gap_rem_dev_from_periodic_adv_list(const ble_addr_t *peer_addr, uint8_t adv_ return BLE_ERR_INV_HCI_CMD_PARMS; } + if (!ble_hs_is_enabled()) { + return BLE_HS_EDISABLED; + } + cmd.peer_addr_type = peer_addr->type; memcpy(cmd.peer_addr, peer_addr->val, BLE_DEV_ADDR_LEN); cmd.sid = adv_sid; @@ -4240,6 +5009,10 @@ ble_gap_disc_cancel(void) #if NIMBLE_BLE_SCAN int rc; + if (!ble_hs_is_enabled()) { + return BLE_HS_EDISABLED; + } + ble_hs_lock(); rc = ble_gap_disc_cancel_no_lock(); ble_hs_unlock(); @@ -4333,6 +5106,10 @@ ble_gap_ext_disc(uint8_t own_addr_type, uint16_t duration, uint16_t period, STATS_INC(ble_gap_stats, discover); + if (!ble_hs_is_enabled()) { + return BLE_HS_EDISABLED; + } + ble_hs_lock(); rc = ble_gap_disc_ext_validate(own_addr_type); @@ -4382,6 +5159,7 @@ ble_gap_ext_disc(uint8_t own_addr_type, uint16_t duration, uint16_t period, } ble_gap_master.op = BLE_GAP_OP_M_DISC; + ble_gap_master.legacy_discovery = 0; rc = ble_gap_ext_disc_enable_tx(1, filter_duplicates, duration, period); if (rc != 0) { @@ -4458,6 +5236,11 @@ ble_gap_disc(uint8_t own_addr_type, int32_t duration_ms, #if NIMBLE_BLE_SCAN #if MYNEWT_VAL(BLE_EXT_ADV) struct ble_gap_ext_disc_params p = {0}; + int rc; + + if (!ble_hs_is_enabled()) { + return BLE_HS_EDISABLED; + } p.itvl = disc_params->itvl; p.passive = disc_params->passive; @@ -4469,10 +5252,14 @@ ble_gap_disc(uint8_t own_addr_type, int32_t duration_ms, duration_ms = BLE_GAP_DISC_DUR_DFLT; } - return ble_gap_ext_disc(own_addr_type, duration_ms/10, 0, + rc = ble_gap_ext_disc(own_addr_type, duration_ms/10, 0, disc_params->filter_duplicates, disc_params->filter_policy, disc_params->limited, &p, NULL, cb, cb_arg); + + ble_gap_master.legacy_discovery = 1; + + return rc; #else struct ble_gap_disc_params params; uint32_t duration_ticks = 0; @@ -4480,6 +5267,10 @@ ble_gap_disc(uint8_t own_addr_type, int32_t duration_ms, STATS_INC(ble_gap_stats, discover); + if (!ble_hs_is_enabled()) { + return BLE_HS_EDISABLED; + } + ble_hs_lock(); /* Make a copy of the parameter strcuture and fill unspecified values with @@ -4606,6 +5397,46 @@ ble_gap_conn_create_tx(uint8_t own_addr_type, const ble_addr_t *peer_addr, } #endif +#if MYNEWT_VAL(BLE_CONN_SUBRATING) +int +ble_gap_set_default_subrate(uint16_t subrate_min, uint16_t subrate_max, uint16_t max_latency, + uint16_t cont_num, uint16_t supervision_tmo) +{ + struct ble_hci_le_set_default_subrate_cp cmd; + uint16_t opcode; + + cmd.subrate_min = htole16(subrate_min); + cmd.subrate_max = htole16(subrate_max); + cmd.max_latency = htole16(max_latency); + cmd.cont_num = htole16(cont_num); + cmd.supervision_tmo = htole16(supervision_tmo); + + opcode = BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_DEFAULT_SUBRATE); + + return ble_hs_hci_cmd_tx(opcode, &cmd, sizeof(cmd), NULL, 0); +} + +int +ble_gap_subrate_req(uint16_t conn_handle, uint16_t subrate_min, uint16_t subrate_max, + uint16_t max_latency, uint16_t cont_num, + uint16_t supervision_tmo) +{ + struct ble_hci_le_subrate_req_cp cmd; + uint16_t opcode; + + cmd.conn_handle = htole16(conn_handle); + cmd.subrate_min = htole16(subrate_min); + cmd.subrate_max = htole16(subrate_max); + cmd.max_latency = htole16(max_latency); + cmd.cont_num = htole16(cont_num); + cmd.supervision_tmo = htole16(supervision_tmo); + + opcode = BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SUBRATE_REQ); + + return ble_hs_hci_cmd_tx(opcode, &cmd, sizeof(cmd), NULL, 0); +} +#endif + #if MYNEWT_VAL(BLE_EXT_ADV) #if MYNEWT_VAL(BLE_ROLE_CENTRAL) static int @@ -4634,8 +5465,7 @@ ble_gap_check_conn_params(uint8_t phy, const struct ble_gap_conn_params *params) } /* Check connection latency */ - if ((params->latency < BLE_HCI_CONN_LATENCY_MIN) || - (params->latency > BLE_HCI_CONN_LATENCY_MAX)) { + if (params->latency > BLE_HCI_CONN_LATENCY_MAX) { return BLE_ERR_INV_HCI_CMD_PARMS; } @@ -4843,7 +5673,8 @@ ble_gap_ext_connect(uint8_t own_addr_type, const ble_addr_t *peer_addr, } if (!ble_hs_is_enabled()) { - return BLE_HS_EDISABLED; + rc = BLE_HS_EDISABLED; + goto done; } if (ble_gap_is_preempted()) { @@ -5119,6 +5950,10 @@ ble_gap_terminate(uint16_t conn_handle, uint8_t hci_reason) STATS_INC(ble_gap_stats, terminate); + if (!ble_hs_is_enabled()) { + return BLE_HS_EDISABLED; + } + ble_hs_lock(); conn = ble_hs_conn_find(conn_handle); @@ -5198,6 +6033,10 @@ ble_gap_conn_cancel(void) #if MYNEWT_VAL(BLE_ROLE_CENTRAL) int rc; + if (!ble_hs_is_enabled()) { + return BLE_HS_EDISABLED; + } + ble_hs_lock(); rc = ble_gap_conn_cancel_no_lock(); ble_hs_unlock(); @@ -5456,6 +6295,10 @@ ble_gap_update_params(uint16_t conn_handle, return BLE_HS_EINVAL; } + if (!ble_hs_is_enabled()) { + return BLE_HS_EDISABLED; + } + STATS_INC(ble_gap_stats, update); memset(&l2cap_params, 0, sizeof l2cap_params); entry = NULL; @@ -5530,14 +6373,32 @@ ble_gap_update_params(uint16_t conn_handle, #endif } -int ble_gap_set_data_len(uint16_t conn_handle, uint16_t tx_octets, uint16_t tx_time) +int +ble_gap_set_data_len(uint16_t conn_handle, uint16_t tx_octets, + uint16_t tx_time) { return ble_hs_hci_util_set_data_len(conn_handle, tx_octets, tx_time); } +int +ble_gap_read_sugg_def_data_len(uint16_t *out_sugg_max_tx_octets, + uint16_t *out_sugg_max_tx_time) +{ + return ble_hs_hci_util_read_sugg_def_data_len(out_sugg_max_tx_octets, + out_sugg_max_tx_time); +} + +int +ble_gap_write_sugg_def_data_len(uint16_t sugg_max_tx_octets, + uint16_t sugg_max_tx_time) +{ + return ble_hs_hci_util_write_sugg_def_data_len(sugg_max_tx_octets, + sugg_max_tx_time); +} + /***************************************************************************** - * $security * - *****************************************************************************/ +* $security * +*****************************************************************************/ int ble_gap_security_initiate(uint16_t conn_handle) { @@ -5551,6 +6412,10 @@ ble_gap_security_initiate(uint16_t conn_handle) STATS_INC(ble_gap_stats, security_initiate); + if (!ble_hs_is_enabled()) { + return BLE_HS_EDISABLED; + } + ble_hs_lock(); conn = ble_hs_conn_find(conn_handle); if (conn != NULL) { @@ -5612,6 +6477,10 @@ ble_gap_pair_initiate(uint16_t conn_handle) { int rc; + if (!ble_hs_is_enabled()) { + return BLE_HS_EDISABLED; + } + rc = ble_sm_pair_initiate(conn_handle); return rc; @@ -5629,6 +6498,10 @@ ble_gap_encryption_initiate(uint16_t conn_handle, ble_hs_conn_flags_t conn_flags; int rc; + if (!ble_hs_is_enabled()) { + return BLE_HS_EDISABLED; + } + rc = ble_hs_atomic_conn_flags(conn_handle, &conn_flags); if (rc != 0) { return rc; @@ -5650,8 +6523,13 @@ int ble_gap_unpair(const ble_addr_t *peer_addr) { #if NIMBLE_BLE_SM + int rc; struct ble_hs_conn *conn; + if (!ble_hs_is_enabled()) { + return BLE_HS_EDISABLED; + } + if (ble_addr_cmp(peer_addr, BLE_ADDR_ANY) == 0) { return BLE_HS_EINVAL; } @@ -5665,9 +6543,17 @@ ble_gap_unpair(const ble_addr_t *peer_addr) ble_hs_unlock(); - ble_hs_pvcy_remove_entry(peer_addr->type, + rc = ble_hs_pvcy_remove_entry(peer_addr->type, peer_addr->val); + /* We allow BLE_ERR_UNK_CONN_ID as the IRK of the peer might not be + * present on the resolving list, but we still should be able to + * remove that entry. + */ + if (rc != 0 && rc != (BLE_HS_ERR_HCI_BASE + BLE_ERR_UNK_CONN_ID)) { + return rc; + } + return ble_store_util_delete_peer(peer_addr); #else return BLE_HS_ENOTSUP; @@ -5682,6 +6568,10 @@ ble_gap_unpair_oldest_peer(void) int num_peers; int rc; + if (!ble_hs_is_enabled()) { + return BLE_HS_EDISABLED; + } + rc = ble_store_util_bonded_peers( &oldest_peer_id_addr, &num_peers, 1); if (rc != 0) { @@ -5707,10 +6597,15 @@ int ble_gap_unpair_oldest_except(const ble_addr_t *peer_addr) { #if NIMBLE_BLE_SM +#if MYNEWT_VAL(BLE_STORE_MAX_BONDS) ble_addr_t peer_id_addrs[MYNEWT_VAL(BLE_STORE_MAX_BONDS)]; int num_peers; int rc, i; + if (!ble_hs_is_enabled()) { + return BLE_HS_EDISABLED; + } + rc = ble_store_util_bonded_peers( &peer_id_addrs[0], &num_peers, MYNEWT_VAL(BLE_STORE_MAX_BONDS)); if (rc != 0) { @@ -5735,6 +6630,9 @@ ble_gap_unpair_oldest_except(const ble_addr_t *peer_addr) #else return BLE_HS_ENOTSUP; #endif +#else + return BLE_HS_ENOTSUP; +#endif } void @@ -5774,7 +6672,7 @@ ble_gap_enc_event(uint16_t conn_handle, int status, return; } - /* If encryption succeded and encryption has been restored for bonded device, + /* If encryption succeeded and encryption has been restored for bonded device, * notify gatt server so it has chance to send notification/indication if needed. */ if (security_restored) { @@ -5793,7 +6691,7 @@ ble_gap_enc_event(uint16_t conn_handle, int status, } void -ble_gap_identity_event(uint16_t conn_handle) +ble_gap_identity_event(uint16_t conn_handle, const ble_addr_t *peer_id_addr) { #if NIMBLE_BLE_SM && NIMBLE_BLE_CONNECT struct ble_gap_event event; @@ -5803,6 +6701,7 @@ ble_gap_identity_event(uint16_t conn_handle) memset(&event, 0, sizeof event); event.type = BLE_GAP_EVENT_IDENTITY_RESOLVED; event.identity_resolved.conn_handle = conn_handle; + event.identity_resolved.peer_id_addr = *peer_id_addr; ble_gap_call_conn_event_cb(&event, conn_handle); #endif } @@ -5824,6 +6723,20 @@ ble_gap_repeat_pairing_event(const struct ble_gap_repeat_pairing *rp) #endif } +void +ble_gap_pairing_complete_event(uint16_t conn_handle, int status) +{ +#if NIMBLE_BLE_SM && NIMBLE_BLE_CONNECT + struct ble_gap_event event; + + memset(&event, 0, sizeof event); + event.type = BLE_GAP_EVENT_PAIRING_COMPLETE; + event.pairing_complete.conn_handle = conn_handle; + event.pairing_complete.status = status; + ble_gap_call_conn_event_cb(&event, conn_handle); +#endif +} + /***************************************************************************** * $rssi * *****************************************************************************/ @@ -5833,6 +6746,10 @@ ble_gap_conn_rssi(uint16_t conn_handle, int8_t *out_rssi) { int rc; + if (!ble_hs_is_enabled()) { + return BLE_HS_EDISABLED; + } + rc = ble_hs_hci_util_read_rssi(conn_handle, out_rssi); return rc; } @@ -5935,6 +6852,24 @@ ble_gap_mtu_event(uint16_t conn_handle, uint16_t cid, uint16_t mtu) #endif } +#if MYNEWT_VAL(BLE_HS_GAP_UNHANDLED_HCI_EVENT) +void +ble_gap_unhandled_hci_event(bool is_le_meta, bool is_vs, const void *buf, + uint8_t len) +{ + struct ble_gap_event event; + + memset(&event, 0, sizeof event); + event.type = BLE_GAP_EVENT_UNHANDLED_HCI_EVENT; + event.unhandled_hci.is_le_meta = is_le_meta; + event.unhandled_hci.is_vs = is_vs; + event.unhandled_hci.ev = buf; + event.unhandled_hci.length = len; + + ble_gap_event_listener_call(&event); +} +#endif + /***************************************************************************** * $preempt * *****************************************************************************/ @@ -6024,10 +6959,13 @@ ble_gap_preempt_done(void) void *arg; } slaves[BLE_ADV_INSTANCES]; + master_cb = NULL; + master_arg = NULL; + disc_preempted = 0; /* Protects slaves from accessing by multiple threads */ - ble_npl_mutex_pend(&preempt_done_mutex, 0xFFFFFFFF); + ble_npl_mutex_pend(&preempt_done_mutex, BLE_NPL_TIME_FOREVER); memset(slaves, 0, sizeof(slaves)); ble_hs_lock(); @@ -6156,7 +7094,12 @@ ble_gap_init(void) memset(&ble_gap_sync, 0, sizeof(ble_gap_sync)); #endif - ble_npl_mutex_init(&preempt_done_mutex); + rc = ble_npl_mutex_init(&preempt_done_mutex); + + if (rc) { + BLE_HS_LOG(ERROR, "mutex init failed with reason %d \n", rc); + return rc; + } SLIST_INIT(&ble_gap_update_entries); SLIST_INIT(&ble_gap_event_listener_list); @@ -6189,3 +7132,122 @@ ble_gap_init(void) err: return rc; } + +int +ble_gap_enh_read_transmit_power_level(uint16_t conn_handle, uint8_t phy, uint8_t *out_status, uint8_t *out_phy , + uint8_t *out_curr_tx_power_level, uint8_t *out_max_tx_power_level) + +{ +#if MYNEWT_VAL(BLE_POWER_CONTROL) + struct ble_hci_le_enh_read_transmit_power_level_cp cmd; + struct ble_hci_le_enh_read_transmit_power_level_rp rsp; + uint16_t opcode; + int rc; + + opcode = BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_ENH_READ_TRANSMIT_POWER_LEVEL); + + cmd.conn_handle = htole16(conn_handle); + cmd.phy = phy; + + rc = ble_hs_hci_cmd_tx(opcode, &cmd, sizeof(cmd), &rsp, sizeof(rsp)); + + if (rc!=0) { + return rc; + } + + *out_status = rc; + *out_phy = rsp.phy; + *out_curr_tx_power_level = rsp.curr_tx_power_level; + *out_max_tx_power_level = rsp.max_tx_power_level; + + return 0; +#else + return BLE_HS_ENOTSUP; +#endif +} + +int +ble_gap_read_remote_transmit_power_level(uint16_t conn_handle, + uint8_t phy) +{ +#if MYNEWT_VAL(BLE_POWER_CONTROL) + struct ble_hci_le_read_remote_transmit_power_level_cp cmd; + uint16_t opcode; + + opcode = BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_READ_REMOTE_TRANSMIT_POWER_LEVEL); + + cmd.conn_handle = htole16(conn_handle); + cmd.phy = phy; + + return ble_hs_hci_cmd_tx(opcode, &cmd, sizeof(cmd), NULL, 0); +#else + return BLE_HS_ENOTSUP; +#endif +} + +int +ble_gap_set_path_loss_reporting_param(uint16_t conn_handle, + uint8_t high_threshold, + uint8_t high_hysteresis, + uint8_t low_threshold, + uint8_t low_hysteresis, + uint16_t min_time_spent) +{ +#if MYNEWT_VAL(BLE_POWER_CONTROL) + struct ble_hci_le_set_path_loss_report_param_cp cmd; + uint16_t opcode; + + opcode = BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_PATH_LOSS_REPORT_PARAM); + + cmd.conn_handle = htole16(conn_handle); + cmd.high_threshold = high_threshold; + cmd.high_hysteresis = high_hysteresis; + cmd.low_threshold = low_threshold; + cmd.low_hysteresis = low_hysteresis; + cmd.min_time_spent = min_time_spent; + + return ble_hs_hci_cmd_tx(opcode, &cmd, sizeof(cmd), NULL, 0); +#else + return BLE_HS_ENOTSUP; +#endif +} + +int +ble_gap_set_path_loss_reporting_enable(uint16_t conn_handle, + uint8_t enable) +{ +#if MYNEWT_VAL(BLE_POWER_CONTROL) + struct ble_hci_le_set_path_loss_report_enable_cp cmd; + uint16_t opcode; + + opcode = BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_PATH_LOSS_REPORT_ENABLE); + + cmd.conn_handle = htole16(conn_handle); + cmd.enable = enable; + + return ble_hs_hci_cmd_tx(opcode, &cmd, sizeof(cmd), NULL, 0); +#else + return BLE_HS_ENOTSUP; +#endif +} + +int +ble_gap_set_transmit_power_reporting_enable(uint16_t conn_handle, + uint8_t local_enable, + uint8_t remote_enable) +{ +#if MYNEWT_VAL(BLE_POWER_CONTROL) + struct ble_hci_le_set_transmit_power_report_enable_cp cmd; + uint16_t opcode; + + opcode = BLE_HCI_OP(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_TRANS_PWR_REPORT_ENABLE); + + cmd.conn_handle = htole16(conn_handle); + cmd.local_enable = local_enable; + cmd.remote_enable = remote_enable; + + return ble_hs_hci_cmd_tx(opcode, &cmd, sizeof(cmd), NULL, 0); +#else + return BLE_HS_ENOTSUP; +#endif +} diff --git a/nimble/host/src/ble_gap_priv.h b/nimble/host/src/ble_gap_priv.h index 499823bc5a..2f875ddf0e 100644 --- a/nimble/host/src/ble_gap_priv.h +++ b/nimble/host/src/ble_gap_priv.h @@ -88,10 +88,20 @@ void ble_gap_rx_periodic_adv_rpt(const struct ble_hci_ev_le_subev_periodic_adv_r void ble_gap_rx_periodic_adv_sync_lost(const struct ble_hci_ev_le_subev_periodic_adv_sync_lost *ev); void ble_gap_rx_periodic_adv_sync_transfer(const struct ble_hci_ev_le_subev_periodic_adv_sync_transfer *ev); #endif +#if MYNEWT_VAL(BLE_PERIODIC_ADV_SYNC_BIGINFO_REPORTS) +void ble_gap_rx_biginfo_adv_rpt(const struct ble_hci_ev_le_subev_biginfo_adv_report *ev); +#endif void ble_gap_rx_scan_req_rcvd(const struct ble_hci_ev_le_subev_scan_req_rcvd *ev); #endif void ble_gap_rx_adv_report(struct ble_gap_disc_desc *desc); void ble_gap_rx_rd_rem_sup_feat_complete(const struct ble_hci_ev_le_subev_rd_rem_used_feat *ev); +#if MYNEWT_VAL(BLE_CONN_SUBRATING) +void ble_gap_rx_subrate_change(const struct ble_hci_ev_le_subev_subrate_change *ev); +#endif +#if MYNEWT_VAL(BLE_POWER_CONTROL) +void ble_gap_rx_transmit_power_report(const struct ble_hci_ev_le_subev_transmit_power_report *ev); +void ble_gap_rx_le_pathloss_threshold(const struct ble_hci_ev_le_subev_path_loss_threshold *ev); +#endif struct ble_gap_conn_complete { @@ -128,8 +138,11 @@ void ble_gap_subscribe_event(uint16_t conn_handle, uint16_t attr_handle, uint8_t prev_notify, uint8_t cur_notify, uint8_t prev_indicate, uint8_t cur_indicate); void ble_gap_mtu_event(uint16_t conn_handle, uint16_t cid, uint16_t mtu); -void ble_gap_identity_event(uint16_t conn_handle); +void ble_gap_identity_event(uint16_t conn_handle, const ble_addr_t *peer_id_addr); int ble_gap_repeat_pairing_event(const struct ble_gap_repeat_pairing *rp); +void ble_gap_pairing_complete_event(uint16_t conn_handle, int status); +void ble_gap_unhandled_hci_event(bool is_le_meta, bool is_vs, const void *buf, + uint8_t len); int ble_gap_master_in_progress(void); void ble_gap_preempt(void); @@ -137,7 +150,6 @@ void ble_gap_preempt_done(void); int ble_gap_terminate_with_conn(struct ble_hs_conn *conn, uint8_t hci_reason); void ble_gap_reset_state(int reason); -void ble_gap_conn_broken(uint16_t conn_handle, int reason); int32_t ble_gap_timer(void); int ble_gap_init(void); diff --git a/nimble/host/src/ble_gatt_priv.h b/nimble/host/src/ble_gatt_priv.h index 4a59635b82..50e0a75b91 100644 --- a/nimble/host/src/ble_gatt_priv.h +++ b/nimble/host/src/ble_gatt_priv.h @@ -86,8 +86,14 @@ STATS_SECT_START(ble_gatts_stats) STATS_SECT_END extern STATS_SECT_DECL(ble_gatts_stats) ble_gatts_stats; -#define BLE_GATT_CHR_DECL_SZ_16 5 -#define BLE_GATT_CHR_DECL_SZ_128 19 +#define BLE_GATT_CHR_DECL_SZ_16 5 +#define BLE_GATT_CHR_DECL_SZ_128 19 +#define BLE_GATT_CHR_CLI_SUP_FEAT_SZ 1 +/** + * For now only 3 bits in first octet are defined + * + */ +#define BLE_GATT_CHR_CLI_SUP_FEAT_MASK 7 typedef uint8_t ble_gatts_conn_flags; @@ -96,6 +102,14 @@ struct ble_gatts_conn { int num_clt_cfgs; uint16_t indicate_val_handle; + + /** + * For now only 3 bits in one octet are defined, but specification expects + * this service to be variable length with no upper bound. Let's make this + * future proof if more octets might be used. + * (Vol. 3, Part G, 7.2) + */ + uint8_t peer_cl_sup_feat[BLE_GATT_CHR_CLI_SUP_FEAT_SZ]; }; /*** @client. */ @@ -103,32 +117,32 @@ struct ble_gatts_conn { int ble_gattc_locked_by_cur_task(void); void ble_gatts_indicate_fail_notconn(uint16_t conn_handle); -void ble_gattc_rx_err(uint16_t conn_handle, uint16_t handle, uint16_t status); -void ble_gattc_rx_mtu(uint16_t conn_handle, int status, uint16_t chan_mtu); -void ble_gattc_rx_read_type_adata(uint16_t conn_handle, +void ble_gattc_rx_err(uint16_t conn_handle, uint16_t cid, uint16_t handle, uint16_t status); +void ble_gattc_rx_mtu(uint16_t conn_handle, uint16_t cid, int status, uint16_t chan_mtu); +void ble_gattc_rx_read_type_adata(uint16_t conn_handle, uint16_t cid, struct ble_att_read_type_adata *adata); -void ble_gattc_rx_read_type_complete(uint16_t conn_handle, int status); -void ble_gattc_rx_read_rsp(uint16_t conn_handle, int status, +void ble_gattc_rx_read_type_complete(uint16_t conn_handle, uint16_t cid, int status); +void ble_gattc_rx_read_rsp(uint16_t conn_handle, uint16_t cid, int status, struct os_mbuf **rxom); -void ble_gattc_rx_read_blob_rsp(uint16_t conn_handle, int status, - struct os_mbuf **rxom); -void ble_gattc_rx_read_mult_rsp(uint16_t conn_handle, int status, +void ble_gattc_rx_read_blob_rsp(uint16_t conn_handle, uint16_t cid, int status, struct os_mbuf **rxom); -void ble_gattc_rx_read_group_type_adata( - uint16_t conn_handle, struct ble_att_read_group_type_adata *adata); -void ble_gattc_rx_read_group_type_complete(uint16_t conn_handle, int rc); -void ble_gattc_rx_find_type_value_hinfo( - uint16_t conn_handle, struct ble_att_find_type_value_hinfo *hinfo); -void ble_gattc_rx_find_type_value_complete(uint16_t conn_handle, int status); -void ble_gattc_rx_write_rsp(uint16_t conn_handle); -void ble_gattc_rx_prep_write_rsp(uint16_t conn_handle, int status, +void ble_gattc_rx_read_mult_rsp(uint16_t conn_handle, uint16_t cid, int status, + struct os_mbuf **rxom, bool variable); +void ble_gattc_rx_read_group_type_adata(uint16_t conn_handle, uint16_t cid, + struct ble_att_read_group_type_adata *adata); +void ble_gattc_rx_read_group_type_complete(uint16_t conn_handle, uint16_t cid, int rc); +void ble_gattc_rx_find_type_value_hinfo(uint16_t conn_handle, uint16_t cid, + struct ble_att_find_type_value_hinfo *hinfo); +void ble_gattc_rx_find_type_value_complete(uint16_t conn_handle, uint16_t cid, int status); +void ble_gattc_rx_write_rsp(uint16_t conn_handle, uint16_t cid); +void ble_gattc_rx_prep_write_rsp(uint16_t conn_handle, uint16_t cid, int status, uint16_t handle, uint16_t offset, struct os_mbuf **rxom); -void ble_gattc_rx_exec_write_rsp(uint16_t conn_handle, int status); -void ble_gattc_rx_indicate_rsp(uint16_t conn_handle); -void ble_gattc_rx_find_info_idata(uint16_t conn_handle, +void ble_gattc_rx_exec_write_rsp(uint16_t conn_handle, uint16_t cid, int status); +void ble_gatts_rx_indicate_rsp(uint16_t conn_handle, uint16_t cid); +void ble_gattc_rx_find_info_idata(uint16_t conn_handle, uint16_t cid, struct ble_att_find_info_idata *idata); -void ble_gattc_rx_find_info_complete(uint16_t conn_handle, int status); +void ble_gattc_rx_find_info_complete(uint16_t conn_handle, uint16_t cid, int status); void ble_gattc_connection_txable(uint16_t conn_handle); void ble_gattc_connection_broken(uint16_t conn_handle); int32_t ble_gattc_timer(void); @@ -187,6 +201,8 @@ int ble_gatts_clt_cfg_access(uint16_t conn_handle, uint16_t attr_handle, uint8_t op, uint16_t offset, struct os_mbuf **om, void *arg); +int ble_gatts_peer_cl_sup_feat_update(uint16_t conn_handle, + struct os_mbuf *om); /*** @misc. */ int ble_gatts_conn_can_alloc(void); int ble_gatts_conn_init(struct ble_gatts_conn *gatts_conn); diff --git a/nimble/host/src/ble_gattc.c b/nimble/host/src/ble_gattc.c index 74a2837ad7..0ff4ec28e6 100644 --- a/nimble/host/src/ble_gattc.c +++ b/nimble/host/src/ble_gattc.c @@ -56,11 +56,21 @@ #include #include "os/os_mempool.h" #include "nimble/ble.h" +#include "host/ble_gatt.h" #include "host/ble_uuid.h" #include "host/ble_gap.h" #include "ble_hs_priv.h" #if NIMBLE_BLE_CONNECT + +#ifndef min +#define min(a, b) ((a) < (b) ? (a) : (b)) +#endif + +#ifndef max +#define max(a, b) ((a) > (b) ? (a) : (b)) +#endif + /***************************************************************************** * $definitions / declarations * *****************************************************************************/ @@ -83,11 +93,12 @@ #define BLE_GATT_OP_READ_UUID 8 #define BLE_GATT_OP_READ_LONG 9 #define BLE_GATT_OP_READ_MULT 10 -#define BLE_GATT_OP_WRITE 11 -#define BLE_GATT_OP_WRITE_LONG 12 -#define BLE_GATT_OP_WRITE_RELIABLE 13 -#define BLE_GATT_OP_INDICATE 14 -#define BLE_GATT_OP_CNT 15 +#define BLE_GATT_OP_READ_MULT_VAR 11 +#define BLE_GATT_OP_WRITE 12 +#define BLE_GATT_OP_WRITE_LONG 13 +#define BLE_GATT_OP_WRITE_RELIABLE 14 +#define BLE_GATT_OP_INDICATE 15 +#define BLE_GATT_OP_CNT 16 /** Procedure stalled due to resource exhaustion. */ #define BLE_GATTC_PROC_F_STALLED 0x01 @@ -98,6 +109,7 @@ struct ble_gattc_proc { uint32_t exp_os_ticks; uint16_t conn_handle; + uint16_t cid; uint8_t op; uint8_t flags; @@ -178,7 +190,9 @@ struct ble_gattc_proc { struct { uint16_t handles[MYNEWT_VAL(BLE_GATT_READ_MAX_ATTRS)]; uint8_t num_handles; + bool variable; ble_gatt_attr_fn *cb; + ble_gatt_attr_mult_fn *cb_mult; void *cb_arg; } read_mult; @@ -229,10 +243,11 @@ static ble_gattc_err_fn ble_gattc_read_err; static ble_gattc_err_fn ble_gattc_read_uuid_err; static ble_gattc_err_fn ble_gattc_read_long_err; static ble_gattc_err_fn ble_gattc_read_mult_err; +static ble_gattc_err_fn ble_gattc_read_mult_var_err; static ble_gattc_err_fn ble_gattc_write_err; static ble_gattc_err_fn ble_gattc_write_long_err; static ble_gattc_err_fn ble_gattc_write_reliable_err; -static ble_gattc_err_fn ble_gattc_indicate_err; +static ble_gattc_err_fn ble_gatts_indicate_err; static ble_gattc_err_fn * const ble_gattc_err_dispatch[BLE_GATT_OP_CNT] = { [BLE_GATT_OP_MTU] = ble_gattc_mtu_err, @@ -246,10 +261,11 @@ static ble_gattc_err_fn * const ble_gattc_err_dispatch[BLE_GATT_OP_CNT] = { [BLE_GATT_OP_READ_UUID] = ble_gattc_read_uuid_err, [BLE_GATT_OP_READ_LONG] = ble_gattc_read_long_err, [BLE_GATT_OP_READ_MULT] = ble_gattc_read_mult_err, + [BLE_GATT_OP_READ_MULT_VAR] = ble_gattc_read_mult_var_err, [BLE_GATT_OP_WRITE] = ble_gattc_write_err, [BLE_GATT_OP_WRITE_LONG] = ble_gattc_write_long_err, [BLE_GATT_OP_WRITE_RELIABLE] = ble_gattc_write_reliable_err, - [BLE_GATT_OP_INDICATE] = ble_gattc_indicate_err, + [BLE_GATT_OP_INDICATE] = ble_gatts_indicate_err, }; /** @@ -307,7 +323,7 @@ static ble_gattc_tmo_fn ble_gattc_read_mult_tmo; static ble_gattc_tmo_fn ble_gattc_write_tmo; static ble_gattc_tmo_fn ble_gattc_write_long_tmo; static ble_gattc_tmo_fn ble_gattc_write_reliable_tmo; -static ble_gattc_tmo_fn ble_gattc_indicate_tmo; +static ble_gattc_tmo_fn ble_gatts_indicate_tmo; static ble_gattc_tmo_fn * const ble_gattc_tmo_dispatch[BLE_GATT_OP_CNT] = { @@ -325,7 +341,7 @@ ble_gattc_tmo_dispatch[BLE_GATT_OP_CNT] = { [BLE_GATT_OP_WRITE] = ble_gattc_write_tmo, [BLE_GATT_OP_WRITE_LONG] = ble_gattc_write_long_tmo, [BLE_GATT_OP_WRITE_RELIABLE] = ble_gattc_write_reliable_tmo, - [BLE_GATT_OP_INDICATE] = ble_gattc_indicate_tmo, + [BLE_GATT_OP_INDICATE] = ble_gatts_indicate_tmo, }; /** @@ -573,7 +589,7 @@ ble_gattc_log_read_long(struct ble_gattc_proc *proc) } static void -ble_gattc_log_read_mult(const uint16_t *handles, uint8_t num_handles) +ble_gattc_log_read_mult(const uint16_t *handles, uint8_t num_handles, bool variable) { int i; @@ -684,6 +700,14 @@ ble_gattc_proc_alloc(void) return proc; } +static void +ble_gattc_proc_prepare(struct ble_gattc_proc *proc, uint16_t conn_handle, uint8_t op) +{ + proc->conn_handle = conn_handle; + proc->op = op; + proc->cid = ble_eatt_get_available_chan_cid(conn_handle, op); +} + /** * Frees the specified proc entry. No-op if passed a null pointer. */ @@ -715,6 +739,12 @@ ble_gattc_proc_free(struct ble_gattc_proc *proc) break; } +#if MYNEWT_VAL(BLE_EATT_CHAN_NUM) > 0 + if (proc->cid != BLE_L2CAP_CID_ATT) { + ble_eatt_release_chan(proc->conn_handle, proc->op); + } +#endif + #if MYNEWT_VAL(BLE_HS_DEBUG) memset(proc, 0xff, sizeof *proc); #endif @@ -835,6 +865,7 @@ typedef int ble_gattc_match_fn(struct ble_gattc_proc *proc, void *arg); struct ble_gattc_criteria_conn_op { uint16_t conn_handle; + uint16_t psm; uint8_t op; }; @@ -866,6 +897,28 @@ ble_gattc_proc_matches_conn_op(struct ble_gattc_proc *proc, void *arg) return 1; } +static int +ble_gattc_proc_matches_conn_cid_op(struct ble_gattc_proc *proc, void *arg) +{ + const struct ble_gattc_criteria_conn_op *criteria; + + criteria = arg; + + if (criteria->conn_handle != proc->conn_handle) { + return 0; + } + + if (criteria->psm != proc->cid) { + return 0; + } + + if (criteria->op != proc->op && criteria->op != BLE_GATT_OP_NONE) { + return 0; + } + + return 1; +} + struct ble_gattc_criteria_exp { ble_npl_time_t now; int32_t next_exp_in; @@ -895,6 +948,7 @@ ble_gattc_proc_matches_expired(struct ble_gattc_proc *proc, void *arg) struct ble_gattc_criteria_conn_rx_entry { uint16_t conn_handle; + uint16_t cid; const void *rx_entries; int num_rx_entries; const void *matching_rx_entry; @@ -907,9 +961,12 @@ ble_gattc_proc_matches_conn_rx_entry(struct ble_gattc_proc *proc, void *arg) criteria = arg; - if (criteria->conn_handle != BLE_HS_CONN_HANDLE_NONE && - criteria->conn_handle != proc->conn_handle) { + if ((criteria->conn_handle != BLE_HS_CONN_HANDLE_NONE) && + (criteria->conn_handle != proc->conn_handle)) { + return 0; + } + if (criteria->cid != proc->cid) { return 0; } @@ -987,12 +1044,26 @@ ble_gattc_extract_by_conn_op(uint16_t conn_handle, uint8_t op, int max_procs, ble_gattc_extract(ble_gattc_proc_matches_conn_op, &criteria, max_procs, dst_list); } +static void +ble_gattc_extract_by_conn_cid_op(uint16_t conn_handle, uint16_t psm, uint8_t op, + int max_procs, + struct ble_gattc_proc_list *dst_list) +{ + struct ble_gattc_criteria_conn_op criteria; + + criteria.conn_handle = conn_handle; + criteria.op = op; + criteria.psm = psm; + + ble_gattc_extract(ble_gattc_proc_matches_conn_cid_op, &criteria, max_procs, dst_list); +} + static struct ble_gattc_proc * -ble_gattc_extract_first_by_conn_op(uint16_t conn_handle, uint8_t op) +ble_gattc_extract_first_by_conn_cid_op(uint16_t conn_handle, uint16_t cid, uint8_t op) { struct ble_gattc_proc_list dst_list; - ble_gattc_extract_by_conn_op(conn_handle, op, 1, &dst_list); + ble_gattc_extract_by_conn_cid_op(conn_handle, cid, op, 1, &dst_list); return STAILQ_FIRST(&dst_list); } @@ -1027,7 +1098,7 @@ ble_gattc_extract_expired(struct ble_gattc_proc_list *dst_list) } static struct ble_gattc_proc * -ble_gattc_extract_with_rx_entry(uint16_t conn_handle, +ble_gattc_extract_with_rx_entry(uint16_t conn_handle, uint16_t cid, const void *rx_entries, int num_rx_entries, const void **out_rx_entry) { @@ -1035,6 +1106,7 @@ ble_gattc_extract_with_rx_entry(uint16_t conn_handle, struct ble_gattc_proc *proc; criteria.conn_handle = conn_handle; + criteria.cid = cid; criteria.rx_entries = rx_entries; criteria.num_rx_entries = num_rx_entries; criteria.matching_rx_entry = NULL; @@ -1052,6 +1124,7 @@ ble_gattc_extract_with_rx_entry(uint16_t conn_handle, * list and returned. * * @param conn_handle The connection handle to match against. + * @param cid Source CID of L2CAP channel used * @param rx_entries The array of rx entries corresponding to the * op code of the incoming response. * @param out_rx_entry On success, the address of the matching rx @@ -1060,9 +1133,9 @@ ble_gattc_extract_with_rx_entry(uint16_t conn_handle, * @return The matching proc entry on success; * null on failure. */ -#define BLE_GATTC_RX_EXTRACT_RX_ENTRY(conn_handle, rx_entries, out_rx_entry) \ +#define BLE_GATTC_RX_EXTRACT_RX_ENTRY(conn_handle, cid, rx_entries, out_rx_entry) \ ble_gattc_extract_with_rx_entry( \ - (conn_handle), (rx_entries), \ + (conn_handle), (cid), (rx_entries), \ sizeof (rx_entries) / sizeof (rx_entries)[0], \ (const void **)(out_rx_entry)) @@ -1280,7 +1353,7 @@ ble_gattc_mtu_tx(struct ble_gattc_proc *proc) int rc; ble_hs_lock(); - rc = ble_att_conn_chan_find(proc->conn_handle, &conn, &chan); + rc = ble_att_conn_chan_find(proc->conn_handle, proc->cid, &conn, &chan); if (rc == 0) { mtu = chan->my_mtu; } @@ -1309,6 +1382,7 @@ ble_gattc_exchange_mtu(uint16_t conn_handle, ble_gatt_mtu_fn *cb, void *cb_arg) proc->op = BLE_GATT_OP_MTU; proc->conn_handle = conn_handle; + proc->cid = BLE_L2CAP_CID_ATT; proc->mtu.cb = cb; proc->mtu.cb_arg = cb_arg; @@ -1385,7 +1459,7 @@ ble_gattc_disc_all_svcs_tx(struct ble_gattc_proc *proc) ble_gattc_dbg_assert_proc_not_inserted(proc); - rc = ble_att_clt_tx_read_group_type(proc->conn_handle, + rc = ble_att_clt_tx_read_group_type(proc->conn_handle, proc->cid, proc->disc_all_svcs.prev_handle + 1, 0xffff, &uuid.u); if (rc != 0) { @@ -1437,7 +1511,7 @@ static int ble_gattc_disc_all_svcs_rx_adata(struct ble_gattc_proc *proc, struct ble_att_read_group_type_adata *adata) { - struct ble_gatt_svc service; + struct ble_gatt_svc service = {0}; int cbrc; int rc; @@ -1531,8 +1605,8 @@ ble_gattc_disc_all_svcs(uint16_t conn_handle, ble_gatt_disc_svc_fn *cb, goto done; } - proc->op = BLE_GATT_OP_DISC_ALL_SVCS; - proc->conn_handle = conn_handle; + ble_gattc_proc_prepare(proc, conn_handle, BLE_GATT_OP_DISC_ALL_SVCS); + proc->disc_all_svcs.prev_handle = 0x0000; proc->disc_all_svcs.cb = cb; proc->disc_all_svcs.cb_arg = cb_arg; @@ -1611,7 +1685,7 @@ ble_gattc_disc_svc_uuid_tx(struct ble_gattc_proc *proc) ble_gattc_dbg_assert_proc_not_inserted(proc); ble_uuid_flat(&proc->disc_svc_uuid.service_uuid.u, val); - rc = ble_att_clt_tx_find_type_value(proc->conn_handle, + rc = ble_att_clt_tx_find_type_value(proc->conn_handle, proc->cid, proc->disc_svc_uuid.prev_handle + 1, 0xffff, BLE_ATT_UUID_PRIMARY_SERVICE, val, @@ -1744,8 +1818,8 @@ ble_gattc_disc_svc_by_uuid(uint16_t conn_handle, const ble_uuid_t *uuid, goto done; } - proc->op = BLE_GATT_OP_DISC_SVC_UUID; - proc->conn_handle = conn_handle; + ble_gattc_proc_prepare(proc, conn_handle, BLE_GATT_OP_DISC_SVC_UUID); + ble_uuid_to_any(uuid, &proc->disc_svc_uuid.service_uuid); proc->disc_svc_uuid.prev_handle = 0x0000; proc->disc_svc_uuid.cb = cb; @@ -1826,7 +1900,7 @@ ble_gattc_find_inc_svcs_tx(struct ble_gattc_proc *proc) if (proc->find_inc_svcs.cur_start == 0) { /* Find the next included service. */ - rc = ble_att_clt_tx_read_type(proc->conn_handle, + rc = ble_att_clt_tx_read_type(proc->conn_handle, proc->cid, proc->find_inc_svcs.prev_handle + 1, proc->find_inc_svcs.end_handle, &uuid.u); if (rc != 0) { @@ -1834,7 +1908,7 @@ ble_gattc_find_inc_svcs_tx(struct ble_gattc_proc *proc) } } else { /* Read the UUID of the previously found service. */ - rc = ble_att_clt_tx_read(proc->conn_handle, + rc = ble_att_clt_tx_read(proc->conn_handle, proc->cid, proc->find_inc_svcs.cur_start); if (rc != 0) { return rc; @@ -1946,7 +2020,7 @@ static int ble_gattc_find_inc_svcs_rx_adata(struct ble_gattc_proc *proc, struct ble_att_read_type_adata *adata) { - struct ble_gatt_svc service; + struct ble_gatt_svc service = {0}; int call_cb; int cbrc; int rc; @@ -2060,8 +2134,8 @@ ble_gattc_find_inc_svcs(uint16_t conn_handle, uint16_t start_handle, goto done; } - proc->op = BLE_GATT_OP_FIND_INC_SVCS; - proc->conn_handle = conn_handle; + ble_gattc_proc_prepare(proc, conn_handle, BLE_GATT_OP_FIND_INC_SVCS); + proc->find_inc_svcs.prev_handle = start_handle - 1; proc->find_inc_svcs.end_handle = end_handle; proc->find_inc_svcs.cb = cb; @@ -2140,7 +2214,7 @@ ble_gattc_disc_all_chrs_tx(struct ble_gattc_proc *proc) ble_gattc_dbg_assert_proc_not_inserted(proc); - rc = ble_att_clt_tx_read_type(proc->conn_handle, + rc = ble_att_clt_tx_read_type(proc->conn_handle, proc->cid, proc->disc_all_chrs.prev_handle + 1, proc->disc_all_chrs.end_handle, &uuid.u); if (rc != 0) { @@ -2225,7 +2299,9 @@ ble_gattc_disc_all_chrs_rx_adata(struct ble_gattc_proc *proc, rc = BLE_HS_EBADDATA; goto done; } - proc->disc_all_chrs.prev_handle = adata->att_handle; + + /* We'll resume after characteristic value */ + proc->disc_all_chrs.prev_handle = chr.val_handle; rc = 0; @@ -2254,7 +2330,10 @@ ble_gattc_disc_all_chrs_rx_complete(struct ble_gattc_proc *proc, int status) return BLE_HS_EDONE; } - if (proc->disc_all_chrs.prev_handle == proc->disc_all_chrs.end_handle) { + /* We can stop discovery if there are less than 2 attributes left since + * complete characteristic requires at least 2 handles. + */ + if (proc->disc_all_chrs.prev_handle + 1 >= proc->disc_all_chrs.end_handle - 1) { /* Characteristic discovery complete. */ ble_gattc_disc_all_chrs_cb(proc, BLE_HS_EDONE, 0, NULL); return BLE_HS_EDONE; @@ -2288,8 +2367,8 @@ ble_gattc_disc_all_chrs(uint16_t conn_handle, uint16_t start_handle, goto done; } - proc->op = BLE_GATT_OP_DISC_ALL_CHRS; - proc->conn_handle = conn_handle; + ble_gattc_proc_prepare(proc, conn_handle, BLE_GATT_OP_DISC_ALL_CHRS); + proc->disc_all_chrs.prev_handle = start_handle - 1; proc->disc_all_chrs.end_handle = end_handle; proc->disc_all_chrs.cb = cb; @@ -2368,7 +2447,7 @@ ble_gattc_disc_chr_uuid_tx(struct ble_gattc_proc *proc) ble_gattc_dbg_assert_proc_not_inserted(proc); - rc = ble_att_clt_tx_read_type(proc->conn_handle, + rc = ble_att_clt_tx_read_type(proc->conn_handle, proc->cid, proc->disc_chr_uuid.prev_handle + 1, proc->disc_chr_uuid.end_handle, &uuid.u); if (rc != 0) { @@ -2527,8 +2606,8 @@ ble_gattc_disc_chrs_by_uuid(uint16_t conn_handle, uint16_t start_handle, goto done; } - proc->op = BLE_GATT_OP_DISC_CHR_UUID; - proc->conn_handle = conn_handle; + ble_gattc_proc_prepare(proc, conn_handle, BLE_GATT_OP_DISC_CHR_UUID); + ble_uuid_to_any(uuid, &proc->disc_chr_uuid.chr_uuid); proc->disc_chr_uuid.prev_handle = start_handle - 1; proc->disc_chr_uuid.end_handle = end_handle; @@ -2607,7 +2686,7 @@ ble_gattc_disc_all_dscs_tx(struct ble_gattc_proc *proc) ble_gattc_dbg_assert_proc_not_inserted(proc); - rc = ble_att_clt_tx_find_info(proc->conn_handle, + rc = ble_att_clt_tx_find_info(proc->conn_handle, proc->cid, proc->disc_all_dscs.prev_handle + 1, proc->disc_all_dscs.end_handle); if (rc != 0) { @@ -2737,8 +2816,8 @@ ble_gattc_disc_all_dscs(uint16_t conn_handle, uint16_t start_handle, goto done; } - proc->op = BLE_GATT_OP_DISC_ALL_DSCS; - proc->conn_handle = conn_handle; + ble_gattc_proc_prepare(proc, conn_handle, BLE_GATT_OP_DISC_ALL_DSCS); + proc->disc_all_dscs.chr_val_handle = start_handle; proc->disc_all_dscs.prev_handle = start_handle; proc->disc_all_dscs.end_handle = end_handle; @@ -2848,7 +2927,7 @@ ble_gattc_read_tx(struct ble_gattc_proc *proc) { int rc; - rc = ble_att_clt_tx_read(proc->conn_handle, proc->read.handle); + rc = ble_att_clt_tx_read(proc->conn_handle, proc->cid, proc->read.handle); if (rc != 0) { return rc; } @@ -2875,8 +2954,8 @@ ble_gattc_read(uint16_t conn_handle, uint16_t attr_handle, goto done; } - proc->op = BLE_GATT_OP_READ; - proc->conn_handle = conn_handle; + ble_gattc_proc_prepare(proc, conn_handle, BLE_GATT_OP_READ); + proc->read.handle = attr_handle; proc->read.cb = cb; proc->read.cb_arg = cb_arg; @@ -3011,7 +3090,7 @@ ble_gattc_read_uuid_rx_complete(struct ble_gattc_proc *proc, int status) static int ble_gattc_read_uuid_tx(struct ble_gattc_proc *proc) { - return ble_att_clt_tx_read_type(proc->conn_handle, + return ble_att_clt_tx_read_type(proc->conn_handle, proc->cid, proc->read_uuid.start_handle, proc->read_uuid.end_handle, &proc->read_uuid.chr_uuid.u); @@ -3037,8 +3116,8 @@ ble_gattc_read_by_uuid(uint16_t conn_handle, uint16_t start_handle, goto done; } - proc->op = BLE_GATT_OP_READ_UUID; - proc->conn_handle = conn_handle; + ble_gattc_proc_prepare(proc, conn_handle, BLE_GATT_OP_READ_UUID); + ble_uuid_to_any(uuid, &proc->read_uuid.chr_uuid); proc->read_uuid.start_handle = start_handle; proc->read_uuid.end_handle = end_handle; @@ -3116,12 +3195,12 @@ ble_gattc_read_long_tx(struct ble_gattc_proc *proc) ble_gattc_dbg_assert_proc_not_inserted(proc); if (proc->read_long.offset == 0) { - rc = ble_att_clt_tx_read(proc->conn_handle, proc->read_long.handle); + rc = ble_att_clt_tx_read(proc->conn_handle, proc->cid, proc->read_long.handle); if (rc != 0) { return rc; } } else { - rc = ble_att_clt_tx_read_blob(proc->conn_handle, + rc = ble_att_clt_tx_read_blob(proc->conn_handle, proc->cid, proc->read_long.handle, proc->read_long.offset); if (rc != 0) { @@ -3192,7 +3271,7 @@ ble_gattc_read_long_rx_read_rsp(struct ble_gattc_proc *proc, int status, } /* Determine if this is the end of the attribute value. */ - mtu = ble_att_mtu(proc->conn_handle); + mtu = ble_att_mtu_by_cid(proc->conn_handle, proc->cid); if (mtu == 0) { /* No longer connected. */ return BLE_HS_EDONE; @@ -3233,8 +3312,8 @@ ble_gattc_read_long(uint16_t conn_handle, uint16_t handle, uint16_t offset, goto done; } - proc->op = BLE_GATT_OP_READ_LONG; - proc->conn_handle = conn_handle; + ble_gattc_proc_prepare(proc, conn_handle, BLE_GATT_OP_READ_LONG); + proc->read_long.handle = handle; proc->read_long.offset = offset; proc->read_long.cb = cb; @@ -3257,8 +3336,74 @@ ble_gattc_read_long(uint16_t conn_handle, uint16_t handle, uint16_t offset, } /***************************************************************************** - * $read multiple * - *****************************************************************************/ +* $read multiple * +*****************************************************************************/ + +static int +ble_gattc_read_mult_cb_var(struct ble_gattc_proc *proc, int status, + uint16_t att_handle, struct os_mbuf **om) +{ + struct ble_gatt_attr attr[proc->read_mult.num_handles]; + int rc; + int i; + uint16_t attr_len; + + if (proc->read_mult.cb_mult == NULL) { + return 0; + } + + memset(attr, 0, sizeof(attr)); + + for (i = 0; i < proc->read_mult.num_handles; i++) { + attr[i].handle = proc->read_mult.handles[i]; + attr[i].offset = 0; + if (om == NULL || OS_MBUF_PKTLEN(*om) == 0) { + continue; + } + + *om = os_mbuf_pullup(*om, 2); + assert(*om); + + attr_len = get_le16((*om)->om_data); + + os_mbuf_adj(*om, 2); + + if (attr_len > BLE_ATT_ATTR_MAX_LEN) { + /*TODO Figure out what to do here */ + break; + } + + attr[i].om = os_msys_get_pkthdr(attr_len, 0); + if (!attr[i].om) { + /*TODO Figure out what to do here */ + break; + } + + rc = os_mbuf_appendfrom(attr[i].om, *om, 0, attr_len); + if (rc) { + /*TODO Figure out what to do here */ + break; + } + + os_mbuf_adj(*om, attr_len); + } + + /*FIXME Testing assert */ + assert(i == proc->read_mult.num_handles); + + proc->read_mult.cb_mult(proc->conn_handle, + ble_gattc_error(status, att_handle), &attr[0], + i, + proc->read_mult.cb_arg); + + for (i = 0; i < proc->read_mult.num_handles; i++) { + if (attr[i].om != NULL) { + os_mbuf_free_chain(attr[i].om); + } + } + + return 0; +} /** * Calls a read-multiple-characteristics proc's callback with the specified @@ -3282,6 +3427,10 @@ ble_gattc_read_mult_cb(struct ble_gattc_proc *proc, int status, STATS_INC(ble_gattc_stats, read_mult_fail); } + if (proc->read_mult.variable) { + return ble_gattc_read_mult_cb_var(proc, status, att_handle, om); + } + attr.handle = 0; attr.offset = 0; if (om == NULL) { @@ -3327,13 +3476,25 @@ ble_gattc_read_mult_err(struct ble_gattc_proc *proc, int status, ble_gattc_read_mult_cb(proc, status, att_handle, NULL); } +/** + * Handles an incoming ATT error response for the specified + * read-multiple-variable-lengthcharacteristics proc. + */ +static void +ble_gattc_read_mult_var_err(struct ble_gattc_proc *proc, int status, + uint16_t att_handle) +{ + ble_gattc_dbg_assert_proc_not_inserted(proc); + ble_gattc_read_mult_cb_var(proc, status, att_handle, NULL); +} + static int ble_gattc_read_mult_tx(struct ble_gattc_proc *proc) { int rc; - rc = ble_att_clt_tx_read_mult(proc->conn_handle, proc->read_mult.handles, - proc->read_mult.num_handles); + rc = ble_att_clt_tx_read_mult(proc->conn_handle, proc->cid, proc->read_mult.handles, + proc->read_mult.num_handles, proc->read_mult.variable); if (rc != 0) { return rc; } @@ -3342,10 +3503,11 @@ ble_gattc_read_mult_tx(struct ble_gattc_proc *proc) } -int -ble_gattc_read_mult(uint16_t conn_handle, const uint16_t *handles, - uint8_t num_handles, ble_gatt_attr_fn *cb, - void *cb_arg) +static int +ble_gattc_read_mult_internal(uint16_t conn_handle, const uint16_t *handles, + uint8_t num_handles, bool variable, ble_gatt_attr_fn *cb, + ble_gatt_attr_mult_fn *cb_mult, + void *cb_arg) { #if !MYNEWT_VAL(BLE_GATT_READ_MULT) return BLE_HS_ENOTSUP; @@ -3369,14 +3531,20 @@ ble_gattc_read_mult(uint16_t conn_handle, const uint16_t *handles, goto done; } - proc->op = BLE_GATT_OP_READ_MULT; - proc->conn_handle = conn_handle; + if (variable) { + ble_gattc_proc_prepare(proc, conn_handle, BLE_GATT_OP_READ_MULT_VAR); + } else { + ble_gattc_proc_prepare(proc, conn_handle, BLE_GATT_OP_READ_MULT); + } + memcpy(proc->read_mult.handles, handles, num_handles * sizeof *handles); proc->read_mult.num_handles = num_handles; + proc->read_mult.variable = variable; proc->read_mult.cb = cb; + proc->read_mult.cb_mult = cb_mult; proc->read_mult.cb_arg = cb_arg; - ble_gattc_log_read_mult(handles, num_handles); + ble_gattc_log_read_mult(handles, num_handles, variable); rc = ble_gattc_read_mult_tx(proc); if (rc != 0) { goto done; @@ -3391,9 +3559,31 @@ ble_gattc_read_mult(uint16_t conn_handle, const uint16_t *handles, return rc; } +int +ble_gattc_read_mult(uint16_t conn_handle, const uint16_t *handles, + uint8_t num_handles, ble_gatt_attr_fn *cb, + void *cb_arg) +{ + return ble_gattc_read_mult_internal(conn_handle, handles, + num_handles, false, cb, NULL, cb_arg); +} + +int +ble_gattc_read_mult_var(uint16_t conn_handle, const uint16_t *handles, + uint8_t num_handles, ble_gatt_attr_mult_fn *cb, + void *cb_arg) +{ +#if MYNEWT_VAL(BLE_GATT_READ_MULT_VAR) + return ble_gattc_read_mult_internal(conn_handle, handles, num_handles, + true, NULL, cb, cb_arg); +#else + return BLE_HS_ENOTSUP; +#endif +} + /***************************************************************************** - * $write no response * - *****************************************************************************/ +* $write no response * +*****************************************************************************/ int ble_gattc_write_no_rsp(uint16_t conn_handle, uint16_t attr_handle, @@ -3404,15 +3594,18 @@ ble_gattc_write_no_rsp(uint16_t conn_handle, uint16_t attr_handle, #endif int rc; + uint16_t cid; STATS_INC(ble_gattc_stats, write_no_rsp); ble_gattc_log_write(attr_handle, OS_MBUF_PKTLEN(txom), 0); - rc = ble_att_clt_tx_write_cmd(conn_handle, attr_handle, txom); + cid = ble_eatt_get_available_chan_cid(conn_handle, BLE_GATT_OP_DUMMY); + rc = ble_att_clt_tx_write_cmd(conn_handle, cid, attr_handle, txom); if (rc != 0) { STATS_INC(ble_gattc_stats, write); } + ble_eatt_release_chan(conn_handle, BLE_GATT_OP_DUMMY); return rc; } @@ -3515,15 +3708,15 @@ ble_gattc_write(uint16_t conn_handle, uint16_t attr_handle, goto done; } - proc->op = BLE_GATT_OP_WRITE; - proc->conn_handle = conn_handle; + ble_gattc_proc_prepare(proc, conn_handle, BLE_GATT_OP_WRITE); + proc->write.att_handle = attr_handle; proc->write.cb = cb; proc->write.cb_arg = cb_arg; ble_gattc_log_write(attr_handle, OS_MBUF_PKTLEN(txom), 1); - rc = ble_att_clt_tx_write_req(conn_handle, attr_handle, txom); + rc = ble_att_clt_tx_write_req(conn_handle, proc->cid, attr_handle, txom); txom = NULL; if (rc != 0) { goto done; @@ -3623,7 +3816,7 @@ ble_gattc_write_long_tx(struct ble_gattc_proc *proc) om = NULL; - max_sz = ble_att_mtu(proc->conn_handle) - BLE_ATT_PREP_WRITE_CMD_BASE_SZ; + max_sz = ble_att_mtu_by_cid(proc->conn_handle, proc->cid) - BLE_ATT_PREP_WRITE_CMD_BASE_SZ; if (max_sz <= 0) { /* Not connected. */ rc = BLE_HS_ENOTCONN; @@ -3635,7 +3828,7 @@ ble_gattc_write_long_tx(struct ble_gattc_proc *proc) proc->write_long.attr.offset); if (write_len <= 0) { - rc = ble_att_clt_tx_exec_write(proc->conn_handle, + rc = ble_att_clt_tx_exec_write(proc->conn_handle, proc->cid, BLE_ATT_EXEC_WRITE_F_EXECUTE); goto done; } @@ -3655,7 +3848,7 @@ ble_gattc_write_long_tx(struct ble_gattc_proc *proc) goto done; } - rc = ble_att_clt_tx_prep_write(proc->conn_handle, + rc = ble_att_clt_tx_prep_write(proc->conn_handle, proc->cid, proc->write_long.attr.handle, proc->write_long.attr.offset, om); om = NULL; @@ -3699,9 +3892,9 @@ ble_gattc_write_long_err(struct ble_gattc_proc *proc, int status, */ if (proc->write_long.attr.offset > 0 && proc->write_long.attr.offset < - OS_MBUF_PKTLEN(proc->write_long.attr.om)) { + OS_MBUF_PKTLEN(proc->write_long.attr.om)) { - ble_att_clt_tx_exec_write(proc->conn_handle, + ble_att_clt_tx_exec_write(proc->conn_handle, proc->cid, BLE_ATT_EXEC_WRITE_F_CANCEL); } @@ -3765,17 +3958,21 @@ ble_gattc_write_long_rx_prep(struct ble_gattc_proc *proc, proc->write_long.length) != 0) { rc = BLE_HS_EBADDATA; - goto err; - } - /* Send follow-up request. */ - proc->write_long.attr.offset += OS_MBUF_PKTLEN(om); - rc = ble_gattc_write_long_resume(proc); - if (rc != 0) { + /* if data doesn't match up send cancel write */ + ble_att_clt_tx_exec_write(proc->conn_handle, proc->cid, + BLE_ATT_EXEC_WRITE_F_CANCEL); goto err; - } + } else { + /* Send follow-up request. */ + proc->write_long.attr.offset += OS_MBUF_PKTLEN(om); + rc = ble_gattc_write_long_resume(proc); + if (rc != 0) { + goto err; + } - return 0; + return 0; + } err: /* XXX: Might need to cancel pending writes. */ @@ -3825,8 +4022,8 @@ ble_gattc_write_long(uint16_t conn_handle, uint16_t attr_handle, goto done; } - proc->op = BLE_GATT_OP_WRITE_LONG; - proc->conn_handle = conn_handle; + ble_gattc_proc_prepare(proc, conn_handle, BLE_GATT_OP_WRITE_LONG); + proc->write_long.attr.handle = attr_handle; proc->write_long.attr.offset = offset; proc->write_long.attr.om = txom; @@ -3921,14 +4118,14 @@ ble_gattc_write_reliable_tx(struct ble_gattc_proc *proc) attr_idx = proc->write_reliable.cur_attr; if (attr_idx >= proc->write_reliable.num_attrs) { - rc = ble_att_clt_tx_exec_write(proc->conn_handle, + rc = ble_att_clt_tx_exec_write(proc->conn_handle, proc->cid, BLE_ATT_EXEC_WRITE_F_EXECUTE); goto done; } attr = proc->write_reliable.attrs + attr_idx; - max_sz = ble_att_mtu(proc->conn_handle) - BLE_ATT_PREP_WRITE_CMD_BASE_SZ; + max_sz = ble_att_mtu_by_cid(proc->conn_handle, proc->cid) - BLE_ATT_PREP_WRITE_CMD_BASE_SZ; if (max_sz <= 0) { /* Not connected. */ rc = BLE_HS_ENOTCONN; @@ -3951,8 +4148,8 @@ ble_gattc_write_reliable_tx(struct ble_gattc_proc *proc) goto done; } - rc = ble_att_clt_tx_prep_write(proc->conn_handle, attr->handle, - attr->offset, om); + rc = ble_att_clt_tx_prep_write(proc->conn_handle, proc->cid, + attr->handle, attr->offset, om); om = NULL; if (rc != 0) { goto done; @@ -3995,7 +4192,7 @@ ble_gattc_write_reliable_err(struct ble_gattc_proc *proc, int status, */ if (proc->write_reliable.cur_attr < proc->write_reliable.num_attrs) { - ble_att_clt_tx_exec_write(proc->conn_handle, + ble_att_clt_tx_exec_write(proc->conn_handle, proc->cid, BLE_ATT_EXEC_WRITE_F_CANCEL); } } @@ -4108,8 +4305,8 @@ ble_gattc_write_reliable(uint16_t conn_handle, goto done; } - proc->op = BLE_GATT_OP_WRITE_RELIABLE; - proc->conn_handle = conn_handle; + ble_gattc_proc_prepare(proc, conn_handle, BLE_GATT_OP_WRITE_RELIABLE); + proc->write_reliable.num_attrs = num_attrs; proc->write_reliable.cur_attr = 0; proc->write_reliable.cb = cb; @@ -4149,7 +4346,7 @@ ble_gattc_write_reliable(uint16_t conn_handle, *****************************************************************************/ int -ble_gattc_notify_custom(uint16_t conn_handle, uint16_t chr_val_handle, +ble_gatts_notify_custom(uint16_t conn_handle, uint16_t chr_val_handle, struct os_mbuf *txom) { #if !MYNEWT_VAL(BLE_GATT_NOTIFY) @@ -4199,8 +4396,18 @@ ble_gattc_notify_custom(uint16_t conn_handle, uint16_t chr_val_handle, return rc; } +/** + * Deprecated. Should not be used. Use ble_gatts_notify_custom instead. + */ int -ble_gattc_notify(uint16_t conn_handle, uint16_t chr_val_handle) +ble_gattc_notify_custom(uint16_t conn_handle, uint16_t chr_val_handle, + struct os_mbuf *txom) +{ + return ble_gatts_notify_custom(conn_handle, chr_val_handle, txom); +} + +int +ble_gatts_notify(uint16_t conn_handle, uint16_t chr_val_handle) { #if !MYNEWT_VAL(BLE_GATT_NOTIFY) return BLE_HS_ENOTSUP; @@ -4208,11 +4415,153 @@ ble_gattc_notify(uint16_t conn_handle, uint16_t chr_val_handle) int rc; - rc = ble_gattc_notify_custom(conn_handle, chr_val_handle, NULL); + rc = ble_gatts_notify_custom(conn_handle, chr_val_handle, NULL); + + return rc; +} + +int +ble_gatts_notify_multiple_custom(uint16_t conn_handle, + size_t chr_count, + struct ble_gatt_notif *tuples) +{ +#if !MYNEWT_VAL(BLE_GATT_NOTIFY_MULTIPLE) + return BLE_HS_ENOTSUP; +#endif + + int rc; + int i = 0; + uint16_t cur_chr_cnt = 0; + /* mtu = MTU - 1 octet (OP code) */ + uint16_t mtu = ble_att_mtu(conn_handle) - 1; + struct os_mbuf *txom; + struct ble_hs_conn *conn; + + txom = ble_hs_mbuf_att_pkt(); + if (txom == NULL) { + return BLE_HS_ENOMEM; + } + + conn = ble_hs_conn_find(conn_handle); + if (conn == NULL) { + return BLE_HS_ENOTCONN; + } + + /* Read missing values */ + for (i = 0; i < chr_count; i++) { + if (tuples->handle == 0) { + rc = BLE_HS_EINVAL; + goto done; + } + if (tuples[i].value == NULL) { + rc = ble_att_svr_read_local(tuples[i].handle, &tuples[i].value); + if (rc != 0) { + goto done; + } + } + } + + /* If peer does not support fall back to multiple single value + * Notifications */ + if ((conn->bhc_gatt_svr.peer_cl_sup_feat[0] & 0x04) == 0) { + for (i = 0; i < chr_count; i++) { + rc = ble_att_clt_tx_notify(conn_handle, tuples[chr_count].handle, + tuples[chr_count].value); + if (rc != 0) { + goto done; + } + } + } + + for (i = 0; i < chr_count; i++) { + if (txom->om_len + tuples[i].value->om_len > mtu && cur_chr_cnt < 2) { + rc = ble_att_clt_tx_notify(conn_handle, tuples[i].handle, + tuples[i].value); + if (rc != 0) { + goto done; + } + continue; + } else if (txom->om_len + tuples[i].value->om_len > mtu) { + rc = ble_att_clt_tx_notify_mult(conn_handle, txom); + if (rc != 0) { + goto done; + } + cur_chr_cnt = 0; + /* buffer was consumed, allocate new one */ + txom = ble_hs_mbuf_att_pkt(); + if (txom == NULL) { + return BLE_HS_ENOMEM; + } + } + + os_mbuf_append(txom, &tuples[i].handle, sizeof(uint16_t)); + os_mbuf_append(txom, &tuples[i].value->om_len, + sizeof(uint16_t)); + os_mbuf_concat(txom, tuples[i].value); + cur_chr_cnt++; + } + + if (cur_chr_cnt == 1) { + rc = ble_att_clt_tx_notify(conn_handle, tuples[chr_count].handle, + tuples[chr_count].value); + } else { + rc = ble_att_clt_tx_notify_mult(conn_handle, txom); + } + +done: + return rc; +} + +int +ble_gatts_notify_multiple(uint16_t conn_handle, + size_t num_handles, + const uint16_t *chr_val_handles) +{ +#if !MYNEWT_VAL(BLE_GATT_NOTIFY_MULTIPLE) + return BLE_HS_ENOTSUP; +#endif + int rc, i; + struct ble_gatt_notif tuples[num_handles]; + struct ble_hs_conn *conn; + + BLE_HS_LOG_DEBUG("conn_handle %d\n", conn_handle); + conn = ble_hs_conn_find(conn_handle); + if (conn == NULL) { + return BLE_HS_ENOTCONN; + } + + /** Skip sending to client that doesn't support this feature */ + BLE_HS_LOG_DEBUG("ble_gatts_notify_multiple: peer_cl_sup_feat %d\n", + conn->bhc_gatt_svr.peer_cl_sup_feat[0]); + if ((conn->bhc_gatt_svr.peer_cl_sup_feat[0] & 0x04) == 0) { + for (i = 0; i < num_handles; i++) { + rc = ble_gatts_notify(conn_handle, chr_val_handles[i]); + if (rc != 0) { + return rc; + } + } + return 0; + } + + for (i = 0; i < num_handles; i++) { + tuples[i].handle = chr_val_handles[i]; + tuples[i].value = NULL; + BLE_HS_LOG(DEBUG, "handle 0x%02x\n", tuples[i].handle); + } + rc = ble_gatts_notify_multiple_custom(conn_handle, num_handles, tuples); return rc; } +/** + * Deprecated. Should not be used. Use ble_gatts_notify instead. + */ +int +ble_gattc_notify(uint16_t conn_handle, uint16_t chr_val_handle) +{ + return ble_gatts_notify(conn_handle, chr_val_handle); +} + /***************************************************************************** * $indicate * *****************************************************************************/ @@ -4224,7 +4573,7 @@ ble_gattc_notify(uint16_t conn_handle, uint16_t chr_val_handle) * error status to the application. */ static void -ble_gattc_indicate_err(struct ble_gattc_proc *proc, int status, +ble_gatts_indicate_err(struct ble_gattc_proc *proc, int status, uint16_t att_handle) { int rc; @@ -4248,7 +4597,7 @@ ble_gattc_indicate_err(struct ble_gattc_proc *proc, int status, } static void -ble_gattc_indicate_tmo(struct ble_gattc_proc *proc) +ble_gatts_indicate_tmo(struct ble_gattc_proc *proc) { BLE_HS_DBG_ASSERT(!ble_hs_locked_by_cur_task()); ble_gattc_dbg_assert_proc_not_inserted(proc); @@ -4262,7 +4611,7 @@ ble_gattc_indicate_tmo(struct ble_gattc_proc *proc) * proc. */ static void -ble_gattc_indicate_rx_rsp(struct ble_gattc_proc *proc) +ble_gatts_indicate_rx_rsp(struct ble_gattc_proc *proc) { int rc; @@ -4293,7 +4642,7 @@ ble_gatts_indicate_fail_notconn(uint16_t conn_handle) } int -ble_gattc_indicate_custom(uint16_t conn_handle, uint16_t chr_val_handle, +ble_gatts_indicate_custom(uint16_t conn_handle, uint16_t chr_val_handle, struct os_mbuf *txom) { #if !MYNEWT_VAL(BLE_GATT_INDICATE) @@ -4312,8 +4661,8 @@ ble_gattc_indicate_custom(uint16_t conn_handle, uint16_t chr_val_handle, goto done; } - proc->op = BLE_GATT_OP_INDICATE; - proc->conn_handle = conn_handle; + ble_gattc_proc_prepare(proc, conn_handle, BLE_GATT_OP_INDICATE); + proc->indicate.chr_val_handle = chr_val_handle; ble_gattc_log_indicate(chr_val_handle); @@ -4338,7 +4687,7 @@ ble_gattc_indicate_custom(uint16_t conn_handle, uint16_t chr_val_handle, } } - rc = ble_att_clt_tx_indicate(conn_handle, chr_val_handle, txom); + rc = ble_att_clt_tx_indicate(conn_handle, proc->cid, chr_val_handle, txom); txom = NULL; if (rc != 0) { goto done; @@ -4365,10 +4714,29 @@ ble_gattc_indicate_custom(uint16_t conn_handle, uint16_t chr_val_handle, return rc; } +/** + * Deprecated. Should not be used. Use ble_gatts_indicate_custom instead. + */ +int +ble_gattc_indicate_custom(uint16_t conn_handle, uint16_t chr_val_handle, + struct os_mbuf *txom) +{ + return ble_gatts_indicate_custom(conn_handle, chr_val_handle, txom); +} + +int +ble_gatts_indicate(uint16_t conn_handle, uint16_t chr_val_handle) +{ + return ble_gatts_indicate_custom(conn_handle, chr_val_handle, NULL); +} + +/** + * Deprecated. Should not be used. Use ble_gatts_indicate instead. + */ int ble_gattc_indicate(uint16_t conn_handle, uint16_t chr_val_handle) { - return ble_gattc_indicate_custom(conn_handle, chr_val_handle, NULL); + return ble_gatts_indicate(conn_handle, chr_val_handle); } /***************************************************************************** @@ -4380,12 +4748,12 @@ ble_gattc_indicate(uint16_t conn_handle, uint16_t chr_val_handle) * procedure. */ void -ble_gattc_rx_err(uint16_t conn_handle, uint16_t handle, uint16_t status) +ble_gattc_rx_err(uint16_t conn_handle, uint16_t cid, uint16_t handle, uint16_t status) { struct ble_gattc_proc *proc; ble_gattc_err_fn *err_cb; - proc = ble_gattc_extract_first_by_conn_op(conn_handle, BLE_GATT_OP_NONE); + proc = ble_gattc_extract_first_by_conn_cid_op(conn_handle, cid, BLE_GATT_OP_NONE); if (proc != NULL) { err_cb = ble_gattc_err_dispatch_get(proc->op); if (err_cb != NULL) { @@ -4400,11 +4768,13 @@ ble_gattc_rx_err(uint16_t conn_handle, uint16_t handle, uint16_t status) * GATT procedure. */ void -ble_gattc_rx_mtu(uint16_t conn_handle, int status, uint16_t chan_mtu) +ble_gattc_rx_mtu(uint16_t conn_handle, uint16_t cid, int status, uint16_t chan_mtu) { struct ble_gattc_proc *proc; - proc = ble_gattc_extract_first_by_conn_op(conn_handle, BLE_GATT_OP_MTU); + assert(cid == BLE_L2CAP_CID_ATT); + + proc = ble_gattc_extract_first_by_conn_cid_op(conn_handle, BLE_L2CAP_CID_ATT, BLE_GATT_OP_MTU); if (proc != NULL) { ble_gattc_mtu_cb(proc, status, 0, chan_mtu); ble_gattc_process_status(proc, BLE_HS_EDONE); @@ -4416,7 +4786,7 @@ ble_gattc_rx_mtu(uint16_t conn_handle, int status, uint16_t chan_mtu) * find-information-response to the appropriate active GATT procedure. */ void -ble_gattc_rx_find_info_idata(uint16_t conn_handle, +ble_gattc_rx_find_info_idata(uint16_t conn_handle, uint16_t cid, struct ble_att_find_info_idata *idata) { #if !NIMBLE_BLE_ATT_CLT_FIND_INFO @@ -4426,7 +4796,7 @@ ble_gattc_rx_find_info_idata(uint16_t conn_handle, struct ble_gattc_proc *proc; int rc; - proc = ble_gattc_extract_first_by_conn_op(conn_handle, + proc = ble_gattc_extract_first_by_conn_cid_op(conn_handle, cid, BLE_GATT_OP_DISC_ALL_DSCS); if (proc != NULL) { rc = ble_gattc_disc_all_dscs_rx_idata(proc, idata); @@ -4439,7 +4809,7 @@ ble_gattc_rx_find_info_idata(uint16_t conn_handle, * find-information-response to the appropriate active GATT procedure. */ void -ble_gattc_rx_find_info_complete(uint16_t conn_handle, int status) +ble_gattc_rx_find_info_complete(uint16_t conn_handle, uint16_t cid, int status) { #if !NIMBLE_BLE_ATT_CLT_FIND_INFO return; @@ -4448,8 +4818,8 @@ ble_gattc_rx_find_info_complete(uint16_t conn_handle, int status) struct ble_gattc_proc *proc; int rc; - proc = ble_gattc_extract_first_by_conn_op(conn_handle, - BLE_GATT_OP_DISC_ALL_DSCS); + proc = ble_gattc_extract_first_by_conn_cid_op(conn_handle, cid, + BLE_GATT_OP_DISC_ALL_DSCS); if (proc != NULL) { rc = ble_gattc_disc_all_dscs_rx_complete(proc, status); ble_gattc_process_status(proc, rc); @@ -4461,7 +4831,7 @@ ble_gattc_rx_find_info_complete(uint16_t conn_handle, int status) * find-by-type-value-response to the appropriate active GATT procedure. */ void -ble_gattc_rx_find_type_value_hinfo(uint16_t conn_handle, +ble_gattc_rx_find_type_value_hinfo(uint16_t conn_handle, uint16_t cid, struct ble_att_find_type_value_hinfo *hinfo) { #if !NIMBLE_BLE_ATT_CLT_FIND_TYPE @@ -4471,7 +4841,7 @@ ble_gattc_rx_find_type_value_hinfo(uint16_t conn_handle, struct ble_gattc_proc *proc; int rc; - proc = ble_gattc_extract_first_by_conn_op(conn_handle, + proc = ble_gattc_extract_first_by_conn_cid_op(conn_handle, cid, BLE_GATT_OP_DISC_SVC_UUID); if (proc != NULL) { rc = ble_gattc_disc_svc_uuid_rx_hinfo(proc, hinfo); @@ -4484,7 +4854,7 @@ ble_gattc_rx_find_type_value_hinfo(uint16_t conn_handle, * find-by-type-value-response to the appropriate active GATT procedure. */ void -ble_gattc_rx_find_type_value_complete(uint16_t conn_handle, int status) +ble_gattc_rx_find_type_value_complete(uint16_t conn_handle, uint16_t cid, int status) { #if !NIMBLE_BLE_ATT_CLT_FIND_TYPE return; @@ -4493,8 +4863,8 @@ ble_gattc_rx_find_type_value_complete(uint16_t conn_handle, int status) struct ble_gattc_proc *proc; int rc; - proc = ble_gattc_extract_first_by_conn_op(conn_handle, - BLE_GATT_OP_DISC_SVC_UUID); + proc = ble_gattc_extract_first_by_conn_cid_op(conn_handle, cid, + BLE_GATT_OP_DISC_SVC_UUID); if (proc != NULL) { rc = ble_gattc_disc_svc_uuid_rx_complete(proc, status); ble_gattc_process_status(proc, rc); @@ -4506,7 +4876,7 @@ ble_gattc_rx_find_type_value_complete(uint16_t conn_handle, int status) * to the appropriate active GATT procedure. */ void -ble_gattc_rx_read_type_adata(uint16_t conn_handle, +ble_gattc_rx_read_type_adata(uint16_t conn_handle, uint16_t cid, struct ble_att_read_type_adata *adata) { #if !NIMBLE_BLE_ATT_CLT_READ_TYPE @@ -4517,7 +4887,7 @@ ble_gattc_rx_read_type_adata(uint16_t conn_handle, struct ble_gattc_proc *proc; int rc; - proc = BLE_GATTC_RX_EXTRACT_RX_ENTRY(conn_handle, + proc = BLE_GATTC_RX_EXTRACT_RX_ENTRY(conn_handle, cid, ble_gattc_rx_read_type_elem_entries, &rx_entry); if (proc != NULL) { @@ -4531,7 +4901,7 @@ ble_gattc_rx_read_type_adata(uint16_t conn_handle, * the appropriate active GATT procedure. */ void -ble_gattc_rx_read_type_complete(uint16_t conn_handle, int status) +ble_gattc_rx_read_type_complete(uint16_t conn_handle, uint16_t cid, int status) { #if !NIMBLE_BLE_ATT_CLT_READ_TYPE return; @@ -4542,7 +4912,7 @@ ble_gattc_rx_read_type_complete(uint16_t conn_handle, int status) int rc; proc = BLE_GATTC_RX_EXTRACT_RX_ENTRY( - conn_handle, ble_gattc_rx_read_type_complete_entries, + conn_handle, cid, ble_gattc_rx_read_type_complete_entries, &rx_entry); if (proc != NULL) { rc = rx_entry->cb(proc, status); @@ -4555,7 +4925,7 @@ ble_gattc_rx_read_type_complete(uint16_t conn_handle, int status) * read-by-group-type-response to the appropriate active GATT procedure. */ void -ble_gattc_rx_read_group_type_adata(uint16_t conn_handle, +ble_gattc_rx_read_group_type_adata(uint16_t conn_handle, uint16_t cid, struct ble_att_read_group_type_adata *adata) { #if !NIMBLE_BLE_ATT_CLT_READ_GROUP_TYPE @@ -4565,7 +4935,7 @@ ble_gattc_rx_read_group_type_adata(uint16_t conn_handle, struct ble_gattc_proc *proc; int rc; - proc = ble_gattc_extract_first_by_conn_op(conn_handle, + proc = ble_gattc_extract_first_by_conn_cid_op(conn_handle, cid, BLE_GATT_OP_DISC_ALL_SVCS); if (proc != NULL) { rc = ble_gattc_disc_all_svcs_rx_adata(proc, adata); @@ -4578,7 +4948,7 @@ ble_gattc_rx_read_group_type_adata(uint16_t conn_handle, * read-by-group-type-response to the appropriate active GATT procedure. */ void -ble_gattc_rx_read_group_type_complete(uint16_t conn_handle, int status) +ble_gattc_rx_read_group_type_complete(uint16_t conn_handle, uint16_t cid, int status) { #if !NIMBLE_BLE_ATT_CLT_READ_GROUP_TYPE return; @@ -4587,8 +4957,8 @@ ble_gattc_rx_read_group_type_complete(uint16_t conn_handle, int status) struct ble_gattc_proc *proc; int rc; - proc = ble_gattc_extract_first_by_conn_op(conn_handle, - BLE_GATT_OP_DISC_ALL_SVCS); + proc = ble_gattc_extract_first_by_conn_cid_op(conn_handle, cid, + BLE_GATT_OP_DISC_ALL_SVCS); if (proc != NULL) { rc = ble_gattc_disc_all_svcs_rx_complete(proc, status); ble_gattc_process_status(proc, rc); @@ -4600,7 +4970,7 @@ ble_gattc_rx_read_group_type_complete(uint16_t conn_handle, int status) * procedure. */ void -ble_gattc_rx_read_rsp(uint16_t conn_handle, int status, struct os_mbuf **om) +ble_gattc_rx_read_rsp(uint16_t conn_handle, uint16_t cid, int status, struct os_mbuf **om) { #if !NIMBLE_BLE_ATT_CLT_READ return; @@ -4610,7 +4980,7 @@ ble_gattc_rx_read_rsp(uint16_t conn_handle, int status, struct os_mbuf **om) struct ble_gattc_proc *proc; int rc; - proc = BLE_GATTC_RX_EXTRACT_RX_ENTRY(conn_handle, + proc = BLE_GATTC_RX_EXTRACT_RX_ENTRY(conn_handle, cid, ble_gattc_rx_read_rsp_entries, &rx_entry); if (proc != NULL) { @@ -4624,7 +4994,7 @@ ble_gattc_rx_read_rsp(uint16_t conn_handle, int status, struct os_mbuf **om) * procedure. */ void -ble_gattc_rx_read_blob_rsp(uint16_t conn_handle, int status, +ble_gattc_rx_read_blob_rsp(uint16_t conn_handle, uint16_t cid, int status, struct os_mbuf **om) { #if !NIMBLE_BLE_ATT_CLT_READ_BLOB @@ -4634,7 +5004,7 @@ ble_gattc_rx_read_blob_rsp(uint16_t conn_handle, int status, struct ble_gattc_proc *proc; int rc; - proc = ble_gattc_extract_first_by_conn_op(conn_handle, + proc = ble_gattc_extract_first_by_conn_cid_op(conn_handle, cid, BLE_GATT_OP_READ_LONG); if (proc != NULL) { rc = ble_gattc_read_long_rx_read_rsp(proc, status, om); @@ -4647,17 +5017,19 @@ ble_gattc_rx_read_blob_rsp(uint16_t conn_handle, int status, * GATT procedure. */ void -ble_gattc_rx_read_mult_rsp(uint16_t conn_handle, int status, - struct os_mbuf **om) +ble_gattc_rx_read_mult_rsp(uint16_t conn_handle, uint16_t cid, int status, + struct os_mbuf **om, bool variable) { #if !NIMBLE_BLE_ATT_CLT_READ_MULT return; #endif struct ble_gattc_proc *proc; + uint8_t op; + + op = variable ? BLE_GATT_OP_READ_MULT_VAR : BLE_GATT_OP_READ_MULT; - proc = ble_gattc_extract_first_by_conn_op(conn_handle, - BLE_GATT_OP_READ_MULT); + proc = ble_gattc_extract_first_by_conn_cid_op(conn_handle, cid, op); if (proc != NULL) { ble_gattc_read_mult_cb(proc, status, 0, om); ble_gattc_process_status(proc, BLE_HS_EDONE); @@ -4669,7 +5041,7 @@ ble_gattc_rx_read_mult_rsp(uint16_t conn_handle, int status, * procedure. */ void -ble_gattc_rx_write_rsp(uint16_t conn_handle) +ble_gattc_rx_write_rsp(uint16_t conn_handle, uint16_t cid) { #if !NIMBLE_BLE_ATT_CLT_WRITE return; @@ -4677,7 +5049,7 @@ ble_gattc_rx_write_rsp(uint16_t conn_handle) struct ble_gattc_proc *proc; - proc = ble_gattc_extract_first_by_conn_op(conn_handle, + proc = ble_gattc_extract_first_by_conn_cid_op(conn_handle, cid, BLE_GATT_OP_WRITE); if (proc != NULL) { ble_gattc_write_cb(proc, 0, 0); @@ -4690,7 +5062,7 @@ ble_gattc_rx_write_rsp(uint16_t conn_handle) * GATT procedure. */ void -ble_gattc_rx_prep_write_rsp(uint16_t conn_handle, int status, +ble_gattc_rx_prep_write_rsp(uint16_t conn_handle, uint16_t cid, int status, uint16_t handle, uint16_t offset, struct os_mbuf **om) { @@ -4702,7 +5074,7 @@ ble_gattc_rx_prep_write_rsp(uint16_t conn_handle, int status, struct ble_gattc_proc *proc; int rc; - proc = BLE_GATTC_RX_EXTRACT_RX_ENTRY(conn_handle, + proc = BLE_GATTC_RX_EXTRACT_RX_ENTRY(conn_handle, cid, ble_gattc_rx_prep_entries, &rx_entry); if (proc != NULL) { @@ -4716,7 +5088,7 @@ ble_gattc_rx_prep_write_rsp(uint16_t conn_handle, int status, * GATT procedure. */ void -ble_gattc_rx_exec_write_rsp(uint16_t conn_handle, int status) +ble_gattc_rx_exec_write_rsp(uint16_t conn_handle, uint16_t cid, int status) { #if !NIMBLE_BLE_ATT_CLT_EXEC_WRITE return; @@ -4726,7 +5098,7 @@ ble_gattc_rx_exec_write_rsp(uint16_t conn_handle, int status) struct ble_gattc_proc *proc; int rc; - proc = BLE_GATTC_RX_EXTRACT_RX_ENTRY(conn_handle, + proc = BLE_GATTC_RX_EXTRACT_RX_ENTRY(conn_handle, cid, ble_gattc_rx_exec_entries, &rx_entry); if (proc != NULL) { rc = rx_entry->cb(proc, status); @@ -4739,7 +5111,7 @@ ble_gattc_rx_exec_write_rsp(uint16_t conn_handle, int status) * active GATT procedure. */ void -ble_gattc_rx_indicate_rsp(uint16_t conn_handle) +ble_gatts_rx_indicate_rsp(uint16_t conn_handle, uint16_t cid) { #if !NIMBLE_BLE_ATT_CLT_INDICATE return; @@ -4747,10 +5119,10 @@ ble_gattc_rx_indicate_rsp(uint16_t conn_handle) struct ble_gattc_proc *proc; - proc = ble_gattc_extract_first_by_conn_op(conn_handle, + proc = ble_gattc_extract_first_by_conn_cid_op(conn_handle, cid, BLE_GATT_OP_INDICATE); if (proc != NULL) { - ble_gattc_indicate_rx_rsp(proc); + ble_gatts_indicate_rx_rsp(proc); ble_gattc_process_status(proc, BLE_HS_EDONE); } } diff --git a/nimble/host/src/ble_gatts.c b/nimble/host/src/ble_gatts.c index a635f2d7f4..6c3ae19de9 100644 --- a/nimble/host/src/ble_gatts.c +++ b/nimble/host/src/ble_gatts.c @@ -21,6 +21,7 @@ #include #include #include "nimble/ble.h" +#include "host/ble_gatt.h" #include "host/ble_uuid.h" #include "host/ble_store.h" #include "ble_hs_priv.h" @@ -364,7 +365,7 @@ ble_gatts_val_access(uint16_t conn_handle, uint16_t attr_handle, gatt_ctxt->om = *om; } else { new_om = 1; - gatt_ctxt->om = os_msys_get_pkthdr(0, 0); + gatt_ctxt->om = ble_hs_mbuf_att_pkt(); if (gatt_ctxt->om == NULL) { return BLE_ATT_ERR_INSUFFICIENT_RES; } @@ -415,6 +416,7 @@ ble_gatts_chr_val_access(uint16_t conn_handle, uint16_t attr_handle, gatt_ctxt.op = ble_gatts_chr_op(att_op); gatt_ctxt.chr = chr_def; + gatt_ctxt.offset = offset; ble_gatts_chr_inc_val_stat(gatt_ctxt.op); rc = ble_gatts_val_access(conn_handle, attr_handle, offset, &gatt_ctxt, om, @@ -735,6 +737,33 @@ ble_gatts_clt_cfg_access_locked(struct ble_hs_conn *conn, uint16_t attr_handle, return 0; } +int +ble_gatts_read_cccd(uint16_t conn_handle, uint16_t chr_val_handle, uint8_t *cccd_value) +{ + struct ble_gatts_clt_cfg *clt_cfg; + struct ble_hs_conn *conn; + + ble_hs_lock(); + + conn = ble_hs_conn_find(conn_handle); + if (conn == NULL) { + ble_hs_unlock(); + return BLE_HS_ENOTCONN; + } + + clt_cfg = ble_gatts_clt_cfg_find(conn->bhc_gatt_svr.clt_cfgs, chr_val_handle); + if (clt_cfg == NULL) { + ble_hs_unlock(); + return BLE_HS_ENOENT; + } + + *cccd_value = clt_cfg->flags & ~BLE_GATTS_CLT_CFG_F_RESERVED; + + ble_hs_unlock(); + + return 0; +} + int ble_gatts_clt_cfg_access(uint16_t conn_handle, uint16_t attr_handle, uint8_t op, uint16_t offset, struct os_mbuf **om, @@ -1396,7 +1425,7 @@ ble_gatts_send_next_indicate(uint16_t conn_handle) return BLE_HS_ENOENT; } - rc = ble_gattc_indicate(conn_handle, chr_val_handle); + rc = ble_gatts_indicate(conn_handle, chr_val_handle); if (rc != 0) { return rc; } @@ -1579,6 +1608,89 @@ ble_gatts_chr_updated(uint16_t chr_val_handle) } } +int +ble_gatts_peer_cl_sup_feat_get(uint16_t conn_handle, uint8_t *out_supported_feat, uint8_t len) +{ + struct ble_hs_conn *conn; + int rc = 0; + + if (out_supported_feat == NULL) { + return BLE_HS_EINVAL; + } + + ble_hs_lock(); + conn = ble_hs_conn_find(conn_handle); + if (conn == NULL) { + rc = BLE_HS_ENOTCONN; + goto done; + } + + if (BLE_GATT_CHR_CLI_SUP_FEAT_SZ < len) { + len = BLE_GATT_CHR_CLI_SUP_FEAT_SZ; + } + + memcpy(out_supported_feat, conn->bhc_gatt_svr.peer_cl_sup_feat, + sizeof(uint8_t) * len); + +done: + ble_hs_unlock(); + return rc; +} + +int +ble_gatts_peer_cl_sup_feat_update(uint16_t conn_handle, struct os_mbuf *om) +{ + struct ble_hs_conn *conn; + uint8_t feat[BLE_GATT_CHR_CLI_SUP_FEAT_SZ] = {}; + uint16_t len; + int rc = 0; + int i; + + if (!om) { + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + + /* RFU bits are ignored so we can skip any bytes larger than supported */ + len = os_mbuf_len(om); + if (len > BLE_GATT_CHR_CLI_SUP_FEAT_SZ) { + len = BLE_GATT_CHR_CLI_SUP_FEAT_SZ; + } + + if (os_mbuf_copydata(om, 0, len, feat) < 0) { + return BLE_ATT_ERR_UNLIKELY; + } + + /* clear RFU bits */ + for (i = 0; i < BLE_GATT_CHR_CLI_SUP_FEAT_SZ; i++) { + feat[i] &= (BLE_GATT_CHR_CLI_SUP_FEAT_MASK >> (8 * i)); + } + + ble_hs_lock(); + conn = ble_hs_conn_find(conn_handle); + if (conn == NULL) { + rc = BLE_ATT_ERR_UNLIKELY; + goto done; + } + + /** + * Disabling already enabled features is not permitted + * (Vol. 3, Part F, 3.3.3) + */ + for (i = 0; i < BLE_GATT_CHR_CLI_SUP_FEAT_SZ; i++) { + if ((conn->bhc_gatt_svr.peer_cl_sup_feat[i] & feat[i]) != + conn->bhc_gatt_svr.peer_cl_sup_feat[i]) { + rc = BLE_ATT_ERR_VALUE_NOT_ALLOWED; + goto done; + } + } + + memcpy(conn->bhc_gatt_svr.peer_cl_sup_feat, feat, BLE_GATT_CHR_CLI_SUP_FEAT_SZ); + +done: + ble_hs_unlock(); + return rc; +} + /** * Sends notifications or indications for the specified characteristic to all * connected devices. The bluetooth spec does not allow more than one @@ -1634,11 +1746,11 @@ ble_gatts_tx_notifications_one_chr(uint16_t chr_val_handle) break; case BLE_ATT_OP_NOTIFY_REQ: - ble_gattc_notify(conn_handle, chr_val_handle); + ble_gatts_notify(conn_handle, chr_val_handle); break; case BLE_ATT_OP_INDICATE_REQ: - ble_gattc_indicate(conn_handle, chr_val_handle); + ble_gatts_indicate(conn_handle, chr_val_handle); break; default: @@ -1781,7 +1893,7 @@ ble_gatts_bonding_restored(uint16_t conn_handle) break; case BLE_ATT_OP_NOTIFY_REQ: - rc = ble_gattc_notify(conn_handle, cccd_value.chr_val_handle); + rc = ble_gatts_notify(conn_handle, cccd_value.chr_val_handle); if (rc == 0) { cccd_value.value_changed = 0; ble_store_write_cccd(&cccd_value); @@ -1789,7 +1901,7 @@ ble_gatts_bonding_restored(uint16_t conn_handle) break; case BLE_ATT_OP_INDICATE_REQ: - ble_gattc_indicate(conn_handle, cccd_value.chr_val_handle); + ble_gatts_indicate(conn_handle, cccd_value.chr_val_handle); break; default: diff --git a/nimble/host/src/ble_gatts_lcl.c b/nimble/host/src/ble_gatts_lcl.c index 938d736223..8d829ae51a 100644 --- a/nimble/host/src/ble_gatts_lcl.c +++ b/nimble/host/src/ble_gatts_lcl.c @@ -19,6 +19,7 @@ #include #include +#include "host/ble_gatt.h" #include "host/ble_uuid.h" #include "console/console.h" #include "nimble/ble.h" @@ -90,10 +91,9 @@ ble_gatts_flags_to_str(uint16_t flags, char *buf, return buf; } - -#define STRINGIFY(X) #X -#define FIELD_NAME_LEN STRINGIFY(12) -#define FIELD_INDENT STRINGIFY(2) +#define NIMBLE_STRINGIFY(X) #X +#define FIELD_NAME_LEN NIMBLE_STRINGIFY(12) +#define FIELD_INDENT NIMBLE_STRINGIFY(2) static void ble_gatt_show_local_chr(const struct ble_gatt_svc_def *svc, diff --git a/nimble/host/src/ble_hs.c b/nimble/host/src/ble_hs.c index 9f39c8e66d..42c83c9b72 100644 --- a/nimble/host/src/ble_hs.c +++ b/nimble/host/src/ble_hs.c @@ -23,17 +23,19 @@ #include "sysinit/sysinit.h" #include "syscfg/syscfg.h" #include "stats/stats.h" -#include "nimble/ble_hci_trans.h" +#include "host/ble_hs.h" +#if MYNEWT_VAL(BLE_AUDIO) && MYNEWT_VAL(BLE_ISO_BROADCAST_SOURCE) +#include "audio/ble_audio_broadcast_source.h" +#endif /* BLE_AUDIO && BLE_ISO_BROADCAST_SOURCE */ #include "ble_hs_priv.h" -#include "ble_monitor_priv.h" +#include "ble_iso_priv.h" #include "nimble/nimble_npl.h" #ifndef MYNEWT #include "nimble/nimble_port.h" #endif -#define BLE_HS_HCI_EVT_COUNT \ - (MYNEWT_VAL(BLE_HCI_EVT_HI_BUF_COUNT) + \ - MYNEWT_VAL(BLE_HCI_EVT_LO_BUF_COUNT)) +#define BLE_HS_HCI_EVT_COUNT (MYNEWT_VAL(BLE_TRANSPORT_EVT_COUNT) + \ + MYNEWT_VAL(BLE_TRANSPORT_EVT_DISCARDABLE_COUNT)) static void ble_hs_event_rx_hci_ev(struct ble_npl_event *ev); #if NIMBLE_BLE_CONNECT @@ -122,7 +124,7 @@ ble_hs_evq_set(struct ble_npl_eventq *evq) int ble_hs_locked_by_cur_task(void) { -#if MYNEWT +#ifdef MYNEWT struct os_task *owner; if (!ble_npl_os_started()) { @@ -162,7 +164,7 @@ ble_hs_lock_nested(void) } #endif - rc = ble_npl_mutex_pend(&ble_hs_mutex, 0xffffffff); + rc = ble_npl_mutex_pend(&ble_hs_mutex, BLE_NPL_TIME_FOREVER); BLE_HS_DBG_ASSERT_EVAL(rc == 0 || rc == OS_NOT_STARTED); } @@ -222,10 +224,6 @@ ble_hs_process_rx_data_queue(void) struct os_mbuf *om; while ((om = ble_mqueue_get(&ble_hs_rx_q)) != NULL) { -#if BLE_MONITOR - ble_monitor_send_om(BLE_MONITOR_OPCODE_ACL_RX_PKT, om); -#endif - ble_hs_hci_evt_acl_process(om); } } @@ -369,12 +367,6 @@ ble_hs_reset(void) ble_hs_sync_state = 0; - /* Reset transport. Assume success; there is nothing we can do in case of - * failure. If the transport failed to reset, the host will reset itself - * again when it fails to sync with the controller. - */ - (void)ble_hci_trans_reset(); - ble_hs_clear_rx_queue(); /* Clear adverising and scanning states. */ @@ -498,7 +490,7 @@ ble_hs_sched_start(void) static void ble_hs_event_rx_hci_ev(struct ble_npl_event *ev) { - const struct ble_hci_ev *hci_ev; + struct ble_hci_ev *hci_ev; int rc; hci_ev = ble_npl_event_get_arg(ev); @@ -506,11 +498,6 @@ ble_hs_event_rx_hci_ev(struct ble_npl_event *ev) rc = os_memblock_put(&ble_hs_hci_ev_pool, ev); BLE_HS_DBG_ASSERT_EVAL(rc == 0); -#if BLE_MONITOR - ble_monitor_send(BLE_MONITOR_OPCODE_EVENT_PKT, hci_ev, - hci_ev->length + sizeof(*hci_ev)); -#endif - ble_hs_hci_evt_process(hci_ev); } @@ -572,7 +559,7 @@ ble_hs_enqueue_hci_event(uint8_t *hci_evt) ev = os_memblock_get(&ble_hs_hci_ev_pool); if (ev == NULL) { - ble_hci_trans_buf_free(hci_evt); + ble_transport_free(hci_evt); } else { ble_npl_event_init(ev, ble_hs_event_rx_hci_ev, hci_evt); ble_npl_eventq_put(ble_hs_evq, ev); @@ -704,11 +691,7 @@ ble_hs_rx_data(struct os_mbuf *om, void *arg) int ble_hs_tx_data(struct os_mbuf *om) { -#if BLE_MONITOR - ble_monitor_send_om(BLE_MONITOR_OPCODE_ACL_TX_PKT, om); -#endif - - return ble_hci_trans_hs_acl_tx(om); + return ble_transport_to_ll_acl(om); } void @@ -755,6 +738,11 @@ ble_hs_init(void) rc = ble_l2cap_init(); SYSINIT_PANIC_ASSERT(rc == 0); +#endif + rc = ble_gap_init(); + SYSINIT_PANIC_ASSERT(rc == 0); +#if NIMBLE_BLE_CONNECT + rc = ble_att_init(); SYSINIT_PANIC_ASSERT(rc == 0); @@ -767,8 +755,20 @@ ble_hs_init(void) rc = ble_gatts_init(); SYSINIT_PANIC_ASSERT(rc == 0); #endif - rc = ble_gap_init(); + +#if MYNEWT_VAL(BLE_ISO) + rc = ble_iso_init(); + SYSINIT_PANIC_ASSERT(rc == 0); +#if MYNEWT_VAL(BLE_AUDIO) && MYNEWT_VAL(BLE_ISO_BROADCAST_SOURCE) + rc = ble_audio_broadcast_init(); SYSINIT_PANIC_ASSERT(rc == 0); +#endif /* BLE_AUDIO && BLE_ISO_BROADCAST_SOURCE */ +#endif + +#if MYNEWT_VAL(BLE_AUDIO_MAX_CODEC_RECORDS) + rc = ble_audio_codec_init(); + SYSINIT_PANIC_ASSERT(rc == 0); +#endif ble_hs_stop_init(); @@ -792,14 +792,6 @@ ble_hs_init(void) ble_hs_evq_set(nimble_port_get_dflt_eventq()); #endif - /* Configure the HCI transport to communicate with a host. */ - ble_hci_trans_cfg_hs(ble_hs_hci_rx_evt, NULL, ble_hs_rx_data, NULL); - -#if BLE_MONITOR - rc = ble_monitor_init(); - SYSINIT_PANIC_ASSERT(rc == 0); -#endif - /* Enqueue the start event to the default event queue. Using the default * queue ensures the event won't run until the end of main(). This allows * the application to configure this package in the meantime. @@ -812,8 +804,36 @@ ble_hs_init(void) ble_npl_eventq_put(nimble_port_get_dflt_eventq(), &ble_hs_ev_start_stage1); #endif #endif +} + +/* Transport APIs for HS side */ + +int +ble_transport_to_hs_evt_impl(void *buf) +{ + return ble_hs_hci_rx_evt(buf, NULL); +} + +int +ble_transport_to_hs_acl_impl(struct os_mbuf *om) +{ + return ble_hs_rx_data(om, NULL); +} + +int +ble_transport_to_hs_iso_impl(struct os_mbuf *om) +{ +#if MYNEWT_VAL(BLE_ISO_BROADCAST_SINK) + return ble_iso_rx_data(om, NULL); +#else + os_mbuf_free_chain(om); -#if BLE_MONITOR - ble_monitor_new_index(0, (uint8_t[6]){ }, "nimble0"); + return 0; #endif } + +void +ble_transport_hs_init(void) +{ + ble_hs_init(); +} diff --git a/nimble/host/src/ble_hs_adv.c b/nimble/host/src/ble_hs_adv.c index 1d938b958c..44c28c0cc6 100644 --- a/nimble/host/src/ble_hs_adv.c +++ b/nimble/host/src/ble_hs_adv.c @@ -354,6 +354,17 @@ adv_set_fields(const struct ble_hs_adv_fields *adv_fields, } } + /*** 0x30 - Broadcast name. */ + if (adv_fields->broadcast_name != NULL && adv_fields->broadcast_name_len > 0) { + rc = ble_hs_adv_set_flat_mbuf(BLE_HS_ADV_TYPE_BROADCAST_NAME, + adv_fields->broadcast_name_len, + adv_fields->broadcast_name, dst, + &dst_len_local, max_len, om); + if (rc != 0) { + return rc; + } + } + /*** 0x16 - Service data - 16-bit UUID. */ if (adv_fields->svc_data_uuid16 != NULL && adv_fields->svc_data_uuid16_len) { rc = ble_hs_adv_set_flat_mbuf(BLE_HS_ADV_TYPE_SVC_DATA_UUID16, diff --git a/nimble/host/src/ble_hs_conn.c b/nimble/host/src/ble_hs_conn.c index ea89460cc4..ba034a2703 100644 --- a/nimble/host/src/ble_hs_conn.c +++ b/nimble/host/src/ble_hs_conn.c @@ -193,6 +193,7 @@ ble_hs_conn_alloc(uint16_t conn_handle) } STAILQ_INIT(&conn->bhc_tx_q); + STAILQ_INIT(&conn->att_tx_q); STATS_INC(ble_hs_stats, conn_create); @@ -206,10 +207,6 @@ ble_hs_conn_alloc(uint16_t conn_handle) void ble_hs_conn_delete_chan(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan) { - if (conn->bhc_rx_chan == chan) { - conn->bhc_rx_chan = NULL; - } - SLIST_REMOVE(&conn->bhc_channels, chan, ble_l2cap_chan, next); ble_l2cap_chan_free(conn, chan); } @@ -243,6 +240,9 @@ ble_hs_conn_free(struct ble_hs_conn *conn) return; } + os_mbuf_free_chain(conn->rx_frags); + conn->rx_frags = NULL; + ble_att_svr_prep_clear(&conn->bhc_att_svr.basc_prep_list); while ((chan = SLIST_FIRST(&conn->bhc_channels)) != NULL) { @@ -254,6 +254,11 @@ ble_hs_conn_free(struct ble_hs_conn *conn) os_mbuf_free_chain(OS_MBUF_PKTHDR_TO_MBUF(omp)); } + while ((omp = STAILQ_FIRST(&conn->att_tx_q)) != NULL) { + STAILQ_REMOVE_HEAD(&conn->att_tx_q, omp_next); + os_mbuf_free_chain(OS_MBUF_PKTHDR_TO_MBUF(omp)); + } + #if MYNEWT_VAL(BLE_HS_DEBUG) memset(conn, 0xff, sizeof *conn); #endif @@ -476,86 +481,73 @@ ble_hs_conn_timer(void) #endif struct ble_hs_conn *conn; - ble_npl_time_t now; - int32_t next_exp_in; + ble_npl_time_t now = ble_npl_time_get(); + int32_t next_exp_in = BLE_HS_FOREVER; + int32_t next_exp_in_new; + bool next_exp_in_updated; int32_t time_diff; - uint16_t conn_handle; - for (;;) { - conn_handle = BLE_HS_CONN_HANDLE_NONE; - next_exp_in = BLE_HS_FOREVER; - now = ble_npl_time_get(); + ble_hs_lock(); - ble_hs_lock(); - - /* This loop performs one of two tasks: - * 1. Determine if any connections need to be terminated due to timeout. - * If so, break out of the loop and terminate the connection. This - * function will need to be executed again. - * 2. Otherwise, determine when the next timeout will occur. - */ - SLIST_FOREACH(conn, &ble_hs_conns, bhc_next) { - if (!(conn->bhc_flags & BLE_HS_CONN_F_TERMINATING)) { + /* This loop performs one of two tasks: + * 1. Determine if any connections need to be terminated due to timeout. If + * so connection is disconnected. + * 2. Otherwise, determine when the next timeout will occur. + */ + SLIST_FOREACH(conn, &ble_hs_conns, bhc_next) { + if (!(conn->bhc_flags & BLE_HS_CONN_F_TERMINATING)) { + next_exp_in_updated = false; #if MYNEWT_VAL(BLE_L2CAP_RX_FRAG_TIMEOUT) != 0 - /* Check each connection's rx fragment timer. If too much time - * passes after a partial packet is received, the connection is - * terminated. - */ - if (conn->bhc_rx_chan != NULL) { - time_diff = conn->bhc_rx_timeout - now; - - if (time_diff <= 0) { - /* ACL reassembly has timed out. Remember the connection - * handle so it can be terminated after the mutex is - * unlocked. - */ - conn_handle = conn->bhc_handle; - break; - } - - /* Determine if this connection is the soonest to time out. */ - if (time_diff < next_exp_in) { - next_exp_in = time_diff; - } - } -#endif + /* Check each connection's rx fragment timer. If too much time + * passes after a partial packet is received, the connection is + * terminated. + */ + if (conn->rx_len) { + time_diff = conn->rx_frag_tmo - now; -#if BLE_HS_ATT_SVR_QUEUED_WRITE_TMO - /* Check each connection's rx queued write timer. If too much - * time passes after a prep write is received, the queue is - * cleared. - */ - time_diff = ble_att_svr_ticks_until_tmo(&conn->bhc_att_svr, now); if (time_diff <= 0) { - /* ACL reassembly has timed out. Remember the connection - * handle so it can be terminated after the mutex is - * unlocked. - */ - conn_handle = conn->bhc_handle; - break; + /* ACL reassembly has timed out.*/ + ble_gap_terminate_with_conn(conn, BLE_ERR_REM_USER_CONN_TERM); + continue; } /* Determine if this connection is the soonest to time out. */ if (time_diff < next_exp_in) { - next_exp_in = time_diff; + next_exp_in_new = time_diff; + next_exp_in_updated = true; } + } #endif + +#if BLE_HS_ATT_SVR_QUEUED_WRITE_TMO + /* Check each connection's rx queued write timer. If too much + * time passes after a prep write is received, the queue is + * cleared. + */ + time_diff = ble_att_svr_ticks_until_tmo(&conn->bhc_att_svr, now); + if (time_diff <= 0) { + /* Queued write has timed out.*/ + ble_gap_terminate_with_conn(conn, BLE_ERR_REM_USER_CONN_TERM); + continue; } - } - ble_hs_unlock(); + /* Determine if this connection is the soonest to time out. */ + if (time_diff < next_exp_in) { + next_exp_in_new = time_diff; + next_exp_in_updated = true; + } +#endif - /* If a connection has timed out, terminate it. We need to repeatedly - * call this function again to determine when the next timeout is. - */ - if (conn_handle != BLE_HS_CONN_HANDLE_NONE) { - ble_gap_terminate(conn_handle, BLE_ERR_REM_USER_CONN_TERM); - continue; + if (next_exp_in_updated) { + next_exp_in = next_exp_in_new; + } } - - return next_exp_in; } + + ble_hs_unlock(); + + return next_exp_in; } int diff --git a/nimble/host/src/ble_hs_conn_priv.h b/nimble/host/src/ble_hs_conn_priv.h index 0e451194d1..8a0412fa5b 100644 --- a/nimble/host/src/ble_hs_conn_priv.h +++ b/nimble/host/src/ble_hs_conn_priv.h @@ -37,6 +37,7 @@ typedef uint8_t ble_hs_conn_flags_t; #define BLE_HS_CONN_F_MASTER 0x01 #define BLE_HS_CONN_F_TERMINATING 0x02 #define BLE_HS_CONN_F_TX_FRAG 0x04 /* Cur ACL packet partially txed. */ +#define BLE_HS_CONN_F_TERMINATED 0x08 #if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) #define BLE_HS_CONN_L2CAP_COC_CID_MASK_LEN_REM \ @@ -68,8 +69,18 @@ struct ble_hs_conn { ble_hs_conn_flags_t bhc_flags; struct ble_l2cap_chan_list bhc_channels; - struct ble_l2cap_chan *bhc_rx_chan; /* Channel rxing current packet. */ - ble_npl_time_t bhc_rx_timeout; + + /* ACL RX fragments */ + struct os_mbuf *rx_frags; + /* Expected data length for ACL RX */ + uint16_t rx_len; + /* L2CAP Source CID for ACL RX */ + uint16_t rx_cid; +#if MYNEWT_VAL(BLE_L2CAP_RX_FRAG_TIMEOUT) != 0 + /* Timeout for next fragment for ACL RX */ + ble_npl_time_t rx_frag_tmo; +#endif + #if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) uint32_t l2cap_coc_cid_mask[BLE_HS_CONN_L2CAP_COC_CID_MASK_LEN]; #endif @@ -102,6 +113,9 @@ struct ble_hs_conn { #if MYNEWT_VAL(BLE_PERIODIC_ADV) struct ble_hs_periodic_sync *psync; #endif + + STAILQ_HEAD(, os_mbuf_pkthdr) att_tx_q; + bool client_att_busy; }; struct ble_hs_conn_addrs { diff --git a/nimble/host/src/ble_hs_flow.c b/nimble/host/src/ble_hs_flow.c index 1eabba9e0c..acd754a3fb 100644 --- a/nimble/host/src/ble_hs_flow.c +++ b/nimble/host/src/ble_hs_flow.c @@ -18,7 +18,6 @@ */ #include "syscfg/syscfg.h" -#include "nimble/ble_hci_trans.h" #include "ble_hs_priv.h" #if MYNEWT_VAL(BLE_HS_FLOW_CTRL) @@ -41,7 +40,7 @@ static ble_npl_event_fn ble_hs_flow_event_cb; static struct ble_npl_event ble_hs_flow_ev; /* Connection handle associated with each mbuf in ACL pool */ -static uint16_t ble_hs_flow_mbuf_conn_handle[ MYNEWT_VAL(BLE_ACL_BUF_COUNT) ]; +static uint16_t ble_hs_flow_mbuf_conn_handle[ MYNEWT_VAL(BLE_TRANSPORT_ACL_FROM_LL_COUNT) ]; static inline int ble_hs_flow_mbuf_index(const struct os_mbuf *om) @@ -136,7 +135,7 @@ ble_hs_flow_inc_completed_pkts(struct ble_hs_conn *conn) conn->bhc_completed_pkts++; ble_hs_flow_num_completed_pkts++; - if (ble_hs_flow_num_completed_pkts > MYNEWT_VAL(BLE_ACL_BUF_COUNT)) { + if (ble_hs_flow_num_completed_pkts > MYNEWT_VAL(BLE_TRANSPORT_ACL_FROM_LL_COUNT)) { ble_hs_sched_reset(BLE_HS_ECONTROLLER); return; } @@ -144,7 +143,8 @@ ble_hs_flow_inc_completed_pkts(struct ble_hs_conn *conn) /* If the number of free buffers is at or below the configured threshold, * send an immediate number-of-copmleted-packets event. */ - num_free = MYNEWT_VAL(BLE_ACL_BUF_COUNT) - ble_hs_flow_num_completed_pkts; + num_free = MYNEWT_VAL(BLE_TRANSPORT_ACL_FROM_LL_COUNT) - + ble_hs_flow_num_completed_pkts; if (num_free <= MYNEWT_VAL(BLE_HS_FLOW_CTRL_THRESH)) { ble_npl_eventq_put(ble_hs_evq_get(), &ble_hs_flow_ev); ble_npl_callout_stop(&ble_hs_flow_timer); @@ -230,16 +230,13 @@ ble_hs_flow_startup(void) #if MYNEWT_VAL(BLE_HS_FLOW_CTRL) struct ble_hci_cb_ctlr_to_host_fc_cp enable_cmd; struct ble_hci_cb_host_buf_size_cp buf_size_cmd = { - .acl_data_len = htole16(MYNEWT_VAL(BLE_ACL_BUF_SIZE)), - .acl_num = htole16(MYNEWT_VAL(BLE_ACL_BUF_COUNT)), + .acl_data_len = htole16(MYNEWT_VAL(BLE_TRANSPORT_ACL_SIZE)), + .acl_num = htole16(MYNEWT_VAL(BLE_TRANSPORT_ACL_FROM_LL_COUNT)), }; int rc; ble_npl_event_init(&ble_hs_flow_ev, ble_hs_flow_event_cb, NULL); - /* Assume failure. */ - ble_hci_trans_set_acl_free_cb(NULL, NULL); - #if MYNEWT_VAL(SELFTEST) ble_npl_callout_stop(&ble_hs_flow_timer); #endif @@ -266,7 +263,7 @@ ble_hs_flow_startup(void) /* Flow control successfully enabled. */ ble_hs_flow_num_completed_pkts = 0; - ble_hci_trans_set_acl_free_cb(ble_hs_flow_acl_free, NULL); + ble_transport_register_put_acl_from_ll_cb(ble_hs_flow_acl_free); ble_npl_callout_init(&ble_hs_flow_timer, ble_hs_evq_get(), ble_hs_flow_event_cb, NULL); #endif diff --git a/nimble/host/src/ble_hs_hci.c b/nimble/host/src/ble_hs_hci.c index e5c3a741e5..e3fe335f5b 100644 --- a/nimble/host/src/ble_hs_hci.c +++ b/nimble/host/src/ble_hs_hci.c @@ -22,10 +22,7 @@ #include #include "os/os.h" #include "mem/mem.h" -#include "nimble/ble_hci_trans.h" -#include "host/ble_monitor.h" #include "ble_hs_priv.h" -#include "ble_monitor_priv.h" #define BLE_HCI_CMD_TIMEOUT_MS 2000 @@ -41,11 +38,22 @@ static uint32_t ble_hs_hci_sup_feat; static uint8_t ble_hs_hci_version; +static struct ble_hs_hci_sup_cmd ble_hs_hci_sup_cmd; + +#if MYNEWT_VAL(BLE_CONTROLLER) #define BLE_HS_HCI_FRAG_DATABUF_SIZE \ (BLE_ACL_MAX_PKT_SIZE + \ BLE_HCI_DATA_HDR_SZ + \ sizeof (struct os_mbuf_pkthdr) + \ + sizeof (struct ble_mbuf_hdr) + \ sizeof (struct os_mbuf)) +#else +#define BLE_HS_HCI_FRAG_DATABUF_SIZE \ + (BLE_ACL_MAX_PKT_SIZE + \ + BLE_HCI_DATA_HDR_SZ + \ + sizeof (struct os_mbuf_pkthdr) + \ + sizeof (struct os_mbuf)) +#endif #define BLE_HS_HCI_FRAG_MEMBLOCK_SIZE \ (OS_ALIGN(BLE_HS_HCI_FRAG_DATABUF_SIZE, 4)) @@ -137,8 +145,8 @@ ble_hs_hci_rx_cmd_complete(const void *data, int len, const struct ble_hci_ev_command_complete_nop *nop = data; uint16_t opcode; - if (len < sizeof(*ev)) { - if (len < sizeof(*nop)) { + if (len < (int)sizeof(*ev)) { + if (len < (int)sizeof(*nop)) { return BLE_HS_ECONTROLLER; } @@ -260,8 +268,7 @@ ble_hs_hci_wait_for_ack(void) if (ble_hs_hci_phony_ack_cb == NULL) { rc = BLE_HS_ETIMEOUT_HCI; } else { - ble_hs_hci_ack = - (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_CMD); + ble_hs_hci_ack = ble_transport_alloc_cmd(); BLE_HS_DBG_ASSERT(ble_hs_hci_ack != NULL); rc = ble_hs_hci_phony_ack_cb((void *)ble_hs_hci_ack, 260); } @@ -271,12 +278,6 @@ ble_hs_hci_wait_for_ack(void) switch (rc) { case 0: BLE_HS_DBG_ASSERT(ble_hs_hci_ack != NULL); - -#if BLE_MONITOR - ble_monitor_send(BLE_MONITOR_OPCODE_EVENT_PKT, (void *) ble_hs_hci_ack, - sizeof(*ble_hs_hci_ack) + ble_hs_hci_ack->length); -#endif - break; case OS_TIMEOUT: rc = BLE_HS_ETIMEOUT_HCI; @@ -342,7 +343,7 @@ ble_hs_hci_cmd_tx(uint16_t opcode, const void *cmd, uint8_t cmd_len, done: if (ble_hs_hci_ack != NULL) { - ble_hci_trans_buf_free((uint8_t *) ble_hs_hci_ack); + ble_transport_free((uint8_t *) ble_hs_hci_ack); ble_hs_hci_ack = NULL; } @@ -350,12 +351,26 @@ ble_hs_hci_cmd_tx(uint16_t opcode, const void *cmd, uint8_t cmd_len, return rc; } +#if MYNEWT_VAL(BLE_HCI_VS) +int +ble_hs_hci_send_vs_cmd(uint16_t ocf, const void *cmdbuf, uint8_t cmdlen, + void *rspbuf, uint8_t rsplen) +{ + int rc; + + rc = ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_VENDOR, ocf), + cmdbuf, cmdlen, rspbuf, rsplen); + + return rc; +} +#endif + static void ble_hs_hci_rx_ack(uint8_t *ack_ev) { if (ble_npl_sem_get_count(&ble_hs_hci_sem) > 0) { /* This ack is unexpected; ignore it. */ - ble_hci_trans_buf_free(ack_ev); + ble_transport_free(ack_ev); return; } BLE_HS_DBG_ASSERT(ble_hs_hci_ack == NULL); @@ -421,7 +436,11 @@ ble_hs_hci_frag_alloc(uint16_t frag_size, void *arg) struct os_mbuf *om; /* Prefer the dedicated one-element fragment pool. */ +#if MYNEWT_VAL(BLE_CONTROLLER) + om = os_mbuf_get_pkthdr(&ble_hs_hci_frag_mbuf_pool, sizeof(struct ble_mbuf_hdr)); +#else om = os_mbuf_get_pkthdr(&ble_hs_hci_frag_mbuf_pool, 0); +#endif if (om != NULL) { om->om_data += BLE_HCI_DATA_HDR_SZ; return om; @@ -496,6 +515,17 @@ ble_hs_hci_acl_tx_now(struct ble_hs_conn *conn, struct os_mbuf **om) BLE_HS_DBG_ASSERT(ble_hs_locked_by_cur_task()); + /* conn may be already disconnected but GAP events were not yet + * processed and thus connection object is stil on list, just ignore it + * in such case as ACL handle is not valid anymore and conn object will + * be removed shortly. + */ + if (conn->bhc_flags & BLE_HS_CONN_F_TERMINATED) { + os_mbuf_free_chain(*om); + *om = NULL; + return 0; + } + txom = *om; *om = NULL; @@ -615,6 +645,18 @@ ble_hs_hci_get_hci_version(void) return ble_hs_hci_version; } +void +ble_hs_hci_set_hci_supported_cmd(struct ble_hs_hci_sup_cmd sup_cmd) +{ + ble_hs_hci_sup_cmd = sup_cmd; +} + +struct ble_hs_hci_sup_cmd +ble_hs_hci_get_hci_supported_cmd(void) +{ + return ble_hs_hci_sup_cmd; +} + void ble_hs_hci_init(void) { diff --git a/nimble/host/src/ble_hs_hci_cmd.c b/nimble/host/src/ble_hs_hci_cmd.c index a0fd1ceac4..9d1ecf9ca2 100644 --- a/nimble/host/src/ble_hs_hci_cmd.c +++ b/nimble/host/src/ble_hs_hci_cmd.c @@ -23,22 +23,14 @@ #include #include "os/os.h" #include "nimble/hci_common.h" -#include "nimble/ble_hci_trans.h" -#include "host/ble_monitor.h" #include "ble_hs_priv.h" -#include "ble_monitor_priv.h" static int ble_hs_hci_cmd_transport(struct ble_hci_cmd *cmd) { int rc; -#if BLE_MONITOR - ble_monitor_send(BLE_MONITOR_OPCODE_COMMAND_PKT, cmd, - cmd->length + sizeof(*cmd)); -#endif - - rc = ble_hci_trans_hs_cmd_tx((uint8_t *) cmd); + rc = ble_transport_to_ll_cmd(cmd); switch (rc) { case 0: return 0; @@ -57,8 +49,11 @@ ble_hs_hci_cmd_send(uint16_t opcode, uint8_t len, const void *cmddata) struct ble_hci_cmd *cmd; int rc; - cmd = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_CMD); + cmd = ble_transport_alloc_cmd(); BLE_HS_DBG_ASSERT(cmd != NULL); + if (cmd == NULL) { + return BLE_HS_ENOMEM; + } cmd->opcode = htole16(opcode); cmd->length = len; diff --git a/nimble/host/src/ble_hs_hci_evt.c b/nimble/host/src/ble_hs_hci_evt.c index 108ee645cd..8526d8caf2 100644 --- a/nimble/host/src/ble_hs_hci_evt.c +++ b/nimble/host/src/ble_hs_hci_evt.c @@ -22,10 +22,13 @@ #include #include "os/os.h" #include "nimble/hci_common.h" -#include "nimble/ble_hci_trans.h" #include "host/ble_gap.h" -#include "host/ble_monitor.h" +#include "host/ble_iso.h" #include "ble_hs_priv.h" +#include "ble_iso_priv.h" +#if MYNEWT_VAL(BLE_CHANNEL_SOUNDING) +#include "ble_cs_priv.h" +#endif _Static_assert(sizeof (struct hci_data_hdr) == BLE_HCI_DATA_HDR_SZ, "struct hci_data_hdr must be 4 bytes"); @@ -40,6 +43,9 @@ static ble_hs_hci_evt_fn ble_hs_hci_evt_encrypt_change; static ble_hs_hci_evt_fn ble_hs_hci_evt_enc_key_refresh; #endif static ble_hs_hci_evt_fn ble_hs_hci_evt_le_meta; +#if MYNEWT_VAL(BLE_HCI_VS) +static ble_hs_hci_evt_fn ble_hs_hci_evt_vs; +#endif typedef int ble_hs_hci_evt_le_fn(uint8_t subevent, const void *data, unsigned int len); @@ -62,10 +68,27 @@ static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_periodic_adv_rpt; static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_periodic_adv_sync_lost; static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_scan_req_rcvd; static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_periodic_adv_sync_transfer; +#if MYNEWT_VAL(BLE_ISO_BROADCAST_SOURCE) +static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_create_big_complete; +static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_terminate_big_complete; +#endif +#if MYNEWT_VAL(BLE_ISO_BROADCAST_SINK) +static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_big_sync_established; +static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_big_sync_lost; +#endif +#if MYNEWT_VAL(BLE_PERIODIC_ADV_SYNC_BIGINFO_REPORTS) +static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_biginfo_adv_report; +#endif +#if MYNEWT_VAL(BLE_POWER_CONTROL) +static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_pathloss_threshold; +static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_transmit_power_report; +#endif +#if MYNEWT_VAL(BLE_CONN_SUBRATING) +static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_subrate_change; +#endif /* Statistics */ -struct host_hci_stats -{ +struct host_hci_stats { uint32_t events_rxd; uint32_t good_acks_rxd; uint32_t bad_acks_rxd; @@ -89,6 +112,9 @@ static const struct ble_hs_hci_evt_dispatch_entry ble_hs_hci_evt_dispatch[] = { { BLE_HCI_EVCODE_ENC_KEY_REFRESH, ble_hs_hci_evt_enc_key_refresh }, #endif { BLE_HCI_EVCODE_HW_ERROR, ble_hs_hci_evt_hw_error }, +#if MYNEWT_VAL(BLE_HCI_VS) + { BLE_HCI_EVCODE_VS, ble_hs_hci_evt_vs }, +#endif }; #define BLE_HS_HCI_EVT_DISPATCH_SZ \ @@ -118,6 +144,38 @@ static ble_hs_hci_evt_le_fn * const ble_hs_hci_evt_le_dispatch[] = { [BLE_HCI_LE_SUBEV_ADV_SET_TERMINATED] = ble_hs_hci_evt_le_adv_set_terminated, [BLE_HCI_LE_SUBEV_SCAN_REQ_RCVD] = ble_hs_hci_evt_le_scan_req_rcvd, [BLE_HCI_LE_SUBEV_PERIODIC_ADV_SYNC_TRANSFER] = ble_hs_hci_evt_le_periodic_adv_sync_transfer, +#if MYNEWT_VAL(BLE_ISO_BROADCAST_SOURCE) + [BLE_HCI_LE_SUBEV_CREATE_BIG_COMPLETE] = + ble_hs_hci_evt_le_create_big_complete, + [BLE_HCI_LE_SUBEV_TERMINATE_BIG_COMPLETE] = + ble_hs_hci_evt_le_terminate_big_complete, +#endif +#if MYNEWT_VAL(BLE_ISO_BROADCAST_SINK) + [BLE_HCI_LE_SUBEV_BIG_SYNC_ESTABLISHED] = + ble_hs_hci_evt_le_big_sync_established, + [BLE_HCI_LE_SUBEV_BIG_SYNC_LOST] = + ble_hs_hci_evt_le_big_sync_lost, +#endif +#if MYNEWT_VAL(BLE_PERIODIC_ADV_SYNC_BIGINFO_REPORTS) + [BLE_HCI_LE_SUBEV_BIGINFO_ADV_REPORT] = ble_hs_hci_evt_le_biginfo_adv_report, +#endif +#if MYNEWT_VAL(BLE_POWER_CONTROL) + [BLE_HCI_LE_SUBEV_PATH_LOSS_THRESHOLD] = ble_hs_hci_evt_le_pathloss_threshold, + [BLE_HCI_LE_SUBEV_TRANSMIT_POWER_REPORT] = ble_hs_hci_evt_le_transmit_power_report, +#endif +#if MYNEWT_VAL(BLE_CONN_SUBRATING) + [BLE_HCI_LE_SUBEV_SUBRATE_CHANGE] = ble_hs_hci_evt_le_subrate_change, +#endif +#if MYNEWT_VAL(BLE_CHANNEL_SOUNDING) + [BLE_HCI_LE_SUBEV_CS_RD_REM_SUPP_CAP_COMPLETE] = ble_hs_hci_evt_le_cs_rd_rem_supp_cap_complete, + [BLE_HCI_LE_SUBEV_CS_RD_REM_FAE_COMPLETE] = ble_hs_hci_evt_le_cs_rd_rem_fae_complete, + [BLE_HCI_LE_SUBEV_CS_SEC_ENABLE_COMPLETE] = ble_hs_hci_evt_le_cs_sec_enable_complete, + [BLE_HCI_LE_SUBEV_CS_CONFIG_COMPLETE] = ble_hs_hci_evt_le_cs_config_complete, + [BLE_HCI_LE_SUBEV_CS_PROC_ENABLE_COMPLETE] = ble_hs_hci_evt_le_cs_proc_enable_complete, + [BLE_HCI_LE_SUBEV_CS_SUBEVENT_RESULT] = ble_hs_hci_evt_le_cs_subevent_result, + [BLE_HCI_LE_SUBEV_CS_SUBEVENT_RESULT_CONTINUE] = ble_hs_hci_evt_le_cs_subevent_result_continue, + [BLE_HCI_LE_SUBEV_CS_TEST_END_COMPLETE] = ble_hs_hci_evt_le_cs_test_end_complete, +#endif }; #define BLE_HS_HCI_EVT_LE_DISPATCH_SZ \ @@ -127,7 +185,7 @@ static const struct ble_hs_hci_evt_dispatch_entry * ble_hs_hci_evt_dispatch_find(uint8_t event_code) { const struct ble_hs_hci_evt_dispatch_entry *entry; - int i; + unsigned int i; for (i = 0; i < BLE_HS_HCI_EVT_DISPATCH_SZ; i++) { entry = ble_hs_hci_evt_dispatch + i; @@ -155,7 +213,7 @@ ble_hs_hci_evt_disconn_complete(uint8_t event_code, const void *data, unsigned int len) { const struct ble_hci_ev_disconn_cmp *ev = data; - const struct ble_hs_conn *conn; + struct ble_hs_conn *conn; if (len != sizeof(*ev)) { return BLE_HS_ECONTROLLER; @@ -165,6 +223,7 @@ ble_hs_hci_evt_disconn_complete(uint8_t event_code, const void *data, conn = ble_hs_conn_find(le16toh(ev->conn_handle)); if (conn != NULL) { ble_hs_hci_add_avail_pkts(conn->bhc_outstanding_pkts); + conn->bhc_flags |= BLE_HS_CONN_F_TERMINATED; } ble_hs_unlock(); @@ -234,6 +293,10 @@ ble_hs_hci_evt_num_completed_pkts(uint8_t event_code, const void *data, uint16_t num_pkts; int i; + if (len < sizeof(*ev)) { + return BLE_HS_ECONTROLLER; + } + if (len != sizeof(*ev) + (ev->count * sizeof(ev->completed[0]))) { return BLE_HS_ECONTROLLER; } @@ -263,6 +326,24 @@ ble_hs_hci_evt_num_completed_pkts(uint8_t event_code, const void *data, return 0; } +#if MYNEWT_VAL(BLE_HCI_VS) +static int +ble_hs_hci_evt_vs(uint8_t event_code, const void *data, unsigned int len) +{ + const struct ble_hci_ev_vs *ev = data; + + if (len < sizeof(*ev)) { + return BLE_HS_ECONTROLLER; + } + +#if MYNEWT_VAL(BLE_HS_GAP_UNHANDLED_HCI_EVENT) + ble_gap_unhandled_hci_event(false, true, data, len); +#endif + + return 0; +} +#endif + static int ble_hs_hci_evt_le_meta(uint8_t event_code, const void *data, unsigned int len) { @@ -276,6 +357,10 @@ ble_hs_hci_evt_le_meta(uint8_t event_code, const void *data, unsigned int len) fn = ble_hs_hci_evt_le_dispatch_find(ev->subevent); if (fn) { return fn(ev->subevent, data, len); + } else { +#if MYNEWT_VAL(BLE_HS_GAP_UNHANDLED_HCI_EVENT) + ble_gap_unhandled_hci_event(true, false, data, len); +#endif } return 0; @@ -399,15 +484,13 @@ ble_hs_hci_evt_le_adv_rpt_first_pass(const void *data, unsigned int len) rpt = data; - len -= sizeof(*rpt) + 1; - data += sizeof(rpt) + 1; - if (rpt->data_len > len) { return BLE_HS_ECONTROLLER; } - len -= rpt->data_len; - data += rpt->data_len; + /* extra byte for RSSI after adv data */ + len -= sizeof(*rpt) + 1 + rpt->data_len; + data += sizeof(*rpt) + 1 + rpt->data_len; } /* Make sure length was correct */ @@ -503,44 +586,82 @@ ble_hs_hci_evt_le_rd_rem_used_feat_complete(uint8_t subevent, const void *data, static int ble_hs_hci_decode_legacy_type(uint16_t evt_type) { - switch (evt_type) { - case BLE_HCI_LEGACY_ADV_EVTYPE_ADV_IND: - return BLE_HCI_ADV_RPT_EVTYPE_ADV_IND; - case BLE_HCI_LEGACY_ADV_EVTYPE_ADV_DIRECT_IND: - return BLE_HCI_ADV_RPT_EVTYPE_DIR_IND; - case BLE_HCI_LEGACY_ADV_EVTYPE_ADV_SCAN_IND: - return BLE_HCI_ADV_RPT_EVTYPE_SCAN_IND; - case BLE_HCI_LEGACY_ADV_EVTYPE_ADV_NONCON_IND: - return BLE_HCI_ADV_RPT_EVTYPE_NONCONN_IND; - case BLE_HCI_LEGACY_ADV_EVTYPE_SCAN_RSP_ADV_IND: - return BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP; - default: - return -1; - } + switch (evt_type) { + case BLE_HCI_LEGACY_ADV_EVTYPE_ADV_IND: + return BLE_HCI_ADV_RPT_EVTYPE_ADV_IND; + case BLE_HCI_LEGACY_ADV_EVTYPE_ADV_DIRECT_IND: + return BLE_HCI_ADV_RPT_EVTYPE_DIR_IND; + case BLE_HCI_LEGACY_ADV_EVTYPE_ADV_SCAN_IND: + return BLE_HCI_ADV_RPT_EVTYPE_SCAN_IND; + case BLE_HCI_LEGACY_ADV_EVTYPE_ADV_NONCON_IND: + return BLE_HCI_ADV_RPT_EVTYPE_NONCONN_IND; + case BLE_HCI_LEGACY_ADV_EVTYPE_SCAN_RSP_ADV_IND: + case BLE_HCI_LEGACY_ADV_EVTYPE_SCAN_RSP_ADV_SCAN_IND: + return BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP; + default: + return -1; + } } -#endif static int -ble_hs_hci_evt_le_ext_adv_rpt(uint8_t subevent, const void *data, - unsigned int len) +ble_hs_hci_evt_le_ext_adv_rpt_first_pass(const void *data, unsigned int len) { -#if MYNEWT_VAL(BLE_EXT_ADV) && NIMBLE_BLE_SCAN const struct ble_hci_ev_le_subev_ext_adv_rpt *ev = data; const struct ext_adv_report *report; - struct ble_gap_ext_disc_desc desc; int i; - int legacy_event_type; if (len < sizeof(*ev)) { - return BLE_HS_EBADDATA; + return BLE_HS_ECONTROLLER; } + len -= sizeof(*ev); + data += sizeof(*ev); + if (ev->num_reports < BLE_HCI_LE_ADV_RPT_NUM_RPTS_MIN || ev->num_reports > BLE_HCI_LE_ADV_RPT_NUM_RPTS_MAX) { return BLE_HS_EBADDATA; } - /* TODO properly validate len of the event */ + for (i = 0; i < ev->num_reports; i++) { + if (len < sizeof(*report)) { + return BLE_HS_ECONTROLLER; + } + + report = data; + + if (report->data_len > len) { + return BLE_HS_ECONTROLLER; + } + + len -= sizeof(*report) + report->data_len; + data += sizeof(*report) + report->data_len; + } + + /* Make sure length was correct */ + if (len) { + return BLE_HS_ECONTROLLER; + } + + return 0; +} +#endif + +static int +ble_hs_hci_evt_le_ext_adv_rpt(uint8_t subevent, const void *data, + unsigned int len) +{ +#if MYNEWT_VAL(BLE_EXT_ADV) && NIMBLE_BLE_SCAN + const struct ble_hci_ev_le_subev_ext_adv_rpt *ev = data; + const struct ext_adv_report *report; + struct ble_gap_ext_disc_desc desc; + int legacy_event_type; + int rc; + int i; + + rc = ble_hs_hci_evt_le_ext_adv_rpt_first_pass(data, len); + if (rc != 0) { + return rc; + } report = &ev->reports[0]; for (i = 0; i < ev->num_reports; i++) { @@ -567,7 +688,8 @@ ble_hs_hci_evt_le_ext_adv_rpt(uint8_t subevent, const void *data, desc.data_status = BLE_GAP_EXT_ADV_DATA_STATUS_TRUNCATED; break; default: - assert(false); + report = (const void *) &report->data[report->data_len]; + continue; } } desc.addr.type = report->addr_type; @@ -642,6 +764,36 @@ ble_hs_hci_evt_le_periodic_adv_sync_lost(uint8_t subevent, const void *data, return 0; } +#if MYNEWT_VAL(BLE_POWER_CONTROL) +static int +ble_hs_hci_evt_le_pathloss_threshold(uint8_t subevent, const void *data, + unsigned int len) +{ + const struct ble_hci_ev_le_subev_path_loss_threshold *ev = data; + + if (len != sizeof(*ev)) { + return BLE_HS_EBADDATA; + } + + ble_gap_rx_le_pathloss_threshold(ev); + return 0; +} + +static int +ble_hs_hci_evt_le_transmit_power_report(uint8_t subevent, const void *data, + unsigned int len) +{ + const struct ble_hci_ev_le_subev_transmit_power_report *ev = data; + + if (len != sizeof(*ev)) { + return BLE_HS_EBADDATA; + } + + ble_gap_rx_transmit_power_report(ev); + return 0; +} +#endif + static int ble_hs_hci_evt_le_periodic_adv_sync_transfer(uint8_t subevent, const void *data, unsigned int len) @@ -659,6 +811,88 @@ ble_hs_hci_evt_le_periodic_adv_sync_transfer(uint8_t subevent, const void *data, return 0; } +#if MYNEWT_VAL(BLE_ISO_BROADCAST_SOURCE) +static int +ble_hs_hci_evt_le_create_big_complete(uint8_t subevent, const void *data, + unsigned int len) +{ + const struct ble_hci_ev_le_subev_create_big_complete *ev = data; + + if (len != sizeof(*ev) + (ev->num_bis * sizeof(ev->conn_handle[0]))) { + return BLE_HS_EBADDATA; + } + + ble_iso_rx_create_big_complete(ev); + + return 0; +} + +static int +ble_hs_hci_evt_le_terminate_big_complete(uint8_t subevent, const void *data, + unsigned int len) +{ + const struct ble_hci_ev_le_subev_terminate_big_complete *ev = data; + + if (len != sizeof(*ev)) { + return BLE_HS_EBADDATA; + } + + ble_iso_rx_terminate_big_complete(ev); + + return 0; +} +#endif + +#if MYNEWT_VAL(BLE_ISO_BROADCAST_SINK) +static int +ble_hs_hci_evt_le_big_sync_established(uint8_t subevent, const void *data, + unsigned int len) +{ + const struct ble_hci_ev_le_subev_big_sync_established *ev = data; + + if (len < sizeof(*ev) || + len != (sizeof(*ev) + ev->num_bis * sizeof(ev->conn_handle[0]))) { + return BLE_HS_EBADDATA; + } + + ble_iso_rx_big_sync_established(ev); + + return 0; +} + +static int +ble_hs_hci_evt_le_big_sync_lost(uint8_t subevent, const void *data, + unsigned int len) +{ + const struct ble_hci_ev_le_subev_big_sync_lost *ev = data; + + if (len != sizeof(*ev)) { + return BLE_HS_EBADDATA; + } + + ble_iso_rx_big_sync_lost(ev); + + return 0; +} +#endif + +#if MYNEWT_VAL(BLE_PERIODIC_ADV_SYNC_BIGINFO_REPORTS) +static int +ble_hs_hci_evt_le_biginfo_adv_report(uint8_t subevent, const void *data, + unsigned int len) +{ + const struct ble_hci_ev_le_subev_biginfo_adv_report *ev = data; + + if (len != sizeof(*ev)) { + return BLE_HS_EBADDATA; + } + + ble_gap_rx_biginfo_adv_rpt(ev); + + return 0; +} +#endif + static int ble_hs_hci_evt_le_scan_timeout(uint8_t subevent, const void *data, unsigned int len) @@ -686,6 +920,13 @@ ble_hs_hci_evt_le_adv_set_terminated(uint8_t subevent, const void *data, return BLE_HS_ECONTROLLER; } + /* this indicates bug in controller as host uses instances from + * 0-BLE_ADV_INSTANCES range only + */ + if (ev->adv_handle >= BLE_ADV_INSTANCES) { + return BLE_HS_ECONTROLLER; + } + if (ev->status == 0) { /* ignore return code as we need to terminate advertising set anyway */ ble_gap_rx_conn_complete(&pend_conn_complete, ev->adv_handle); @@ -707,12 +948,36 @@ ble_hs_hci_evt_le_scan_req_rcvd(uint8_t subevent, const void *data, return BLE_HS_ECONTROLLER; } + /* this indicates bug in controller as host uses instances from + * 0-BLE_ADV_INSTANCES range only + */ + if (ev->adv_handle >= BLE_ADV_INSTANCES) { + return BLE_HS_ECONTROLLER; + } + ble_gap_rx_scan_req_rcvd(ev); #endif return 0; } +#if MYNEWT_VAL(BLE_CONN_SUBRATING) +static int +ble_hs_hci_evt_le_subrate_change(uint8_t subevent, const void *data, + unsigned int len) +{ + const struct ble_hci_ev_le_subev_subrate_change *ev = data; + + if (len != sizeof(*ev)) { + return BLE_HS_ECONTROLLER; + } + + ble_gap_rx_subrate_change(ev); + + return 0; +} +#endif + #if NIMBLE_BLE_CONNECT static int ble_hs_hci_evt_le_conn_upd_complete(uint8_t subevent, const void *data, @@ -795,7 +1060,7 @@ ble_hs_hci_evt_le_phy_update_complete(uint8_t subevent, const void *data, #endif int -ble_hs_hci_evt_process(const struct ble_hci_ev *ev) +ble_hs_hci_evt_process(struct ble_hci_ev *ev) { const struct ble_hs_hci_evt_dispatch_entry *entry; int rc; @@ -806,13 +1071,16 @@ ble_hs_hci_evt_process(const struct ble_hci_ev *ev) entry = ble_hs_hci_evt_dispatch_find(ev->opcode); if (entry == NULL) { +#if MYNEWT_VAL(BLE_HS_GAP_UNHANDLED_HCI_EVENT) + ble_gap_unhandled_hci_event(false, false, ev->data, ev->length); +#endif STATS_INC(ble_hs_stats, hci_unknown_event); rc = BLE_HS_ENOTSUP; } else { rc = entry->cb(ev->opcode, ev->data, ev->length); } - ble_hci_trans_buf_free((uint8_t *) ev); + ble_transport_free(ev); return rc; } @@ -831,15 +1099,14 @@ ble_hs_hci_evt_acl_process(struct os_mbuf *om) { #if NIMBLE_BLE_CONNECT struct hci_data_hdr hci_hdr; - struct ble_hs_conn *conn; - ble_l2cap_rx_fn *rx_cb; uint16_t conn_handle; - int reject_cid; + uint8_t pb; int rc; rc = ble_hs_hci_util_data_hdr_strip(om, &hci_hdr); if (rc != 0) { - goto err; + os_mbuf_free_chain(om); + return rc; } #if (BLETEST_THROUGHPUT_TEST == 0) @@ -855,50 +1122,14 @@ ble_hs_hci_evt_acl_process(struct os_mbuf *om) #endif if (hci_hdr.hdh_len != OS_MBUF_PKTHDR(om)->omp_len) { - rc = BLE_HS_EBADDATA; - goto err; + os_mbuf_free_chain(om); + return BLE_HS_EBADDATA; } conn_handle = BLE_HCI_DATA_HANDLE(hci_hdr.hdh_handle_pb_bc); + pb = BLE_HCI_DATA_PB(hci_hdr.hdh_handle_pb_bc); + rc = ble_l2cap_rx(conn_handle, pb, om); - ble_hs_lock(); - - conn = ble_hs_conn_find(conn_handle); - if (conn == NULL) { - /* Peer not connected; quietly discard packet. */ - rc = BLE_HS_ENOTCONN; - reject_cid = -1; - } else { - /* Forward ACL data to L2CAP. */ - rc = ble_l2cap_rx(conn, &hci_hdr, om, &rx_cb, &reject_cid); - om = NULL; - } - - ble_hs_unlock(); - - switch (rc) { - case 0: - /* Final fragment received. */ - BLE_HS_DBG_ASSERT(rx_cb != NULL); - rc = rx_cb(conn->bhc_rx_chan); - ble_l2cap_remove_rx(conn, conn->bhc_rx_chan); - break; - - case BLE_HS_EAGAIN: - /* More fragments on the way. */ - break; - - default: - if (reject_cid != -1) { - ble_l2cap_sig_reject_invalid_cid_tx(conn_handle, 0, 0, reject_cid); - } - goto err; - } - - return 0; - -err: - os_mbuf_free_chain(om); return rc; #else return BLE_HS_ENOTSUP; diff --git a/nimble/host/src/ble_hs_hci_priv.h b/nimble/host/src/ble_hs_hci_priv.h index 11e544f18f..211f3f931c 100644 --- a/nimble/host/src/ble_hs_hci_priv.h +++ b/nimble/host/src/ble_hs_hci_priv.h @@ -79,6 +79,10 @@ struct hci_periodic_adv_params #endif #endif +struct ble_hs_hci_sup_cmd { + uint8_t commands[64]; +}; + extern uint16_t ble_hs_hci_avail_pkts; /* This function is not waiting for command status/complete HCI events */ @@ -91,6 +95,8 @@ void ble_hs_hci_set_le_supported_feat(uint32_t feat); uint32_t ble_hs_hci_get_le_supported_feat(void); void ble_hs_hci_set_hci_version(uint8_t hci_version); uint8_t ble_hs_hci_get_hci_version(void); +void ble_hs_hci_set_hci_supported_cmd(struct ble_hs_hci_sup_cmd sup_cmd); +struct ble_hs_hci_sup_cmd ble_hs_hci_get_hci_supported_cmd(void); #if MYNEWT_VAL(BLE_HS_PHONY_HCI_ACKS) typedef int ble_hs_hci_phony_ack_fn(uint8_t *ack, int ack_buf_len); @@ -98,14 +104,17 @@ void ble_hs_hci_set_phony_ack_cb(ble_hs_hci_phony_ack_fn *cb); #endif int ble_hs_hci_util_read_adv_tx_pwr(int8_t *out_pwr); -int ble_hs_hci_util_rand(void *dst, int len); int ble_hs_hci_util_read_rssi(uint16_t conn_handle, int8_t *out_rssi); int ble_hs_hci_util_set_random_addr(const uint8_t *addr); int ble_hs_hci_util_set_data_len(uint16_t conn_handle, uint16_t tx_octets, uint16_t tx_time); +int ble_hs_hci_util_read_sugg_def_data_len(uint16_t *out_sugg_max_tx_octets, + uint16_t *out_sugg_max_tx_time); +int ble_hs_hci_util_write_sugg_def_data_len(uint16_t sugg_max_tx_octets, + uint16_t sugg_max_tx_time); int ble_hs_hci_util_data_hdr_strip(struct os_mbuf *om, struct hci_data_hdr *out_hdr); -int ble_hs_hci_evt_process(const struct ble_hci_ev *ev); +int ble_hs_hci_evt_process(struct ble_hci_ev *ev); int ble_hs_hci_cmd_send_buf(uint16_t opcode, const void *buf, uint8_t buf_len); int ble_hs_hci_set_buf_sz(uint16_t pktlen, uint16_t max_pkts); diff --git a/nimble/host/src/ble_hs_hci_util.c b/nimble/host/src/ble_hs_hci_util.c index 996e0fc107..7803252696 100644 --- a/nimble/host/src/ble_hs_hci_util.c +++ b/nimble/host/src/ble_hs_hci_util.c @@ -22,6 +22,14 @@ #include "host/ble_hs_hci.h" #include "ble_hs_priv.h" +#ifndef min +#define min(a, b) ((a) < (b) ? (a) : (b)) +#endif + +#ifndef max +#define max(a, b) ((a) > (b) ? (a) : (b)) +#endif + uint16_t ble_hs_hci_util_handle_pb_bc_join(uint16_t handle, uint8_t pb, uint8_t bc) { @@ -58,7 +66,7 @@ ble_hs_hci_util_read_adv_tx_pwr(int8_t *out_tx_pwr) } int -ble_hs_hci_util_rand(void *dst, int len) +ble_hs_hci_rand(void *dst, int len) { struct ble_hci_le_rand_rp rsp; uint8_t *u8ptr; @@ -73,7 +81,7 @@ ble_hs_hci_util_rand(void *dst, int len) return rc; } - chunk_sz = min(len, sizeof(rsp)); + chunk_sz = min(len, (int)sizeof(rsp)); memcpy(u8ptr, &rsp.random_number, chunk_sz); len -= chunk_sz; @@ -157,6 +165,62 @@ ble_hs_hci_util_set_data_len(uint16_t conn_handle, uint16_t tx_octets, return 0; } +int +ble_hs_hci_util_read_sugg_def_data_len(uint16_t *out_sugg_max_tx_octets, + uint16_t *out_sugg_max_tx_time) +{ + struct ble_hci_le_rd_sugg_def_data_len_rp rsp; + int rc; + + rc = ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_RD_SUGG_DEF_DATA_LEN), + NULL, 0, &rsp, sizeof(rsp)); + if (rc != 0) { + return rc; + } + + *out_sugg_max_tx_octets = le16toh(rsp.max_tx_octets); + *out_sugg_max_tx_time = le16toh(rsp.max_tx_time); + + if (*out_sugg_max_tx_octets < BLE_HCI_SUGG_DEF_DATALEN_TX_OCTETS_MIN || + *out_sugg_max_tx_octets > BLE_HCI_SUGG_DEF_DATALEN_TX_OCTETS_MAX) { + BLE_HS_LOG(WARN, + "received suggested maximum tx octets is out of range\n"); + } + + if (*out_sugg_max_tx_time < BLE_HCI_SUGG_DEF_DATALEN_TX_TIME_MIN || + *out_sugg_max_tx_time > BLE_HCI_SUGG_DEF_DATALEN_TX_TIME_MAX) { + BLE_HS_LOG(WARN, + "received suggested maximum tx time is out of range\n"); + } + + return 0; +} + +int +ble_hs_hci_util_write_sugg_def_data_len(uint16_t sugg_max_tx_octets, + uint16_t sugg_max_tx_time) +{ + struct ble_hci_le_wr_sugg_def_data_len_cp cmd; + + if (sugg_max_tx_octets < BLE_HCI_SUGG_DEF_DATALEN_TX_OCTETS_MIN || + sugg_max_tx_octets > BLE_HCI_SUGG_DEF_DATALEN_TX_OCTETS_MAX) { + return BLE_HS_EINVAL; + } + + if (sugg_max_tx_time < BLE_HCI_SUGG_DEF_DATALEN_TX_TIME_MIN || + sugg_max_tx_time > BLE_HCI_SUGG_DEF_DATALEN_TX_TIME_MAX) { + return BLE_HS_EINVAL; + } + + cmd.max_tx_octets = htole16(sugg_max_tx_octets); + cmd.max_tx_time = htole16(sugg_max_tx_time); + + return ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_WR_SUGG_DEF_DATA_LEN), + &cmd, sizeof(cmd), NULL, 0); +} + int ble_hs_hci_util_data_hdr_strip(struct os_mbuf *om, struct hci_data_hdr *out_hdr) diff --git a/nimble/host/src/ble_hs_id.c b/nimble/host/src/ble_hs_id.c index e8b6c8b630..2dd21aa785 100644 --- a/nimble/host/src/ble_hs_id.c +++ b/nimble/host/src/ble_hs_id.c @@ -23,6 +23,8 @@ static uint8_t ble_hs_id_pub[6]; static uint8_t ble_hs_id_rnd[6]; +static const uint8_t ble_hs_misc_null_addr[6]; + void ble_hs_id_set_pub(const uint8_t *pub_addr) @@ -39,7 +41,7 @@ ble_hs_id_gen_rnd(int nrpa, ble_addr_t *out_addr) out_addr->type = BLE_ADDR_RANDOM; - rc = ble_hs_hci_util_rand(out_addr->val, 6); + rc = ble_hs_hci_rand(out_addr->val, 6); if (rc != 0) { return rc; } diff --git a/nimble/host/src/ble_hs_log.c b/nimble/host/src/ble_hs_log.c index 7ec69469eb..01f1ea641b 100644 --- a/nimble/host/src/ble_hs_log.c +++ b/nimble/host/src/ble_hs_log.c @@ -19,8 +19,7 @@ #include "os/os.h" #include "host/ble_hs.h" - -struct log ble_hs_log; +#include "host/ble_hs_log.h" void ble_hs_log_mbuf(const struct os_mbuf *om) diff --git a/nimble/host/src/ble_hs_mbuf.c b/nimble/host/src/ble_hs_mbuf.c index 6e920f94fe..a80392aa8e 100644 --- a/nimble/host/src/ble_hs_mbuf.c +++ b/nimble/host/src/ble_hs_mbuf.c @@ -18,6 +18,7 @@ */ #include "host/ble_hs.h" +#include "host/ble_hs_mbuf.h" #include "ble_hs_priv.h" /** @@ -91,12 +92,12 @@ ble_hs_mbuf_l2cap_pkt(void) struct os_mbuf * ble_hs_mbuf_att_pkt(void) { - /* Prepare write request and response are the larget ATT commands which + /* Prepare write request and response are the largest ATT commands which * contain attribute data. */ - return ble_hs_mbuf_gen_pkt(BLE_HCI_DATA_HDR_SZ + - BLE_L2CAP_HDR_SZ + - BLE_ATT_PREP_WRITE_CMD_BASE_SZ); + return ble_hs_mbuf_gen_pkt(BLE_HCI_DATA_HDR_SZ + + BLE_L2CAP_HDR_SZ + + BLE_ATT_PREP_WRITE_CMD_BASE_SZ); } struct os_mbuf * diff --git a/nimble/host/src/ble_hs_misc.c b/nimble/host/src/ble_hs_misc.c index dfb46b7414..c016ce75eb 100644 --- a/nimble/host/src/ble_hs_misc.c +++ b/nimble/host/src/ble_hs_misc.c @@ -22,8 +22,6 @@ #include "os/os.h" #include "ble_hs_priv.h" -const uint8_t ble_hs_misc_null_addr[6]; - int ble_hs_misc_conn_chan_find(uint16_t conn_handle, uint16_t cid, struct ble_hs_conn **out_conn, diff --git a/nimble/host/src/ble_hs_priv.h b/nimble/host/src/ble_hs_priv.h index 538d07a972..49022b17b7 100644 --- a/nimble/host/src/ble_hs_priv.h +++ b/nimble/host/src/ble_hs_priv.h @@ -24,12 +24,13 @@ #include #include "ble_att_cmd_priv.h" #include "ble_att_priv.h" +#include "ble_eatt_priv.h" #include "ble_gap_priv.h" +#include "ble_audio_codec_priv.h" #include "ble_gatt_priv.h" #include "ble_hs_hci_priv.h" #include "ble_hs_atomic_priv.h" #include "ble_hs_conn_priv.h" -#include "ble_hs_atomic_priv.h" #include "ble_hs_mbuf_priv.h" #include "ble_hs_startup_priv.h" #include "ble_l2cap_priv.h" @@ -43,7 +44,6 @@ #include "ble_hs_periodic_sync_priv.h" #include "ble_uuid_priv.h" #include "host/ble_hs.h" -#include "host/ble_monitor.h" #include "nimble/nimble_opt.h" #include "stats/stats.h" #ifdef __cplusplus @@ -96,8 +96,6 @@ extern struct os_mbuf_pool ble_hs_mbuf_pool; extern uint8_t ble_hs_sync_state; extern uint8_t ble_hs_enabled_state; -extern const uint8_t ble_hs_misc_null_addr[6]; - extern uint16_t ble_hs_max_attrs; extern uint16_t ble_hs_max_services; extern uint16_t ble_hs_max_client_configs; diff --git a/nimble/host/src/ble_hs_pvcy.c b/nimble/host/src/ble_hs_pvcy.c index dc09b51ba8..c122633563 100644 --- a/nimble/host/src/ble_hs_pvcy.c +++ b/nimble/host/src/ble_hs_pvcy.c @@ -59,8 +59,8 @@ ble_hs_pvcy_set_resolve_enabled(int enable) &cmd, sizeof(cmd), NULL, 0); } -int -ble_hs_pvcy_remove_entry(uint8_t addr_type, const uint8_t *addr) +static int +ble_hs_pvcy_remove_entry_hci(uint8_t addr_type, const uint8_t *addr) { struct ble_hci_le_rmv_resolve_list_cp cmd; @@ -76,6 +76,21 @@ ble_hs_pvcy_remove_entry(uint8_t addr_type, const uint8_t *addr) &cmd, sizeof(cmd), NULL, 0); } +int +ble_hs_pvcy_remove_entry(uint8_t addr_type, const uint8_t *addr) +{ + int rc; + + /* Need to preempt all GAP procedures (advertising, pending connections) + * before modifying resolving list in the controller + */ + ble_gap_preempt(); + rc = ble_hs_pvcy_remove_entry_hci(addr_type, addr); + ble_gap_preempt_done(); + + return rc; +} + static int ble_hs_pvcy_clear_entries(void) { @@ -246,3 +261,10 @@ ble_hs_pvcy_set_mode(const ble_addr_t *addr, uint8_t priv_mode) BLE_HCI_OCF_LE_SET_PRIVACY_MODE), &cmd, sizeof(cmd), NULL, 0); } + +void +ble_hs_pvcy_reset(void) +{ + ble_hs_pvcy_started = 0; + memset(ble_hs_pvcy_irk, 0, sizeof(ble_hs_pvcy_irk)); +} diff --git a/nimble/host/src/ble_hs_pvcy_priv.h b/nimble/host/src/ble_hs_pvcy_priv.h index 7f0aa4b907..59a132cd4d 100644 --- a/nimble/host/src/ble_hs_pvcy_priv.h +++ b/nimble/host/src/ble_hs_pvcy_priv.h @@ -35,6 +35,7 @@ int ble_hs_pvcy_add_entry(const uint8_t *addr, uint8_t addrtype, const uint8_t *irk); int ble_hs_pvcy_ensure_started(void); int ble_hs_pvcy_set_mode(const ble_addr_t *addr, uint8_t priv_mode); +void ble_hs_pvcy_reset(void); #ifdef __cplusplus } diff --git a/nimble/host/src/ble_hs_shutdown.c b/nimble/host/src/ble_hs_shutdown.c index f29d4a6692..bdd7f727df 100644 --- a/nimble/host/src/ble_hs_shutdown.c +++ b/nimble/host/src/ble_hs_shutdown.c @@ -17,7 +17,7 @@ * under the License. */ -#if MYNEWT +#ifdef MYNEWT #include "os/mynewt.h" #include "ble_hs_priv.h" diff --git a/nimble/host/src/ble_hs_startup.c b/nimble/host/src/ble_hs_startup.c index 83026ac18b..2f95880be9 100644 --- a/nimble/host/src/ble_hs_startup.c +++ b/nimble/host/src/ble_hs_startup.c @@ -40,7 +40,7 @@ ble_hs_startup_read_sup_f_tx(void) /* for now we don't use it outside of init sequence so check this here * LE Supported (Controller) byte 4, bit 6 */ - if (!(rsp.features & 0x0000006000000000)) { + if (!(le64toh(rsp.features) & 0x0000006000000000)) { BLE_HS_LOG(ERROR, "Controller doesn't support LE\n"); return BLE_HS_ECONTROLLER; } @@ -68,6 +68,26 @@ ble_hs_startup_read_local_ver_tx(void) return 0; } +static int +ble_hs_startup_read_sup_cmd_tx(void) +{ + struct ble_hci_ip_rd_loc_supp_cmd_rp rsp; + struct ble_hs_hci_sup_cmd sup_cmd; + int rc; + + rc = ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_INFO_PARAMS, + BLE_HCI_OCF_IP_RD_LOC_SUPP_CMD), + NULL, 0, &rsp, sizeof(rsp)); + if (rc != 0) { + return rc; + } + + memcpy(&sup_cmd.commands, &rsp.commands, sizeof(sup_cmd)); + ble_hs_hci_set_hci_supported_cmd(sup_cmd); + + return 0; +} + static int ble_hs_startup_le_read_sup_f_tx(void) { @@ -86,6 +106,7 @@ ble_hs_startup_le_read_sup_f_tx(void) return 0; } +#if MYNEWT_VAL(BLE_ROLE_CENTRAL) || MYNEWT_VAL(BLE_ROLE_PERIPHERAL) static int ble_hs_startup_le_read_buf_sz_tx(uint16_t *out_pktlen, uint8_t *out_max_pkts) { @@ -155,6 +176,7 @@ ble_hs_startup_read_buf_sz(void) return 0; } +#endif static int ble_hs_startup_read_bd_addr(void) @@ -238,6 +260,76 @@ ble_hs_startup_le_set_evmask_tx(void) } #endif +#if MYNEWT_VAL(BLE_CONN_SUBRATING) + if (version >= BLE_HCI_VER_BCS_5_3) { + /** + * Enable the following LE events: + * 0x0000000400000000 LE Subrate change event + */ + mask |= 0x0000000400000000; + } +#endif + +#if MYNEWT_VAL(BLE_POWER_CONTROL) + if (version >= BLE_HCI_VER_BCS_5_2) { + /** + * Enable the following LE events: + * 0x0000000080000000 LE Path Loss Threshold event + * 0x0000000100000000 LE Transmit Power Reporting event + */ + mask |= 0x0000000180000000; + } +#endif + +#if MYNEWT_VAL(BLE_PERIODIC_ADV_SYNC_BIGINFO_REPORTS) + if (version >= BLE_HCI_VER_BCS_5_2) { + /** + * Enable the following LE events: + * 0x0000000200000000 LE BIGInfo Advertising Report event + */ + mask |= 0x0000000200000000; + } +#endif + +#if MYNEWT_VAL(BLE_ISO_BROADCAST_SOURCE) + if (version >= BLE_HCI_VER_BCS_5_2) { + /** + * Enable the following LE events: + * 0x0000000004000000 LE Create BIG Complete event + * 0x0000000008000000 LE Terminate BIG Complete event + */ + mask |= 0x000000000C000000; + } +#endif + +#if MYNEWT_VAL(BLE_ISO_BROADCAST_SINK) + if (version >= BLE_HCI_VER_BCS_5_2) { + /** + * Enable the following LE events: + * 0x0000000010000000 LE BIG Sync Established Complete event + * 0x0000000020000000 LE BIG Sync lost event + */ + mask |= 0x0000000030000000; + } +#endif + +#if MYNEWT_VAL(BLE_CHANNEL_SOUNDING) + if (version >= BLE_HCI_VER_BCS_5_4) { + /** + * Enable the following LE events: + * 0x0000080000000000 LE CS Read Remote Supported Capabilities Complete event + * 0x0000100000000000 LE CS Read Remote FAE Table Complete event + * 0x0000200000000000 LE CS Security Enable Complete event + * 0x0000400000000000 LE CS Config Complete event + * 0x0000800000000000 LE CS Procedure Enable Complete event + * 0x0001000000000000 LE CS Subevent Result event + * 0x0002000000000000 LE CS Subevent Result Continue event + * 0x0004000000000000 LE CS Test End Complete event + */ + mask |= 0x0007f80000000000; + } +#endif + cmd.event_mask = htole64(mask); rc = ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE, @@ -256,9 +348,11 @@ ble_hs_startup_set_evmask_tx(void) struct ble_hci_cb_set_event_mask_cp cmd; struct ble_hci_cb_set_event_mask2_cp cmd2; uint8_t version; + struct ble_hs_hci_sup_cmd sup_cmd; int rc; version = ble_hs_hci_get_hci_version(); + sup_cmd = ble_hs_hci_get_hci_supported_cmd(); /** * Enable the following events: @@ -278,7 +372,7 @@ ble_hs_startup_set_evmask_tx(void) return rc; } - if (version >= BLE_HCI_VER_BCS_4_1) { + if ((version >= BLE_HCI_VER_BCS_4_1) && ((sup_cmd.commands[22] & 0x04) != 0)) { /** * Enable the following events: * 0x0000000000800000 Authenticated Payload Timeout Event @@ -306,6 +400,7 @@ ble_hs_startup_reset_tx(void) int ble_hs_startup_go(void) { + struct ble_store_gen_key gen_key; int rc; rc = ble_hs_startup_reset_tx(); @@ -318,7 +413,11 @@ ble_hs_startup_go(void) return rc; } - /* XXX: Read local supported commands. */ + /* Read local supported commands. */ + rc = ble_hs_startup_read_sup_cmd_tx(); + if (rc != 0) { + return rc; + } /* we need to check this only if using external controller */ #if !MYNEWT_VAL(BLE_CONTROLLER) @@ -343,10 +442,12 @@ ble_hs_startup_go(void) return rc; } +#if MYNEWT_VAL(BLE_ROLE_CENTRAL) || MYNEWT_VAL(BLE_ROLE_PERIPHERAL) rc = ble_hs_startup_read_buf_sz(); if (rc != 0) { return rc; } +#endif rc = ble_hs_startup_le_read_sup_f_tx(); if (rc != 0) { @@ -358,7 +459,20 @@ ble_hs_startup_go(void) return rc; } - ble_hs_pvcy_set_our_irk(NULL); + if (ble_hs_cfg.store_gen_key_cb) { + memset(&gen_key, 0, sizeof(gen_key)); + rc = ble_hs_cfg.store_gen_key_cb(BLE_STORE_GEN_KEY_IRK, &gen_key, + BLE_HS_CONN_HANDLE_NONE); + if (rc == 0) { + ble_hs_pvcy_set_our_irk(gen_key.irk); + } + } else { + rc = -1; + } + + if (rc != 0) { + ble_hs_pvcy_set_our_irk(NULL); + } /* If flow control is enabled, configure the controller to use it. */ ble_hs_flow_startup(); diff --git a/nimble/host/src/ble_hs_stop.c b/nimble/host/src/ble_hs_stop.c index b90d3ec6fc..c0ff67e455 100644 --- a/nimble/host/src/ble_hs_stop.c +++ b/nimble/host/src/ble_hs_stop.c @@ -21,6 +21,7 @@ #include "sysinit/sysinit.h" #include "syscfg/syscfg.h" #include "ble_hs_priv.h" +#include "host/ble_hs_stop.h" #include "nimble/nimble_npl.h" #ifndef MYNEWT #include "nimble/nimble_port.h" @@ -41,6 +42,13 @@ static uint8_t ble_hs_stop_conn_cnt; static struct ble_npl_callout ble_hs_stop_terminate_tmo; +static int +ble_hs_stop_hci_reset(void) +{ + return ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_CTLR_BASEBAND, BLE_HCI_OCF_CB_RESET), + NULL, 0, NULL, 0); +} + /** * Called when a stop procedure has completed. */ @@ -61,6 +69,16 @@ ble_hs_stop_done(int status) ble_hs_enabled_state = BLE_HS_ENABLED_STATE_OFF; + ble_hs_stop_hci_reset(); + + /* Clear advertising, scanning and connection states. */ + ble_gap_reset_state(0); + + /* After LL reset the controller loses its random address */ + ble_hs_id_reset(); + + ble_hs_pvcy_reset(); + ble_hs_unlock(); SLIST_FOREACH(listener, &slist, link) { @@ -113,7 +131,7 @@ ble_hs_stop_terminate_conn(struct ble_hs_conn *conn, void *arg) int rc; rc = ble_gap_terminate_with_conn(conn, BLE_ERR_REM_USER_CONN_TERM); - if (rc == 0) { + if (rc == 0 || rc == BLE_HS_EALREADY) { /* Terminate procedure successfully initiated. Let the GAP event * handler deal with the result. */ @@ -217,7 +235,7 @@ ble_hs_stop_begin(struct ble_hs_stop_listener *listener, } int -ble_hs_stop(struct ble_hs_stop_listener *listener, +ble_hs_stop(struct ble_hs_stop_listener *listener, ble_hs_stop_fn *fn, void *arg) { int rc; @@ -255,6 +273,8 @@ ble_hs_stop(struct ble_hs_stop_listener *listener, return rc; } + ble_hs_stop_conn_cnt = 0; + ble_hs_lock(); ble_hs_conn_foreach(ble_hs_stop_terminate_conn, NULL); ble_hs_unlock(); diff --git a/nimble/host/src/ble_ibeacon.c b/nimble/host/src/ble_ibeacon.c index 0c6ef99d5b..bbd353cc98 100644 --- a/nimble/host/src/ble_ibeacon.c +++ b/nimble/host/src/ble_ibeacon.c @@ -19,6 +19,7 @@ #include #include "host/ble_hs_adv.h" +#include "host/ble_ibeacon.h" #include "ble_hs_priv.h" #define BLE_IBEACON_MFG_DATA_SIZE 25 diff --git a/nimble/host/src/ble_iso.c b/nimble/host/src/ble_iso.c new file mode 100644 index 0000000000..600e7ed5bf --- /dev/null +++ b/nimble/host/src/ble_iso.c @@ -0,0 +1,981 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "syscfg/syscfg.h" + +#if MYNEWT_VAL(BLE_ISO) +#include "os/os_mbuf.h" +#include "host/ble_hs_log.h" +#include "host/ble_hs.h" +#include "host/ble_iso.h" +#include "nimble/hci_common.h" +#include "sys/queue.h" +#include "ble_hs_priv.h" +#include "ble_hs_hci_priv.h" +#include "ble_hs_mbuf_priv.h" + +#ifndef min +#define min(a, b) ((a) < (b) ? (a) : (b)) +#endif + +#define ble_iso_big_conn_handles_init(_big, _handles, _num_handles) \ + do { \ + struct ble_iso_conn *conn = SLIST_FIRST(&ble_iso_conns); \ + \ + for (uint8_t i = 0; i < (_num_handles); i++) { \ + while (conn != NULL) { \ + if (conn->type == BLE_ISO_CONN_BIS) { \ + struct ble_iso_bis *bis; \ + \ + bis = CONTAINER_OF(conn, struct ble_iso_bis, conn); \ + if (bis->big == (_big)) { \ + conn->handle = le16toh((_handles)[i]); \ + conn = SLIST_NEXT(conn, next); \ + break; \ + } \ + } \ + \ + conn = SLIST_NEXT(conn, next); \ + } \ + } \ + } while (0); + +enum ble_iso_conn_type { + BLE_ISO_CONN_BIS, +}; + +struct ble_iso_big { + SLIST_ENTRY(ble_iso_big) next; + uint8_t handle; + uint16_t max_pdu; + uint8_t bis_cnt; + + ble_iso_event_fn *cb; + void *cb_arg; +}; + +struct ble_iso_conn { + SLIST_ENTRY(ble_iso_conn) next; + enum ble_iso_conn_type type; + uint8_t handle; + + struct ble_iso_rx_data_info rx_info; + struct os_mbuf *rx_buf; + + ble_iso_event_fn *cb; + void *cb_arg; +}; + +struct ble_iso_bis { + struct ble_iso_conn conn; + struct ble_iso_big *big; +}; + +static SLIST_HEAD(, ble_iso_big) ble_iso_bigs; +static SLIST_HEAD(, ble_iso_conn) ble_iso_conns; +static struct os_mempool ble_iso_big_pool; +static os_membuf_t ble_iso_big_mem[ + OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_ISO_MAX_BIGS), sizeof (struct ble_iso_big))]; +static struct os_mempool ble_iso_bis_pool; +static os_membuf_t ble_iso_bis_mem[ + OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_ISO_MAX_BISES), sizeof (struct ble_iso_bis))]; + +static void +ble_iso_conn_append(struct ble_iso_conn *conn) +{ + struct ble_iso_conn *entry, *prev = NULL; + + SLIST_FOREACH(entry, &ble_iso_conns, next) { + prev = entry; + } + + if (prev == NULL) { + SLIST_INSERT_HEAD(&ble_iso_conns, conn, next); + } else { + SLIST_INSERT_AFTER(prev, conn, next); + } +} + +static int +ble_iso_big_handle_set(struct ble_iso_big *big) +{ + static uint8_t free_handle; + uint8_t i; + + /* Set next free handle */ + for (i = BLE_HCI_ISO_BIG_HANDLE_MIN; i < BLE_HCI_ISO_BIG_HANDLE_MAX; i++) { + struct ble_iso_big *node = NULL; + + if (free_handle > BLE_HCI_ISO_BIG_HANDLE_MAX) { + free_handle = BLE_HCI_ISO_BIG_HANDLE_MIN; + } + + big->handle = free_handle++; + + SLIST_FOREACH(node, &ble_iso_bigs, next) { + if (node->handle == big->handle) { + break; + } + } + + if (node == NULL || node->handle != big->handle) { + return 0; + } + } + + BLE_HS_DBG_ASSERT(0); + + return BLE_HS_EOS; +} + +static struct ble_iso_big * +ble_iso_big_alloc(void) +{ + struct ble_iso_big *new_big; + int rc; + + new_big = os_memblock_get(&ble_iso_big_pool); + if (new_big == NULL) { + BLE_HS_LOG_ERROR("No more memory in pool\n"); + /* Out of memory. */ + return NULL; + } + + memset(new_big, 0, sizeof *new_big); + + rc = ble_iso_big_handle_set(new_big); + if (rc != 0) { + os_memblock_put(&ble_iso_big_pool, new_big); + return NULL; + } + + SLIST_INSERT_HEAD(&ble_iso_bigs, new_big, next); + + return new_big; +} + +static struct ble_iso_bis * +ble_iso_bis_alloc(struct ble_iso_big *big) +{ + struct ble_iso_bis *new_bis; + + new_bis = os_memblock_get(&ble_iso_bis_pool); + if (new_bis == NULL) { + BLE_HS_LOG_ERROR("No more memory in pool\n"); + /* Out of memory. */ + return NULL; + } + + memset(new_bis, 0, sizeof *new_bis); + new_bis->conn.type = BLE_ISO_CONN_BIS; + new_bis->big = big; + + ble_iso_conn_append(&new_bis->conn); + + return new_bis; +} + +static struct ble_iso_big * +ble_iso_big_find_by_handle(uint8_t big_handle) +{ + struct ble_iso_big *big; + + SLIST_FOREACH(big, &ble_iso_bigs, next) { + if (big->handle == big_handle) { + return big; + } + } + + return NULL; +} + +static int +ble_iso_big_free(struct ble_iso_big *big) +{ + struct ble_iso_conn *conn; + struct ble_iso_bis *rem_bis[MYNEWT_VAL(BLE_ISO_MAX_BISES)] = { + [0 ... MYNEWT_VAL(BLE_ISO_MAX_BISES) - 1] = NULL + }; + uint8_t i = 0; + + SLIST_FOREACH(conn, &ble_iso_conns, next) { + struct ble_iso_bis *bis; + + if (conn->type != BLE_ISO_CONN_BIS) { + continue; + } + + bis = CONTAINER_OF(conn, struct ble_iso_bis, conn); + if (bis->big == big) { + SLIST_REMOVE(&ble_iso_conns, conn, ble_iso_conn, next); + rem_bis[i++] = bis; + } + } + + while (i > 0) { + os_memblock_put(&ble_iso_bis_pool, rem_bis[--i]); + } + + SLIST_REMOVE(&ble_iso_bigs, big, ble_iso_big, next); + os_memblock_put(&ble_iso_big_pool, big); + return 0; +} + +static struct ble_iso_conn * +ble_iso_conn_lookup_handle(uint16_t handle) +{ + struct ble_iso_conn *conn; + + SLIST_FOREACH(conn, &ble_iso_conns, next) { + if (conn->handle == handle) { + return conn; + } + } + + return NULL; +} + +#if MYNEWT_VAL(BLE_ISO_BROADCAST_SOURCE) +int +ble_iso_create_big(const struct ble_iso_create_big_params *create_params, + const struct ble_iso_big_params *big_params, + uint8_t *big_handle) +{ + struct ble_hci_le_create_big_cp cp = { 0 }; + struct ble_iso_big *big; + int rc; + + cp.adv_handle = create_params->adv_handle; + if (create_params->bis_cnt > MYNEWT_VAL(BLE_ISO_MAX_BISES)) { + return BLE_HS_EINVAL; + } + + big = ble_iso_big_alloc(); + if (big == NULL) { + return BLE_HS_ENOMEM; + } + + big->bis_cnt = create_params->bis_cnt; + big->cb = create_params->cb; + big->cb_arg = create_params->cb_arg; + + for (uint8_t i = 0; i < create_params->bis_cnt; i++) { + struct ble_iso_bis *bis; + + bis = ble_iso_bis_alloc(big); + if (bis == NULL) { + ble_iso_big_free(big); + return BLE_HS_ENOMEM; + } + } + + cp.adv_handle = create_params->adv_handle; + cp.num_bis = create_params->bis_cnt; + put_le24(cp.sdu_interval, big_params->sdu_interval); + cp.max_sdu = big_params->max_sdu; + cp.max_transport_latency = big_params->max_transport_latency; + cp.rtn = big_params->rtn; + cp.phy = big_params->phy; + cp.packing = big_params->packing; + cp.framing = big_params->framing; + cp.encryption = big_params->encryption; + if (big_params->encryption) { + memcpy(cp.broadcast_code, big_params->broadcast_code, 16); + } + + rc = ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_CREATE_BIG), + &cp, sizeof(cp),NULL, 0); + if (rc != 0) { + ble_iso_big_free(big); + } else { + *big_handle = big->handle; + } + + return rc; +} + +int +ble_iso_terminate_big(uint8_t big_handle) +{ + struct ble_hci_le_terminate_big_cp cp; + struct ble_iso_big *big; + int rc; + + big = ble_iso_big_find_by_handle(big_handle); + if (big == NULL) { + BLE_HS_LOG_ERROR("No BIG with handle=%d\n", big_handle); + return BLE_HS_ENOENT; + } + + cp.big_handle = big->handle; + cp.reason = BLE_ERR_CONN_TERM_LOCAL; + + rc = ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_TERMINATE_BIG), + &cp, sizeof(cp),NULL, 0); + + return rc; +} + +void +ble_iso_rx_create_big_complete(const struct ble_hci_ev_le_subev_create_big_complete *ev) +{ + struct ble_iso_event event; + struct ble_iso_big *big; + + big = ble_iso_big_find_by_handle(ev->big_handle); + if (big == NULL) { + BLE_HS_LOG_ERROR("No BIG with handle=%d\n", ev->big_handle); + return; + } + + memset(&event, 0, sizeof(event)); + event.type = BLE_ISO_EVENT_BIG_CREATE_COMPLETE; + event.big_created.status = ev->status; + + if (event.big_created.status != 0) { + ble_iso_big_free(big); + } else { + if (big->bis_cnt != ev->num_bis) { + BLE_HS_LOG_ERROR("Unexpected num_bis=%d != bis_cnt=%d\n", + ev->num_bis, big->bis_cnt); + /* XXX: Should we destroy the group? */ + } + + ble_iso_big_conn_handles_init(big, ev->conn_handle, ev->num_bis); + + big->max_pdu = ev->max_pdu; + + event.big_created.desc.big_handle = ev->big_handle; + event.big_created.desc.big_sync_delay = get_le24(ev->big_sync_delay); + event.big_created.desc.transport_latency_big = + get_le24(ev->transport_latency_big); + event.big_created.desc.nse = ev->nse; + event.big_created.desc.bn = ev->bn; + event.big_created.desc.pto = ev->pto; + event.big_created.desc.irc = ev->irc; + event.big_created.desc.max_pdu = ev->max_pdu; + event.big_created.desc.iso_interval = ev->iso_interval; + event.big_created.desc.num_bis = ev->num_bis; + memcpy(event.big_created.desc.conn_handle, ev->conn_handle, + ev->num_bis * sizeof(uint16_t)); + event.big_created.phy = ev->phy; + } + + if (big->cb != NULL) { + big->cb(&event, big->cb_arg); + } +} + +void +ble_iso_rx_terminate_big_complete(const struct ble_hci_ev_le_subev_terminate_big_complete *ev) +{ + struct ble_iso_event event; + struct ble_iso_big *big; + + big = ble_iso_big_find_by_handle(ev->big_handle); + if (big == NULL) { + BLE_HS_LOG_ERROR("No BIG with handle=%d\n", ev->big_handle); + return; + } + + event.type = BLE_ISO_EVENT_BIG_TERMINATE_COMPLETE; + event.big_terminated.big_handle = ev->big_handle; + event.big_terminated.reason = ev->reason; + + if (big->cb != NULL) { + big->cb(&event, big->cb_arg); + } + + ble_iso_big_free(big); +} + +static int +ble_iso_tx_complete(uint16_t conn_handle, const uint8_t *data, + uint16_t data_len) +{ + struct os_mbuf *om; + int rc; + + om = ble_hs_mbuf_bare_pkt(); + if (!om) { + return BLE_HS_ENOMEM; + } + + os_mbuf_extend(om, 8); + /* Connection_Handle, PB_Flag, TS_Flag */ + put_le16(&om->om_data[0], + BLE_HCI_ISO_HANDLE(conn_handle, BLE_HCI_ISO_PB_COMPLETE, 0)); + /* Data_Total_Length = Data length + Packet_Sequence_Number placeholder */ + put_le16(&om->om_data[2], data_len + 4); + /* Packet_Sequence_Number placeholder */ + put_le16(&om->om_data[4], 0); + /* ISO_SDU_Length */ + put_le16(&om->om_data[6], data_len); + + rc = os_mbuf_append(om, data, data_len); + if (rc) { + return rc; + } + + return ble_transport_to_ll_iso(om); +} + +static int +ble_iso_tx_segmented(uint16_t conn_handle, const uint8_t *data, + uint16_t data_len) +{ + struct os_mbuf *om; + uint16_t data_left = data_len; + uint16_t packet_len; + uint16_t offset = 0; + uint8_t pb; + int rc; + + while (data_left) { + packet_len = min(MYNEWT_VAL(BLE_TRANSPORT_ISO_SIZE), data_left); + if (data_left == data_len) { + pb = BLE_HCI_ISO_PB_FIRST; + } else if (packet_len == data_left) { + pb = BLE_HCI_ISO_PB_LAST; + } else { + pb = BLE_HCI_ISO_PB_CONTINUATION; + } + + om = ble_hs_mbuf_bare_pkt(); + if (!om) { + return BLE_HS_ENOMEM; + } + + os_mbuf_extend(om, pb == BLE_HCI_ISO_PB_FIRST ? 8: 4); + + /* Connection_Handle, PB_Flag, TS_Flag */ + put_le16(&om->om_data[0], + BLE_HCI_ISO_HANDLE(conn_handle, pb, 0)); + + if (pb == BLE_HCI_ISO_PB_FIRST) { + /* Data_Total_Length = Data length + + * Packet_Sequence_Number placeholder*/ + put_le16(&om->om_data[2], packet_len + 4); + + /* Packet_Sequence_Number placeholder */ + put_le16(&om->om_data[8], 0); + + /* ISO_SDU_Length */ + put_le16(&om->om_data[10], packet_len); + } else { + put_le16(&om->om_data[2], packet_len); + } + + rc = os_mbuf_append(om, data + offset, packet_len); + if (rc) { + return rc; + } + + ble_transport_to_ll_iso(om); + + offset += packet_len; + data_left -= packet_len; + } + + return 0; +} + +int +ble_iso_tx(uint16_t conn_handle, void *data, uint16_t data_len) +{ + int rc; + + if (data_len <= MYNEWT_VAL(BLE_TRANSPORT_ISO_SIZE)) { + rc = ble_iso_tx_complete(conn_handle, data, data_len); + } else { + rc = ble_iso_tx_segmented(conn_handle, data, data_len); + } + + return rc; +} +#endif /* BLE_ISO_BROADCAST_SOURCE */ + +#if MYNEWT_VAL(BLE_ISO_BROADCAST_SINK) +int +ble_iso_big_sync_create(const struct ble_iso_big_sync_create_params *param, + uint8_t *big_handle) +{ + struct ble_hci_le_big_create_sync_cp *cp; + uint8_t buf[sizeof(*cp) + MYNEWT_VAL(BLE_ISO_MAX_BISES)]; + struct ble_iso_big *big; + int rc; + + big = ble_iso_big_alloc(); + if (big == NULL) { + return BLE_HS_ENOMEM; + } + + big->bis_cnt = param->bis_cnt; + big->cb = param->cb; + big->cb_arg = param->cb_arg; + + cp = (void *)buf; + cp->big_handle = big->handle; + put_le16(&cp->sync_handle, param->sync_handle); + + if (param->broadcast_code != NULL) { + cp->encryption = BLE_HCI_ISO_BIG_ENCRYPTION_ENCRYPTED; + memcpy(cp->broadcast_code, param->broadcast_code, sizeof(cp->broadcast_code)); + } else { + cp->encryption = BLE_HCI_ISO_BIG_ENCRYPTION_UNENCRYPTED; + memset(cp->broadcast_code, 0, sizeof(cp->broadcast_code)); + } + + cp->mse = param->mse; + put_le16(&cp->sync_timeout, param->sync_timeout); + cp->num_bis = param->bis_cnt; + + for (uint8_t i = 0; i < param->bis_cnt; i++) { + struct ble_iso_bis *bis; + + bis = ble_iso_bis_alloc(big); + if (bis == NULL) { + ble_iso_big_free(big); + return BLE_HS_ENOMEM; + } + + cp->bis[i] = param->bis_params[i].bis_index; + } + + rc = ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_BIG_CREATE_SYNC), + cp, sizeof(*cp) + cp->num_bis, NULL, 0); + if (rc != 0) { + ble_iso_big_free(big); + } else { + *big_handle = big->handle; + } + + return rc; +} + +int +ble_iso_big_sync_terminate(uint8_t big_handle) +{ + struct ble_hci_le_big_terminate_sync_cp cp; + struct ble_hci_le_big_terminate_sync_rp rp; + struct ble_iso_big *big; + int rc; + + big = ble_iso_big_find_by_handle(big_handle); + if (big == NULL) { + BLE_HS_LOG_ERROR("No BIG with handle=%d\n", big_handle); + return BLE_HS_ENOENT; + } + + cp.big_handle = big->handle; + + rc = ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_BIG_TERMINATE_SYNC), + &cp, sizeof(cp), &rp, sizeof(rp)); + if (rc == 0) { + struct ble_iso_event event; + ble_iso_event_fn *cb; + void *cb_arg; + + event.type = BLE_ISO_EVENT_BIG_SYNC_TERMINATED; + event.big_terminated.big_handle = big_handle; + event.big_terminated.reason = BLE_ERR_CONN_TERM_LOCAL; + + cb = big->cb; + cb_arg = big->cb_arg; + + ble_iso_big_free(big); + + if (cb != NULL) { + cb(&event, cb_arg); + } + } + + return rc; +} + +void +ble_iso_rx_big_sync_established(const struct ble_hci_ev_le_subev_big_sync_established *ev) +{ + struct ble_iso_event event; + struct ble_iso_big *big; + ble_iso_event_fn *cb; + void *cb_arg; + + big = ble_iso_big_find_by_handle(ev->big_handle); + if (big == NULL) { + return; + } + + cb = big->cb; + cb_arg = big->cb_arg; + + memset(&event, 0, sizeof(event)); + event.type = BLE_ISO_EVENT_BIG_SYNC_ESTABLISHED; + event.big_sync_established.status = ev->status; + + if (event.big_sync_established.status != 0) { + ble_iso_big_free(big); + } else { + if (big->bis_cnt != ev->num_bis) { + BLE_HS_LOG_ERROR("Unexpected num_bis=%d != bis_cnt=%d\n", + ev->num_bis, big->bis_cnt); + /* XXX: Should we destroy the group? */ + } + + ble_iso_big_conn_handles_init(big, ev->conn_handle, ev->num_bis); + + event.big_sync_established.desc.big_handle = ev->big_handle; + event.big_sync_established.desc.transport_latency_big = + get_le24(ev->transport_latency_big); + event.big_sync_established.desc.nse = ev->nse; + event.big_sync_established.desc.bn = ev->bn; + event.big_sync_established.desc.pto = ev->pto; + event.big_sync_established.desc.irc = ev->irc; + event.big_sync_established.desc.max_pdu = le16toh(ev->max_pdu); + event.big_sync_established.desc.iso_interval = le16toh(ev->iso_interval); + event.big_sync_established.desc.num_bis = ev->num_bis; + memcpy(event.big_sync_established.desc.conn_handle, ev->conn_handle, + ev->num_bis * sizeof(uint16_t)); + } + + if (cb != NULL) { + cb(&event, cb_arg); + } +} + +void +ble_iso_rx_big_sync_lost(const struct ble_hci_ev_le_subev_big_sync_lost *ev) +{ + struct ble_iso_event event; + struct ble_iso_big *big; + ble_iso_event_fn *cb; + void *cb_arg; + + big = ble_iso_big_find_by_handle(ev->big_handle); + if (big == NULL) { + BLE_HS_LOG_ERROR("No BIG with handle=%d\n", ev->big_handle); + return; + } + + event.type = BLE_ISO_EVENT_BIG_SYNC_TERMINATED; + event.big_terminated.big_handle = ev->big_handle; + event.big_terminated.reason = ev->reason; + + cb = big->cb; + cb_arg = big->cb_arg; + + ble_iso_big_free(big); + + if (cb != NULL) { + cb(&event, cb_arg); + } +} + +static int +ble_iso_rx_data_info_parse(struct os_mbuf *om, bool ts_available, + struct ble_iso_rx_data_info *info) +{ + struct ble_hci_iso_data *iso_data; + uint16_t u16; + + if (ts_available) { + if (os_mbuf_len(om) < sizeof(info->ts)) { + BLE_HS_LOG_DEBUG("Data missing\n"); + return BLE_HS_EMSGSIZE; + } + + info->ts = get_le32(om->om_data); + os_mbuf_adj(om, sizeof(info->ts)); + } else { + info->ts = 0; + } + + if (os_mbuf_len(om) < sizeof(*iso_data)) { + BLE_HS_LOG_DEBUG("Data missing\n"); + return BLE_HS_EMSGSIZE; + } + + iso_data = (void *)(om->om_data); + + info->seq_num = le16toh(iso_data->packet_seq_num); + u16 = le16toh(iso_data->sdu_len); + info->sdu_len = BLE_HCI_ISO_SDU_LENGTH(u16); + info->status = BLE_HCI_ISO_PKT_STATUS_FLAG(u16); + info->ts_valid = ts_available; + + os_mbuf_adj(om, sizeof(*iso_data)); + + return 0; +} + +static void +ble_iso_conn_rx_reset(struct ble_iso_conn *conn) +{ + memset(&conn->rx_info, 0, sizeof(conn->rx_info)); + conn->rx_buf = NULL; +} + +static void +ble_iso_conn_rx_data_discard(struct ble_iso_conn *conn) +{ + os_mbuf_free_chain(conn->rx_buf); + ble_iso_conn_rx_reset(conn); +} + +static void +ble_iso_event_iso_rx_emit(struct ble_iso_conn *conn) +{ + struct ble_iso_event event = { + .type = BLE_ISO_EVENT_ISO_RX, + .iso_rx.conn_handle = conn->handle, + .iso_rx.info = &conn->rx_info, + .iso_rx.om = conn->rx_buf, + }; + + if (conn->cb != NULL) { + conn->cb(&event, conn->cb_arg); + } +} + +static int +ble_iso_conn_rx_data_load(struct ble_iso_conn *conn, struct os_mbuf *frag, + uint8_t pb_flag, bool ts_available, void *arg) +{ + int len_remaining; + int rc; + + switch (pb_flag) { + case BLE_HCI_ISO_PB_FIRST: + case BLE_HCI_ISO_PB_COMPLETE: + if (conn->rx_buf != NULL) { + /* Previous data packet never completed. Discard old packet. */ + ble_iso_conn_rx_data_discard(conn); + } + + rc = ble_iso_rx_data_info_parse(frag, ts_available, &conn->rx_info); + if (rc != 0) { + return rc; + } + + conn->rx_buf = frag; + break; + + case BLE_HCI_ISO_PB_CONTINUATION: + case BLE_HCI_ISO_PB_LAST: + if (conn->rx_buf == NULL) { + /* Last fragment without the start. Discard new packet. */ + return BLE_HS_EBADDATA; + } + + /* Determine whether the total length won't exceed the declared SDU length */ + len_remaining = conn->rx_info.sdu_len - OS_MBUF_PKTLEN(conn->rx_buf); + if (len_remaining - os_mbuf_len(frag) < 0) { + /* SDU Length exceeded. Discard all packets. */ + ble_iso_conn_rx_data_discard(conn); + return BLE_HS_EBADDATA; + } + + os_mbuf_concat(conn->rx_buf, frag); + break; + + default: + BLE_HS_LOG_ERROR("Invalid pb_flag %d\n", pb_flag); + return BLE_HS_EBADDATA; + } + + if (pb_flag == BLE_HCI_ISO_PB_COMPLETE || pb_flag == BLE_HCI_ISO_PB_LAST) { + ble_iso_event_iso_rx_emit(conn); + ble_iso_conn_rx_reset(conn); + } + + return 0; +} + +int +ble_iso_rx_data(struct os_mbuf *om, void *arg) +{ + struct ble_iso_conn *conn; + struct ble_hci_iso *hci_iso; + uint16_t conn_handle; + uint16_t length; + uint16_t pb_flag; + uint16_t ts_flag; + uint16_t u16; + int rc; + + if (os_mbuf_len(om) < sizeof(*hci_iso)) { + BLE_HS_LOG_DEBUG("Data missing\n"); + os_mbuf_free_chain(om); + return BLE_HS_EMSGSIZE; + } + + hci_iso = (void *)om->om_data; + + u16 = le16toh(hci_iso->handle); + conn_handle = BLE_HCI_ISO_CONN_HANDLE(u16); + pb_flag = BLE_HCI_ISO_PB_FLAG(u16); + ts_flag = BLE_HCI_ISO_TS_FLAG(u16); + length = BLE_HCI_ISO_LENGTH(le16toh(hci_iso->length)); + + os_mbuf_adj(om, sizeof(*hci_iso)); + + if (os_mbuf_len(om) < length) { + BLE_HS_LOG_DEBUG("Data missing\n"); + os_mbuf_free_chain(om); + return BLE_HS_EMSGSIZE; + } + + conn = ble_iso_conn_lookup_handle(conn_handle); + if (conn == NULL) { + BLE_HS_LOG_DEBUG("Unknown handle=%d\n", conn_handle); + os_mbuf_free_chain(om); + return BLE_HS_EMSGSIZE; + } + + rc = ble_iso_conn_rx_data_load(conn, om, pb_flag, ts_flag > 0, arg); + if (rc != 0) { + os_mbuf_free_chain(om); + return rc; + } + + return 0; +} +#endif /* BLE_ISO_BROADCAST_SINK */ + +int +ble_iso_data_path_setup(const struct ble_iso_data_path_setup_params *param) +{ + struct ble_hci_le_setup_iso_data_path_rp rp; + struct ble_hci_le_setup_iso_data_path_cp *cp; + uint8_t buf[sizeof(*cp) + UINT8_MAX]; + struct ble_iso_conn *conn; + int rc; + + conn = ble_iso_conn_lookup_handle(param->conn_handle); + if (conn == NULL) { + BLE_HS_LOG_ERROR("invalid conn_handle\n"); + return BLE_HS_ENOTCONN; + } + + if (param->codec_config_len > 0 && param->codec_config == NULL) { + BLE_HS_LOG_ERROR("Missing codec_config\n"); + return BLE_HS_EINVAL; + } + + cp = (void *)buf; + put_le16(&cp->conn_handle, param->conn_handle); + cp->data_path_dir = 0; + + if (param->data_path_dir & BLE_ISO_DATA_DIR_TX) { + /* Input (Host to Controller) */ + cp->data_path_dir |= BLE_HCI_ISO_DATA_PATH_DIR_INPUT; + } + + if (param->data_path_dir & BLE_ISO_DATA_DIR_RX) { + /* Output (Controller to Host) */ + cp->data_path_dir |= BLE_HCI_ISO_DATA_PATH_DIR_OUTPUT; + + if (cp->data_path_id == BLE_HCI_ISO_DATA_PATH_ID_HCI && param->cb == NULL) { + BLE_HS_LOG_ERROR("param->cb is NULL\n"); + return BLE_HS_EINVAL; + } + + conn->cb = param->cb; + conn->cb_arg = param->cb_arg; + } + + cp->data_path_id = param->data_path_id; + cp->codec_id[0] = param->codec_id.format; + put_le16(&cp->codec_id[1], param->codec_id.company_id); + put_le16(&cp->codec_id[3], param->codec_id.vendor_specific); + put_le24(cp->controller_delay, param->ctrl_delay); + + cp->codec_config_len = param->codec_config_len; + memcpy(cp->codec_config, param->codec_config, cp->codec_config_len); + + rc = ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_SETUP_ISO_DATA_PATH), + cp, sizeof(*cp) + cp->codec_config_len, &rp, + sizeof(rp)); + + return rc; +} + +int +ble_iso_data_path_remove(const struct ble_iso_data_path_remove_params *param) +{ + struct ble_hci_le_remove_iso_data_path_rp rp; + struct ble_hci_le_remove_iso_data_path_cp cp = { 0 }; + struct ble_iso_conn *conn; + int rc; + + conn = ble_iso_conn_lookup_handle(param->conn_handle); + if (conn == NULL) { + BLE_HS_LOG_ERROR("invalid conn_handle\n"); + return BLE_HS_ENOTCONN; + } + + put_le16(&cp.conn_handle, param->conn_handle); + + if (param->data_path_dir & BLE_ISO_DATA_DIR_TX) { + /* Input (Host to Controller) */ + cp.data_path_dir |= BLE_HCI_ISO_DATA_PATH_DIR_INPUT; + } + + if (param->data_path_dir & BLE_ISO_DATA_DIR_RX) { + /* Output (Controller to Host) */ + cp.data_path_dir |= BLE_HCI_ISO_DATA_PATH_DIR_OUTPUT; + + conn->cb = NULL; + conn->cb_arg = NULL; + } + + rc = ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE, + BLE_HCI_OCF_LE_REMOVE_ISO_DATA_PATH), + &cp, sizeof(cp), &rp, sizeof(rp)); + + return rc; +} + +int +ble_iso_init(void) +{ + int rc; + + SLIST_INIT(&ble_iso_bigs); + + rc = os_mempool_init(&ble_iso_big_pool, + MYNEWT_VAL(BLE_ISO_MAX_BIGS), + sizeof (struct ble_iso_big), + ble_iso_big_mem, "ble_iso_big_pool"); + SYSINIT_PANIC_ASSERT(rc == 0); + + rc = os_mempool_init(&ble_iso_bis_pool, + MYNEWT_VAL(BLE_ISO_MAX_BISES), + sizeof (struct ble_iso_bis), + ble_iso_bis_mem, "ble_iso_bis_pool"); + SYSINIT_PANIC_ASSERT(rc == 0); + + return 0; +} +#endif /* BLE_ISO */ diff --git a/porting/nimble/include/log/log.h b/nimble/host/src/ble_iso_priv.h similarity index 62% rename from porting/nimble/include/log/log.h rename to nimble/host/src/ble_iso_priv.h index b50c5b1709..9005b5067f 100644 --- a/porting/nimble/include/log/log.h +++ b/nimble/host/src/ble_iso_priv.h @@ -17,32 +17,31 @@ * under the License. */ -#ifndef __LOG_H__ -#define __LOG_H__ +#ifndef H_BLE_ISO_PRIV_ +#define H_BLE_ISO_PRIV_ +#include "nimble/hci_common.h" #ifdef __cplusplus extern "C" { #endif -static inline void -log_dummy(void *log, ...) -{ - (void)log; -} +void +ble_iso_rx_create_big_complete(const struct ble_hci_ev_le_subev_create_big_complete *ev); -#if MYNEWT -#define LOG_DEBUG(_log, _mod, ...) log_dummy(_log, ## __VA_ARGS__) -#define LOG_INFO(_log, _mod, ...) log_dummy(_log, ## __VA_ARGS__) -#define LOG_WARN(_log, _mod, ...) log_dummy(_log, ## __VA_ARGS__) -#define LOG_ERROR(_log, _mod, ...) log_dummy(_log, ## __VA_ARGS__) -#define LOG_CRITICAL(_log, _mod, ...) log_dummy(_log, ## __VA_ARGS__) -#endif +void +ble_iso_rx_terminate_big_complete(const struct ble_hci_ev_le_subev_terminate_big_complete *ev); + +void +ble_iso_rx_big_sync_established(const struct ble_hci_ev_le_subev_big_sync_established *ev); + +void +ble_iso_rx_big_sync_lost(const struct ble_hci_ev_le_subev_big_sync_lost *ev); -struct log { -}; +int +ble_iso_rx_data(struct os_mbuf *om, void *arg); #ifdef __cplusplus } #endif -#endif /* __LOG_H__ */ +#endif /* H_BLE_ISO_PRIV_ */ diff --git a/nimble/host/src/ble_l2cap.c b/nimble/host/src/ble_l2cap.c index a2c5156339..5a4ff9ad4b 100644 --- a/nimble/host/src/ble_l2cap.c +++ b/nimble/host/src/ble_l2cap.c @@ -21,6 +21,7 @@ #include #include "syscfg/syscfg.h" #include "os/os.h" +#include "host/ble_l2cap.h" #include "nimble/ble.h" #include "nimble/hci_common.h" #include "ble_hs_priv.h" @@ -79,7 +80,6 @@ ble_l2cap_chan_free(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan) return; } - os_mbuf_free_chain(chan->rx_buf); ble_l2cap_coc_cleanup_chan(conn, chan); #if MYNEWT_VAL(BLE_HS_DEBUG) @@ -98,18 +98,17 @@ ble_l2cap_is_mtu_req_sent(const struct ble_l2cap_chan *chan) } int -ble_l2cap_parse_hdr(struct os_mbuf *om, int off, - struct ble_l2cap_hdr *l2cap_hdr) +ble_l2cap_parse_hdr(struct os_mbuf *om, struct ble_l2cap_hdr *hdr) { int rc; - rc = os_mbuf_copydata(om, off, sizeof *l2cap_hdr, l2cap_hdr); + rc = os_mbuf_copydata(om, 0, sizeof(*hdr), hdr); if (rc != 0) { return BLE_HS_EMSGSIZE; } - l2cap_hdr->len = get_le16(&l2cap_hdr->len); - l2cap_hdr->cid = get_le16(&l2cap_hdr->cid); + hdr->len = get_le16(&hdr->len); + hdr->cid = get_le16(&hdr->cid); return 0; } @@ -178,13 +177,6 @@ ble_l2cap_get_chan_info(struct ble_l2cap_chan *chan, struct ble_l2cap_chan_info return 0; } -int -ble_l2cap_ping(uint16_t conn_handle, ble_l2cap_ping_fn cb, - const void *data, uint16_t data_len) -{ - return ble_l2cap_sig_ping(conn_handle, cb, data, data_len); -} - int ble_l2cap_enhanced_connect(uint16_t conn_handle, uint16_t psm, uint16_t mtu, @@ -239,201 +231,168 @@ ble_l2cap_recv_ready(struct ble_l2cap_chan *chan, struct os_mbuf *sdu_rx) return ble_l2cap_coc_recv_ready(chan, sdu_rx); } -void -ble_l2cap_remove_rx(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan) +static uint16_t +ble_l2cap_get_mtu(struct ble_l2cap_chan *chan) { - conn->bhc_rx_chan = NULL; - os_mbuf_free_chain(chan->rx_buf); - chan->rx_buf = NULL; - chan->rx_len = 0; + if (chan->scid == BLE_L2CAP_CID_ATT) { + /* In case of ATT chan->my_mtu keeps preferred MTU which is later + * used during exchange MTU procedure. Helper below gives us actual + * MTU on the channel, which is 23 or higher if exchange MTU has been + * done + */ + return ble_att_chan_mtu(chan); + } + + return chan->my_mtu; } static void -ble_l2cap_append_rx(struct ble_l2cap_chan *chan, struct os_mbuf *frag) +ble_l2cap_rx_free(struct ble_hs_conn *conn) { -#if MYNEWT_VAL(BLE_L2CAP_JOIN_RX_FRAGS) - struct os_mbuf *m; - - /* Copy the data from the incoming fragment into the packet in progress. */ - m = os_mbuf_pack_chains(chan->rx_buf, frag); - assert(m); -#else - /* Join disabled or append failed due to mbuf shortage. Just attach the - * mbuf to the end of the packet. - */ - os_mbuf_concat(chan->rx_buf, frag); -#endif + os_mbuf_free_chain(conn->rx_frags); + conn->rx_frags = NULL; + conn->rx_len = 0; + conn->rx_cid = 0; } static int -ble_l2cap_rx_payload(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan, - struct os_mbuf *om, - ble_l2cap_rx_fn **out_rx_cb) +ble_l2cap_rx_frags_process(struct ble_hs_conn *conn) { - int len_diff; + int rem_rx_len; int rc; - if (chan->rx_buf == NULL) { - /* First fragment in packet. */ - chan->rx_buf = om; - } else { - /* Continuation of packet in progress. */ - ble_l2cap_append_rx(chan, om); - } - - /* Determine if packet is fully reassembled. */ - len_diff = OS_MBUF_PKTLEN(chan->rx_buf) - chan->rx_len; - if (len_diff > 0) { - /* More data than expected; data corruption. */ - ble_l2cap_remove_rx(conn, chan); - rc = BLE_HS_EBADDATA; - } else if (len_diff == 0) { - /* All fragments received. */ - *out_rx_cb = chan->rx_fn; + rem_rx_len = conn->rx_len - OS_MBUF_PKTLEN(conn->rx_frags); + if (rem_rx_len == 0) { rc = 0; - } else { - /* More fragments remain. */ + } else if (rem_rx_len > 0) { #if MYNEWT_VAL(BLE_L2CAP_RX_FRAG_TIMEOUT) != 0 - conn->bhc_rx_timeout = - ble_npl_time_get() + MYNEWT_VAL(BLE_L2CAP_RX_FRAG_TIMEOUT); + conn->rx_frag_tmo = + ble_npl_time_get() + + ble_npl_time_ms_to_ticks32(MYNEWT_VAL(BLE_L2CAP_RX_FRAG_TIMEOUT)); ble_hs_timer_resched(); #endif rc = BLE_HS_EAGAIN; + } else { + ble_l2cap_rx_free(conn); + rc = BLE_HS_EBADDATA; } return rc; } -static uint16_t -ble_l2cap_get_mtu(struct ble_l2cap_chan *chan) -{ - if (chan->scid == BLE_L2CAP_CID_ATT) { - /* In case of ATT chan->my_mtu keeps preferred MTU which is later - * used during exchange MTU procedure. Helper below will gives us actual - * MTU on the channel, which is 23 or higher if exchange MTU has been - * done - */ - return ble_att_chan_mtu(chan); - } - - return chan->my_mtu; -} - -/** - * Processes an incoming L2CAP fragment. - * - * @param conn The connection the L2CAP fragment was sent - * over. - * @param hci_hdr The ACL data header that was at the start of - * the L2CAP fragment. This header has been - * stripped from the mbuf parameter. - * @param om An mbuf containing the L2CAP data. If this is - * the first fragment, the L2CAP header is at - * the start of the mbuf. For subsequent - * fragments, the mbuf starts with L2CAP - * payload data. - * @param out_rx_cb If a full L2CAP packet has been received, a - * pointer to the appropriate handler gets - * written here. The caller should pass the - * receive buffer to this callback. - * @param out_rx_buf If a full L2CAP packet has been received, this - * will point to the entire L2CAP packet. To - * process the packet, pass this buffer to the - * receive handler (out_rx_cb). - * @param out_reject_cid Indicates whether an L2CAP Command Reject - * command should be sent. If this equals -1, - * no reject should get sent. Otherwise, the - * value indicates the CID that the outgoing - * reject should specify. - * - * @return 0 if a complete L2CAP packet has been received. - * BLE_HS_EAGAIN if a partial L2CAP packet has - * been received; more fragments are expected. - * Other value on error. - */ int -ble_l2cap_rx(struct ble_hs_conn *conn, - struct hci_data_hdr *hci_hdr, - struct os_mbuf *om, - ble_l2cap_rx_fn **out_rx_cb, - int *out_reject_cid) +ble_l2cap_rx(uint16_t conn_handle, uint8_t pb, struct os_mbuf *om) { + struct ble_hs_conn *conn; struct ble_l2cap_chan *chan; - struct ble_l2cap_hdr l2cap_hdr; - uint8_t pb; + struct ble_l2cap_hdr hdr; + struct os_mbuf *rx_frags; + uint16_t rx_len; + uint16_t rx_cid; int rc; - *out_reject_cid = -1; + ble_hs_lock(); + + conn = ble_hs_conn_find(conn_handle); + if (!conn) { + /* Invalid connection handle, discard packet */ + os_mbuf_free_chain(om); + rc = BLE_HS_ENOTCONN; + goto done; + } - pb = BLE_HCI_DATA_PB(hci_hdr->hdh_handle_pb_bc); switch (pb) { case BLE_HCI_PB_FIRST_FLUSH: - /* First fragment. */ - rc = ble_l2cap_parse_hdr(om, 0, &l2cap_hdr); - if (rc != 0) { - goto err; + if (conn->rx_frags) { + /* Previously received data is incomplete, discard it */ + ble_l2cap_rx_free(conn); } - - /* Strip L2CAP header from the front of the mbuf. */ - os_mbuf_adj(om, BLE_L2CAP_HDR_SZ); - - chan = ble_hs_conn_chan_find_by_scid(conn, l2cap_hdr.cid); - if (chan == NULL) { - rc = BLE_HS_ENOENT; - - /* Unsupported channel. If the target CID is the black hole - * channel, quietly drop the packet. Otherwise, send an invalid - * CID response. + conn->rx_frags = om; + break; + case BLE_HCI_PB_MIDDLE: + if (!conn->rx_frags) { + /* Received continuation without 1st packet, discard it. + * This can also happen if we received invalid data earlier which + * was discarded, so we'll just keep discarding until valid 1st + * packet is received. */ - if (l2cap_hdr.cid != BLE_L2CAP_CID_BLACK_HOLE) { - BLE_HS_LOG(DEBUG, "rx on unknown L2CAP channel: %d\n", - l2cap_hdr.cid); - *out_reject_cid = l2cap_hdr.cid; - } - goto err; - } - - if (chan->rx_buf != NULL) { - /* Previous data packet never completed. Discard old packet. */ - ble_l2cap_remove_rx(conn, chan); - } - - if (l2cap_hdr.len > ble_l2cap_get_mtu(chan)) { - /* More data then we expected on the channel */ + os_mbuf_free_chain(om); rc = BLE_HS_EBADDATA; - goto err; + goto done; } - /* Remember channel and length of L2CAP data for reassembly. */ - conn->bhc_rx_chan = chan; - chan->rx_len = l2cap_hdr.len; + /* Append fragment to rx buffer */ +#if MYNEWT_VAL(BLE_L2CAP_JOIN_RX_FRAGS) + os_mbuf_pack_chains(conn->rx_frags, om); +#else + os_mbuf_concat(conn->rx_frag, om); +#endif break; + default: + /* Invalid PB, discard packet */ + os_mbuf_free_chain(om); + ble_l2cap_rx_free(conn); + rc = BLE_HS_EBADDATA; + goto done; + } - case BLE_HCI_PB_MIDDLE: - chan = conn->bhc_rx_chan; - if (chan == NULL || chan->rx_buf == NULL) { - /* Middle fragment without the start. Discard new packet. */ - rc = BLE_HS_EBADDATA; - goto err; + /* Parse L2CAP header if not yet done */ + if (!conn->rx_len) { + rc = ble_l2cap_parse_hdr(conn->rx_frags, &hdr); + if (rc) { + /* Incomplete header, wait for continuation */ + rc = BLE_HS_EAGAIN; + goto done; } - break; - default: - rc = BLE_HS_EBADDATA; - goto err; + os_mbuf_adj(conn->rx_frags, BLE_L2CAP_HDR_SZ); + + conn->rx_len = hdr.len; + conn->rx_cid = hdr.cid; } - rc = ble_l2cap_rx_payload(conn, chan, om, out_rx_cb); - om = NULL; - if (rc != 0) { - goto err; + /* Process fragments */ + rc = ble_l2cap_rx_frags_process(conn); + if (rc) { + goto done; } - return 0; + rx_frags = conn->rx_frags; + rx_len = conn->rx_len; + rx_cid = conn->rx_cid; + + conn->rx_frags = NULL; + ble_l2cap_rx_free(conn); + + chan = ble_hs_conn_chan_find_by_scid(conn, rx_cid); + + ble_hs_unlock(); + + if (!chan) { + ble_l2cap_sig_reject_invalid_cid_tx(conn_handle, 0, 0, rx_cid); + return BLE_HS_ENOENT; + } + + if (chan->dcid >= BLE_L2CAP_COC_CID_START && + chan->dcid <= BLE_L2CAP_COC_CID_END && rx_len > chan->my_coc_mps) { + ble_l2cap_disconnect(chan); + return BLE_HS_EBADDATA; + } + + if (rx_len > ble_l2cap_get_mtu(chan)) { + ble_l2cap_disconnect(chan); + return BLE_HS_EBADDATA; + } + + rc = chan->rx_fn(chan, &rx_frags); + os_mbuf_free_chain(rx_frags); + + return rc; + +done: + ble_hs_unlock(); -err: - os_mbuf_free_chain(om); return rc; } diff --git a/nimble/host/src/ble_l2cap_coc.c b/nimble/host/src/ble_l2cap_coc.c index aa953d79c5..cb74e7b70d 100644 --- a/nimble/host/src/ble_l2cap_coc.c +++ b/nimble/host/src/ble_l2cap_coc.c @@ -25,8 +25,20 @@ #include "ble_l2cap_coc_priv.h" #include "ble_l2cap_sig_priv.h" +#ifndef min +#define min(a, b) ((a) < (b) ? (a) : (b)) +#endif + #if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) != 0 && NIMBLE_BLE_CONNECT +#ifndef min +#define min(a, b) ((a) < (b) ? (a) : (b)) +#endif + +#ifndef max +#define max(a, b) ((a) > (b) ? (a) : (b)) +#endif + #define BLE_L2CAP_SDU_SIZE 2 STAILQ_HEAD(ble_l2cap_coc_srv_list, ble_l2cap_coc_srv); @@ -35,7 +47,7 @@ static struct ble_l2cap_coc_srv_list ble_l2cap_coc_srvs; static os_membuf_t ble_l2cap_coc_srv_mem[ OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM), - sizeof (struct ble_l2cap_coc_srv)) + sizeof(struct ble_l2cap_coc_srv)) ]; static struct os_mempool ble_l2cap_coc_srv_pool; @@ -67,9 +79,9 @@ ble_l2cap_coc_srv_alloc(void) int ble_l2cap_coc_create_server(uint16_t psm, uint16_t mtu, - ble_l2cap_event_fn *cb, void *cb_arg) + ble_l2cap_event_fn *cb, void *cb_arg) { - struct ble_l2cap_coc_srv * srv; + struct ble_l2cap_coc_srv *srv; srv = ble_l2cap_coc_srv_alloc(); if (!srv) { @@ -103,7 +115,7 @@ ble_l2cap_clear_used_cid(uint32_t *cid_mask, int bit) static inline int ble_l2cap_get_first_available_bit(uint32_t *cid_mask) { - int i; + unsigned int i; int bit = 0; for (i = 0; i < BLE_HS_CONN_L2CAP_COC_CID_MASK_LEN; i++) { @@ -113,7 +125,7 @@ ble_l2cap_get_first_available_bit(uint32_t *cid_mask) * a) If bit == 0 means all the bits are used * b) this function returns 1 + index */ - bit = __builtin_ffs(~(unsigned int)(cid_mask[i])); + bit = __builtin_ffs(~(unsigned int) (cid_mask[i])); if (bit != 0) { break; } @@ -148,8 +160,8 @@ ble_l2cap_coc_srv_find(uint16_t psm) srv = NULL; STAILQ_FOREACH(cur, &ble_l2cap_coc_srvs, next) { if (cur->psm == psm) { - srv = cur; - break; + srv = cur; + break; } } @@ -171,25 +183,24 @@ ble_l2cap_event_coc_received_data(struct ble_l2cap_chan *chan, } static int -ble_l2cap_coc_rx_fn(struct ble_l2cap_chan *chan) +ble_l2cap_coc_rx_fn(struct ble_l2cap_chan *chan, struct os_mbuf **om) { int rc; - struct os_mbuf **om; + struct os_mbuf *rx_sdu; struct ble_l2cap_coc_endpoint *rx; uint16_t om_total; - /* Create a shortcut to rx_buf */ - om = &chan->rx_buf; - BLE_HS_DBG_ASSERT(*om != NULL); - /* Create a shortcut to rx endpoint */ rx = &chan->coc_rx; BLE_HS_DBG_ASSERT(rx != NULL); + rx_sdu = rx->sdus[chan->coc_rx.current_sdu_idx]; + BLE_HS_DBG_ASSERT(rx_sdu != NULL); + om_total = OS_MBUF_PKTLEN(*om); /* First LE frame */ - if (OS_MBUF_PKTLEN(rx->sdu) == 0) { + if (OS_MBUF_PKTLEN(rx_sdu) == 0) { uint16_t sdu_len; rc = ble_hs_mbuf_pullup_base(om, BLE_L2CAP_SDU_SIZE); @@ -198,6 +209,20 @@ ble_l2cap_coc_rx_fn(struct ble_l2cap_chan *chan) } sdu_len = get_le16((*om)->om_data); + + BLE_HS_LOG(INFO, "First LE frame received %d, SDU len: %d\n", + om_total, sdu_len + 2); + + /* We should receive payload of size sdu_len + 2 bytes of sdu_len field */ + if (om_total > sdu_len + 2) { + BLE_HS_LOG(ERROR, "Payload larger than expected (%d>%d)\n", + om_total, sdu_len + 2); + /* Disconnect peer with invalid behaviour */ + rx_sdu = NULL; + rx->data_offset = 0; + ble_l2cap_disconnect(chan); + return BLE_HS_EBADDATA; + } if (sdu_len > rx->mtu) { BLE_HS_LOG(INFO, "error: sdu_len > rx->mtu (%d>%d)\n", sdu_len, rx->mtu); @@ -207,12 +232,13 @@ ble_l2cap_coc_rx_fn(struct ble_l2cap_chan *chan) return BLE_HS_EBADDATA; } - BLE_HS_LOG(DEBUG, "sdu_len=%d, received LE frame=%d, credits=%d\n", - sdu_len, om_total, rx->credits); + BLE_HS_LOG(DEBUG, + "sdu_len=%d, received LE frame=%d, credits=%d, current_sdu_idx=%d\n", + sdu_len, om_total, rx->credits, chan->coc_rx.current_sdu_idx); - os_mbuf_adj(*om , BLE_L2CAP_SDU_SIZE); + os_mbuf_adj(*om, BLE_L2CAP_SDU_SIZE); - rc = os_mbuf_appendfrom(rx->sdu, *om, 0, om_total - BLE_L2CAP_SDU_SIZE); + rc = os_mbuf_appendfrom(rx_sdu, *om, 0, om_total - BLE_L2CAP_SDU_SIZE); if (rc != 0) { /* FIXME: User shall give us big enough buffer. * need to handle it better @@ -227,7 +253,16 @@ ble_l2cap_coc_rx_fn(struct ble_l2cap_chan *chan) } else { BLE_HS_LOG(DEBUG, "Continuation...received %d\n", (*om)->om_len); - rc = os_mbuf_appendfrom(rx->sdu, *om, 0, om_total); + if (OS_MBUF_PKTLEN(rx_sdu) + (*om)->om_len > rx->data_offset) { + /* Disconnect peer with invalid behaviour */ + BLE_HS_LOG(ERROR, "Payload larger than expected (%d>%d)\n", + OS_MBUF_PKTLEN(rx_sdu) + (*om)->om_len, rx->data_offset); + rx_sdu = NULL; + rx->data_offset = 0; + ble_l2cap_disconnect(chan); + return BLE_HS_EBADDATA; + } + rc = os_mbuf_appendfrom(rx_sdu, *om, 0, om_total); if (rc != 0) { /* FIXME: need to handle it better */ BLE_HS_LOG(DEBUG, "Could not append data rc=%d\n", rc); @@ -237,17 +272,19 @@ ble_l2cap_coc_rx_fn(struct ble_l2cap_chan *chan) rx->credits--; - if (OS_MBUF_PKTLEN(rx->sdu) == rx->data_offset) { - struct os_mbuf *sdu_rx = rx->sdu; + if (OS_MBUF_PKTLEN(rx_sdu) == rx->data_offset) { + struct os_mbuf *sdu_rx = rx_sdu; BLE_HS_LOG(DEBUG, "Received sdu_len=%d, credits left=%d\n", - OS_MBUF_PKTLEN(rx->sdu), rx->credits); + OS_MBUF_PKTLEN(rx_sdu), rx->credits); /* Lets get back control to os_mbuf to application. * Since it this callback application might want to set new sdu * we need to prepare space for this. Therefore we need sdu_rx */ - rx->sdu = NULL; + rx_sdu = NULL; + chan->coc_rx.current_sdu_idx = + (chan->coc_rx.current_sdu_idx + 1) % BLE_L2CAP_SDU_BUFF_CNT; rx->data_offset = 0; ble_l2cap_event_coc_received_data(chan, sdu_rx); @@ -268,14 +305,16 @@ ble_l2cap_coc_rx_fn(struct ble_l2cap_chan *chan) ble_l2cap_sig_le_credits(chan->conn_handle, chan->scid, rx->credits); } - BLE_HS_LOG(DEBUG, "Received partial sdu_len=%d, credits left=%d\n", - OS_MBUF_PKTLEN(rx->sdu), rx->credits); + BLE_HS_LOG(DEBUG, + "Received partial sdu_len=%d, credits left=%d, current_sdu_idx=%d\n", + OS_MBUF_PKTLEN(rx_sdu), rx->credits, chan->coc_rx.current_sdu_idx); return 0; } void -ble_l2cap_coc_set_new_mtu_mps(struct ble_l2cap_chan *chan, uint16_t mtu, uint16_t mps) +ble_l2cap_coc_set_new_mtu_mps(struct ble_l2cap_chan *chan, uint16_t mtu, + uint16_t mps) { chan->my_coc_mps = mps; chan->coc_rx.mtu = mtu; @@ -304,7 +343,17 @@ ble_l2cap_coc_chan_alloc(struct ble_hs_conn *conn, uint16_t psm, uint16_t mtu, chan->my_coc_mps = MYNEWT_VAL(BLE_L2CAP_COC_MPS); chan->rx_fn = ble_l2cap_coc_rx_fn; chan->coc_rx.mtu = mtu; - chan->coc_rx.sdu = sdu_rx; + chan->coc_rx.sdus[0] = sdu_rx; + for (int i = 1; i < BLE_L2CAP_SDU_BUFF_CNT; i++) { + chan->coc_rx.sdus[i] = NULL; + } + chan->coc_rx.current_sdu_idx = 0; + + if (BLE_L2CAP_SDU_BUFF_CNT == 1) { + chan->coc_rx.next_sdu_alloc_idx = 0; + } else { + chan->coc_rx.next_sdu_alloc_idx = chan->coc_rx.sdus[0] == NULL ? 0 : 1; + } /* Number of credits should allow to send full SDU with on given * L2CAP MTU @@ -342,7 +391,7 @@ ble_l2cap_coc_create_srv_chan(struct ble_hs_conn *conn, uint16_t psm, static void ble_l2cap_event_coc_disconnected(struct ble_l2cap_chan *chan) { - struct ble_l2cap_event event = { }; + struct ble_l2cap_event event = {}; /* FIXME */ if (!chan->cb) { @@ -361,7 +410,7 @@ ble_l2cap_coc_cleanup_chan(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan { /* PSM 0 is used for fixed channels. */ if (chan->psm == 0) { - return; + return; } ble_l2cap_event_coc_disconnected(chan); @@ -371,14 +420,16 @@ ble_l2cap_coc_cleanup_chan(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan chan->scid - BLE_L2CAP_COC_CID_START); } - os_mbuf_free_chain(chan->coc_rx.sdu); - os_mbuf_free_chain(chan->coc_tx.sdu); + for (int i = 0; i < BLE_L2CAP_SDU_BUFF_CNT; i++) { + os_mbuf_free_chain(chan->coc_rx.sdus[i]); + } + os_mbuf_free_chain(chan->coc_tx.sdus[0]); } static void ble_l2cap_event_coc_unstalled(struct ble_l2cap_chan *chan, int status) { - struct ble_l2cap_event event = { }; + struct ble_l2cap_event event = {}; if (!chan->cb) { return; @@ -407,7 +458,7 @@ ble_l2cap_coc_continue_tx(struct ble_l2cap_chan *chan) /* If there is no data to send, just return success */ tx = &chan->coc_tx; - if (!tx->sdu) { + if (!tx->sdus[0]) { ble_hs_unlock(); return 0; } @@ -418,7 +469,7 @@ ble_l2cap_coc_continue_tx(struct ble_l2cap_chan *chan) BLE_HS_LOG(DEBUG, "Available credits %d\n", tx->credits); /* lets calculate data we are going to send */ - left_to_send = OS_MBUF_PKTLEN(tx->sdu) - tx->data_offset; + left_to_send = OS_MBUF_PKTLEN(tx->sdus[0]) - tx->data_offset; if (tx->data_offset == 0) { sdu_size_offset = BLE_L2CAP_SDU_SIZE; @@ -438,9 +489,10 @@ ble_l2cap_coc_continue_tx(struct ble_l2cap_chan *chan) if (tx->data_offset == 0) { /* First packet needs SDU len first. Left to send */ - uint16_t l = htole16(OS_MBUF_PKTLEN(tx->sdu)); + uint16_t l = htole16(OS_MBUF_PKTLEN(tx->sdus[0])); - BLE_HS_LOG(DEBUG, "Sending SDU len=%d\n", OS_MBUF_PKTLEN(tx->sdu)); + BLE_HS_LOG(DEBUG, "Sending SDU len=%d\n", + OS_MBUF_PKTLEN(tx->sdus[0])); rc = os_mbuf_append(txom, &l, sizeof(uint16_t)); if (rc) { rc = BLE_HS_ENOMEM; @@ -453,7 +505,7 @@ ble_l2cap_coc_continue_tx(struct ble_l2cap_chan *chan) * that for first packet we need to decrease data size by 2 bytes for sdu * size */ - rc = os_mbuf_appendfrom(txom, tx->sdu, tx->data_offset, + rc = os_mbuf_appendfrom(txom, tx->sdus[0], tx->data_offset, len - sdu_size_offset); if (rc) { rc = BLE_HS_ENOMEM; @@ -461,7 +513,12 @@ ble_l2cap_coc_continue_tx(struct ble_l2cap_chan *chan) goto failed; } - conn = ble_hs_conn_find_assert(chan->conn_handle); + conn = ble_hs_conn_find(chan->conn_handle); + if (!conn) { + rc = BLE_HS_ENOTCONN; + BLE_HS_LOG(DEBUG, "Connection does not exist"); + goto failed; + } rc = ble_l2cap_tx(conn, chan, txom); if (rc) { @@ -474,18 +531,19 @@ ble_l2cap_coc_continue_tx(struct ble_l2cap_chan *chan) } BLE_HS_LOG(DEBUG, "Sent %d bytes, credits=%d, to send %d bytes \n", - len, tx->credits, OS_MBUF_PKTLEN(tx->sdu)- tx->data_offset); + len, tx->credits, + OS_MBUF_PKTLEN(tx->sdus[0]) - tx->data_offset); - if (tx->data_offset == OS_MBUF_PKTLEN(tx->sdu)) { + if (tx->data_offset == OS_MBUF_PKTLEN(tx->sdus[0])) { BLE_HS_LOG(DEBUG, "Complete package sent\n"); - os_mbuf_free_chain(tx->sdu); - tx->sdu = NULL; + os_mbuf_free_chain(tx->sdus[0]); + tx->sdus[0] = NULL; tx->data_offset = 0; break; } } - if (tx->sdu) { + if (tx->sdus[0]) { /* Not complete SDU sent, wait for credits */ tx->flags |= BLE_L2CAP_COC_FLAG_STALLED; ble_hs_unlock(); @@ -503,8 +561,8 @@ ble_l2cap_coc_continue_tx(struct ble_l2cap_chan *chan) return 0; failed: - os_mbuf_free_chain(tx->sdu); - tx->sdu = NULL; + os_mbuf_free_chain(tx->sdus[0]); + tx->sdus[0] = NULL; os_mbuf_free_chain(txom); if (tx->flags & BLE_L2CAP_COC_FLAG_STALLED) { @@ -562,10 +620,24 @@ ble_l2cap_coc_recv_ready(struct ble_l2cap_chan *chan, struct os_mbuf *sdu_rx) return BLE_HS_EINVAL; } - chan->coc_rx.sdu = sdu_rx; + if (chan->coc_rx.sdus[0] != NULL && + chan->coc_rx.next_sdu_alloc_idx == chan->coc_rx.current_sdu_idx && + BLE_L2CAP_SDU_BUFF_CNT != 1) { + return BLE_HS_EBUSY; + } + + chan->coc_rx.sdus[chan->coc_rx.next_sdu_alloc_idx] = sdu_rx; + chan->coc_rx.next_sdu_alloc_idx = + (chan->coc_rx.next_sdu_alloc_idx + 1) % BLE_L2CAP_SDU_BUFF_CNT; ble_hs_lock(); - conn = ble_hs_conn_find_assert(chan->conn_handle); + conn = ble_hs_conn_find(chan->conn_handle); + if (!conn) { + BLE_HS_LOG(DEBUG, "Connection does not exist"); + ble_hs_unlock(); + return BLE_HS_ENOTCONN; + } + c = ble_hs_conn_chan_find_by_scid(conn, chan->scid); if (!c) { ble_hs_unlock(); @@ -605,11 +677,11 @@ ble_l2cap_coc_send(struct ble_l2cap_chan *chan, struct os_mbuf *sdu_tx) } ble_hs_lock(); - if (tx->sdu) { + if (tx->sdus[0]) { ble_hs_unlock(); return BLE_HS_EBUSY; } - tx->sdu = sdu_tx; + tx->sdus[0] = sdu_tx; /* leave the host locked on purpose when ble_l2cap_coc_continue_tx() */ @@ -622,10 +694,10 @@ ble_l2cap_coc_init(void) STAILQ_INIT(&ble_l2cap_coc_srvs); return os_mempool_init(&ble_l2cap_coc_srv_pool, - MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM), - sizeof (struct ble_l2cap_coc_srv), - ble_l2cap_coc_srv_mem, - "ble_l2cap_coc_srv_pool"); + MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM), + sizeof(struct ble_l2cap_coc_srv), + ble_l2cap_coc_srv_mem, + "ble_l2cap_coc_srv_pool"); } #endif diff --git a/nimble/host/src/ble_l2cap_coc_priv.h b/nimble/host/src/ble_l2cap_coc_priv.h index 5ebdaa050c..8a87303fb7 100644 --- a/nimble/host/src/ble_l2cap_coc_priv.h +++ b/nimble/host/src/ble_l2cap_coc_priv.h @@ -30,15 +30,18 @@ extern "C" { #endif -#define BLE_L2CAP_COC_CID_START 0x0040 -#define BLE_L2CAP_COC_CID_END 0x007F - struct ble_l2cap_chan; #define BLE_L2CAP_COC_FLAG_STALLED 0x01 +#define BLE_L2CAP_SDU_BUFF_CNT (MYNEWT_VAL(BLE_L2CAP_COC_SDU_BUFF_COUNT)) + struct ble_l2cap_coc_endpoint { - struct os_mbuf *sdu; + struct os_mbuf *sdus[BLE_L2CAP_SDU_BUFF_CNT]; + /* Index for currently used sdu from sdus */ + uint16_t current_sdu_idx; + /* Index indicating free sdus slot to allocate next sdu */ + uint16_t next_sdu_alloc_idx; uint16_t mtu; uint16_t credits; uint16_t data_offset; diff --git a/nimble/host/src/ble_l2cap_priv.h b/nimble/host/src/ble_l2cap_priv.h index 21e6a8bf64..926d1b9acb 100644 --- a/nimble/host/src/ble_l2cap_priv.h +++ b/nimble/host/src/ble_l2cap_priv.h @@ -49,16 +49,11 @@ extern STATS_SECT_DECL(ble_l2cap_stats) ble_l2cap_stats; extern struct os_mempool ble_l2cap_chan_pool; -/* This is nimble specific; packets sent to the black hole CID do not elicit - * an "invalid CID" response. - */ -#define BLE_L2CAP_CID_BLACK_HOLE 0xffff - #define BLE_L2CAP_HDR_SZ 4 typedef uint8_t ble_l2cap_chan_flags; -typedef int ble_l2cap_rx_fn(struct ble_l2cap_chan *chan); +typedef int ble_l2cap_rx_fn(struct ble_l2cap_chan *chan, struct os_mbuf **om); struct ble_l2cap_chan { SLIST_ENTRY(ble_l2cap_chan) next; @@ -81,9 +76,6 @@ struct ble_l2cap_chan { ble_l2cap_chan_flags flags; - struct os_mbuf *rx_buf; - uint16_t rx_len; /* Length of current reassembled rx packet. */ - ble_l2cap_rx_fn *rx_fn; #if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) != 0 @@ -109,8 +101,7 @@ typedef int ble_l2cap_tx_fn(struct ble_hs_conn *conn, SLIST_HEAD(ble_l2cap_chan_list, ble_l2cap_chan); -int ble_l2cap_parse_hdr(struct os_mbuf *om, int off, - struct ble_l2cap_hdr *l2cap_hdr); +int ble_l2cap_parse_hdr(struct os_mbuf *om, struct ble_l2cap_hdr *hdr); struct os_mbuf *ble_l2cap_prepend_hdr(struct os_mbuf *om, uint16_t cid, uint16_t len); @@ -119,16 +110,10 @@ void ble_l2cap_chan_free(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan); bool ble_l2cap_is_mtu_req_sent(const struct ble_l2cap_chan *chan); -int ble_l2cap_rx(struct ble_hs_conn *conn, - struct hci_data_hdr *hci_hdr, - struct os_mbuf *om, - ble_l2cap_rx_fn **out_rx_cb, - int *out_reject_cid); +int ble_l2cap_rx(uint16_t conn_handle, uint8_t pb, struct os_mbuf *om); int ble_l2cap_tx(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan, struct os_mbuf *txom); -void ble_l2cap_remove_rx(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan); - int ble_l2cap_init(void); /* Below experimental API is available when BLE_VERSION >= 52 */ diff --git a/nimble/host/src/ble_l2cap_sig.c b/nimble/host/src/ble_l2cap_sig.c index fab16ea441..3b9e452e5b 100644 --- a/nimble/host/src/ble_l2cap_sig.c +++ b/nimble/host/src/ble_l2cap_sig.c @@ -45,7 +45,6 @@ #include #include #include "nimble/ble.h" -#include "host/ble_monitor.h" #include "ble_hs_priv.h" #if NIMBLE_BLE_CONNECT @@ -60,7 +59,6 @@ #define BLE_L2CAP_SIG_PROC_OP_RECONFIG 2 #define BLE_L2CAP_SIG_PROC_OP_DISCONNECT 3 #define BLE_L2CAP_SIG_PROC_OP_MAX 4 -#define BLE_L2CAP_SIG_PROC_OP_PING 5 #if MYNEWT_VAL(BLE_L2CAP_ENHANCED_COC) #define BLE_L2CAP_ECOC_MIN_MTU (64) @@ -98,10 +96,6 @@ struct ble_l2cap_sig_proc { uint16_t new_mtu; } reconfig; #endif - struct { - ble_l2cap_ping_fn *cb; - ble_npl_time_t time_sent; - } ping; }; }; @@ -117,10 +111,6 @@ static ble_l2cap_sig_rx_fn ble_l2cap_sig_rx_noop; static ble_l2cap_sig_rx_fn ble_l2cap_sig_update_req_rx; static ble_l2cap_sig_rx_fn ble_l2cap_sig_update_rsp_rx; static ble_l2cap_sig_rx_fn ble_l2cap_sig_rx_reject; -#if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) != 0 -static ble_l2cap_sig_rx_fn ble_l2cap_sig_echo_req; -static ble_l2cap_sig_rx_fn ble_l2cap_sig_echo_rsp; -#endif #if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) != 0 static ble_l2cap_sig_rx_fn ble_l2cap_sig_coc_req_rx; @@ -154,10 +144,7 @@ static ble_l2cap_sig_rx_fn * const ble_l2cap_sig_dispatch[] = { [BLE_L2CAP_SIG_OP_CONFIG_RSP] = ble_l2cap_sig_rx_noop, [BLE_L2CAP_SIG_OP_DISCONN_REQ] = ble_l2cap_sig_disc_req_rx, [BLE_L2CAP_SIG_OP_DISCONN_RSP] = ble_l2cap_sig_disc_rsp_rx, -#if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) != 0 - [BLE_L2CAP_SIG_OP_ECHO_REQ] = ble_l2cap_sig_echo_req, - [BLE_L2CAP_SIG_OP_ECHO_RSP] = ble_l2cap_sig_echo_rsp, -#endif + [BLE_L2CAP_SIG_OP_ECHO_RSP] = ble_l2cap_sig_rx_noop, [BLE_L2CAP_SIG_OP_INFO_RSP] = ble_l2cap_sig_rx_noop, [BLE_L2CAP_SIG_OP_CREATE_CHAN_RSP] = ble_l2cap_sig_rx_noop, [BLE_L2CAP_SIG_OP_MOVE_CHAN_RSP] = ble_l2cap_sig_rx_noop, @@ -386,6 +373,72 @@ ble_l2cap_sig_update_call_cb(struct ble_l2cap_sig_proc *proc, int status) } } +static int +ble_l2cap_sig_check_conn_params(const struct ble_gap_upd_params *params) +{ + /* Check connection interval min */ + if ((params->itvl_min < BLE_HCI_CONN_ITVL_MIN) || + (params->itvl_min > BLE_HCI_CONN_ITVL_MAX)) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + /* Check connection interval max */ + if ((params->itvl_max < BLE_HCI_CONN_ITVL_MIN) || + (params->itvl_max > BLE_HCI_CONN_ITVL_MAX) || + (params->itvl_max < params->itvl_min)) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + /* Check connection latency */ + if (params->latency > BLE_HCI_CONN_LATENCY_MAX) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + /* Check supervision timeout */ + if ((params->supervision_timeout < BLE_HCI_CONN_SPVN_TIMEOUT_MIN) || + (params->supervision_timeout > BLE_HCI_CONN_SPVN_TIMEOUT_MAX)) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + /* Check connection event length */ + if (params->min_ce_len > params->max_ce_len) { + return BLE_ERR_INV_HCI_CMD_PARMS; + } + + return 0; +} + +/* This helper does validation of sizes and (if requested) CIDs sizes */ +static int +ble_l2cap_sig_mbuf_pullup_base(struct os_mbuf **om, int base_len, unsigned int *cids_count) +{ + if (cids_count) { + if (OS_MBUF_PKTLEN(*om) < base_len) { + return BLE_HS_EBADDATA; + } + + if ((OS_MBUF_PKTLEN(*om) - base_len) % sizeof(uint16_t)) { + return BLE_HS_EBADDATA; + } + + *cids_count = (OS_MBUF_PKTLEN(*om) - base_len) / sizeof(uint16_t); + if (*cids_count == 0 || *cids_count > BLE_L2CAP_MAX_COC_CONN_REQ) { + return BLE_HS_EBADDATA; + } + } else { + if (OS_MBUF_PKTLEN(*om) != base_len) { + return BLE_HS_EBADDATA; + } + } + + /* data sizes validated, just pullup all */ + *om = os_mbuf_pullup(*om, OS_MBUF_PKTLEN(*om)); + if (*om == NULL) { + return BLE_HS_ENOMEM; + } + + return 0; +} + int ble_l2cap_sig_update_req_rx(uint16_t conn_handle, struct ble_l2cap_sig_hdr *hdr, @@ -402,7 +455,7 @@ ble_l2cap_sig_update_req_rx(uint16_t conn_handle, l2cap_result = 0; /* Silence spurious gcc warning. */ - rc = ble_hs_mbuf_pullup_base(om, BLE_L2CAP_SIG_UPDATE_REQ_SZ); + rc = ble_l2cap_sig_mbuf_pullup_base(om, sizeof(*req), NULL); if (rc != 0) { return rc; } @@ -427,6 +480,12 @@ ble_l2cap_sig_update_req_rx(uint16_t conn_handle, params.min_ce_len = BLE_GAP_INITIAL_CONN_MIN_CE_LEN; params.max_ce_len = BLE_GAP_INITIAL_CONN_MAX_CE_LEN; + rc = ble_l2cap_sig_check_conn_params(¶ms); + if (rc != 0) { + /* Invalid parameters */ + goto result; + } + /* Ask application if slave's connection parameters are acceptable. */ rc = ble_gap_rx_l2cap_update_req(conn_handle, ¶ms); if (rc == 0) { @@ -434,6 +493,7 @@ ble_l2cap_sig_update_req_rx(uint16_t conn_handle, rc = ble_gap_update_params(conn_handle, ¶ms); } +result: if (rc == 0) { l2cap_result = BLE_L2CAP_SIG_UPDATE_RSP_RESULT_ACCEPT; } else { @@ -472,7 +532,7 @@ ble_l2cap_sig_update_rsp_rx(uint16_t conn_handle, return 0; } - rc = ble_hs_mbuf_pullup_base(om, BLE_L2CAP_SIG_UPDATE_RSP_SZ); + rc = ble_l2cap_sig_mbuf_pullup_base(om, sizeof(*rsp), NULL); if (rc != 0) { cb_status = rc; goto done; @@ -738,12 +798,12 @@ ble_l2cap_sig_credit_base_reconfig_req_rx(uint16_t conn_handle, struct ble_l2cap_sig_credit_base_reconfig_rsp *rsp; struct ble_hs_conn *conn; struct os_mbuf *txom; - int i; + unsigned int i; int rc; - uint8_t cid_cnt; + unsigned int cid_cnt; uint8_t reduction_mps = 0; - rc = ble_hs_mbuf_pullup_base(om, hdr->length); + rc = ble_l2cap_sig_mbuf_pullup_base(om, sizeof(*req), &cid_cnt); if (rc != 0) { return rc; } @@ -766,27 +826,16 @@ ble_l2cap_sig_credit_base_reconfig_req_rx(uint16_t conn_handle, return 0; } - if (hdr->length <= sizeof(*req)) { - rsp->result = htole16(BLE_L2CAP_ERR_RECONFIG_UNACCAPTED_PARAM); - goto failed; - } - req = (struct ble_l2cap_sig_credit_base_reconfig_req *)(*om)->om_data; if ((req->mps < BLE_L2CAP_ECOC_MIN_MTU) || (req->mtu < BLE_L2CAP_ECOC_MIN_MTU)) { - rsp->result = htole16(BLE_L2CAP_ERR_RECONFIG_UNACCAPTED_PARAM); + rsp->result = htole16(BLE_L2CAP_ERR_RECONFIG_UNACCEPTED_PARAM); goto failed; } /* Assume request will succeed. If not, result will be updated */ rsp->result = htole16(BLE_L2CAP_ERR_RECONFIG_SUCCEED); - cid_cnt = (hdr->length - sizeof(*req)) / sizeof(uint16_t); - if (cid_cnt > BLE_L2CAP_MAX_COC_CONN_REQ) { - rsp->result = htole16(BLE_L2CAP_ERR_RECONFIG_UNACCAPTED_PARAM); - goto failed; - } - for (i = 0; i < cid_cnt; i++) { chan[i] = ble_hs_conn_chan_find_by_dcid(conn, req->dcids[i]); if (!chan[i]) { @@ -796,10 +845,6 @@ ble_l2cap_sig_credit_base_reconfig_req_rx(uint16_t conn_handle, if (chan[i]->peer_coc_mps > req->mps) { reduction_mps++; - if (reduction_mps > 1) { - rsp->result = htole16(BLE_L2CAP_ERR_RECONFIG_REDUCTION_MPS_NOT_ALLOWED); - goto failed; - } } if (chan[i]->coc_tx.mtu > req->mtu) { @@ -808,6 +853,11 @@ ble_l2cap_sig_credit_base_reconfig_req_rx(uint16_t conn_handle, } } + if (reduction_mps > 0 && cid_cnt > 1) { + rsp->result = htole16(BLE_L2CAP_ERR_RECONFIG_REDUCTION_MPS_NOT_ALLOWED); + goto failed; + } + ble_hs_unlock(); for (i = 0; i < cid_cnt; i++) { @@ -870,7 +920,7 @@ ble_l2cap_sig_credit_base_reconfig_rsp_rx(uint16_t conn_handle, return 0; } - rc = ble_hs_mbuf_pullup_base(om, hdr->length); + rc = ble_l2cap_sig_mbuf_pullup_base(om, sizeof(*rsp), NULL); if (rc != 0) { return rc; } @@ -894,17 +944,17 @@ ble_l2cap_sig_credit_base_con_req_rx(uint16_t conn_handle, struct ble_l2cap_chan *chans[5] = { 0 }; struct ble_hs_conn *conn; uint16_t scid; - uint8_t num_of_scids; + unsigned int num_of_scids; uint8_t chan_created = 0; int i; - uint8_t len; + unsigned int len; - rc = ble_hs_mbuf_pullup_base(om, hdr->length); + rc = ble_l2cap_sig_mbuf_pullup_base(om, sizeof(*req), &num_of_scids); if (rc != 0) { return rc; } - len = (hdr->length > sizeof(*req)) ? hdr->length : sizeof(*req); + len = sizeof(*rsp) + (num_of_scids * sizeof(rsp->dcids[0])); rsp = ble_l2cap_sig_cmd_get(BLE_L2CAP_SIG_OP_CREDIT_CONNECT_RSP, hdr->identifier, len , &txom); @@ -931,12 +981,6 @@ ble_l2cap_sig_credit_base_con_req_rx(uint16_t conn_handle, req = (struct ble_l2cap_sig_credit_base_connect_req *)(*om)->om_data; - num_of_scids = (hdr->length - sizeof(*req)) / sizeof(uint16_t); - if (num_of_scids > 5) { - rsp->result = htole16(BLE_L2CAP_COC_ERR_INVALID_PARAMETERS); - goto failed; - } - if ((req->mtu < BLE_L2CAP_ECOC_MIN_MTU) || (req->mps < BLE_L2CAP_ECOC_MIN_MTU)) { rsp->result = htole16(BLE_L2CAP_COC_ERR_INVALID_PARAMETERS); goto failed; @@ -1059,6 +1103,8 @@ ble_l2cap_sig_credit_base_con_rsp_rx(uint16_t conn_handle, struct ble_hs_conn *conn; int rc; int i; + uint16_t duplicated_cids[5] = {}; + unsigned int num_of_dcids; #if !BLE_MONITOR BLE_HS_LOG(DEBUG, "L2CAP LE COC connection response received\n"); @@ -1071,11 +1117,16 @@ ble_l2cap_sig_credit_base_con_rsp_rx(uint16_t conn_handle, return 0; } - rc = ble_hs_mbuf_pullup_base(om, hdr->length); + rc = ble_l2cap_sig_mbuf_pullup_base(om, sizeof(*rsp), &num_of_dcids); if (rc != 0) { goto done; } + /* spec doesn't say what to do in that case so just fail */ + if (proc->connect.chan_cnt != num_of_dcids) { + goto done; + } + rsp = (struct ble_l2cap_sig_credit_base_connect_rsp *)(*om)->om_data; if (rsp->result) { @@ -1104,6 +1155,12 @@ ble_l2cap_sig_credit_base_con_rsp_rx(uint16_t conn_handle, chan->dcid = 0; continue; } + if (ble_hs_conn_chan_find_by_dcid(conn, rsp->dcids[i])) { + duplicated_cids[i] = rsp->dcids[i]; + chan->dcid = 0; + continue; + } + chan->peer_coc_mps = le16toh(rsp->mps); chan->dcid = le16toh(rsp->dcids[i]); chan->coc_tx.mtu = le16toh(rsp->mtu); @@ -1115,6 +1172,16 @@ ble_l2cap_sig_credit_base_con_rsp_rx(uint16_t conn_handle, ble_hs_unlock(); done: + for (i = 0; i < 5; i++){ + if (duplicated_cids[i] != 0){ + ble_hs_lock(); + conn = ble_hs_conn_find(conn_handle); + chan = ble_hs_conn_chan_find_by_dcid(conn, duplicated_cids[i]); + ble_hs_unlock(); + rc = ble_l2cap_sig_disconnect(chan); + } + } + ble_l2cap_sig_coc_connect_cb(proc, rc); ble_l2cap_sig_proc_free(proc); @@ -1135,7 +1202,7 @@ ble_l2cap_sig_coc_req_rx(uint16_t conn_handle, struct ble_l2cap_sig_hdr *hdr, struct ble_hs_conn *conn; uint16_t scid; - rc = ble_hs_mbuf_pullup_base(om, sizeof(req)); + rc = ble_l2cap_sig_mbuf_pullup_base(om, sizeof(*req), NULL); if (rc != 0) { return rc; } @@ -1249,7 +1316,7 @@ ble_l2cap_sig_coc_rsp_rx(uint16_t conn_handle, struct ble_l2cap_sig_hdr *hdr, return 0; } - rc = ble_hs_mbuf_pullup_base(om, sizeof(*rsp)); + rc = ble_l2cap_sig_mbuf_pullup_base(om, sizeof(*rsp), NULL); if (rc != 0) { goto done; } @@ -1528,8 +1595,10 @@ ble_l2cap_sig_disc_req_rx(uint16_t conn_handle, struct ble_l2cap_sig_hdr *hdr, struct ble_l2cap_chan *chan; struct ble_hs_conn *conn; int rc; + uint16_t scid; + uint16_t dcid; - rc = ble_hs_mbuf_pullup_base(om, sizeof(*req)); + rc = ble_l2cap_sig_mbuf_pullup_base(om, sizeof(*req), NULL); if (rc != 0) { return rc; } @@ -1547,12 +1616,34 @@ ble_l2cap_sig_disc_req_rx(uint16_t conn_handle, struct ble_l2cap_sig_hdr *hdr, conn = ble_hs_conn_find_assert(conn_handle); req = (struct ble_l2cap_sig_disc_req *) (*om)->om_data; + scid = le16toh(req->scid); + dcid = le16toh(req->dcid); + + if (scid < BLE_L2CAP_COC_CID_START || scid > BLE_L2CAP_COC_CID_END || + dcid < BLE_L2CAP_COC_CID_START || dcid > BLE_L2CAP_COC_CID_END) { + /* Don't bother with look-up if it is not for connection oriented + * channel + */ + chan = NULL; + } else { + /* Let's find matching channel. Note that destination CID in the request + * is from peer perspective. It is source CID from nimble perspective + */ + chan = ble_hs_conn_chan_find_by_scid(conn, dcid); + } + + if (!chan) { + os_mbuf_free_chain(txom); + ble_hs_unlock(); + ble_l2cap_sig_reject_invalid_cid_tx(conn_handle, hdr->identifier, req->dcid, req->scid); + return 0; + } - /* Let's find matching channel. Note that destination CID in the request - * is from peer perspective. It is source CID from nimble perspective + /* Core Spec 6.0 Vol3 PartA 4.6 + * If the receiver finds a DCID match but the SCID fails to find the same + * match, the request should be silently discarded. */ - chan = ble_hs_conn_chan_find_by_scid(conn, le16toh(req->dcid)); - if (!chan || (le16toh(req->scid) != chan->dcid)) { + if (scid != chan->dcid) { os_mbuf_free_chain(txom); ble_hs_unlock(); return 0; @@ -1575,25 +1666,15 @@ static void ble_l2cap_sig_coc_disconnect_cb(struct ble_l2cap_sig_proc *proc, int status) { struct ble_l2cap_chan *chan; - struct ble_l2cap_event event; struct ble_hs_conn *conn; - if (!proc) { - return; - } + assert(proc); - memset(&event, 0, sizeof(event)); chan = proc->disconnect.chan; - if (!chan) { return; } - if (!chan->cb) { - goto done; - } - -done: ble_hs_lock(); conn = ble_hs_conn_find_assert(chan->conn_handle); if (conn) { @@ -1620,7 +1701,7 @@ ble_l2cap_sig_disc_rsp_rx(uint16_t conn_handle, struct ble_l2cap_sig_hdr *hdr, return 0; } - rc = ble_hs_mbuf_pullup_base(om, sizeof(*rsp)); + rc = ble_l2cap_sig_mbuf_pullup_base(om, sizeof(*rsp), NULL); if (rc != 0) { goto done; } @@ -1644,58 +1725,6 @@ ble_l2cap_sig_disc_rsp_rx(uint16_t conn_handle, struct ble_l2cap_sig_hdr *hdr, return 0; } -static int -ble_l2cap_sig_echo_req(uint16_t conn_handle, struct ble_l2cap_sig_hdr *hdr, - struct os_mbuf **om) -{ - void *rsp; - struct os_mbuf *txom; - struct ble_l2cap_sig_hdr *rsp_hdr; - int rc; - - /* we temporarily set size to 0 as we do not want to allocate additional - * space yet */ - rsp = ble_l2cap_sig_cmd_get(BLE_L2CAP_SIG_OP_ECHO_RSP, - hdr->identifier, 0, &txom); - if (rsp == NULL) { - return BLE_HS_ENOMEM; - } - rc = os_mbuf_appendfrom(txom, *om, 0, OS_MBUF_PKTLEN(*om)); - if (rc != 0) { - os_mbuf_free_chain(txom); - return BLE_HS_ENOMEM; - } - /* after copying the request payload into the response, we need to adjust - * the size field in the header to the actual value */ - rsp_hdr = (struct ble_l2cap_sig_hdr *)txom->om_data; - rsp_hdr->length = htole16(OS_MBUF_PKTLEN(*om)); - - return ble_l2cap_sig_tx(conn_handle, txom); -} - -static int -ble_l2cap_sig_echo_rsp(uint16_t conn_handle, struct ble_l2cap_sig_hdr *hdr, - struct os_mbuf **om) -{ - struct ble_l2cap_sig_proc *proc; - uint32_t rtt_ms; - - proc = ble_l2cap_sig_proc_extract(conn_handle, BLE_L2CAP_SIG_PROC_OP_PING, - hdr->identifier); - if (proc == NULL) { - return BLE_HS_ENOENT; - } - - if (proc->ping.cb != NULL) { - ble_npl_time_t now = ble_npl_time_get(); - rtt_ms = ble_npl_time_ticks_to_ms32(now - proc->ping.time_sent); - proc->ping.cb(conn_handle, rtt_ms, *om); - ble_l2cap_sig_proc_free(proc); - } - - return 0; -} - int ble_l2cap_sig_disconnect(struct ble_l2cap_chan *chan) { @@ -1704,6 +1733,11 @@ ble_l2cap_sig_disconnect(struct ble_l2cap_chan *chan) struct ble_l2cap_sig_proc *proc; int rc; + /* this is allowed only for connection oriented channels */ + if (chan->scid < BLE_L2CAP_COC_CID_START || chan->scid > BLE_L2CAP_COC_CID_END) { + return BLE_HS_EREJECT; + } + if (chan->flags & BLE_L2CAP_CHAN_F_DISCONNECTING) { return 0; } @@ -1747,7 +1781,7 @@ ble_l2cap_sig_le_credits_rx(uint16_t conn_handle, struct ble_l2cap_sig_hdr *hdr, struct ble_l2cap_sig_le_credits *req; int rc; - rc = ble_hs_mbuf_pullup_base(om, sizeof(*req)); + rc = ble_l2cap_sig_mbuf_pullup_base(om, sizeof(*req), NULL); if (rc != 0) { return 0; } @@ -1798,14 +1832,14 @@ ble_l2cap_sig_rx_reject(uint16_t conn_handle, return 0; } - switch (proc->id) { + switch (proc->op) { #if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) != 0 - case BLE_L2CAP_SIG_PROC_OP_CONNECT: - ble_l2cap_sig_coc_connect_cb(proc, BLE_HS_EREJECT); - break; + case BLE_L2CAP_SIG_PROC_OP_CONNECT: + ble_l2cap_sig_coc_connect_cb(proc, BLE_HS_EREJECT); + break; #endif - default: - break; + default: + break; } ble_l2cap_sig_proc_free(proc); @@ -1816,16 +1850,14 @@ ble_l2cap_sig_rx_reject(uint16_t conn_handle, *****************************************************************************/ static int -ble_l2cap_sig_rx(struct ble_l2cap_chan *chan) +ble_l2cap_sig_rx(struct ble_l2cap_chan *chan, struct os_mbuf **om) { struct ble_l2cap_sig_hdr hdr; ble_l2cap_sig_rx_fn *rx_cb; uint16_t conn_handle; - struct os_mbuf **om; int rc; conn_handle = chan->conn_handle; - om = &chan->rx_buf; STATS_INC(ble_l2cap_stats, sig_rx); @@ -1905,9 +1937,10 @@ ble_l2cap_sig_extract_expired(struct ble_l2cap_sig_proc_list *dst_list) ble_hs_lock(); - prev = NULL; + next = NULL; proc = STAILQ_FIRST(&ble_l2cap_sig_procs); while (proc != NULL) { + prev = next; next = STAILQ_NEXT(proc, next); time_diff = proc->exp_os_ticks - now; @@ -1933,90 +1966,42 @@ ble_l2cap_sig_extract_expired(struct ble_l2cap_sig_proc_list *dst_list) return next_exp_in; } -int -ble_l2cap_sig_ping(uint16_t conn_handle, ble_l2cap_ping_fn cb, - const void *data, uint16_t data_len) +void +ble_l2cap_sig_conn_broken(uint16_t conn_handle, int reason) { struct ble_l2cap_sig_proc *proc; - struct os_mbuf *txom; - void *req; - struct ble_l2cap_sig_hdr *hdr; - int rc; - if ((data_len > 0) && (data == NULL)) { - return BLE_HS_EBADDATA; + /* If there were any pending procedure, indicate to the application that it + * did not complete. + */ + proc = ble_l2cap_sig_proc_extract(conn_handle, BLE_L2CAP_SIG_PROC_OP_UPDATE, 0); + if (proc != NULL) { + ble_l2cap_sig_update_call_cb(proc, reason); + ble_l2cap_sig_proc_free(proc); } - ble_hs_lock(); - proc = ble_l2cap_sig_proc_alloc(); - ble_hs_unlock(); - - if (!proc) { - return BLE_HS_ENOMEM; +#if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) != 0 + proc = ble_l2cap_sig_proc_extract(conn_handle, BLE_L2CAP_SIG_PROC_OP_CONNECT, 0); + if (proc != NULL) { + ble_l2cap_sig_coc_connect_cb(proc, reason); + ble_l2cap_sig_proc_free(proc); } - /* allocate and fill procedure context */ - proc->op = BLE_L2CAP_SIG_PROC_OP_PING; - proc->id = ble_l2cap_sig_next_id(); - proc->conn_handle = conn_handle; - proc->ping.cb = cb; - proc->ping.time_sent = ble_npl_time_get(); - - /* allocate signalling packet and copy payload into packet */ - req = ble_l2cap_sig_cmd_get(BLE_L2CAP_SIG_OP_ECHO_REQ, - proc->id, 0, &txom); - if (req == NULL) { + proc = ble_l2cap_sig_proc_extract(conn_handle, + BLE_L2CAP_SIG_PROC_OP_DISCONNECT, 0); + if (proc != NULL) { + ble_l2cap_sig_coc_disconnect_cb(proc, reason); ble_l2cap_sig_proc_free(proc); - return BLE_HS_ENOMEM; } - if (data_len > 0) { - rc = os_mbuf_append(txom, data, data_len); - if (rc != 0) { - os_mbuf_free_chain(txom); - ble_l2cap_sig_proc_free(proc); - return BLE_HS_ENOMEM; - } - /* adjust the size field in the signalling header */ - hdr = (struct ble_l2cap_sig_hdr *)txom->om_data; - hdr->length = htole16(data_len); - } - - rc = ble_l2cap_sig_tx(proc->conn_handle, txom); - ble_l2cap_sig_process_status(proc, rc); - return rc; -} - -void -ble_l2cap_sig_conn_broken(uint16_t conn_handle, int reason) -{ - struct ble_l2cap_sig_proc *proc; - - /* Report a failure for each timed out procedure. */ - while ((proc = STAILQ_FIRST(&ble_l2cap_sig_procs)) != NULL) { - switch(proc->op) { - case BLE_L2CAP_SIG_PROC_OP_UPDATE: - ble_l2cap_sig_update_call_cb(proc, reason); - break; -#if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) != 0 - case BLE_L2CAP_SIG_PROC_OP_CONNECT: - ble_l2cap_sig_coc_connect_cb(proc, reason); - break; - case BLE_L2CAP_SIG_PROC_OP_DISCONNECT: - ble_l2cap_sig_coc_disconnect_cb(proc, reason); - break; #if MYNEWT_VAL(BLE_L2CAP_ENHANCED_COC) - case BLE_L2CAP_SIG_PROC_OP_RECONFIG: - ble_l2cap_sig_coc_reconfig_cb(proc, reason); - break; + proc = ble_l2cap_sig_proc_extract(conn_handle, BLE_L2CAP_SIG_PROC_OP_RECONFIG, 0); + if (proc != NULL) { + ble_l2cap_sig_coc_reconfig_cb(proc, reason); + ble_l2cap_sig_proc_free(proc); + } #endif #endif - } - - STAILQ_REMOVE_HEAD(&ble_l2cap_sig_procs, next); - ble_l2cap_sig_proc_free(proc); - } - } /** @@ -2042,15 +2027,15 @@ ble_l2cap_sig_timer(void) while ((proc = STAILQ_FIRST(&temp_list)) != NULL) { STATS_INC(ble_l2cap_stats, proc_timeout); switch(proc->op) { - case BLE_L2CAP_SIG_PROC_OP_UPDATE: - ble_l2cap_sig_update_call_cb(proc, BLE_HS_ETIMEOUT); - break; + case BLE_L2CAP_SIG_PROC_OP_UPDATE: + ble_l2cap_sig_update_call_cb(proc, BLE_HS_ETIMEOUT); + break; #if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) != 0 - case BLE_L2CAP_SIG_PROC_OP_CONNECT: - ble_l2cap_sig_coc_connect_cb(proc, BLE_HS_ETIMEOUT); + case BLE_L2CAP_SIG_PROC_OP_CONNECT: + ble_l2cap_sig_coc_connect_cb(proc, BLE_HS_ETIMEOUT); break; - case BLE_L2CAP_SIG_PROC_OP_DISCONNECT: - ble_l2cap_sig_coc_disconnect_cb(proc, BLE_HS_ETIMEOUT); + case BLE_L2CAP_SIG_PROC_OP_DISCONNECT: + ble_l2cap_sig_coc_disconnect_cb(proc, BLE_HS_ETIMEOUT); break; #endif } diff --git a/nimble/host/src/ble_l2cap_sig_priv.h b/nimble/host/src/ble_l2cap_sig_priv.h index 55b37cd206..a698cd0d8f 100644 --- a/nimble/host/src/ble_l2cap_sig_priv.h +++ b/nimble/host/src/ble_l2cap_sig_priv.h @@ -172,8 +172,6 @@ ble_l2cap_sig_coc_reconfig(uint16_t conn_handle, struct ble_l2cap_chan *chans[], } #endif -int ble_l2cap_sig_ping(uint16_t conn_handle, ble_l2cap_ping_fn cb, - const void *data, uint16_t data_len); void ble_l2cap_sig_conn_broken(uint16_t conn_handle, int reason); int32_t ble_l2cap_sig_timer(void); struct ble_l2cap_chan *ble_l2cap_sig_create_chan(uint16_t conn_handle); diff --git a/nimble/host/src/ble_sm.c b/nimble/host/src/ble_sm.c index c63af4087c..a6ed2986ce 100644 --- a/nimble/host/src/ble_sm.c +++ b/nimble/host/src/ble_sm.c @@ -49,6 +49,15 @@ #include "ble_hs_priv.h" #if NIMBLE_BLE_CONNECT + +#ifndef min +#define min(a, b) ((a) < (b) ? (a) : (b)) +#endif + +#ifndef max +#define max(a, b) ((a) > (b) ? (a) : (b)) +#endif + #if NIMBLE_BLE_SM /** Procedure timeout; 30 seconds. */ @@ -261,7 +270,7 @@ ble_sm_gen_pair_rand(uint8_t *pair_rand) } #endif - rc = ble_hs_hci_util_rand(pair_rand, 16); + rc = ble_hs_hci_rand(pair_rand, 16); if (rc != 0) { return rc; } @@ -282,7 +291,7 @@ ble_sm_gen_ediv(struct ble_sm_master_id *master_id) } #endif - rc = ble_hs_hci_util_rand(&master_id->ediv, sizeof master_id->ediv); + rc = ble_hs_hci_rand(&master_id->ediv, sizeof master_id->ediv); if (rc != 0) { return rc; } @@ -303,7 +312,7 @@ ble_sm_gen_master_id_rand(struct ble_sm_master_id *master_id) } #endif - rc = ble_hs_hci_util_rand(&master_id->rand_val, sizeof master_id->rand_val); + rc = ble_hs_hci_rand(&master_id->rand_val, sizeof master_id->rand_val); if (rc != 0) { return rc; } @@ -325,7 +334,7 @@ ble_sm_gen_ltk(struct ble_sm_proc *proc, uint8_t *ltk) } #endif - rc = ble_hs_hci_util_rand(ltk, proc->key_size); + rc = ble_hs_hci_rand(ltk, proc->key_size); if (rc != 0) { return rc; } @@ -350,7 +359,7 @@ ble_sm_gen_csrk(struct ble_sm_proc *proc, uint8_t *csrk) } #endif - rc = ble_hs_hci_util_rand(csrk, 16); + rc = ble_hs_hci_rand(csrk, 16); if (rc != 0) { return rc; } @@ -564,7 +573,8 @@ ble_sm_persist_keys(struct ble_sm_proc *proc) ble_hs_unlock(); if (identity_ev) { - ble_gap_identity_event(proc->conn_handle); + /* Use peer_addr since it does have proper addr type (i.e. 0/1, not 2/3) */ + ble_gap_identity_event(proc->conn_handle, &peer_addr); } authenticated = proc->flags & BLE_SM_PROC_F_AUTHENTICATED; @@ -894,7 +904,8 @@ ble_sm_chk_repeat_pairing(uint16_t conn_handle, } void -ble_sm_process_result(uint16_t conn_handle, struct ble_sm_result *res) +ble_sm_process_result(uint16_t conn_handle, struct ble_sm_result *res, + bool tx_fail) { struct ble_sm_proc *prev; struct ble_sm_proc *proc; @@ -927,12 +938,18 @@ ble_sm_process_result(uint16_t conn_handle, struct ble_sm_result *res) } } - if (res->sm_err != 0) { + if (res->sm_err != 0 && tx_fail) { ble_sm_pair_fail_tx(conn_handle, res->sm_err); } ble_hs_unlock(); + if (res->enc_cb && + res->app_status != BLE_HS_ENOTCONN) { + /* Do not send this event on broken connection */ + ble_gap_pairing_complete_event(conn_handle, res->sm_err); + } + if (proc == NULL) { break; } @@ -1192,7 +1209,7 @@ ble_sm_enc_event_rx(uint16_t conn_handle, uint8_t evt_status, int encrypted) ble_hs_unlock(); res.bonded = bonded; - ble_sm_process_result(conn_handle, &res); + ble_sm_process_result(conn_handle, &res, true); } void @@ -1222,15 +1239,15 @@ ble_sm_retrieve_ltk(uint16_t ediv, uint64_t rand, uint8_t peer_addr_type, struct ble_store_key_sec key_sec; int rc; - /* Tell applicaiton to look up LTK by peer address and ediv/rand pair. */ + /* Tell application to look up LTK by peer address and ediv/rand pair. */ memset(&key_sec, 0, sizeof key_sec); key_sec.peer_addr.type = peer_addr_type; memcpy(key_sec.peer_addr.val, peer_addr, 6); - key_sec.ediv = ediv; - key_sec.rand_num = rand; - key_sec.ediv_rand_present = 1; rc = ble_store_read_our_sec(&key_sec, value_sec); + if (value_sec->ediv != ediv || value_sec->rand_num != rand) { + return BLE_HS_ENOENT; + } return rc; } @@ -1413,7 +1430,7 @@ ble_sm_ltk_req_rx(const struct ble_hci_ev_le_subev_lt_key_req *ev) } } - ble_sm_process_result(conn_handle, &res); + ble_sm_process_result(conn_handle, &res, true); return 0; } @@ -1737,10 +1754,10 @@ ble_sm_verify_auth_requirements(uint8_t cmd) return false; } } - /* Fail if Secure Connections level forces MITM protection and remote does not + /* Fail if security level forces MITM protection and remote does not * support it */ - if (MYNEWT_VAL(BLE_SM_SC_LVL) >= 3 && !(cmd & BLE_SM_PAIR_AUTHREQ_MITM)) { + if (MYNEWT_VAL(BLE_SM_LVL) >= 3 && !(cmd & BLE_SM_PAIR_AUTHREQ_MITM)) { return false; } return true; @@ -1823,7 +1840,7 @@ ble_sm_pair_req_rx(uint16_t conn_handle, struct os_mbuf **om, if (conn->bhc_flags & BLE_HS_CONN_F_MASTER) { res->sm_err = BLE_SM_ERR_CMD_NOT_SUPP; res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_CMD_NOT_SUPP); - } else if (MYNEWT_VAL(BLE_SM_SC_LVL) == 1) { + } else if (MYNEWT_VAL(BLE_SM_LVL) == 1) { res->sm_err = BLE_SM_ERR_CMD_NOT_SUPP; res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_CMD_NOT_SUPP); } else if (req->max_enc_key_size < BLE_SM_PAIR_KEY_SZ_MIN) { @@ -1832,12 +1849,18 @@ ble_sm_pair_req_rx(uint16_t conn_handle, struct os_mbuf **om, } else if (req->max_enc_key_size > BLE_SM_PAIR_KEY_SZ_MAX) { res->sm_err = BLE_SM_ERR_INVAL; res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_INVAL); + } else if (MYNEWT_VAL(BLE_SM_SC_ONLY) && !(req->authreq & BLE_SM_PAIR_AUTHREQ_SC)) { + /* Fail if Secure Connections Only mode is on and SC is not supported by peer + */ + res->sm_err = BLE_SM_ERR_AUTHREQ; + res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_AUTHREQ); + res->enc_cb = 1; } else if (MYNEWT_VAL(BLE_SM_SC_ONLY) && (req->max_enc_key_size != BLE_SM_PAIR_KEY_SZ_MAX)) { - /* Fail if Secure Connections Only mode is on and remote does not meet - * key size requirements - MITM was checked in last step - */ + /* Fail if Secure Connections Only mode is on and key size is too small + */ res->sm_err = BLE_SM_ERR_ENC_KEY_SZ; res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_ENC_KEY_SZ); + res->enc_cb = 1; } else if (!ble_sm_verify_auth_requirements(req->authreq)) { res->sm_err = BLE_SM_ERR_AUTHREQ; res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_AUTHREQ); @@ -1984,6 +2007,14 @@ ble_sm_sec_req_rx(uint16_t conn_handle, struct os_mbuf **om, ble_hs_lock(); conn = ble_hs_conn_find_assert(conn_handle); + + /* Check if pairing procedure is already in progress */ + if (ble_sm_proc_find(conn_handle, BLE_SM_PROC_STATE_PAIR, 1, NULL)) { + ble_hs_unlock(); + res->app_status = 0; + return; + } + if (!(conn->bhc_flags & BLE_HS_CONN_F_MASTER)) { res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_CMD_NOT_SUPP); res->sm_err = BLE_SM_ERR_CMD_NOT_SUPP; @@ -2041,14 +2072,17 @@ ble_sm_key_exch_success(struct ble_sm_proc *proc, struct ble_sm_result *res) /* The procedure is now complete. Update connection bonded state and * terminate procedure. */ + int bonded = !!(proc->flags & BLE_SM_PROC_F_BONDING); ble_sm_update_sec_state(proc->conn_handle, 1, !!(proc->flags & BLE_SM_PROC_F_AUTHENTICATED), - !!(proc->flags & BLE_SM_PROC_F_BONDING), + bonded, proc->key_size); proc->state = BLE_SM_PROC_STATE_NONE; res->app_status = 0; res->enc_cb = 1; + res->bonded = bonded; + res->sm_err = BLE_SM_ERR_SUCCESS; } static void @@ -2067,6 +2101,8 @@ ble_sm_key_exch_exec(struct ble_sm_proc *proc, struct ble_sm_result *res, uint8_t our_key_dist; struct os_mbuf *txom; const uint8_t *irk; + struct ble_store_gen_key gen_key; + int ltk_gen = 0; int rc; ble_sm_key_dist(proc, &init_key_dist, &resp_key_dist); @@ -2084,15 +2120,37 @@ ble_sm_key_exch_exec(struct ble_sm_proc *proc, struct ble_sm_result *res, goto err; } - rc = ble_sm_gen_ltk(proc, enc_info->ltk); - if (rc != 0) { - os_mbuf_free_chain(txom); - goto err; + proc->our_keys.key_size = proc->key_size; + + if (ble_hs_cfg.store_gen_key_cb) { + memset(&gen_key, 0, sizeof(gen_key)); + rc = ble_hs_cfg.store_gen_key_cb(BLE_STORE_GEN_KEY_LTK, &gen_key, + proc->conn_handle); + if (rc == 0) { + /* Trim LRK to keysize */ + memset(gen_key.ltk_periph + proc->key_size, 0, + 16 - proc->key_size); + + proc->our_keys.ediv = gen_key.ediv; + proc->our_keys.rand_val = gen_key.rand; + memcpy(proc->our_keys.ltk, gen_key.ltk_periph, 16); + + ltk_gen = 1; + } } - /* store LTK before sending since ble_sm_tx consumes tx mbuf */ - memcpy(proc->our_keys.ltk, enc_info->ltk, 16); - proc->our_keys.key_size = proc->key_size; + if (!ltk_gen) { + rc = ble_sm_gen_ltk(proc, enc_info->ltk); + if (rc != 0) { + os_mbuf_free_chain(txom); + goto err; + } + + /* store LTK before sending since ble_sm_tx consumes tx mbuf */ + memcpy(proc->our_keys.ltk, enc_info->ltk, 16); + } else { + memcpy(enc_info->ltk, proc->our_keys.ltk, 16); + } proc->our_keys.ltk_valid = 1; rc = ble_sm_tx(proc->conn_handle, txom); @@ -2108,20 +2166,25 @@ ble_sm_key_exch_exec(struct ble_sm_proc *proc, struct ble_sm_result *res, goto err; } - rc = ble_sm_gen_ediv(master_id); - if (rc != 0) { - os_mbuf_free_chain(txom); - goto err; - } - rc = ble_sm_gen_master_id_rand(master_id); - if (rc != 0) { - os_mbuf_free_chain(txom); - goto err; - } + if (!ltk_gen) { + rc = ble_sm_gen_ediv(master_id); + if (rc != 0) { + os_mbuf_free_chain(txom); + goto err; + } + rc = ble_sm_gen_master_id_rand(master_id); + if (rc != 0) { + os_mbuf_free_chain(txom); + goto err; + } + proc->our_keys.rand_val = master_id->rand_val; + proc->our_keys.ediv = master_id->ediv; + } else { + master_id->ediv = proc->our_keys.ediv; + master_id->rand_val = proc->our_keys.rand_val; + } proc->our_keys.ediv_rand_valid = 1; - proc->our_keys.rand_val = master_id->rand_val; - proc->our_keys.ediv = master_id->ediv; rc = ble_sm_tx(proc->conn_handle, txom); if (rc != 0) { @@ -2186,14 +2249,29 @@ ble_sm_key_exch_exec(struct ble_sm_proc *proc, struct ble_sm_result *res, goto err; } - rc = ble_sm_gen_csrk(proc, sign_info->sig_key); - if (rc != 0) { - os_mbuf_free_chain(txom); - goto err; + if (ble_hs_cfg.store_gen_key_cb) { + memset(&gen_key, 0, sizeof(gen_key)); + rc = ble_hs_cfg.store_gen_key_cb(BLE_STORE_GEN_KEY_CSRK, &gen_key, + proc->conn_handle); + if (rc == 0) { + memcpy(proc->our_keys.csrk, gen_key.csrk, 16); + } + } else { + rc = -1; } + if (rc != 0) { + rc = ble_sm_gen_csrk(proc, sign_info->sig_key); + if (rc != 0) { + os_mbuf_free_chain(txom); + goto err; + } + + memcpy(proc->our_keys.csrk, sign_info->sig_key, 16); + } else { + memcpy(sign_info->sig_key, proc->our_keys.csrk, 16); + } proc->our_keys.csrk_valid = 1; - memcpy(proc->our_keys.csrk, sign_info->sig_key, 16); rc = ble_sm_tx(proc->conn_handle, txom); if (rc != 0) { @@ -2419,6 +2497,7 @@ ble_sm_fail_rx(uint16_t conn_handle, struct os_mbuf **om, cmd = (struct ble_sm_pair_fail *)(*om)->om_data; res->app_status = BLE_HS_SM_PEER_ERR(cmd->reason); + res->sm_err = cmd->reason; } } @@ -2506,7 +2585,7 @@ ble_sm_pair_initiate(uint16_t conn_handle) } if (proc != NULL) { - ble_sm_process_result(conn_handle, &res); + ble_sm_process_result(conn_handle, &res, true); } return res.app_status; @@ -2545,7 +2624,7 @@ ble_sm_slave_initiate(uint16_t conn_handle) ble_hs_unlock(); if (proc != NULL) { - ble_sm_process_result(conn_handle, &res); + ble_sm_process_result(conn_handle, &res, true); } return res.app_status; @@ -2599,19 +2678,18 @@ ble_sm_enc_initiate(uint16_t conn_handle, uint8_t key_size, ble_hs_unlock(); - ble_sm_process_result(conn_handle, &res); + ble_sm_process_result(conn_handle, &res, true); return res.app_status; } static int -ble_sm_rx(struct ble_l2cap_chan *chan) +ble_sm_rx(struct ble_l2cap_chan *chan, struct os_mbuf **om) { struct ble_sm_result res; ble_sm_rx_fn *rx_cb; uint8_t op; uint16_t conn_handle; - struct os_mbuf **om; int rc; STATS_INC(ble_l2cap_stats, sm_rx); @@ -2621,9 +2699,6 @@ ble_sm_rx(struct ble_l2cap_chan *chan) return BLE_HS_ENOTCONN; } - om = &chan->rx_buf; - BLE_HS_DBG_ASSERT(*om != NULL); - rc = os_mbuf_copydata(*om, 0, 1, &op); if (rc != 0) { return BLE_HS_EBADDATA; @@ -2637,7 +2712,8 @@ ble_sm_rx(struct ble_l2cap_chan *chan) memset(&res, 0, sizeof res); rx_cb(conn_handle, om, &res); - ble_sm_process_result(conn_handle, &res); + ble_sm_process_result(conn_handle, &res, op == BLE_SM_OP_PAIR_FAIL ? + false : true); rc = res.app_status; } else { rc = BLE_HS_ENOTSUP; @@ -2751,7 +2827,7 @@ ble_sm_inject_io(uint16_t conn_handle, struct ble_sm_io *pkey) return rc; } - ble_sm_process_result(conn_handle, &res); + ble_sm_process_result(conn_handle, &res, true); return res.app_status; } @@ -2764,7 +2840,7 @@ ble_sm_connection_broken(uint16_t conn_handle) res.app_status = BLE_HS_ENOTCONN; res.enc_cb = 1; - ble_sm_process_result(conn_handle, &res); + ble_sm_process_result(conn_handle, &res, true); } int @@ -2793,7 +2869,7 @@ ble_sm_init(void) * simple */ static int -ble_sm_rx(struct ble_l2cap_chan *chan) +ble_sm_rx(struct ble_l2cap_chan *chan, struct os_mbuf **om) { struct ble_sm_pair_fail *cmd; struct os_mbuf *txom; @@ -2801,7 +2877,7 @@ ble_sm_rx(struct ble_l2cap_chan *chan) int rc; handle = ble_l2cap_get_conn_handle(chan); - if (!handle) { + if (handle == BLE_HS_CONN_HANDLE_NONE) { return BLE_HS_ENOTCONN; } @@ -2838,4 +2914,107 @@ ble_sm_create_chan(uint16_t conn_handle) return chan; } +#if MYNEWT_VAL(BLE_SM_CSIS_SIRK) +int +ble_sm_csis_decrypt_sirk(const uint8_t *ltk, const uint8_t *enc_sirk, uint8_t *out) +{ + int rc; + + /* Decrypt SIRK with sdf(K, EncSIRK) */ + rc = ble_sm_alg_csis_sdf(ltk, enc_sirk, out); + + return rc; +} + +int +ble_sm_csis_resolve_rsi(const uint8_t *rsi, const uint8_t *sirk, + const ble_addr_t *ltk_peer_addr) +{ + struct ble_store_key_sec key_sec; + struct ble_store_value_sec value_sec; + uint8_t plaintext_sirk[16] = {0}; + uint8_t local_hash[3] = {0}; + uint8_t prand[3] = {0}; + uint8_t hash[3] = {0}; + int rc; + + memcpy(hash, rsi, 3); + memcpy(prand, rsi + 3, 3); + + if (ltk_peer_addr) { + memset(&key_sec, 0, sizeof(key_sec)); + key_sec.peer_addr = *ltk_peer_addr; + + rc = ble_store_read_peer_sec(&key_sec, &value_sec); + if (rc != 0) { + return rc; + } else if (!value_sec.ltk_present) { + return BLE_HS_ENOENT; + } + + rc = ble_sm_csis_decrypt_sirk(value_sec.ltk, sirk, plaintext_sirk); + if (rc != 0) { + return rc; + } + } else { + memcpy(plaintext_sirk, sirk, 16); + } + + rc = ble_sm_alg_csis_sih(plaintext_sirk, prand, local_hash); + if (rc != 0) { + return rc; + } + + if (memcmp(local_hash, hash, 3)) { + return BLE_HS_EAUTHEN; + } + + return 0; +} + +int +ble_sm_csis_encrypt_sirk(const uint8_t *ltk, const uint8_t *plaintext_sirk, uint8_t *out) +{ + int rc; + + /* Encrypt SIRK with sef(K, SIRK) */ + rc = ble_sm_alg_csis_sef(ltk, plaintext_sirk, out); + + return rc; +} + +int +ble_sm_csis_generate_rsi(const uint8_t *sirk, uint8_t *out) +{ + const uint8_t prand_check_all_set[3] = {0xff, 0xff, 0xef}; + const uint8_t prand_check_all_reset[3] = {0x0, 0x0, 0x40}; + uint8_t prand[3] = {0}; + uint8_t hash[3] = {0}; + int rc; + + do { + rc = ble_hs_hci_rand(prand, 3); + if (rc != 0) { + return rc; + } + /* Two MSBs of prand shall be equal to 0 and 1 */ + prand[2] &= ~0xc0; + prand[2] |= 0x40; + + /* prand's random part shall not be all 0s nor all 1s */ + } while (memcmp(prand, prand_check_all_set, 3) || + memcmp(prand, prand_check_all_reset, 3)); + + rc = ble_sm_alg_csis_sih(sirk, prand, hash); + if (rc != 0) { + return rc; + } + + memcpy(out, hash, 3); + memcpy(out + 3, prand, 3); + + return 0; +} + +#endif #endif diff --git a/nimble/host/src/ble_sm_alg.c b/nimble/host/src/ble_sm_alg.c index 8b3326deb4..bf81f21ffb 100644 --- a/nimble/host/src/ble_sm_alg.c +++ b/nimble/host/src/ble_sm_alg.c @@ -418,6 +418,139 @@ ble_sm_alg_g2(const uint8_t *u, const uint8_t *v, const uint8_t *x, return 0; } +int +ble_sm_alg_csis_k1(const uint8_t *n, size_t n_len, const uint8_t *salt, + const uint8_t *p, size_t p_len, uint8_t *out) +{ + int rc; + uint8_t t[16] = {0}; + uint8_t salt_be[16] = {0}; + uint8_t n_be[16] = {0}; + + /* XXX: Spec does not specify the maximum N and P parameters length. + * We assume that 16 bytes is enough and return error if passed len value is greater + * than that */ + if ((n_len > 16) || (p_len > 16)) { + return BLE_HS_EINVAL; + } + + swap_buf(salt_be, salt, 16); + swap_buf(n_be, n, n_len); + + /* T = AES-CMAC_SALT (N) */ + rc = ble_sm_alg_aes_cmac(salt_be, n_be, n_len, t); + if (rc != 0) { + return rc; + } + + /* AES-CMAC_T (P) */ + rc = ble_sm_alg_aes_cmac(t, p, p_len, out); + if (rc != 0) { + return rc; + } + + swap_in_place(out, 16); + + return 0; +} + +int +ble_sm_alg_csis_s1(const uint8_t *m, size_t m_len, uint8_t *out) +{ + int rc; + uint8_t k_zero[16] = {0}; + + /* XXX: Spec does not specify the maximum M parameter length. + * We assume that 16 bytes is enough and return error if passed len value is greater + * than that */ + if (m_len > 16) { + return BLE_HS_EINVAL; + } + + /* AES-CMAC_zero (M) */ + rc = ble_sm_alg_aes_cmac(k_zero, m, m_len, out); + if (rc != 0) { + return rc; + } + + swap_in_place(out, 16); + + return 0; +} + +int +ble_sm_alg_csis_sef(const uint8_t *k, const uint8_t *plaintext_sirk, uint8_t *out) +{ + uint8_t salt[16]; + int rc; + int i; + + /* s1("SIRKenc") */ + rc = ble_sm_alg_csis_s1((const uint8_t *) "SIRKenc", 7, salt); + if (rc != 0) { + return rc; + } + + /* k1(K, s1("SIRKenc"), "csis") */ + rc = ble_sm_alg_csis_k1(k, 16, salt, (const uint8_t *) "csis", 4, out); + if (rc != 0) { + return rc; + } + + /* k1(K, s1("SIRKenc"), "csis") ^ SIRK */ + for (i = 0; i < 16; i++) { + out[i] ^= plaintext_sirk[i]; + } + + return 0; +} + +int +ble_sm_alg_csis_sdf(const uint8_t *k, const uint8_t *enc_sirk, uint8_t *out) +{ + uint8_t salt[16]; + int rc; + int i; + + /* s1("SIRKenc") */ + rc = ble_sm_alg_csis_s1((const uint8_t *) "SIRKenc", 7, salt); + if (rc != 0) { + return rc; + } + + /* k1(K, s1("SIRKenc"), "csis") */ + rc = ble_sm_alg_csis_k1(k, 16, salt, (const uint8_t *) "csis", 4, out); + if (rc != 0) { + return rc; + } + + /* k1(K, s1("SIRKenc"), "csis") ^ EncSIRK */ + for (i = 0; i < 16; i++) { + out[i] ^= enc_sirk[i]; + } + + return 0; +} + +int +ble_sm_alg_csis_sih(const uint8_t *k, const uint8_t *r, uint8_t *out) +{ + uint8_t r1[16]; + int rc; + + memcpy(r1, r, 3); + memset(r1 + 3, 0, 13); + + rc = ble_sm_alg_encrypt(k, r1, r1); + if (rc != 0) { + return rc; + } + + memcpy(out, r1, 3); + + return 0; +} + int ble_sm_alg_gen_dhkey(const uint8_t *peer_pub_key_x, const uint8_t *peer_pub_key_y, const uint8_t *our_priv_key, uint8_t *out_dhkey) @@ -517,7 +650,7 @@ ble_sm_alg_rand(uint8_t *dst, unsigned int size) size -= num; } #else - if (ble_hs_hci_util_rand(dst, size)) { + if (ble_hs_hci_rand(dst, size)) { return 0; } #endif diff --git a/nimble/host/src/ble_sm_cmd.c b/nimble/host/src/ble_sm_cmd.c index b84df1ec75..a740dc3ac2 100644 --- a/nimble/host/src/ble_sm_cmd.c +++ b/nimble/host/src/ble_sm_cmd.c @@ -29,18 +29,20 @@ void * ble_sm_cmd_get(uint8_t opcode, size_t len, struct os_mbuf **txom) { struct ble_sm_hdr *hdr; + void *data; *txom = ble_hs_mbuf_l2cap_pkt(); if (*txom == NULL) { return NULL; } - if (os_mbuf_extend(*txom, sizeof(*hdr) + len) == NULL) { + data = os_mbuf_extend(*txom, sizeof(*hdr) + len); + if (data == NULL) { os_mbuf_free_chain(*txom); return NULL; } - hdr = (struct ble_sm_hdr *)(*txom)->om_data; + hdr = (struct ble_sm_hdr *)data; hdr->opcode = opcode; diff --git a/nimble/host/src/ble_sm_lgcy.c b/nimble/host/src/ble_sm_lgcy.c index 0259ff4682..1a500fb746 100644 --- a/nimble/host/src/ble_sm_lgcy.c +++ b/nimble/host/src/ble_sm_lgcy.c @@ -36,7 +36,7 @@ #define IOACT_INPUT BLE_SM_IOACT_INPUT #define IOACT_DISP BLE_SM_IOACT_DISP -/* This is the initiator passkey action action dpeneding on the io +/* This is the initiator passkey action action depending on the io * capabilties of both parties */ static const uint8_t ble_sm_lgcy_init_ioa[5 /*resp*/ ][5 /*init*/ ] = diff --git a/nimble/host/src/ble_sm_priv.h b/nimble/host/src/ble_sm_priv.h index 27e75aa1d9..d8e1f0358e 100644 --- a/nimble/host/src/ble_sm_priv.h +++ b/nimble/host/src/ble_sm_priv.h @@ -314,12 +314,25 @@ int ble_sm_alg_f6(const uint8_t *w, const uint8_t *n1, const uint8_t *n2, const uint8_t *r, const uint8_t *iocap, uint8_t a1t, const uint8_t *a1, uint8_t a2t, const uint8_t *a2, uint8_t *check); +int ble_sm_alg_csis_k1(const uint8_t *n, size_t n_len, const uint8_t *salt, + const uint8_t *p, size_t p_len, uint8_t *out); +int ble_sm_alg_csis_s1(const uint8_t *m, size_t m_len, uint8_t *out); +int ble_sm_alg_csis_sef(const uint8_t *k, const uint8_t *plaintext_sirk, + uint8_t *out); +int ble_sm_alg_csis_sdf(const uint8_t *k, const uint8_t *enc_sirk, + uint8_t *out); +int ble_sm_alg_csis_sih(const uint8_t *k, const uint8_t *r, uint8_t *out); int ble_sm_alg_gen_dhkey(const uint8_t *peer_pub_key_x, const uint8_t *peer_pub_key_y, const uint8_t *our_priv_key, uint8_t *out_dhkey); int ble_sm_alg_gen_key_pair(uint8_t *pub, uint8_t *priv); void ble_sm_alg_ecc_init(void); +int ble_sm_csis_generate_rsi(const uint8_t *sirk, uint8_t *out); +int ble_sm_csis_encrypt_sirk(const uint8_t *ltk, const uint8_t *plaintext_sirk, + uint8_t *out); +int ble_sm_csis_decrypt_sirk(const uint8_t *ltk, const uint8_t *enc_sirk, uint8_t *out); + void ble_sm_enc_change_rx(const struct ble_hci_ev_enrypt_chg *ev); void ble_sm_enc_key_refresh_rx(const struct ble_hci_ev_enc_key_refresh *ev); int ble_sm_ltk_req_rx(const struct ble_hci_ev_le_subev_lt_key_req *ev); @@ -381,7 +394,8 @@ uint8_t *ble_sm_our_pair_rand(struct ble_sm_proc *proc); uint8_t *ble_sm_peer_pair_rand(struct ble_sm_proc *proc); int ble_sm_ioact_state(uint8_t action); int ble_sm_proc_can_advance(struct ble_sm_proc *proc); -void ble_sm_process_result(uint16_t conn_handle, struct ble_sm_result *res); +void ble_sm_process_result(uint16_t conn_handle, struct ble_sm_result *res, + bool tx_fail); void ble_sm_confirm_advance(struct ble_sm_proc *proc); void ble_sm_ia_ra(struct ble_sm_proc *proc, uint8_t *out_iat, uint8_t *out_ia, diff --git a/nimble/host/src/ble_sm_sc.c b/nimble/host/src/ble_sm_sc.c index 162a4a2ba1..0cd2b2ee86 100644 --- a/nimble/host/src/ble_sm_sc.c +++ b/nimble/host/src/ble_sm_sc.c @@ -893,7 +893,7 @@ ble_sm_sc_oob_generate_data(struct ble_sm_sc_oob_data *oob_data) return rc; } - rc = ble_hs_hci_util_rand(oob_data->r, 16); + rc = ble_hs_hci_rand(oob_data->r, 16); if (rc) { return rc; } diff --git a/nimble/host/src/ble_store.c b/nimble/host/src/ble_store.c index 22e6089471..79b2f7b95e 100644 --- a/nimble/host/src/ble_store.c +++ b/nimble/host/src/ble_store.c @@ -299,10 +299,6 @@ ble_store_key_from_value_sec(struct ble_store_key_sec *out_key, const struct ble_store_value_sec *value) { out_key->peer_addr = value->peer_addr; - - out_key->ediv = value->ediv; - out_key->rand_num = value->rand_num; - out_key->ediv_rand_present = 1; out_key->idx = 0; } @@ -341,18 +337,18 @@ ble_store_iterate(int obj_type, /* a magic value to retrieve anything */ memset(&key, 0, sizeof(key)); switch(obj_type) { - case BLE_STORE_OBJ_TYPE_PEER_SEC: - case BLE_STORE_OBJ_TYPE_OUR_SEC: - key.sec.peer_addr = *BLE_ADDR_ANY; - pidx = &key.sec.idx; - break; - case BLE_STORE_OBJ_TYPE_CCCD: - key.cccd.peer_addr = *BLE_ADDR_ANY; - pidx = &key.cccd.idx; - break; - default: - BLE_HS_DBG_ASSERT(0); - return BLE_HS_EINVAL; + case BLE_STORE_OBJ_TYPE_PEER_SEC: + case BLE_STORE_OBJ_TYPE_OUR_SEC: + key.sec.peer_addr = *BLE_ADDR_ANY; + pidx = &key.sec.idx; + break; + case BLE_STORE_OBJ_TYPE_CCCD: + key.cccd.peer_addr = *BLE_ADDR_ANY; + pidx = &key.cccd.idx; + break; + default: + BLE_HS_DBG_ASSERT(0); + return BLE_HS_EINVAL; } while (1) { @@ -398,7 +394,7 @@ ble_store_clear(void) union ble_store_key key; int obj_type; int rc; - int i; + unsigned int i; /* A zeroed key will always retrieve the first value. */ memset(&key, 0, sizeof key); diff --git a/nimble/host/src/ble_store_util.c b/nimble/host/src/ble_store_util.c index 7de482721b..6dcbca25a1 100644 --- a/nimble/host/src/ble_store_util.c +++ b/nimble/host/src/ble_store_util.c @@ -59,20 +59,6 @@ ble_store_util_iter_unique_peer(int obj_type, return 0; } -/** - * Retrieves the set of peer addresses for which a bond has been established. - * - * @param out_peer_id_addrs On success, the set of bonded peer addresses - * gets written here. - * @param out_num_peers On success, the number of bonds gets written - * here. - * @param max_peers The capacity of the destination buffer. - * - * @return 0 on success; - * BLE_HS_ENOMEM if the destination buffer is too - * small; - * Other nonzero on error. - */ int ble_store_util_bonded_peers(ble_addr_t *out_peer_id_addrs, int *out_num_peers, int max_peers) @@ -91,23 +77,11 @@ ble_store_util_bonded_peers(ble_addr_t *out_peer_id_addrs, int *out_num_peers, if (rc != 0) { return rc; } - if (set.status != 0) { - return set.status; - } *out_num_peers = set.num_peers; return 0; } -/** - * Deletes all entries from the store that are attached to the specified peer - * address. This function deletes security entries and CCCD records. - * - * @param peer_id_addr Entries with this peer address get deleted. - * - * @return 0 on success; - * Other nonzero on error. - */ int ble_store_util_delete_peer(const ble_addr_t *peer_id_addr) { @@ -138,15 +112,6 @@ ble_store_util_delete_peer(const ble_addr_t *peer_id_addr) return 0; } -/** - * Deletes all entries from the store that match the specified key. - * - * @param type The type of store entry to delete. - * @param key Entries matching this key get deleted. - * - * @return 0 on success; - * Other nonzero on error. - */ int ble_store_util_delete_all(int type, const union ble_store_key *key) { @@ -195,6 +160,7 @@ ble_store_util_count(int type, int *out_count) int ble_store_util_delete_oldest_peer(void) { +#if MYNEWT_VAL(BLE_STORE_MAX_BONDS) ble_addr_t peer_id_addrs[MYNEWT_VAL(BLE_STORE_MAX_BONDS)]; int num_peers; int rc; @@ -214,19 +180,10 @@ ble_store_util_delete_oldest_peer(void) if (rc != 0) { return rc; } - +#endif return 0; } -/** - * Round-robin status callback. If a there is insufficient storage capacity - * for a new record, delete the oldest bond and proceed with the persist - * operation. - * - * Note: This is not the best behavior for an actual product because - * uninteresting peers could cause important bonds to be deleted. This is - * useful for demonstrations and sample apps. - */ int ble_store_util_status_rr(struct ble_store_status_event *event, void *arg) { diff --git a/nimble/host/src/ble_uuid.c b/nimble/host/src/ble_uuid.c index 16352cf6e0..15f6637480 100644 --- a/nimble/host/src/ble_uuid.c +++ b/nimble/host/src/ble_uuid.c @@ -21,12 +21,15 @@ #include #include #include -#include #include "os/os_mbuf.h" #include "nimble/ble.h" #include "ble_hs_priv.h" #include "host/ble_uuid.h" +#define BLE_UUID16_STR_MAX_LEN 6 +#define BLE_UUID32_STR_MAX_LEN 10 +#define BLE_UUID128_STR_MAX_LEN 36 + static uint8_t ble_uuid_base[16] = { 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 @@ -41,6 +44,52 @@ static uint8_t ble_uuid_base[16] = { #define VERIFY_UUID(uuid) #endif +static int +hex2val(char c, uint8_t *value) +{ + if (c >= '0' && c <= '9') { + *value = c - '0'; + } else if (c >= 'a' && c <= 'f') { + *value = c - 'a' + 10; + } else if (c >= 'A' && c <= 'F') { + *value = c - 'A' + 10; + } else { + return BLE_HS_EINVAL; + } + return 0; +} + + +static size_t +hex2bin(const char *hex, uint8_t *bin, size_t bin_len) +{ + size_t len = 0; + uint8_t tmp_val; + int rc; + + while (*hex && len < bin_len) { + rc = hex2val(*hex++, &tmp_val); + if (rc != 0) { + return 0; + } + + bin[len] = tmp_val << 4; + + if (!*hex) { + len++; + break; + } + + rc = hex2val(*hex++, &tmp_val); + if (rc != 0) { + return 0; + } + bin[len++] |= tmp_val; + } + + return len; +} + int ble_uuid_init_from_buf(ble_uuid_any_t *uuid, const void *buf, size_t len) { @@ -137,6 +186,106 @@ ble_uuid_to_str(const ble_uuid_t *uuid, char *dst) return dst; } +int +ble_uuid_from_str(ble_uuid_any_t *uuid, const char *str) +{ + uint8_t tmp_rslt = 0; + uint8_t *u8p; + const char *str_ptr; + uint16_t u16 = 0; + uint32_t u32 = 0; + int len = (int) strlen(str); + + if ((len < 4) || (len % 2 != 0)) { + return BLE_HS_EINVAL; + } + + str_ptr = &str[len - 2]; + + if (len <= BLE_UUID16_STR_MAX_LEN) { + uuid->u.type = BLE_UUID_TYPE_16; + } else if (len <= BLE_UUID32_STR_MAX_LEN) { + uuid->u.type = BLE_UUID_TYPE_32; + } else if (len <= BLE_UUID128_STR_MAX_LEN) { + uuid->u.type = BLE_UUID_TYPE_128; + } else { + return BLE_HS_EINVAL; + } + + switch (uuid->u.type) { + case BLE_UUID_TYPE_128: + uuid->u.type = BLE_UUID_TYPE_128; + u8p = uuid->u128.value; + for (int i = 0; i < 16; i++) { + if (hex2bin(str_ptr, u8p, 1) != 1) { + return BLE_HS_EINVAL; + } + + /* Check if string end */ + if (str_ptr == str) { + break; + } + + /* Remove '-' */ + if (*(str_ptr - 1) == '-') { + str_ptr--; + } + + str_ptr -= 2; + u8p++; + } + + if (memcmp(ble_uuid_base, uuid->u128.value, 12) == 0) { + uint8_t *tmp_ptr = &uuid->u128.value[12]; + uint32_t tmp_val32 = 0; + for (int i = 0; i < 4; i++) { + tmp_val32 |= ((uint32_t)(*tmp_ptr++) << 8 * i); + } + + if (tmp_val32 <= UINT16_MAX) { + uuid->u.type = BLE_UUID_TYPE_16; + uuid->u16.value = (uint16_t) tmp_val32; + } else { + uuid->u.type = BLE_UUID_TYPE_32; + uuid->u32.value = tmp_val32; + } + } + break; + case BLE_UUID_TYPE_32: + for (int i = 0; i < 4; i++) { + if (hex2bin(str_ptr, &tmp_rslt, 1) != 1) { + return BLE_HS_EINVAL; + } + u32 |= ((uint32_t) tmp_rslt) << (i * 8); + + if (str_ptr == str) { + break; + } + str_ptr -= 2; + } + uuid->u32.value = u32; + break; + case BLE_UUID_TYPE_16: + for (int i = 0; i < 2; i++) { + if (hex2bin(str_ptr, &tmp_rslt, 1) != 1) { + return BLE_HS_EINVAL; + } + u16 |= ((uint32_t) tmp_rslt) << (i * 8); + + if (str_ptr == str) { + break; + } + str_ptr -= 2; + } + uuid->u16.value = u16; + break; + default: + return BLE_HS_EINVAL; + } + + return 0; +} + uint16_t ble_uuid_u16(const ble_uuid_t *uuid) { diff --git a/nimble/host/store/config/src/ble_store_config.c b/nimble/host/store/config/src/ble_store_config.c index cc1d59afd5..741c73a5f5 100644 --- a/nimble/host/store/config/src/ble_store_config.c +++ b/nimble/host/store/config/src/ble_store_config.c @@ -23,26 +23,35 @@ #include "sysinit/sysinit.h" #include "syscfg/syscfg.h" #include "host/ble_hs.h" -#include "base64/base64.h" +#include "os/util.h" #include "store/config/ble_store_config.h" #include "ble_store_config_priv.h" +#if MYNEWT_VAL(BLE_STORE_MAX_BONDS) struct ble_store_value_sec ble_store_config_our_secs[MYNEWT_VAL(BLE_STORE_MAX_BONDS)]; +#endif int ble_store_config_num_our_secs; +#if MYNEWT_VAL(BLE_STORE_MAX_BONDS) struct ble_store_value_sec ble_store_config_peer_secs[MYNEWT_VAL(BLE_STORE_MAX_BONDS)]; +#endif + int ble_store_config_num_peer_secs; +#if MYNEWT_VAL(BLE_STORE_MAX_CCCDS) struct ble_store_value_cccd ble_store_config_cccds[MYNEWT_VAL(BLE_STORE_MAX_CCCDS)]; +#endif + int ble_store_config_num_cccds; /***************************************************************************** * $sec * *****************************************************************************/ +#if MYNEWT_VAL(BLE_STORE_MAX_BONDS) static void ble_store_config_print_value_sec(const struct ble_store_value_sec *sec) { @@ -65,6 +74,7 @@ ble_store_config_print_value_sec(const struct ble_store_value_sec *sec) BLE_HS_LOG(DEBUG, "\n"); } +#endif static void ble_store_config_print_key_sec(const struct ble_store_key_sec *key_sec) @@ -75,57 +85,40 @@ ble_store_config_print_key_sec(const struct ble_store_key_sec *key_sec) ble_hs_log_flat_buf(key_sec->peer_addr.val, 6); BLE_HS_LOG(DEBUG, " "); } - if (key_sec->ediv_rand_present) { - BLE_HS_LOG(DEBUG, "ediv=0x%02x rand=0x%llx ", - key_sec->ediv, key_sec->rand_num); - } } +#if MYNEWT_VAL(BLE_STORE_MAX_BONDS) static int ble_store_config_find_sec(const struct ble_store_key_sec *key_sec, const struct ble_store_value_sec *value_secs, int num_value_secs) { const struct ble_store_value_sec *cur; - int skipped; int i; - skipped = 0; - - for (i = 0; i < num_value_secs; i++) { - cur = value_secs + i; - - if (ble_addr_cmp(&key_sec->peer_addr, BLE_ADDR_ANY)) { - if (ble_addr_cmp(&cur->peer_addr, &key_sec->peer_addr)) { - continue; - } + if (!ble_addr_cmp(&key_sec->peer_addr, BLE_ADDR_ANY)) { + if (key_sec->idx < num_value_secs) { + return key_sec->idx; } + } else if (key_sec->idx == 0) { + for (i = 0; i < num_value_secs; i++) { + cur = &value_secs[i]; - if (key_sec->ediv_rand_present) { - if (cur->ediv != key_sec->ediv) { - continue; - } - - if (cur->rand_num != key_sec->rand_num) { - continue; + if (!ble_addr_cmp(&cur->peer_addr, &key_sec->peer_addr)) { + return i; } } - - if (key_sec->idx > skipped) { - skipped++; - continue; - } - - return i; } return -1; } +#endif static int ble_store_config_read_our_sec(const struct ble_store_key_sec *key_sec, struct ble_store_value_sec *value_sec) { +#if MYNEWT_VAL(BLE_STORE_MAX_BONDS) int idx; idx = ble_store_config_find_sec(key_sec, ble_store_config_our_secs, @@ -136,12 +129,16 @@ ble_store_config_read_our_sec(const struct ble_store_key_sec *key_sec, *value_sec = ble_store_config_our_secs[idx]; return 0; +#else + return BLE_HS_ENOENT; +#endif } static int ble_store_config_write_our_sec(const struct ble_store_value_sec *value_sec) { +#if MYNEWT_VAL(BLE_STORE_MAX_BONDS) struct ble_store_key_sec key_sec; int idx; int rc; @@ -171,8 +168,13 @@ ble_store_config_write_our_sec(const struct ble_store_value_sec *value_sec) } return 0; +#else + return BLE_HS_ENOENT; +#endif + } +#if MYNEWT_VAL(BLE_STORE_MAX_BONDS) static int ble_store_config_delete_obj(void *values, int value_size, int idx, int *num_values) @@ -215,12 +217,15 @@ ble_store_config_delete_sec(const struct ble_store_key_sec *key_sec, return 0; } +#endif static int ble_store_config_delete_our_sec(const struct ble_store_key_sec *key_sec) { +#if MYNEWT_VAL(BLE_STORE_MAX_BONDS) int rc; + assert(ble_store_config_num_our_secs <= ARRAY_SIZE(ble_store_config_our_secs)); rc = ble_store_config_delete_sec(key_sec, ble_store_config_our_secs, &ble_store_config_num_our_secs); if (rc != 0) { @@ -233,13 +238,18 @@ ble_store_config_delete_our_sec(const struct ble_store_key_sec *key_sec) } return 0; +#else + return BLE_HS_ENOENT; +#endif } static int ble_store_config_delete_peer_sec(const struct ble_store_key_sec *key_sec) { +#if MYNEWT_VAL(BLE_STORE_MAX_BONDS) int rc; + assert(ble_store_config_num_peer_secs <= ARRAY_SIZE(ble_store_config_peer_secs)); rc = ble_store_config_delete_sec(key_sec, ble_store_config_peer_secs, &ble_store_config_num_peer_secs); if (rc != 0) { @@ -250,14 +260,17 @@ ble_store_config_delete_peer_sec(const struct ble_store_key_sec *key_sec) if (rc != 0) { return rc; } - return 0; +#else + return BLE_HS_ENOENT; +#endif } static int ble_store_config_read_peer_sec(const struct ble_store_key_sec *key_sec, struct ble_store_value_sec *value_sec) { +#if MYNEWT_VAL(BLE_STORE_MAX_BONDS) int idx; idx = ble_store_config_find_sec(key_sec, ble_store_config_peer_secs, @@ -268,11 +281,16 @@ ble_store_config_read_peer_sec(const struct ble_store_key_sec *key_sec, *value_sec = ble_store_config_peer_secs[idx]; return 0; +#else + return BLE_HS_ENOENT; +#endif + } static int ble_store_config_write_peer_sec(const struct ble_store_value_sec *value_sec) { +#if MYNEWT_VAL(BLE_STORE_MAX_BONDS) struct ble_store_key_sec key_sec; int idx; int rc; @@ -300,14 +318,17 @@ ble_store_config_write_peer_sec(const struct ble_store_value_sec *value_sec) if (rc != 0) { return rc; } - return 0; +#else + return BLE_HS_ENOENT; +#endif } /***************************************************************************** * $cccd * *****************************************************************************/ +#if MYNEWT_VAL(BLE_STORE_MAX_CCCDS) static int ble_store_config_find_cccd(const struct ble_store_key_cccd *key) { @@ -338,21 +359,23 @@ ble_store_config_find_cccd(const struct ble_store_key_cccd *key) return i; } - return -1; } +#endif static int ble_store_config_delete_cccd(const struct ble_store_key_cccd *key_cccd) { +#if MYNEWT_VAL(BLE_STORE_MAX_CCCDS) int idx; int rc; idx = ble_store_config_find_cccd(key_cccd); - if (idx == -1) { + if (idx < 0) { return BLE_HS_ENOENT; } + assert(ble_store_config_num_cccds < ARRAY_SIZE(ble_store_config_cccds)); rc = ble_store_config_delete_obj(ble_store_config_cccds, sizeof *ble_store_config_cccds, idx, @@ -365,14 +388,17 @@ ble_store_config_delete_cccd(const struct ble_store_key_cccd *key_cccd) if (rc != 0) { return rc; } - return 0; +#else + return BLE_HS_ENOENT; +#endif } static int ble_store_config_read_cccd(const struct ble_store_key_cccd *key_cccd, struct ble_store_value_cccd *value_cccd) { +#if MYNEWT_VAL(BLE_STORE_MAX_CCCDS) int idx; idx = ble_store_config_find_cccd(key_cccd); @@ -382,11 +408,15 @@ ble_store_config_read_cccd(const struct ble_store_key_cccd *key_cccd, *value_cccd = ble_store_config_cccds[idx]; return 0; +#else + return BLE_HS_ENOENT; +#endif } static int ble_store_config_write_cccd(const struct ble_store_value_cccd *value_cccd) { +#if MYNEWT_VAL(BLE_STORE_MAX_CCCDS) struct ble_store_key_cccd key_cccd; int idx; int rc; @@ -412,6 +442,9 @@ ble_store_config_write_cccd(const struct ble_store_value_cccd *value_cccd) } return 0; +#else + return BLE_HS_ENOENT; +#endif } /***************************************************************************** diff --git a/nimble/host/store/config/src/ble_store_config_conf.c b/nimble/host/store/config/src/ble_store_config_conf.c index e74127ae93..4090b6020b 100644 --- a/nimble/host/store/config/src/ble_store_config_conf.c +++ b/nimble/host/store/config/src/ble_store_config_conf.c @@ -91,6 +91,11 @@ ble_store_config_conf_set(int argc, char **argv, char *val) { int rc; + /* Config returns NULL pointer if it reads an empty string. We change this back into an empty string. */ + if (!val) { + val = ""; + } + if (argc == 1) { if (strcmp(argv[0], "our_sec") == 0) { rc = ble_store_config_deserialize_arr( diff --git a/nimble/host/store/ram/src/ble_store_ram.c b/nimble/host/store/ram/src/ble_store_ram.c index b912ea476a..9359f6d399 100644 --- a/nimble/host/store/ram/src/ble_store_ram.c +++ b/nimble/host/store/ram/src/ble_store_ram.c @@ -36,22 +36,32 @@ #include "host/ble_hs.h" #include "store/ram/ble_store_ram.h" +#if MYNEWT_VAL(BLE_STORE_MAX_BONDS) static struct ble_store_value_sec ble_store_ram_our_secs[MYNEWT_VAL(BLE_STORE_MAX_BONDS)]; +#endif + static int ble_store_ram_num_our_secs; +#if MYNEWT_VAL(BLE_STORE_MAX_BONDS) static struct ble_store_value_sec ble_store_ram_peer_secs[MYNEWT_VAL(BLE_STORE_MAX_BONDS)]; +#endif + static int ble_store_ram_num_peer_secs; +#if MYNEWT_VAL(BLE_STORE_MAX_CCCDS) static struct ble_store_value_cccd ble_store_ram_cccds[MYNEWT_VAL(BLE_STORE_MAX_CCCDS)]; +#endif + static int ble_store_ram_num_cccds; /***************************************************************************** * $sec * *****************************************************************************/ +#if MYNEWT_VAL(BLE_STORE_MAX_BONDS) static void ble_store_ram_print_value_sec(const struct ble_store_value_sec *sec) { @@ -74,6 +84,7 @@ ble_store_ram_print_value_sec(const struct ble_store_value_sec *sec) BLE_HS_LOG(DEBUG, "\n"); } +#endif static void ble_store_ram_print_key_sec(const struct ble_store_key_sec *key_sec) @@ -84,57 +95,40 @@ ble_store_ram_print_key_sec(const struct ble_store_key_sec *key_sec) ble_hs_log_flat_buf(key_sec->peer_addr.val, 6); BLE_HS_LOG(DEBUG, " "); } - if (key_sec->ediv_rand_present) { - BLE_HS_LOG(DEBUG, "ediv=0x%02x rand=0x%llx ", - key_sec->ediv, key_sec->rand_num); - } } +#if MYNEWT_VAL(BLE_STORE_MAX_BONDS) static int ble_store_ram_find_sec(const struct ble_store_key_sec *key_sec, const struct ble_store_value_sec *value_secs, int num_value_secs) { const struct ble_store_value_sec *cur; - int skipped; int i; - skipped = 0; - - for (i = 0; i < num_value_secs; i++) { - cur = value_secs + i; - - if (ble_addr_cmp(&key_sec->peer_addr, BLE_ADDR_ANY)) { - if (ble_addr_cmp(&cur->peer_addr, &key_sec->peer_addr)) { - continue; - } + if (!ble_addr_cmp(&key_sec->peer_addr, BLE_ADDR_ANY)) { + if (key_sec->idx < num_value_secs) { + return key_sec->idx; } + } else if (key_sec->idx == 0) { + for (i = 0; i < num_value_secs; i++) { + cur = &value_secs[i]; - if (key_sec->ediv_rand_present) { - if (cur->ediv != key_sec->ediv) { - continue; - } - - if (cur->rand_num != key_sec->rand_num) { - continue; + if (!ble_addr_cmp(&cur->peer_addr, &key_sec->peer_addr)) { + return i; } } - - if (key_sec->idx > skipped) { - skipped++; - continue; - } - - return i; } return -1; } +#endif static int ble_store_ram_read_our_sec(const struct ble_store_key_sec *key_sec, struct ble_store_value_sec *value_sec) { +#if MYNEWT_VAL(BLE_STORE_MAX_BONDS) int idx; idx = ble_store_ram_find_sec(key_sec, ble_store_ram_our_secs, @@ -145,11 +139,16 @@ ble_store_ram_read_our_sec(const struct ble_store_key_sec *key_sec, *value_sec = ble_store_ram_our_secs[idx]; return 0; +#else + return BLE_HS_ENOENT; +#endif + } static int ble_store_ram_write_our_sec(const struct ble_store_value_sec *value_sec) { +#if MYNEWT_VAL(BLE_STORE_MAX_BONDS) struct ble_store_key_sec key_sec; int idx; @@ -171,9 +170,15 @@ ble_store_ram_write_our_sec(const struct ble_store_value_sec *value_sec) } ble_store_ram_our_secs[idx] = *value_sec; + return 0; +#else + return BLE_HS_ENOENT; +#endif + } +#if MYNEWT_VAL(BLE_STORE_MAX_BONDS) static int ble_store_ram_delete_obj(void *values, int value_size, int idx, int *num_values) @@ -216,10 +221,12 @@ ble_store_ram_delete_sec(const struct ble_store_key_sec *key_sec, return 0; } +#endif static int ble_store_ram_delete_our_sec(const struct ble_store_key_sec *key_sec) { +#if MYNEWT_VAL(BLE_STORE_MAX_BONDS) int rc; rc = ble_store_ram_delete_sec(key_sec, ble_store_ram_our_secs, @@ -227,13 +234,17 @@ ble_store_ram_delete_our_sec(const struct ble_store_key_sec *key_sec) if (rc != 0) { return rc; } - return 0; +#else + return BLE_HS_ENOENT; +#endif + } static int ble_store_ram_delete_peer_sec(const struct ble_store_key_sec *key_sec) { +#if MYNEWT_VAL(BLE_STORE_MAX_BONDS) int rc; rc = ble_store_ram_delete_sec(key_sec, ble_store_ram_peer_secs, @@ -241,14 +252,18 @@ ble_store_ram_delete_peer_sec(const struct ble_store_key_sec *key_sec) if (rc != 0) { return rc; } - return 0; +#else + return BLE_HS_ENOENT; +#endif + } static int ble_store_ram_read_peer_sec(const struct ble_store_key_sec *key_sec, struct ble_store_value_sec *value_sec) { +#if MYNEWT_VAL(BLE_STORE_MAX_BONDS) int idx; idx = ble_store_ram_find_sec(key_sec, ble_store_ram_peer_secs, @@ -259,11 +274,16 @@ ble_store_ram_read_peer_sec(const struct ble_store_key_sec *key_sec, *value_sec = ble_store_ram_peer_secs[idx]; return 0; +#else + return BLE_HS_ENOENT; +#endif + } static int ble_store_ram_write_peer_sec(const struct ble_store_value_sec *value_sec) { +#if MYNEWT_VAL(BLE_STORE_MAX_BONDS) struct ble_store_key_sec key_sec; int idx; @@ -286,12 +306,17 @@ ble_store_ram_write_peer_sec(const struct ble_store_value_sec *value_sec) ble_store_ram_peer_secs[idx] = *value_sec; return 0; +#else + return BLE_HS_ENOENT; +#endif + } /***************************************************************************** * $cccd * *****************************************************************************/ +#if MYNEWT_VAL(BLE_STORE_MAX_CCCDS) static int ble_store_ram_find_cccd(const struct ble_store_key_cccd *key) { @@ -325,10 +350,12 @@ ble_store_ram_find_cccd(const struct ble_store_key_cccd *key) return -1; } +#endif static int ble_store_ram_delete_cccd(const struct ble_store_key_cccd *key_cccd) { +#if MYNEWT_VAL(BLE_STORE_MAX_CCCDS) int idx; int rc; @@ -344,14 +371,18 @@ ble_store_ram_delete_cccd(const struct ble_store_key_cccd *key_cccd) if (rc != 0) { return rc; } - return 0; +#else + return BLE_HS_ENOENT; +#endif + } static int ble_store_ram_read_cccd(const struct ble_store_key_cccd *key_cccd, struct ble_store_value_cccd *value_cccd) { +#if MYNEWT_VAL(BLE_STORE_MAX_CCCDS) int idx; idx = ble_store_ram_find_cccd(key_cccd); @@ -360,12 +391,17 @@ ble_store_ram_read_cccd(const struct ble_store_key_cccd *key_cccd, } *value_cccd = ble_store_ram_cccds[idx]; + return 0; +#else + return BLE_HS_ENOENT; +#endif } static int ble_store_ram_write_cccd(const struct ble_store_value_cccd *value_cccd) { +#if MYNEWT_VAL(BLE_STORE_MAX_CCCDS) struct ble_store_key_cccd key_cccd; int idx; @@ -384,6 +420,10 @@ ble_store_ram_write_cccd(const struct ble_store_value_cccd *value_cccd) ble_store_ram_cccds[idx] = *value_cccd; return 0; +#else + return BLE_HS_ENOENT; +#endif + } /***************************************************************************** diff --git a/nimble/host/syscfg.yml b/nimble/host/syscfg.yml index c814ba5695..873dcae4bf 100644 --- a/nimble/host/syscfg.yml +++ b/nimble/host/syscfg.yml @@ -27,6 +27,13 @@ syscfg.defs: initialization. value: 1 + BLE_HS_EXT_ADV_LEGACY_INSTANCE: + description: > + Advertising instance that is used when extended advertising + support is enabled but legacy GAP API is used. + range: 0..BLE_MULTI_ADV_INSTANCES + value: 0 + # Debug settings. BLE_HS_DEBUG: description: 'Enables extra runtime assertions.' @@ -44,44 +51,6 @@ syscfg.defs: simulator. value: 1 - # Monitor interface settings - BLE_MONITOR_UART: - description: Enables monitor interface over UART - value: 0 - BLE_MONITOR_UART_DEV: - description: Monitor interface UART device - value: '"uart0"' - BLE_MONITOR_UART_BAUDRATE: - description: Baudrate for monitor interface UART - value: 1000000 - BLE_MONITOR_UART_BUFFER_SIZE: - description: > - Monitor interface ringbuffer size for UART. - This value should be a power of 2. - value: 64 - BLE_MONITOR_RTT: - description: Enables monitor interface over RTT - value: 0 - BLE_MONITOR_RTT_BUFFER_NAME: - description: Monitor interface upstream buffer name - value: '"btmonitor"' - BLE_MONITOR_RTT_BUFFER_SIZE: - description: Monitor interface upstream buffer size - value: 256 - BLE_MONITOR_RTT_BUFFERED: - description: > - Enables buffering when using monitor interface over RTT. The data - are written to RTT once complete packet is created in intermediate - buffer. This allows to skip complete packet if there is not enough - space in RTT buffer (e.g. there is no reader connected). If disabled, - monitor will simply block waiting for RTT to free space in buffer. - value: 1 - BLE_MONITOR_CONSOLE_BUFFER_SIZE: - description: > - Size of internal buffer for console output. Any line exceeding this - length value will be split. - value: 128 - # L2CAP settings. BLE_L2CAP_MAX_CHANS: description: > @@ -117,7 +86,13 @@ syscfg.defs: the required HCI and L2CAP headers fit into the smallest available MSYS blocks. value: 'MYNEWT_VAL_MSYS_1_BLOCK_SIZE-8' - + BLE_L2CAP_COC_SDU_BUFF_COUNT: + description: > + Defines maximum number of SDU buffers in L2CAP COC endpoints. + Provides more currently available credits to receive more data packets. + value: 1 + restrictions: + - 'BLE_L2CAP_COC_SDU_BUFF_COUNT > 0' BLE_L2CAP_ENHANCED_COC: description: > Enables LE Enhanced CoC mode. @@ -141,9 +116,12 @@ syscfg.defs: requiring mode 1 level 1. value: 0 restrictions: - - 'BLE_SM_SC_LVL == 4 if 1' + - 'BLE_SM_LVL == 4 if 1' + - BLE_SM_MITM + - 'BLE_SM_SC if 1' + - '!BLE_SM_LEGACY if 1' - BLE_SM_SC_LVL: + BLE_SM_LVL: description: > Force global Secure Connections mode 1 level. This level describes requirements for pairing response/request received @@ -152,7 +130,8 @@ syscfg.defs: authentication requirements is granted - 2 - allow to pair despite MITM being on or off - 3 - allow to pair only when MITM protection is on - - 4 - allow to pair only when 128 bit key is used and MITM is on + - 4 - allow to pair only with Secure Connections and + when 128 bit key is used and MITM is on When set to 0 level is no forced and pairing is allowed for all requests/responses with valid values (for example pairing will be rejected with key longer than 128 bits). Successful pairing with @@ -216,6 +195,11 @@ syscfg.defs: allows to decrypt air traffic easily and thus should be only used for debugging. value: 0 + BLE_SM_CSIS_SIRK: + description: > + Enable LE Audio CSIS SIRK Encryption and Decryption API. + value: 0 + experimental: 1 # GAP options. BLE_GAP_MAX_PENDING_CONN_PARAM_UPDATE: @@ -272,6 +256,11 @@ syscfg.defs: Enables the Read Multiple Characteristic Values GATT procedure. (0/1) value: MYNEWT_VAL_BLE_ROLE_CENTRAL + BLE_GATT_READ_MULT_VAR: + description: > + Enables the Read Multiple Variable Characteristic Values GATT procedure. + (0/1) + value: MYNEWT_VAL_BLE_ROLE_CENTRAL && (MYNEWT_VAL_BLE_VERSION >= 52) BLE_GATT_WRITE_NO_RSP: description: > Enables the Write Without Response GATT procedure. (0/1) @@ -300,6 +289,12 @@ syscfg.defs: description: > Enables sending and receiving of GATT indications. (0/1) value: 1 + BLE_GATT_NOTIFY_MULTIPLE: + description: > + Enables sending and receiving of GATT multiple handle notifications. (0/1) + value: (MYNEWT_VAL_BLE_VERSION >= 52) + restrictions: + - '(BLE_VERSION >= 52) if 1' # GATT options. BLE_GATT_READ_MAX_ATTRS: @@ -322,6 +317,21 @@ syscfg.defs: due to memory exhaustion. (0/1) Units are milliseconds. (0/1) value: 1000 + # Enhanced ATT bearer options + BLE_EATT_CHAN_NUM: + description: > + Maximum number of supported EATT channels (in total). If set to 0 + EATT support it disabled. + value: 0 + restrictions: + - BLE_GATT_NOTIFY_MULTIPLE + - BLE_L2CAP_ENHANCED_COC + - 'BLE_L2CAP_COC_MAX_NUM >= BLE_EATT_CHAN_NUM' + BLE_EATT_MTU: + description: > + MTU used for EATT channels. + value: 128 + # Supported server ATT commands. (0/1) BLE_ATT_SVR_FIND_INFO: description: > @@ -380,6 +390,12 @@ syscfg.defs: Enables processing of incoming Handle Value Notification ATT commands. (0/1) value: 1 + BLE_ATT_SVR_NOTIFY_MULTI: + description: > + Enables processing of incoming Multi Handle Value Notification ATT + commands. (0/1) + value: MYNEWT_VAL_BLE_ATT_SVR_NOTIFY && (MYNEWT_VAL_BLE_VERSION >= 52) + BLE_ATT_SVR_INDICATE: description: > Enables processing of incoming Handle Value Indication ATT @@ -435,6 +451,11 @@ syscfg.defs: that have been enabled in the stack, such as GATT support. value: 0 + BLE_AUDIO: + description: 'This option enables Bluetooth LE Audio support' + value: 0 + experimental: 1 + # Flow control settings. BLE_HS_FLOW_CTRL: description: > @@ -481,6 +502,13 @@ syscfg.defs: Sysinit stage for the NimBLE host. value: 200 + BLE_HS_GAP_UNHANDLED_HCI_EVENT: + description: > + Enables GAP event for received HCI events that are not handled by + host. This can be used to implement/test features that are not yet + supported by host. + value: 0 + ### Log settings. BLE_HS_LOG_MOD: @@ -490,10 +518,38 @@ syscfg.defs: description: 'Minimum level for the BLE host log.' value: 1 + BLE_EATT_LOG_MOD: + description: 'Numeric module ID to use for BLE EATT log messages.' + value: 27 + BLE_EATT_LOG_LVL: + description: 'Minimum level for the BLE EATT log.' + value: 1 + + BLE_ISO_MAX_BIGS: + description: > + Number of available BIGs + value: 'MYNEWT_VAL_BLE_MULTI_ADV_INSTANCES' + restrictions: + - 'BLE_ISO_BROADCAST_SOURCE if 0' + + BLE_ISO_MAX_BISES: + description: > + Number of supported BISes + value: 4 + restrictions: + - 'BLE_ISO_BROADCAST_SOURCE if 0' + syscfg.logs: BLE_HS_LOG: module: MYNEWT_VAL(BLE_HS_LOG_MOD) level: MYNEWT_VAL(BLE_HS_LOG_LVL) + BLE_EATT_LOG: + module: MYNEWT_VAL(BLE_EATT_LOG_MOD) + level: MYNEWT_VAL(BLE_EATT_LOG_LVL) + syscfg.vals.BLE_MESH: BLE_SM_SC: 1 + +syscfg.restrictions: + - BLE_TRANSPORT_HS == "native" diff --git a/nimble/host/test/pkg.yml b/nimble/host/test/pkg.yml index dd1ad18bf3..1698043e4f 100644 --- a/nimble/host/test/pkg.yml +++ b/nimble/host/test/pkg.yml @@ -31,4 +31,7 @@ pkg.deps.SELFTEST: - "@apache-mynewt-core/sys/console/stub" - "@apache-mynewt-core/sys/log/full" - "@apache-mynewt-core/sys/stats/stub" - - nimble/transport/ram + - nimble/transport + +pkg.apis: + - ble_driver diff --git a/nimble/host/test/src/ble_att_clt_test.c b/nimble/host/test/src/ble_att_clt_test.c index 787d4bca3b..849603daac 100644 --- a/nimble/host/test/src/ble_att_clt_test.c +++ b/nimble/host/test/src/ble_att_clt_test.c @@ -67,9 +67,9 @@ ble_att_clt_test_tx_write_req_or_cmd(uint16_t conn_handle, uint16_t handle, om = ble_hs_test_util_om_from_flat(value, value_len); if (is_req) { - rc = ble_att_clt_tx_write_req(conn_handle, handle, om); + rc = ble_att_clt_tx_write_req(conn_handle, BLE_L2CAP_CID_ATT, handle, om); } else { - rc = ble_att_clt_tx_write_cmd(conn_handle, handle, om); + rc = ble_att_clt_tx_write_cmd(conn_handle, BLE_L2CAP_CID_ATT, handle, om); } TEST_ASSERT(rc == 0); } @@ -78,25 +78,35 @@ TEST_CASE_SELF(ble_att_clt_test_tx_find_info) { uint16_t conn_handle; int rc; + struct ble_hs_conn *conn; ble_hs_test_util_assert_mbufs_freed(NULL); conn_handle = ble_att_clt_test_misc_init(); + ble_hs_lock(); + conn = ble_hs_conn_find(conn_handle); + ble_hs_unlock(); /*** Success. */ - rc = ble_att_clt_tx_find_info(conn_handle, 1, 0xffff); + rc = ble_att_clt_tx_find_info(conn_handle, BLE_L2CAP_CID_ATT, 1, 0xffff); TEST_ASSERT(rc == 0); /*** Error: start handle of 0. */ - rc = ble_att_clt_tx_find_info(conn_handle, 0, 0xffff); + /** In unit tests we don't are not receiving response - procedure will + * not complete. Reset `client_att_busy` flag so new request can be sent + */ + conn->client_att_busy = false; + rc = ble_att_clt_tx_find_info(conn_handle, BLE_L2CAP_CID_ATT, 0, 0xffff); TEST_ASSERT(rc == BLE_HS_EINVAL); /*** Error: start handle greater than end handle. */ - rc = ble_att_clt_tx_find_info(conn_handle, 500, 499); + conn->client_att_busy = false; + rc = ble_att_clt_tx_find_info(conn_handle, BLE_L2CAP_CID_ATT, 500, 499); TEST_ASSERT(rc == BLE_HS_EINVAL); /*** Success; start and end handles equal. */ - rc = ble_att_clt_tx_find_info(conn_handle, 500, 500); + conn->client_att_busy = false; + rc = ble_att_clt_tx_find_info(conn_handle, BLE_L2CAP_CID_ATT, 500, 500); TEST_ASSERT(rc == 0); ble_hs_test_util_assert_mbufs_freed(NULL); @@ -175,9 +185,14 @@ ble_att_clt_test_case_tx_write_req_or_cmd(int is_req) uint16_t conn_handle; uint8_t value300[500] = { 0 }; uint8_t value5[5] = { 6, 7, 54, 34, 8 }; + struct ble_hs_conn *conn; conn_handle = ble_att_clt_test_misc_init(); + ble_hs_lock(); + conn = ble_hs_conn_find(conn_handle); + ble_hs_unlock(); + /*** 5-byte write. */ ble_att_clt_test_tx_write_req_or_cmd(conn_handle, 0x1234, value5, sizeof value5, is_req); @@ -185,6 +200,10 @@ ble_att_clt_test_case_tx_write_req_or_cmd(int is_req) is_req); /*** Overlong write; verify command truncated to ATT MTU. */ + /** In unit tests we are not receiving response - procedure will + * not complete. Reset `client_att_busy` flag so new request can be sent + */ + conn->client_att_busy = false; ble_att_clt_test_tx_write_req_or_cmd(conn_handle, 0xab83, value300, sizeof value300, is_req); ble_att_clt_test_misc_verify_tx_write(0xab83, value300, @@ -206,7 +225,7 @@ ble_att_clt_test_misc_prep_good(uint16_t handle, uint16_t offset, conn_handle = ble_att_clt_test_misc_init(); om = ble_hs_test_util_om_from_flat(attr_data, attr_data_len); - rc = ble_att_clt_tx_prep_write(conn_handle, handle, offset, om); + rc = ble_att_clt_tx_prep_write(conn_handle, BLE_L2CAP_CID_ATT, handle, offset, om); TEST_ASSERT(rc == 0); om = ble_hs_test_util_prev_tx_dequeue_pullup(); @@ -232,7 +251,7 @@ ble_att_clt_test_misc_exec_good(uint8_t flags) conn_handle = ble_att_clt_test_misc_init(); - rc = ble_att_clt_tx_exec_write(conn_handle, flags); + rc = ble_att_clt_tx_exec_write(conn_handle, BLE_L2CAP_CID_ATT, flags); TEST_ASSERT(rc == 0); om = ble_hs_test_util_prev_tx_dequeue_pullup(); @@ -256,7 +275,7 @@ ble_att_clt_test_misc_prep_bad(uint16_t handle, uint16_t offset, om = ble_hs_test_util_om_from_flat(attr_data, attr_data_len); - rc = ble_att_clt_tx_prep_write(conn_handle, handle, offset, om); + rc = ble_att_clt_tx_prep_write(conn_handle, BLE_L2CAP_CID_ATT, handle, offset, om); TEST_ASSERT(rc == status); } @@ -287,11 +306,11 @@ TEST_CASE_SELF(ble_att_clt_test_tx_read) conn_handle = ble_att_clt_test_misc_init(); /*** Success. */ - rc = ble_att_clt_tx_read(conn_handle, 1); + rc = ble_att_clt_tx_read(conn_handle, BLE_L2CAP_CID_ATT, 1); TEST_ASSERT(rc == 0); /*** Error: handle of 0. */ - rc = ble_att_clt_tx_read(conn_handle, 0); + rc = ble_att_clt_tx_read(conn_handle, BLE_L2CAP_CID_ATT, 0); TEST_ASSERT(rc == BLE_HS_EINVAL); ble_hs_test_util_assert_mbufs_freed(NULL); @@ -333,11 +352,11 @@ TEST_CASE_SELF(ble_att_clt_test_tx_read_blob) conn_handle = ble_att_clt_test_misc_init(); /*** Success. */ - rc = ble_att_clt_tx_read_blob(conn_handle, 1, 0); + rc = ble_att_clt_tx_read_blob(conn_handle, BLE_L2CAP_CID_ATT, 1, 0); TEST_ASSERT(rc == 0); /*** Error: handle of 0. */ - rc = ble_att_clt_tx_read_blob(conn_handle, 0, 0); + rc = ble_att_clt_tx_read_blob(conn_handle, BLE_L2CAP_CID_ATT, 0, 0); TEST_ASSERT(rc == BLE_HS_EINVAL); ble_hs_test_util_assert_mbufs_freed(NULL); @@ -380,7 +399,7 @@ TEST_CASE_SELF(ble_att_clt_test_tx_read_mult) conn_handle = ble_att_clt_test_misc_init(); /*** Success. */ - rc = ble_att_clt_tx_read_mult(conn_handle, ((uint16_t[]){ 1, 2 }), 2); + rc = ble_att_clt_tx_read_mult(conn_handle, BLE_L2CAP_CID_ATT, ((uint16_t[]) { 1, 2 }), 2, false); TEST_ASSERT(rc == 0); om = ble_hs_test_util_prev_tx_dequeue_pullup(); @@ -392,7 +411,7 @@ TEST_CASE_SELF(ble_att_clt_test_tx_read_mult) TEST_ASSERT(get_le16(om->om_data + BLE_ATT_READ_MULT_REQ_BASE_SZ + 2) == 2); /*** Error: no handles. */ - rc = ble_att_clt_tx_read_mult(conn_handle, NULL, 0); + rc = ble_att_clt_tx_read_mult(conn_handle, BLE_L2CAP_CID_ATT, NULL, 0, false); TEST_ASSERT(rc == BLE_HS_EINVAL); ble_hs_test_util_assert_mbufs_freed(NULL); @@ -501,14 +520,14 @@ TEST_CASE_SELF(ble_att_clt_test_tx_exec_write) uint16_t conn_handle; int rc; - conn_handle = ble_att_clt_test_misc_init(); /*** Success. */ ble_att_clt_test_misc_exec_good(BLE_ATT_EXEC_WRITE_F_CANCEL); ble_att_clt_test_misc_exec_good(BLE_ATT_EXEC_WRITE_F_EXECUTE); /*** Success: nonzero == execute. */ - rc = ble_att_clt_tx_exec_write(conn_handle, 0x02); + conn_handle = ble_att_clt_test_misc_init(); + rc = ble_att_clt_tx_exec_write(conn_handle, BLE_L2CAP_CID_ATT, 0x02); TEST_ASSERT(rc == 0); ble_hs_test_util_assert_mbufs_freed(NULL); diff --git a/nimble/host/test/src/ble_att_svr_test.c b/nimble/host/test/src/ble_att_svr_test.c index 60ab14b4e1..c61c7d413c 100644 --- a/nimble/host/test/src/ble_att_svr_test.c +++ b/nimble/host/test/src/ble_att_svr_test.c @@ -24,8 +24,13 @@ #include "nimble/hci_common.h" #include "ble_hs_test.h" #include "host/ble_uuid.h" +#include "host/ble_l2cap.h" #include "ble_hs_test_util.h" +#ifndef min +#define min(a, b) ((a) < (b) ? (a) : (b)) +#endif + static uint8_t *ble_att_svr_test_attr_r_1; static uint16_t ble_att_svr_test_attr_r_1_len; static uint8_t *ble_att_svr_test_attr_r_2; @@ -478,7 +483,7 @@ ble_att_svr_test_misc_verify_all_read_mult( } static void -ble_att_svr_test_misc_verify_tx_mtu_rsp(uint16_t conn_handle) +ble_att_svr_test_misc_verify_tx_mtu_rsp(uint16_t conn_handle, uint16_t cid) { struct ble_l2cap_chan *chan; struct ble_hs_conn *conn; @@ -487,7 +492,7 @@ ble_att_svr_test_misc_verify_tx_mtu_rsp(uint16_t conn_handle) ble_hs_lock(); - rc = ble_att_conn_chan_find(conn_handle, &conn, &chan); + rc = ble_att_conn_chan_find(conn_handle, cid, &conn, &chan); assert(rc == 0); my_mtu = chan->my_mtu; @@ -644,7 +649,7 @@ ble_att_svr_test_misc_mtu_exchange(uint16_t my_mtu, uint16_t peer_sent, buf, sizeof buf); TEST_ASSERT(rc == 0); - ble_att_svr_test_misc_verify_tx_mtu_rsp(conn_handle); + ble_att_svr_test_misc_verify_tx_mtu_rsp(conn_handle, BLE_L2CAP_CID_ATT); ble_hs_lock(); rc = ble_hs_misc_conn_chan_find(conn_handle, BLE_L2CAP_CID_ATT, @@ -1021,7 +1026,7 @@ TEST_CASE_SELF(ble_att_svr_test_read_mult) attrs[1].value_len = 20; memcpy(attrs[1].value, ((uint8_t[]){ - 22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39 + 20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39 }), attrs[1].value_len); ble_att_svr_test_attr_r_2_len = attrs[1].value_len; @@ -1138,19 +1143,19 @@ TEST_CASE_SELF(ble_att_svr_test_find_info) conn_handle = ble_att_svr_test_misc_init(128); /*** Start handle of 0. */ - rc = ble_hs_test_util_rx_att_find_info_req(conn_handle, 0, 0); + rc = ble_hs_test_util_rx_att_find_info_req(conn_handle, BLE_L2CAP_CID_ATT, 0, 0); TEST_ASSERT(rc != 0); ble_hs_test_util_verify_tx_err_rsp( BLE_ATT_OP_FIND_INFO_REQ, 0, BLE_ATT_ERR_INVALID_HANDLE); /*** Start handle > end handle. */ - rc = ble_hs_test_util_rx_att_find_info_req(conn_handle, 101, 100); + rc = ble_hs_test_util_rx_att_find_info_req(conn_handle, BLE_L2CAP_CID_ATT, 101, 100); TEST_ASSERT(rc != 0); ble_hs_test_util_verify_tx_err_rsp( BLE_ATT_OP_FIND_INFO_REQ, 101, BLE_ATT_ERR_INVALID_HANDLE); /*** No attributes. */ - rc = ble_hs_test_util_rx_att_find_info_req(conn_handle, 200, 300); + rc = ble_hs_test_util_rx_att_find_info_req(conn_handle, BLE_L2CAP_CID_ATT, 200, 300); TEST_ASSERT(rc != 0); ble_hs_test_util_verify_tx_err_rsp( BLE_ATT_OP_FIND_INFO_REQ, 200, BLE_ATT_ERR_ATTR_NOT_FOUND); @@ -1160,13 +1165,13 @@ TEST_CASE_SELF(ble_att_svr_test_find_info) ble_att_svr_test_misc_attr_fn_r_1, NULL); TEST_ASSERT(rc == 0); - rc = ble_hs_test_util_rx_att_find_info_req(conn_handle, 200, 300); + rc = ble_hs_test_util_rx_att_find_info_req(conn_handle, BLE_L2CAP_CID_ATT, 200, 300); TEST_ASSERT(rc != 0); ble_hs_test_util_verify_tx_err_rsp( BLE_ATT_OP_FIND_INFO_REQ, 200, BLE_ATT_ERR_ATTR_NOT_FOUND); /*** One 128-bit entry. */ - rc = ble_hs_test_util_rx_att_find_info_req(conn_handle, handle1, handle1); + rc = ble_hs_test_util_rx_att_find_info_req(conn_handle, BLE_L2CAP_CID_ATT, handle1, handle1); TEST_ASSERT(rc == 0); ble_hs_test_util_verify_tx_find_info_rsp( ((struct ble_hs_test_util_att_info_entry[]) { { @@ -1181,7 +1186,7 @@ TEST_CASE_SELF(ble_att_svr_test_find_info) ble_att_svr_test_misc_attr_fn_r_1, NULL); TEST_ASSERT(rc == 0); - rc = ble_hs_test_util_rx_att_find_info_req(conn_handle, handle1, handle2); + rc = ble_hs_test_util_rx_att_find_info_req(conn_handle, BLE_L2CAP_CID_ATT, handle1, handle2); TEST_ASSERT(rc == 0); ble_hs_test_util_verify_tx_find_info_rsp( ((struct ble_hs_test_util_att_info_entry[]) { { @@ -1199,7 +1204,7 @@ TEST_CASE_SELF(ble_att_svr_test_find_info) ble_att_svr_test_misc_attr_fn_r_1, NULL); TEST_ASSERT(rc == 0); - rc = ble_hs_test_util_rx_att_find_info_req(conn_handle, handle1, handle3); + rc = ble_hs_test_util_rx_att_find_info_req(conn_handle, BLE_L2CAP_CID_ATT, handle1, handle3); TEST_ASSERT(rc == 0); ble_hs_test_util_verify_tx_find_info_rsp( ((struct ble_hs_test_util_att_info_entry[]) { { @@ -1213,7 +1218,7 @@ TEST_CASE_SELF(ble_att_svr_test_find_info) } })); /*** Remaining 16-bit entry requested. */ - rc = ble_hs_test_util_rx_att_find_info_req(conn_handle, handle3, handle3); + rc = ble_hs_test_util_rx_att_find_info_req(conn_handle, BLE_L2CAP_CID_ATT, handle3, handle3); TEST_ASSERT(rc == 0); ble_hs_test_util_verify_tx_find_info_rsp( ((struct ble_hs_test_util_att_info_entry[]) { { @@ -1827,12 +1832,15 @@ TEST_CASE_SELF(ble_att_svr_test_notify) TEST_CASE_SELF(ble_att_svr_test_prep_write_tmo) { int32_t ticks_from_now; + uint32_t timeout_ticks; uint16_t conn_handle; int rc; int i; static uint8_t data[1024]; + timeout_ticks = ble_npl_time_ms_to_ticks32(BLE_HS_ATT_SVR_QUEUED_WRITE_TMO); + conn_handle = ble_att_svr_test_misc_init(205); /* Initialize some attribute data. */ @@ -1854,10 +1862,10 @@ TEST_CASE_SELF(ble_att_svr_test_prep_write_tmo) /* Ensure timer will expire in 30 seconds. */ ticks_from_now = ble_hs_conn_timer(); - TEST_ASSERT(ticks_from_now == BLE_HS_ATT_SVR_QUEUED_WRITE_TMO); + TEST_ASSERT(ticks_from_now == timeout_ticks); /* Almost let the timer expire. */ - os_time_advance(BLE_HS_ATT_SVR_QUEUED_WRITE_TMO - 1); + os_time_advance(timeout_ticks - 1); ticks_from_now = ble_hs_conn_timer(); TEST_ASSERT(ticks_from_now == 1); @@ -1866,11 +1874,11 @@ TEST_CASE_SELF(ble_att_svr_test_prep_write_tmo) /* Ensure timer got reset. */ ticks_from_now = ble_hs_conn_timer(); - TEST_ASSERT(ticks_from_now == BLE_HS_ATT_SVR_QUEUED_WRITE_TMO); + TEST_ASSERT(ticks_from_now == timeout_ticks); /* Allow the timer to expire. */ ble_hs_test_util_hci_ack_set_disconnect(0); - os_time_advance(BLE_HS_ATT_SVR_QUEUED_WRITE_TMO); + os_time_advance(timeout_ticks); ticks_from_now = ble_hs_conn_timer(); TEST_ASSERT(ticks_from_now == BLE_HS_FOREVER); @@ -1936,13 +1944,13 @@ TEST_CASE_SELF(ble_att_svr_test_oom) TEST_ASSERT_FATAL(rc == 0); /* Ensure we were able to send a real response. */ - ble_att_svr_test_misc_verify_tx_mtu_rsp(conn_handle); + ble_att_svr_test_misc_verify_tx_mtu_rsp(conn_handle, BLE_L2CAP_CID_ATT); /*** Find information; always respond affirmatively, even when no mbufs. */ ble_hs_test_util_prev_tx_dequeue(); /* Receive a request. */ - rc = ble_hs_test_util_rx_att_find_info_req(conn_handle, 1, 100); + rc = ble_hs_test_util_rx_att_find_info_req(conn_handle, BLE_L2CAP_CID_ATT, 1, 100); TEST_ASSERT_FATAL(rc == 0); /* Ensure we were able to send a real response. */ diff --git a/nimble/host/test/src/ble_gatt_conn_test.c b/nimble/host/test/src/ble_gatt_conn_test.c index 8d95f74337..d74dd6fcfe 100644 --- a/nimble/host/test/src/ble_gatt_conn_test.c +++ b/nimble/host/test/src/ble_gatt_conn_test.c @@ -385,6 +385,7 @@ TEST_CASE_SELF(ble_gatt_conn_test_disconnect) uint16_t attr_handle; uint16_t offset = 0; int rc; + struct ble_hs_conn *conn; ble_gatt_conn_test_util_init(); @@ -405,65 +406,92 @@ TEST_CASE_SELF(ble_gatt_conn_test_disconnect) /*** Schedule some GATT procedures. */ /* Connection 1. */ mtu_arg.exp_conn_handle = 1; + ble_hs_lock(); + conn = ble_hs_conn_find(1); + ble_hs_unlock(); + + /** In unit tests we are not receiving response - procedure will + * not complete. Reset `client_att_busy` flag so new request can be sent + */ + conn->client_att_busy = false; ble_gattc_exchange_mtu(1, ble_gatt_conn_test_mtu_cb, &mtu_arg); disc_all_svcs_arg.exp_conn_handle = 1; + conn->client_att_busy = false; rc = ble_gattc_disc_all_svcs(1, ble_gatt_conn_test_disc_all_svcs_cb, &disc_all_svcs_arg); TEST_ASSERT_FATAL(rc == 0); disc_svc_uuid_arg.exp_conn_handle = 1; + conn->client_att_busy = false; rc = ble_gattc_disc_svc_by_uuid(1, BLE_UUID16_DECLARE(0x1111), ble_gatt_conn_test_disc_svc_uuid_cb, &disc_svc_uuid_arg); TEST_ASSERT_FATAL(rc == 0); find_inc_svcs_arg.exp_conn_handle = 1; + conn->client_att_busy = false; rc = ble_gattc_find_inc_svcs(1, 1, 0xffff, ble_gatt_conn_test_find_inc_svcs_cb, &find_inc_svcs_arg); TEST_ASSERT_FATAL(rc == 0); disc_all_chrs_arg.exp_conn_handle = 1; + conn->client_att_busy = false; rc = ble_gattc_disc_all_chrs(1, 1, 0xffff, ble_gatt_conn_test_disc_all_chrs_cb, &disc_all_chrs_arg); TEST_ASSERT_FATAL(rc == 0); /* Connection 2. */ + ble_hs_lock(); + conn = ble_hs_conn_find(2); + ble_hs_unlock(); + disc_all_dscs_arg.exp_conn_handle = 2; + conn->client_att_busy = false; rc = ble_gattc_disc_all_dscs(2, 3, 0xffff, ble_gatt_conn_test_disc_all_dscs_cb, &disc_all_dscs_arg); disc_chr_uuid_arg.exp_conn_handle = 2; + conn->client_att_busy = false; rc = ble_gattc_disc_chrs_by_uuid(2, 2, 0xffff, BLE_UUID16_DECLARE(0x2222), ble_gatt_conn_test_disc_chr_uuid_cb, &disc_chr_uuid_arg); read_arg.exp_conn_handle = 2; + conn->client_att_busy = false; rc = ble_gattc_read(2, BLE_GATT_BREAK_TEST_READ_ATTR_HANDLE, ble_gatt_conn_test_read_cb, &read_arg); TEST_ASSERT_FATAL(rc == 0); read_uuid_arg.exp_conn_handle = 2; + conn->client_att_busy = false; rc = ble_gattc_read_by_uuid(2, 1, 0xffff, BLE_UUID16_DECLARE(0x3333), ble_gatt_conn_test_read_uuid_cb, &read_uuid_arg); TEST_ASSERT_FATAL(rc == 0); read_long_arg.exp_conn_handle = 2; + conn->client_att_busy = false; rc = ble_gattc_read_long(2, BLE_GATT_BREAK_TEST_READ_ATTR_HANDLE, offset, ble_gatt_conn_test_read_long_cb, &read_long_arg); TEST_ASSERT_FATAL(rc == 0); /* Connection 3. */ + ble_hs_lock(); + conn = ble_hs_conn_find(3); + ble_hs_unlock(); + read_mult_arg.exp_conn_handle = 3; + conn->client_att_busy = false; rc = ble_gattc_read_mult(3, ((uint16_t[3]){5,6,7}), 3, ble_gatt_conn_test_read_mult_cb, &read_mult_arg); TEST_ASSERT_FATAL(rc == 0); write_arg.exp_conn_handle = 3; + conn->client_att_busy = false; rc = ble_hs_test_util_gatt_write_flat( 3, BLE_GATT_BREAK_TEST_WRITE_ATTR_HANDLE, ble_gatt_conn_test_write_value, sizeof ble_gatt_conn_test_write_value, @@ -471,6 +499,7 @@ TEST_CASE_SELF(ble_gatt_conn_test_disconnect) TEST_ASSERT_FATAL(rc == 0); write_long_arg.exp_conn_handle = 3; + conn->client_att_busy = false; rc = ble_hs_test_util_gatt_write_long_flat( 3, BLE_GATT_BREAK_TEST_WRITE_ATTR_HANDLE, ble_gatt_conn_test_write_value, sizeof ble_gatt_conn_test_write_value, @@ -481,11 +510,13 @@ TEST_CASE_SELF(ble_gatt_conn_test_disconnect) attr.offset = 0; attr.om = os_msys_get_pkthdr(0, 0); write_rel_arg.exp_conn_handle = 3; + conn->client_att_busy = false; rc = ble_gattc_write_reliable( 3, &attr, 1, ble_gatt_conn_test_write_rel_cb, &write_rel_arg); TEST_ASSERT_FATAL(rc == 0); - rc = ble_gattc_indicate(3, attr_handle); + conn->client_att_busy = false; + rc = ble_gatts_indicate(3, attr_handle); TEST_ASSERT_FATAL(rc == 0); /*** Start the procedures. */ @@ -528,6 +559,11 @@ TEST_CASE_SELF(ble_gatt_conn_test_disconnect) TEST_ASSERT(ble_gatt_conn_test_gap_event.type == 255); /* Connection 3. */ + /** This is required because of call ble_att_clt_tx_exec_write + * from ble_att_clt_tx_exec_write after broken connection - + * ble_gattc_fail_procs is called + */ + conn->client_att_busy = false; ble_gattc_connection_broken(3); TEST_ASSERT(mtu_arg.called == 1); TEST_ASSERT(disc_all_svcs_arg.called == 1); @@ -732,7 +768,7 @@ TEST_CASE_SELF(ble_gatt_conn_test_timeout) /*** Indication. */ ble_hs_test_util_create_conn(1, peer_addr, NULL, NULL); - rc = ble_gattc_indicate(1, attr_handle); + rc = ble_gatts_indicate(1, attr_handle); TEST_ASSERT_FATAL(rc == 0); ble_gatt_conn_test_util_timeout(1, NULL); diff --git a/nimble/host/test/src/ble_gatt_disc_c_test.c b/nimble/host/test/src/ble_gatt_disc_c_test.c index e19db341bb..d0034889f0 100644 --- a/nimble/host/test/src/ble_gatt_disc_c_test.c +++ b/nimble/host/test/src/ble_gatt_disc_c_test.c @@ -25,6 +25,7 @@ #include "ble_hs_test.h" #include "host/ble_gatt.h" #include "host/ble_uuid.h" +#include "host/ble_l2cap.h" #include "ble_hs_test_util.h" struct ble_gatt_disc_c_test_char { @@ -50,8 +51,8 @@ ble_gatt_disc_c_test_init(void) } static int -ble_gatt_disc_c_test_misc_rx_rsp_once( - uint16_t conn_handle, struct ble_gatt_disc_c_test_char *chars) +ble_gatt_disc_c_test_misc_rx_rsp_once(uint16_t conn_handle, uint16_t cid, + struct ble_gatt_disc_c_test_char *chars) { struct ble_att_read_type_rsp rsp; uint8_t buf[1024]; @@ -86,14 +87,14 @@ ble_gatt_disc_c_test_misc_rx_rsp_once( if (chars[i].uuid->type == BLE_UUID_TYPE_16) { if (off + BLE_ATT_READ_TYPE_ADATA_SZ_16 > - ble_att_mtu(conn_handle)) { + ble_att_mtu_by_cid(conn_handle, cid)) { /* Can't fit any more entries. */ break; } } else { if (off + BLE_ATT_READ_TYPE_ADATA_SZ_128 > - ble_att_mtu(conn_handle)) { + ble_att_mtu_by_cid(conn_handle, cid)) { /* Can't fit any more entries. */ break; @@ -121,7 +122,7 @@ ble_gatt_disc_c_test_misc_rx_rsp_once( } static void -ble_gatt_disc_c_test_misc_rx_rsp(uint16_t conn_handle, +ble_gatt_disc_c_test_misc_rx_rsp(uint16_t conn_handle, uint16_t cid, uint16_t end_handle, struct ble_gatt_disc_c_test_char *chars) { @@ -130,7 +131,7 @@ ble_gatt_disc_c_test_misc_rx_rsp(uint16_t conn_handle, idx = 0; while (chars[idx].def_handle != 0) { - count = ble_gatt_disc_c_test_misc_rx_rsp_once(conn_handle, + count = ble_gatt_disc_c_test_misc_rx_rsp_once(conn_handle, cid, chars + idx); if (count == 0) { break; @@ -140,7 +141,8 @@ ble_gatt_disc_c_test_misc_rx_rsp(uint16_t conn_handle, if (chars[idx - 1].def_handle != end_handle) { /* Send the pending ATT Request. */ - ble_hs_test_util_rx_att_err_rsp(conn_handle, BLE_ATT_OP_READ_TYPE_REQ, + ble_hs_test_util_rx_att_err_rsp(conn_handle, cid, + BLE_ATT_OP_READ_TYPE_REQ, BLE_ATT_ERR_ATTR_NOT_FOUND, chars[idx - 1].def_handle); } @@ -229,7 +231,7 @@ ble_gatt_disc_c_test_misc_all(uint16_t start_handle, uint16_t end_handle, ble_gatt_disc_c_test_misc_cb, &num_left); TEST_ASSERT(rc == 0); - ble_gatt_disc_c_test_misc_rx_rsp(2, end_handle, chars); + ble_gatt_disc_c_test_misc_rx_rsp(2, BLE_L2CAP_CID_ATT, end_handle, chars); ble_gatt_disc_c_test_misc_verify_chars(chars, stop_after); } @@ -252,7 +254,7 @@ ble_gatt_disc_c_test_misc_uuid(uint16_t start_handle, uint16_t end_handle, &stop_after); TEST_ASSERT(rc == 0); - ble_gatt_disc_c_test_misc_rx_rsp(2, end_handle, rsp_chars); + ble_gatt_disc_c_test_misc_rx_rsp(2, BLE_L2CAP_CID_ATT, end_handle, rsp_chars); ble_gatt_disc_c_test_misc_verify_chars(ret_chars, 0); } @@ -574,7 +576,7 @@ TEST_CASE_SELF(ble_gatt_disc_c_test_oom_all) /* Exhaust the msys pool. Leave one mbuf for the forthcoming response. */ oms = ble_hs_test_util_mbuf_alloc_all_but(1); - num_chrs = ble_gatt_disc_c_test_misc_rx_rsp_once(1, chrs); + num_chrs = ble_gatt_disc_c_test_misc_rx_rsp_once(1, BLE_L2CAP_CID_ATT, chrs); /* Make sure there are still undiscovered characteristics. */ TEST_ASSERT_FATAL(num_chrs < sizeof chrs / sizeof chrs[0] - 1); @@ -598,7 +600,7 @@ TEST_CASE_SELF(ble_gatt_disc_c_test_oom_all) /* Exhaust the msys pool. Leave one mbuf for the forthcoming response. */ oms = ble_hs_test_util_mbuf_alloc_all_but(1); - ble_gatt_disc_c_test_misc_rx_rsp_once(1, chrs + num_chrs); + ble_gatt_disc_c_test_misc_rx_rsp_once(1, BLE_L2CAP_CID_ATT, chrs + num_chrs); /* Ensure no follow-up request got sent. It should not have gotten sent * due to mbuf exhaustion. @@ -617,7 +619,7 @@ TEST_CASE_SELF(ble_gatt_disc_c_test_oom_all) os_time_advance(ticks_until); ble_gattc_timer(); - ble_hs_test_util_rx_att_err_rsp(1, + ble_hs_test_util_rx_att_err_rsp(1, BLE_L2CAP_CID_ATT, BLE_ATT_OP_READ_TYPE_REQ, BLE_ATT_ERR_ATTR_NOT_FOUND, 1); @@ -663,7 +665,7 @@ TEST_CASE_SELF(ble_gatt_disc_c_test_oom_uuid) /* Exhaust the msys pool. Leave one mbuf for the forthcoming response. */ oms = ble_hs_test_util_mbuf_alloc_all_but(1); - num_chrs = ble_gatt_disc_c_test_misc_rx_rsp_once(1, chrs); + num_chrs = ble_gatt_disc_c_test_misc_rx_rsp_once(1, BLE_L2CAP_CID_ATT, chrs); /* Make sure there are still undiscovered characteristics. */ TEST_ASSERT_FATAL(num_chrs < sizeof chrs / sizeof chrs[0] - 1); @@ -686,7 +688,7 @@ TEST_CASE_SELF(ble_gatt_disc_c_test_oom_uuid) /* Exhaust the msys pool. Leave one mbuf for the forthcoming response. */ oms = ble_hs_test_util_mbuf_alloc_all_but(1); - ble_gatt_disc_c_test_misc_rx_rsp_once(1, chrs + num_chrs); + ble_gatt_disc_c_test_misc_rx_rsp_once(1, BLE_L2CAP_CID_ATT, chrs + num_chrs); /* Ensure no follow-up request got sent. It should not have gotten sent * due to mbuf exhaustion. @@ -704,7 +706,7 @@ TEST_CASE_SELF(ble_gatt_disc_c_test_oom_uuid) os_time_advance(ticks_until); ble_gattc_timer(); - ble_hs_test_util_rx_att_err_rsp(1, + ble_hs_test_util_rx_att_err_rsp(1, BLE_L2CAP_CID_ATT, BLE_ATT_OP_READ_TYPE_REQ, BLE_ATT_ERR_ATTR_NOT_FOUND, 1); diff --git a/nimble/host/test/src/ble_gatt_disc_d_test.c b/nimble/host/test/src/ble_gatt_disc_d_test.c index e405c86f1d..acee2ef8d6 100644 --- a/nimble/host/test/src/ble_gatt_disc_d_test.c +++ b/nimble/host/test/src/ble_gatt_disc_d_test.c @@ -49,8 +49,8 @@ ble_gatt_disc_d_test_init(void) } static int -ble_gatt_disc_d_test_misc_rx_rsp_once( - uint16_t conn_handle, struct ble_gatt_disc_d_test_dsc *dscs) +ble_gatt_disc_d_test_misc_rx_rsp_once(uint16_t conn_handle, uint16_t cid, + struct ble_gatt_disc_d_test_dsc *dscs) { struct ble_att_find_info_rsp rsp; uint8_t buf[1024]; @@ -77,14 +77,14 @@ ble_gatt_disc_d_test_misc_rx_rsp_once( if (dscs[i].dsc_uuid.u.type == BLE_UUID_TYPE_16) { if (off + BLE_ATT_FIND_INFO_IDATA_16_SZ > - ble_att_mtu(conn_handle)) { + ble_att_mtu_by_cid(conn_handle, cid)) { /* Can't fit any more entries. */ break; } } else { if (off + BLE_ATT_FIND_INFO_IDATA_128_SZ > - ble_att_mtu(conn_handle)) { + ble_att_mtu_by_cid(conn_handle, cid)) { /* Can't fit any more entries. */ break; @@ -104,7 +104,7 @@ ble_gatt_disc_d_test_misc_rx_rsp_once( off += ble_uuid_length(&dscs[i].dsc_uuid.u); } - rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, + rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, cid, buf, off); TEST_ASSERT(rc == 0); @@ -113,6 +113,7 @@ ble_gatt_disc_d_test_misc_rx_rsp_once( static void ble_gatt_disc_d_test_misc_rx_rsp(uint16_t conn_handle, + uint16_t cid, uint16_t end_handle, struct ble_gatt_disc_d_test_dsc *dscs) { @@ -121,7 +122,7 @@ ble_gatt_disc_d_test_misc_rx_rsp(uint16_t conn_handle, idx = 0; while (dscs[idx].chr_val_handle != 0) { - count = ble_gatt_disc_d_test_misc_rx_rsp_once(conn_handle, dscs + idx); + count = ble_gatt_disc_d_test_misc_rx_rsp_once(conn_handle, cid, dscs + idx); if (count == 0) { break; } @@ -130,7 +131,8 @@ ble_gatt_disc_d_test_misc_rx_rsp(uint16_t conn_handle, if (dscs[idx - 1].dsc_handle != end_handle) { /* Send the pending ATT Request. */ - ble_hs_test_util_rx_att_err_rsp(conn_handle, BLE_ATT_OP_FIND_INFO_REQ, + ble_hs_test_util_rx_att_err_rsp(conn_handle, cid, + BLE_ATT_OP_FIND_INFO_REQ, BLE_ATT_ERR_ATTR_NOT_FOUND, end_handle); } @@ -223,7 +225,7 @@ ble_gatt_disc_d_test_misc_all(uint16_t chr_val_handle, uint16_t end_handle, ble_gatt_disc_d_test_misc_cb, &num_left); TEST_ASSERT(rc == 0); - ble_gatt_disc_d_test_misc_rx_rsp(2, end_handle, dscs); + ble_gatt_disc_d_test_misc_rx_rsp(2, BLE_L2CAP_CID_ATT, end_handle, dscs); ble_gatt_disc_d_test_misc_verify_dscs(dscs, stop_after); } @@ -389,7 +391,7 @@ TEST_CASE_SELF(ble_gatt_disc_d_test_oom_all) /* Exhaust the msys pool. Leave one mbuf for the forthcoming response. */ oms = ble_hs_test_util_mbuf_alloc_all_but(1); - num_dscs = ble_gatt_disc_d_test_misc_rx_rsp_once(1, dscs); + num_dscs = ble_gatt_disc_d_test_misc_rx_rsp_once(1, BLE_L2CAP_CID_ATT, dscs); /* Make sure there are still undiscovered services. */ TEST_ASSERT_FATAL(num_dscs < sizeof dscs / sizeof dscs[0] - 1); @@ -412,7 +414,7 @@ TEST_CASE_SELF(ble_gatt_disc_d_test_oom_all) /* Exhaust the msys pool. Leave one mbuf for the forthcoming response. */ oms = ble_hs_test_util_mbuf_alloc_all_but(1); - ble_gatt_disc_d_test_misc_rx_rsp_once(1, dscs + num_dscs); + ble_gatt_disc_d_test_misc_rx_rsp_once(1, BLE_L2CAP_CID_ATT, dscs + num_dscs); /* Ensure no follow-up request got sent. It should not have gotten sent * due to mbuf exhaustion. @@ -430,7 +432,7 @@ TEST_CASE_SELF(ble_gatt_disc_d_test_oom_all) os_time_advance(ticks_until); ble_gattc_timer(); - ble_hs_test_util_rx_att_err_rsp(1, + ble_hs_test_util_rx_att_err_rsp(1, BLE_L2CAP_CID_ATT, BLE_ATT_OP_READ_TYPE_REQ, BLE_ATT_ERR_ATTR_NOT_FOUND, 1); diff --git a/nimble/host/test/src/ble_gatt_disc_s_test.c b/nimble/host/test/src/ble_gatt_disc_s_test.c index 3e7a30266c..87735f7dff 100644 --- a/nimble/host/test/src/ble_gatt_disc_s_test.c +++ b/nimble/host/test/src/ble_gatt_disc_s_test.c @@ -56,8 +56,8 @@ ble_gatt_disc_s_test_misc_svc_length(struct ble_gatt_disc_s_test_svc *service) } static int -ble_gatt_disc_s_test_misc_rx_all_rsp_once( - uint16_t conn_handle, struct ble_gatt_disc_s_test_svc *services) +ble_gatt_disc_s_test_misc_rx_all_rsp_once(uint16_t conn_handle, uint16_t cid, + struct ble_gatt_disc_s_test_svc *services) { struct ble_att_read_group_type_rsp rsp; uint8_t buf[1024]; @@ -86,14 +86,14 @@ ble_gatt_disc_s_test_misc_rx_all_rsp_once( if (services[i].uuid->type == BLE_UUID_TYPE_16) { if (off + BLE_ATT_READ_GROUP_TYPE_ADATA_SZ_16 > - ble_att_mtu(conn_handle)) { + ble_att_mtu_by_cid(conn_handle, cid)) { /* Can't fit any more entries. */ break; } } else { if (off + BLE_ATT_READ_GROUP_TYPE_ADATA_SZ_128 > - ble_att_mtu(conn_handle)) { + ble_att_mtu_by_cid(conn_handle,cid)) { /* Can't fit any more entries. */ break; @@ -110,7 +110,7 @@ ble_gatt_disc_s_test_misc_rx_all_rsp_once( off += ble_uuid_length(services[i].uuid); } - rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, + rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, cid, buf, off); TEST_ASSERT(rc == 0); @@ -118,22 +118,22 @@ ble_gatt_disc_s_test_misc_rx_all_rsp_once( } static void -ble_gatt_disc_s_test_misc_rx_all_rsp( - uint16_t conn_handle, struct ble_gatt_disc_s_test_svc *services) +ble_gatt_disc_s_test_misc_rx_all_rsp(uint16_t conn_handle, uint16_t cid, + struct ble_gatt_disc_s_test_svc *services) { int count; int idx; idx = 0; while (services[idx].start_handle != 0) { - count = ble_gatt_disc_s_test_misc_rx_all_rsp_once(conn_handle, + count = ble_gatt_disc_s_test_misc_rx_all_rsp_once(conn_handle, cid, services + idx); idx += count; } if (services[idx - 1].end_handle != 0xffff) { /* Send the pending ATT Request. */ - ble_hs_test_util_rx_att_err_rsp(conn_handle, + ble_hs_test_util_rx_att_err_rsp(conn_handle, cid, BLE_ATT_OP_READ_GROUP_TYPE_REQ, BLE_ATT_ERR_ATTR_NOT_FOUND, services[idx - 1].start_handle); @@ -141,8 +141,8 @@ ble_gatt_disc_s_test_misc_rx_all_rsp( } static int -ble_gatt_disc_s_test_misc_rx_uuid_rsp_once( - uint16_t conn_handle, struct ble_gatt_disc_s_test_svc *services) +ble_gatt_disc_s_test_misc_rx_uuid_rsp_once(uint16_t conn_handle, uint16_t cid, + struct ble_gatt_disc_s_test_svc *services) { uint8_t buf[1024]; int off; @@ -160,7 +160,7 @@ ble_gatt_disc_s_test_misc_rx_uuid_rsp_once( } if (off + BLE_ATT_FIND_TYPE_VALUE_HINFO_BASE_SZ > - ble_att_mtu(conn_handle)) { + ble_att_mtu_by_cid(conn_handle, cid)) { /* Can't fit any more entries. */ break; @@ -173,7 +173,7 @@ ble_gatt_disc_s_test_misc_rx_uuid_rsp_once( off += 2; } - rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, + rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, cid, buf, off); TEST_ASSERT(rc == 0); @@ -181,22 +181,22 @@ ble_gatt_disc_s_test_misc_rx_uuid_rsp_once( } static void -ble_gatt_disc_s_test_misc_rx_uuid_rsp( - uint16_t conn_handle, struct ble_gatt_disc_s_test_svc *services) +ble_gatt_disc_s_test_misc_rx_uuid_rsp(uint16_t conn_handle, uint16_t cid, + struct ble_gatt_disc_s_test_svc *services) { int count; int idx; idx = 0; while (services[idx].start_handle != 0) { - count = ble_gatt_disc_s_test_misc_rx_uuid_rsp_once(conn_handle, + count = ble_gatt_disc_s_test_misc_rx_uuid_rsp_once(conn_handle, cid, services + idx); idx += count; } if (services[idx - 1].end_handle != 0xffff) { /* Send the pending ATT Request. */ - ble_hs_test_util_rx_att_err_rsp(conn_handle, + ble_hs_test_util_rx_att_err_rsp(conn_handle, cid, BLE_ATT_OP_FIND_TYPE_VALUE_REQ, BLE_ATT_ERR_ATTR_NOT_FOUND, services[idx - 1].start_handle); @@ -269,7 +269,7 @@ ble_gatt_disc_s_test_misc_good_all(struct ble_gatt_disc_s_test_svc *services) rc = ble_gattc_disc_all_svcs(2, ble_gatt_disc_s_test_misc_disc_cb, NULL); TEST_ASSERT(rc == 0); - ble_gatt_disc_s_test_misc_rx_all_rsp(2, services); + ble_gatt_disc_s_test_misc_rx_all_rsp(2, BLE_L2CAP_CID_ATT, services); ble_gatt_disc_s_test_misc_verify_services(services); } @@ -290,7 +290,7 @@ ble_gatt_disc_s_test_misc_good_uuid( ble_hs_test_util_verify_tx_disc_svc_uuid(services[0].uuid); - ble_gatt_disc_s_test_misc_rx_uuid_rsp(2, services); + ble_gatt_disc_s_test_misc_rx_uuid_rsp(2, BLE_L2CAP_CID_ATT, services); ble_gatt_disc_s_test_misc_verify_services(services); } @@ -425,7 +425,7 @@ TEST_CASE_SELF(ble_gatt_disc_s_test_oom_all) /* Exhaust the msys pool. Leave one mbuf for the forthcoming response. */ oms = ble_hs_test_util_mbuf_alloc_all_but(1); - num_svcs = ble_gatt_disc_s_test_misc_rx_all_rsp_once(1, svcs); + num_svcs = ble_gatt_disc_s_test_misc_rx_all_rsp_once(1, BLE_L2CAP_CID_ATT, svcs); /* Make sure there are still undiscovered services. */ TEST_ASSERT_FATAL(num_svcs < sizeof svcs / sizeof svcs[0] - 1); @@ -448,7 +448,7 @@ TEST_CASE_SELF(ble_gatt_disc_s_test_oom_all) /* Exhaust the msys pool. Leave one mbuf for the forthcoming response. */ oms = ble_hs_test_util_mbuf_alloc_all_but(1); - ble_gatt_disc_s_test_misc_rx_all_rsp_once(1, svcs + num_svcs); + ble_gatt_disc_s_test_misc_rx_all_rsp_once(1, BLE_L2CAP_CID_ATT, svcs + num_svcs); /* Ensure no follow-up request got sent. It should not have gotten sent * due to mbuf exhaustion. @@ -465,7 +465,7 @@ TEST_CASE_SELF(ble_gatt_disc_s_test_oom_all) os_time_advance(ticks_until); ble_gattc_timer(); - ble_hs_test_util_rx_att_err_rsp(1, + ble_hs_test_util_rx_att_err_rsp(1, BLE_L2CAP_CID_ATT, BLE_ATT_OP_READ_GROUP_TYPE_REQ, BLE_ATT_ERR_ATTR_NOT_FOUND, 1); @@ -504,7 +504,7 @@ TEST_CASE_SELF(ble_gatt_disc_s_test_oom_uuid) /* Exhaust the msys pool. Leave one mbuf for the forthcoming response. */ oms = ble_hs_test_util_mbuf_alloc_all_but(1); - num_svcs = ble_gatt_disc_s_test_misc_rx_uuid_rsp_once(1, svcs); + num_svcs = ble_gatt_disc_s_test_misc_rx_uuid_rsp_once(1, BLE_L2CAP_CID_ATT, svcs); /* Make sure there are still undiscovered services. */ TEST_ASSERT_FATAL(num_svcs < sizeof svcs / sizeof svcs[0] - 1); @@ -527,7 +527,7 @@ TEST_CASE_SELF(ble_gatt_disc_s_test_oom_uuid) /* Exhaust the msys pool. Leave one mbuf for the forthcoming response. */ oms = ble_hs_test_util_mbuf_alloc_all_but(1); - ble_gatt_disc_s_test_misc_rx_uuid_rsp_once(1, svcs + num_svcs); + ble_gatt_disc_s_test_misc_rx_uuid_rsp_once(1, BLE_L2CAP_CID_ATT, svcs + num_svcs); /* Ensure no follow-up request got sent. It should not have gotten sent * due to mbuf exhaustion. @@ -545,7 +545,7 @@ TEST_CASE_SELF(ble_gatt_disc_s_test_oom_uuid) os_time_advance(ticks_until); ble_gattc_timer(); - ble_hs_test_util_rx_att_err_rsp(1, + ble_hs_test_util_rx_att_err_rsp(1, BLE_L2CAP_CID_ATT, BLE_ATT_OP_READ_GROUP_TYPE_REQ, BLE_ATT_ERR_ATTR_NOT_FOUND, 1); @@ -579,7 +579,7 @@ TEST_CASE_SELF(ble_gatt_disc_s_test_oom_timeout) /* Exhaust the msys pool. Leave one mbuf for the forthcoming response. */ oms = ble_hs_test_util_mbuf_alloc_all_but(1); - ble_gatt_disc_s_test_misc_rx_all_rsp_once(1, svcs); + ble_gatt_disc_s_test_misc_rx_all_rsp_once(1, BLE_L2CAP_CID_ATT, svcs); /* Keep trying to resume for 30 seconds, but never free any mbufs. Verify * procedure eventually times out. diff --git a/nimble/host/test/src/ble_gatt_find_s_test.c b/nimble/host/test/src/ble_gatt_find_s_test.c index 172bdd3321..5f8075c9a8 100644 --- a/nimble/host/test/src/ble_gatt_find_s_test.c +++ b/nimble/host/test/src/ble_gatt_find_s_test.c @@ -90,8 +90,8 @@ ble_gatt_find_s_test_misc_verify_incs( } static int -ble_gatt_find_s_test_misc_rx_read_type( - uint16_t conn_handle, struct ble_gatt_find_s_test_entry *entries) +ble_gatt_find_s_test_misc_rx_read_type(uint16_t conn_handle, uint16_t cid, + struct ble_gatt_find_s_test_entry *entries) { struct ble_att_read_type_rsp rsp; uint8_t buf[1024]; @@ -134,14 +134,15 @@ ble_gatt_find_s_test_misc_rx_read_type( } if (i == 0) { - ble_hs_test_util_rx_att_err_rsp(conn_handle, BLE_ATT_OP_READ_TYPE_REQ, + ble_hs_test_util_rx_att_err_rsp(conn_handle, cid, + BLE_ATT_OP_READ_TYPE_REQ, BLE_ATT_ERR_ATTR_NOT_FOUND, 0); return 0; } ble_att_read_type_rsp_write(buf + 0, BLE_ATT_READ_TYPE_RSP_BASE_SZ, &rsp); - rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, + rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, cid, buf, off); TEST_ASSERT(rc == 0); @@ -149,7 +150,7 @@ ble_gatt_find_s_test_misc_rx_read_type( } static void -ble_gatt_find_s_test_misc_rx_read(uint16_t conn_handle, const ble_uuid_t *uuid) +ble_gatt_find_s_test_misc_rx_read(uint16_t conn_handle, uint16_t cid, const ble_uuid_t *uuid) { uint8_t buf[17]; int rc; @@ -159,7 +160,7 @@ ble_gatt_find_s_test_misc_rx_read(uint16_t conn_handle, const ble_uuid_t *uuid) buf[0] = BLE_ATT_OP_READ_RSP; ble_uuid_flat(uuid, buf + 1); - rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, + rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, cid, buf, 17); TEST_ASSERT(rc == 0); } @@ -200,7 +201,7 @@ ble_gatt_find_s_test_misc_verify_tx_read(uint16_t handle) } static void -ble_gatt_find_s_test_misc_find_inc(uint16_t conn_handle, +ble_gatt_find_s_test_misc_find_inc(uint16_t conn_handle, uint16_t cid, uint16_t start_handle, uint16_t end_handle, struct ble_gatt_find_s_test_entry *entries) { @@ -219,7 +220,7 @@ ble_gatt_find_s_test_misc_find_inc(uint16_t conn_handle, idx = 0; while (1) { ble_gatt_find_s_test_misc_verify_tx_read_type(cur_start, end_handle); - num_found = ble_gatt_find_s_test_misc_rx_read_type(conn_handle, + num_found = ble_gatt_find_s_test_misc_rx_read_type(conn_handle, cid, entries + idx); if (num_found == 0) { break; @@ -229,7 +230,7 @@ ble_gatt_find_s_test_misc_find_inc(uint16_t conn_handle, TEST_ASSERT(num_found == 1); ble_gatt_find_s_test_misc_verify_tx_read( entries[idx].start_handle); - ble_gatt_find_s_test_misc_rx_read(conn_handle, + ble_gatt_find_s_test_misc_rx_read(conn_handle, cid, entries[idx].uuid); } @@ -255,7 +256,7 @@ TEST_CASE_SELF(ble_gatt_find_s_test_1) ble_gatt_find_s_test_misc_init(); ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}), NULL, NULL); - ble_gatt_find_s_test_misc_find_inc(2, 5, 10, + ble_gatt_find_s_test_misc_find_inc(2, BLE_L2CAP_CID_ATT, 5, 10, ((struct ble_gatt_find_s_test_entry[]) { { .inc_handle = 6, .start_handle = 35, @@ -275,7 +276,7 @@ TEST_CASE_SELF(ble_gatt_find_s_test_1) ble_gatt_find_s_test_misc_init(); ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}), NULL, NULL); - ble_gatt_find_s_test_misc_find_inc(2, 34, 100, + ble_gatt_find_s_test_misc_find_inc(2, BLE_L2CAP_CID_ATT, 34, 100, ((struct ble_gatt_find_s_test_entry[]) { { .inc_handle = 36, .start_handle = 403, @@ -290,7 +291,7 @@ TEST_CASE_SELF(ble_gatt_find_s_test_1) ble_gatt_find_s_test_misc_init(); ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}), NULL, NULL); - ble_gatt_find_s_test_misc_find_inc(2, 34, 100, + ble_gatt_find_s_test_misc_find_inc(2, BLE_L2CAP_CID_ATT, 34, 100, ((struct ble_gatt_find_s_test_entry[]) { { .inc_handle = 36, .start_handle = 403, @@ -310,7 +311,7 @@ TEST_CASE_SELF(ble_gatt_find_s_test_1) ble_gatt_find_s_test_misc_init(); ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}), NULL, NULL); - ble_gatt_find_s_test_misc_find_inc(2, 1, 100, + ble_gatt_find_s_test_misc_find_inc(2, BLE_L2CAP_CID_ATT, 1, 100, ((struct ble_gatt_find_s_test_entry[]) { { .inc_handle = 36, .start_handle = 403, @@ -379,7 +380,7 @@ TEST_CASE_SELF(ble_gatt_find_s_test_oom) /* Exhaust the msys pool. Leave one mbuf for the forthcoming response. */ oms = ble_hs_test_util_mbuf_alloc_all_but(1); - ble_gatt_find_s_test_misc_rx_read_type(1, incs); + ble_gatt_find_s_test_misc_rx_read_type(1, BLE_L2CAP_CID_ATT, incs); /* Ensure no follow-up request got sent. It should not have gotten sent * due to mbuf exhaustion. @@ -402,11 +403,11 @@ TEST_CASE_SELF(ble_gatt_find_s_test_oom) * follow-up request, so there is always an mbuf available. */ /* XXX: Find a way to test this. */ - ble_gatt_find_s_test_misc_rx_read(1, incs[0].uuid); + ble_gatt_find_s_test_misc_rx_read(1, BLE_L2CAP_CID_ATT, incs[0].uuid); /* Exhaust the msys pool. Leave one mbuf for the forthcoming response. */ oms = ble_hs_test_util_mbuf_alloc_all_but(1); - ble_gatt_find_s_test_misc_rx_read_type(1, incs + 1); + ble_gatt_find_s_test_misc_rx_read_type(1, BLE_L2CAP_CID_ATT, incs + 1); /* Verify the procedure succeeds after mbufs become available. */ rc = os_mbuf_free_chain(oms); @@ -414,9 +415,9 @@ TEST_CASE_SELF(ble_gatt_find_s_test_oom) os_time_advance(ticks_until); ble_gattc_timer(); - ble_gatt_find_s_test_misc_rx_read(1, incs[1].uuid); + ble_gatt_find_s_test_misc_rx_read(1, BLE_L2CAP_CID_ATT, incs[1].uuid); - ble_hs_test_util_rx_att_err_rsp(1, + ble_hs_test_util_rx_att_err_rsp(1, BLE_L2CAP_CID_ATT, BLE_ATT_OP_READ_TYPE_REQ, BLE_ATT_ERR_ATTR_NOT_FOUND, 1); diff --git a/nimble/host/test/src/ble_gatt_read_test.c b/nimble/host/test/src/ble_gatt_read_test.c index 572b0bf1c6..a22e5a559f 100644 --- a/nimble/host/test/src/ble_gatt_read_test.c +++ b/nimble/host/test/src/ble_gatt_read_test.c @@ -160,7 +160,7 @@ ble_gatt_read_test_long_cb(uint16_t conn_handle, } static void -ble_gatt_read_test_misc_rx_rsp_good_raw(uint16_t conn_handle, +ble_gatt_read_test_misc_rx_rsp_good_raw(uint16_t conn_handle, uint16_t cid, uint8_t att_op, const void *data, int data_len) { @@ -174,27 +174,28 @@ ble_gatt_read_test_misc_rx_rsp_good_raw(uint16_t conn_handle, buf[0] = att_op; memcpy(buf + 1, data, data_len); - rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, + rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, cid, buf, 1 + data_len); TEST_ASSERT(rc == 0); } static void -ble_gatt_read_test_misc_rx_rsp_good(uint16_t conn_handle, +ble_gatt_read_test_misc_rx_rsp_good(uint16_t conn_handle, uint16_t cid, struct ble_hs_test_util_flat_attr *attr) { - ble_gatt_read_test_misc_rx_rsp_good_raw(conn_handle, BLE_ATT_OP_READ_RSP, + ble_gatt_read_test_misc_rx_rsp_good_raw(conn_handle, cid, + BLE_ATT_OP_READ_RSP, attr->value, attr->value_len); } static void -ble_gatt_read_test_misc_rx_rsp_bad(uint16_t conn_handle, +ble_gatt_read_test_misc_rx_rsp_bad(uint16_t conn_handle, uint16_t cid, uint8_t att_error, uint16_t err_handle) { /* Send the pending ATT Read Request. */ - ble_hs_test_util_rx_att_err_rsp(conn_handle, BLE_ATT_OP_READ_REQ, + ble_hs_test_util_rx_att_err_rsp(conn_handle, cid, BLE_ATT_OP_READ_REQ, att_error, err_handle); } @@ -255,7 +256,7 @@ ble_gatt_read_test_misc_verify_good(struct ble_hs_test_util_flat_attr *attr) rc = ble_gattc_read(2, attr->handle, ble_gatt_read_test_cb, NULL); TEST_ASSERT_FATAL(rc == 0); - ble_gatt_read_test_misc_rx_rsp_good(2, attr); + ble_gatt_read_test_misc_rx_rsp_good(2, BLE_L2CAP_CID_ATT, attr); TEST_ASSERT(ble_gatt_read_test_num_attrs == 1); TEST_ASSERT(ble_gatt_read_test_attrs[0].conn_handle == 2); @@ -278,7 +279,7 @@ ble_gatt_read_test_misc_verify_bad(uint8_t att_status, rc = ble_gattc_read(2, attr->handle, ble_gatt_read_test_cb, NULL); TEST_ASSERT_FATAL(rc == 0); - ble_gatt_read_test_misc_rx_rsp_bad(2, att_status, attr->handle); + ble_gatt_read_test_misc_rx_rsp_bad(2, BLE_L2CAP_CID_ATT, att_status, attr->handle); TEST_ASSERT(ble_gatt_read_test_num_attrs == 0); TEST_ASSERT(ble_gatt_read_test_bad_conn_handle == 2); @@ -309,7 +310,8 @@ ble_gatt_read_test_misc_uuid_verify_good( while (1) { num_read = ble_gatt_read_test_misc_uuid_rx_rsp_good(2, attrs + idx); if (num_read == 0) { - ble_hs_test_util_rx_att_err_rsp(2, BLE_ATT_OP_READ_TYPE_REQ, + ble_hs_test_util_rx_att_err_rsp(2, BLE_L2CAP_CID_ATT, + BLE_ATT_OP_READ_TYPE_REQ, BLE_ATT_ERR_ATTR_NOT_FOUND, start_handle); break; @@ -369,7 +371,7 @@ ble_gatt_read_test_misc_long_verify_good( } else { att_op = BLE_ATT_OP_READ_BLOB_RSP; } - ble_gatt_read_test_misc_rx_rsp_good_raw(2, att_op, + ble_gatt_read_test_misc_rx_rsp_good_raw(2, BLE_L2CAP_CID_ATT, att_op, attr->value + off, chunk_sz); rem_len -= chunk_sz; off += chunk_sz; @@ -401,7 +403,7 @@ ble_gatt_read_test_misc_long_verify_bad( ble_gatt_read_test_long_cb, NULL); TEST_ASSERT_FATAL(rc == 0); - ble_gatt_read_test_misc_rx_rsp_bad(2, att_status, attr->handle); + ble_gatt_read_test_misc_rx_rsp_bad(2, BLE_L2CAP_CID_ATT, att_status, attr->handle); TEST_ASSERT(ble_gatt_read_test_num_attrs == 0); TEST_ASSERT(ble_gatt_read_test_bad_conn_handle == 2); @@ -458,7 +460,7 @@ ble_gatt_read_test_misc_mult_verify_good( ble_gatt_read_test_cb, NULL); TEST_ASSERT_FATAL(rc == 0); - ble_gatt_read_test_misc_rx_rsp_good_raw(2, BLE_ATT_OP_READ_MULT_RSP, + ble_gatt_read_test_misc_rx_rsp_good_raw(2, BLE_L2CAP_CID_ATT, BLE_ATT_OP_READ_MULT_RSP, expected_value, off); TEST_ASSERT(ble_gatt_read_test_complete); @@ -488,7 +490,7 @@ ble_gatt_read_test_misc_mult_verify_bad( ble_gatt_read_test_cb, NULL); TEST_ASSERT_FATAL(rc == 0); - ble_gatt_read_test_misc_rx_rsp_bad(2, att_status, err_handle); + ble_gatt_read_test_misc_rx_rsp_bad(2, BLE_L2CAP_CID_ATT, att_status, err_handle); TEST_ASSERT(ble_gatt_read_test_num_attrs == 0); TEST_ASSERT(ble_gatt_read_test_bad_conn_handle == 2); @@ -801,9 +803,9 @@ TEST_CASE_SELF(ble_gatt_read_test_concurrent) rc = ble_gattc_read(2, attrs[2].handle, ble_gatt_read_test_cb, NULL); TEST_ASSERT_FATAL(rc == 0); - ble_gatt_read_test_misc_rx_rsp_good(2, attrs + 0); - ble_gatt_read_test_misc_rx_rsp_good(2, attrs + 1); - ble_gatt_read_test_misc_rx_rsp_good(2, attrs + 2); + ble_gatt_read_test_misc_rx_rsp_good(2, BLE_L2CAP_CID_ATT, attrs + 0); + ble_gatt_read_test_misc_rx_rsp_good(2, BLE_L2CAP_CID_ATT, attrs + 1); + ble_gatt_read_test_misc_rx_rsp_good(2, BLE_L2CAP_CID_ATT, attrs + 2); TEST_ASSERT(ble_gatt_read_test_num_attrs == 3); @@ -852,8 +854,8 @@ TEST_CASE_SELF(ble_gatt_read_test_long_oom) /* Exhaust the msys pool. Leave one mbuf for the forthcoming response. */ oms = ble_hs_test_util_mbuf_alloc_all_but(1); - chunk_sz = ble_att_mtu(2) - BLE_ATT_READ_RSP_BASE_SZ; - ble_gatt_read_test_misc_rx_rsp_good_raw(2, BLE_ATT_OP_READ_RSP, + chunk_sz = ble_att_mtu_by_cid(2, BLE_L2CAP_CID_ATT) - BLE_ATT_READ_RSP_BASE_SZ; + ble_gatt_read_test_misc_rx_rsp_good_raw(2, BLE_L2CAP_CID_ATT, BLE_ATT_OP_READ_RSP, attr.value + off, chunk_sz); off += chunk_sz; @@ -875,8 +877,8 @@ TEST_CASE_SELF(ble_gatt_read_test_long_oom) /* Exhaust the msys pool. Leave one mbuf for the forthcoming response. */ oms = ble_hs_test_util_mbuf_alloc_all_but(1); - chunk_sz = ble_att_mtu(2) - BLE_ATT_READ_RSP_BASE_SZ; - ble_gatt_read_test_misc_rx_rsp_good_raw(2, BLE_ATT_OP_READ_RSP, + chunk_sz = ble_att_mtu_by_cid(2, BLE_L2CAP_CID_ATT) - BLE_ATT_READ_RSP_BASE_SZ; + ble_gatt_read_test_misc_rx_rsp_good_raw(2, BLE_L2CAP_CID_ATT, BLE_ATT_OP_READ_RSP, attr.value + off, chunk_sz); off += chunk_sz; @@ -897,7 +899,7 @@ TEST_CASE_SELF(ble_gatt_read_test_long_oom) ble_gattc_timer(); chunk_sz = attr.value_len - off; - ble_gatt_read_test_misc_rx_rsp_good_raw(2, BLE_ATT_OP_READ_RSP, + ble_gatt_read_test_misc_rx_rsp_good_raw(2, BLE_L2CAP_CID_ATT, BLE_ATT_OP_READ_RSP, attr.value + off, chunk_sz); off += chunk_sz; diff --git a/nimble/host/test/src/ble_gatt_write_test.c b/nimble/host/test/src/ble_gatt_write_test.c index caa8e56571..ea815c0d5c 100644 --- a/nimble/host/test/src/ble_gatt_write_test.c +++ b/nimble/host/test/src/ble_gatt_write_test.c @@ -87,8 +87,8 @@ ble_gatt_write_test_rx_rsp(uint16_t conn_handle) } static void -ble_gatt_write_test_rx_prep_rsp(uint16_t conn_handle, uint16_t attr_handle, - uint16_t offset, +ble_gatt_write_test_rx_prep_rsp(uint16_t conn_handle, uint16_t cid, + uint16_t attr_handle, uint16_t offset, const void *attr_data, uint16_t attr_data_len) { struct ble_att_prep_write_cmd rsp; @@ -102,19 +102,19 @@ ble_gatt_write_test_rx_prep_rsp(uint16_t conn_handle, uint16_t attr_handle, memcpy(buf + BLE_ATT_PREP_WRITE_CMD_BASE_SZ, attr_data, attr_data_len); rc = ble_hs_test_util_l2cap_rx_payload_flat( - conn_handle, BLE_L2CAP_CID_ATT, buf, + conn_handle, cid, buf, BLE_ATT_PREP_WRITE_CMD_BASE_SZ + attr_data_len); TEST_ASSERT(rc == 0); } static void -ble_gatt_write_test_rx_exec_rsp(uint16_t conn_handle) +ble_gatt_write_test_rx_exec_rsp(uint16_t conn_handle, uint16_t cid) { uint8_t op; int rc; op = BLE_ATT_OP_EXEC_WRITE_RSP; - rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, + rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, cid, &op, 1); TEST_ASSERT(rc == 0); } @@ -129,10 +129,10 @@ ble_gatt_write_test_misc_long_good(int attr_len) ble_gatt_write_test_init(); - ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}), + ble_hs_test_util_create_conn(2, ((uint8_t[]) {2,3,4,5,6,7,8,9}), NULL, NULL); - mtu = ble_att_mtu(2); + mtu = ble_att_mtu_by_cid(2, BLE_L2CAP_CID_ATT); rc = ble_hs_test_util_gatt_write_long_flat( 2, 100, ble_gatt_write_test_attr_value, attr_len, @@ -152,7 +152,7 @@ ble_gatt_write_test_misc_long_good(int attr_len) /* Receive Prep Write response. */ ble_gatt_write_test_rx_prep_rsp( - 2, 100, off, ble_gatt_write_test_attr_value + off, len); + 2, BLE_L2CAP_CID_ATT, 100, off, ble_gatt_write_test_attr_value + off, len); /* Verify callback hasn't gotten called. */ TEST_ASSERT(!ble_gatt_write_test_cb_called); @@ -164,13 +164,13 @@ ble_gatt_write_test_misc_long_good(int attr_len) ble_hs_test_util_verify_tx_exec_write(BLE_ATT_EXEC_WRITE_F_EXECUTE); /* Receive Exec Write response. */ - ble_gatt_write_test_rx_exec_rsp(2); + ble_gatt_write_test_rx_exec_rsp(2, BLE_L2CAP_CID_ATT); /* Verify callback got called. */ TEST_ASSERT(ble_gatt_write_test_cb_called); } -typedef void ble_gatt_write_test_long_fail_fn(uint16_t conn_handle, +typedef void ble_gatt_write_test_long_fail_fn(uint16_t conn_handle, uint16_t cid, int off, int len); static void @@ -185,9 +185,9 @@ ble_gatt_write_test_misc_long_bad(int attr_len, ble_gatt_write_test_init(); - ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}), + ble_hs_test_util_create_conn(2, ((uint8_t[]) {2,3,4,5,6,7,8,9}), NULL, NULL); - mtu = ble_att_mtu(2); + mtu = ble_att_mtu_by_cid(2, BLE_L2CAP_CID_ATT); rc = ble_hs_test_util_gatt_write_long_flat( 2, 100, ble_gatt_write_test_attr_value, attr_len, @@ -214,9 +214,9 @@ ble_gatt_write_test_misc_long_bad(int attr_len, } if (!fail_now) { ble_gatt_write_test_rx_prep_rsp( - 2, 100, off, ble_gatt_write_test_attr_value + off, len); + 2, BLE_L2CAP_CID_ATT, 100, off, ble_gatt_write_test_attr_value + off, len); } else { - cb(2, off, len); + cb(2, BLE_L2CAP_CID_ATT, off, len); break; } @@ -233,38 +233,38 @@ ble_gatt_write_test_misc_long_bad(int attr_len, } static void -ble_gatt_write_test_misc_long_fail_handle(uint16_t conn_handle, +ble_gatt_write_test_misc_long_fail_handle(uint16_t conn_handle, uint16_t cid, int off, int len) { ble_gatt_write_test_rx_prep_rsp( - conn_handle, 99, off, ble_gatt_write_test_attr_value + off, + conn_handle, cid, 99, off, ble_gatt_write_test_attr_value + off, len); } static void -ble_gatt_write_test_misc_long_fail_offset(uint16_t conn_handle, +ble_gatt_write_test_misc_long_fail_offset(uint16_t conn_handle, uint16_t cid, int off, int len) { ble_gatt_write_test_rx_prep_rsp( - conn_handle, 100, off + 1, ble_gatt_write_test_attr_value + off, + conn_handle, cid, 100, off + 1, ble_gatt_write_test_attr_value + off, len); } static void -ble_gatt_write_test_misc_long_fail_value(uint16_t conn_handle, +ble_gatt_write_test_misc_long_fail_value(uint16_t conn_handle, uint16_t cid, int off, int len) { ble_gatt_write_test_rx_prep_rsp( - conn_handle, 100, off, ble_gatt_write_test_attr_value + off + 1, + conn_handle, cid, 100, off, ble_gatt_write_test_attr_value + off + 1, len); } static void -ble_gatt_write_test_misc_long_fail_length(uint16_t conn_handle, +ble_gatt_write_test_misc_long_fail_length(uint16_t conn_handle, uint16_t cid, int off, int len) { ble_gatt_write_test_rx_prep_rsp( - conn_handle, 100, off, ble_gatt_write_test_attr_value + off, + conn_handle, cid, 100, off, ble_gatt_write_test_attr_value + off, len - 1); } @@ -313,9 +313,9 @@ ble_gatt_write_test_misc_reliable_good( flat_attrs + num_attrs); } - ble_hs_test_util_create_conn(2, ((uint8_t[]){2,3,4,5,6,7,8,9}), + ble_hs_test_util_create_conn(2, ((uint8_t[]) {2,3,4,5,6,7,8,9}), NULL, NULL); - mtu = ble_att_mtu(2); + mtu = ble_att_mtu_by_cid(2, BLE_L2CAP_CID_ATT); rc = ble_gattc_write_reliable(2, attrs, num_attrs, ble_gatt_write_test_reliable_cb_good, NULL); @@ -336,7 +336,7 @@ ble_gatt_write_test_misc_reliable_good( attr->value + off, len); /* Receive Prep Write response. */ - ble_gatt_write_test_rx_prep_rsp(2, attr->handle, off, + ble_gatt_write_test_rx_prep_rsp(2, BLE_L2CAP_CID_ATT, attr->handle, off, attr->value + off, len); /* Verify callback hasn't gotten called. */ @@ -353,7 +353,7 @@ ble_gatt_write_test_misc_reliable_good( ble_hs_test_util_verify_tx_exec_write(BLE_ATT_EXEC_WRITE_F_EXECUTE); /* Receive Exec Write response. */ - ble_gatt_write_test_rx_exec_rsp(2); + ble_gatt_write_test_rx_exec_rsp(2, BLE_L2CAP_CID_ATT); /* Verify callback got called. */ TEST_ASSERT(ble_gatt_write_test_cb_called); @@ -599,7 +599,7 @@ TEST_CASE_SELF(ble_gatt_write_test_long_queue_full) /* Receive Prep Write response. */ len = BLE_ATT_MTU_DFLT - BLE_ATT_PREP_WRITE_CMD_BASE_SZ; ble_gatt_write_test_rx_prep_rsp( - 2, 100, off, ble_gatt_write_test_attr_value + off, len); + 2, BLE_L2CAP_CID_ATT, 100, off, ble_gatt_write_test_attr_value + off, len); /* Verify callback hasn't gotten called. */ TEST_ASSERT(!ble_gatt_write_test_cb_called); @@ -611,7 +611,8 @@ TEST_CASE_SELF(ble_gatt_write_test_long_queue_full) TEST_ASSERT(ble_hs_test_util_prev_tx_dequeue() != NULL); /* Receive queue full error. */ - ble_hs_test_util_rx_att_err_rsp(2, BLE_ATT_OP_PREP_WRITE_REQ, + ble_hs_test_util_rx_att_err_rsp(2, BLE_L2CAP_CID_ATT, + BLE_ATT_OP_PREP_WRITE_REQ, BLE_ATT_ERR_PREPARE_QUEUE_FULL, 100); /* Verify callback was called. */ @@ -654,14 +655,14 @@ TEST_CASE_SELF(ble_gatt_write_test_long_oom) ble_gatt_write_test_cb_good, NULL); TEST_ASSERT_FATAL(rc == 0); - chunk_sz = ble_att_mtu(2) - BLE_ATT_PREP_WRITE_CMD_BASE_SZ; + chunk_sz = ble_att_mtu_by_cid(2, BLE_L2CAP_CID_ATT) - BLE_ATT_PREP_WRITE_CMD_BASE_SZ; ble_hs_test_util_verify_tx_prep_write(attr.handle, off, attr.value + off, chunk_sz); /* Exhaust the msys pool. Leave one mbuf for the forthcoming response. */ oms = ble_hs_test_util_mbuf_alloc_all_but(1); - ble_gatt_write_test_rx_prep_rsp(2, attr.handle, off, attr.value + off, + ble_gatt_write_test_rx_prep_rsp(2, BLE_L2CAP_CID_ATT, attr.handle, off, attr.value + off, chunk_sz); off += chunk_sz; @@ -688,7 +689,7 @@ TEST_CASE_SELF(ble_gatt_write_test_long_oom) /* Exhaust the msys pool. Leave one mbuf for the forthcoming response. */ oms = ble_hs_test_util_mbuf_alloc_all_but(1); ble_gatt_write_test_rx_prep_rsp( - 2, attr.handle, off, attr.value + off, chunk_sz); + 2, BLE_L2CAP_CID_ATT, attr.handle, off, attr.value + off, chunk_sz); off += chunk_sz; /* Ensure no follow-up request got sent. It should not have gotten sent @@ -711,7 +712,7 @@ TEST_CASE_SELF(ble_gatt_write_test_long_oom) ble_hs_test_util_verify_tx_exec_write(BLE_ATT_EXEC_WRITE_F_EXECUTE); /* Receive Exec Write response. */ - ble_gatt_write_test_rx_exec_rsp(2); + ble_gatt_write_test_rx_exec_rsp(2, BLE_L2CAP_CID_ATT); /* Verify callback got called. */ TEST_ASSERT(ble_gatt_write_test_cb_called); @@ -750,14 +751,14 @@ TEST_CASE_SELF(ble_gatt_write_test_reliable_oom) ble_gatt_write_test_reliable_cb_good, NULL); TEST_ASSERT_FATAL(rc == 0); - chunk_sz = ble_att_mtu(2) - BLE_ATT_PREP_WRITE_CMD_BASE_SZ; + chunk_sz = ble_att_mtu_by_cid(2, BLE_L2CAP_CID_ATT) - BLE_ATT_PREP_WRITE_CMD_BASE_SZ; ble_hs_test_util_verify_tx_prep_write(attr.handle, off, attr.value + off, chunk_sz); /* Exhaust the msys pool. Leave one mbuf for the forthcoming response. */ oms = ble_hs_test_util_mbuf_alloc_all_but(1); - ble_gatt_write_test_rx_prep_rsp(2, attr.handle, off, attr.value + off, + ble_gatt_write_test_rx_prep_rsp(2, BLE_L2CAP_CID_ATT, attr.handle, off, attr.value + off, chunk_sz); off += chunk_sz; @@ -784,7 +785,7 @@ TEST_CASE_SELF(ble_gatt_write_test_reliable_oom) /* Exhaust the msys pool. Leave one mbuf for the forthcoming response. */ oms = ble_hs_test_util_mbuf_alloc_all_but(1); ble_gatt_write_test_rx_prep_rsp( - 2, attr.handle, off, attr.value + off, chunk_sz); + 2, BLE_L2CAP_CID_ATT, attr.handle, off, attr.value + off, chunk_sz); off += chunk_sz; /* Ensure no follow-up request got sent. It should not have gotten sent @@ -807,7 +808,7 @@ TEST_CASE_SELF(ble_gatt_write_test_reliable_oom) ble_hs_test_util_verify_tx_exec_write(BLE_ATT_EXEC_WRITE_F_EXECUTE); /* Receive Exec Write response. */ - ble_gatt_write_test_rx_exec_rsp(2); + ble_gatt_write_test_rx_exec_rsp(2, BLE_L2CAP_CID_ATT); /* Verify callback got called. */ TEST_ASSERT(ble_gatt_write_test_cb_called); diff --git a/nimble/host/test/src/ble_gatts_notify_test.c b/nimble/host/test/src/ble_gatts_notify_test.c index 6e04ac3626..72fd637512 100644 --- a/nimble/host/test/src/ble_gatts_notify_test.c +++ b/nimble/host/test/src/ble_gatts_notify_test.c @@ -474,9 +474,9 @@ static void ble_gatts_notify_test_misc_verify_tx_gen(uint16_t conn_handle, int attr_idx, uint8_t chr_flags) { - uint16_t attr_handle; - uint16_t attr_len; - void *attr_val; + uint16_t attr_handle = 0; + uint16_t attr_len = 0; + void *attr_val = NULL; switch (attr_idx) { case 1: @@ -586,7 +586,7 @@ TEST_CASE_SELF(ble_gatts_notify_test_n) om = ble_hs_mbuf_from_flat(fourbytes, sizeof fourbytes); TEST_ASSERT_FATAL(om != NULL); - rc = ble_gattc_notify_custom(conn_handle, + rc = ble_gatts_notify_custom(conn_handle, ble_gatts_notify_test_chr_1_def_handle + 1, om); TEST_ASSERT_FATAL(rc == 0); @@ -675,7 +675,7 @@ TEST_CASE_SELF(ble_gatts_notify_test_i) om = ble_hs_mbuf_from_flat(fourbytes, sizeof fourbytes); TEST_ASSERT_FATAL(om != NULL); - rc = ble_gattc_indicate_custom(conn_handle, + rc = ble_gatts_indicate_custom(conn_handle, ble_gatts_notify_test_chr_1_def_handle + 1, om); TEST_ASSERT_FATAL(rc == 0); diff --git a/nimble/host/test/src/ble_gatts_reg_test.c b/nimble/host/test/src/ble_gatts_reg_test.c index ea69028e88..ddbfe8f24f 100644 --- a/nimble/host/test/src/ble_gatts_reg_test.c +++ b/nimble/host/test/src/ble_gatts_reg_test.c @@ -261,7 +261,7 @@ ble_gatts_reg_test_misc_lookup_bad(struct ble_gatts_reg_test_entry *entry) static void ble_gatts_reg_test_misc_verify_entry(uint8_t op, const ble_uuid_t *uuid) { - struct ble_gatts_reg_test_entry *entry; + struct ble_gatts_reg_test_entry *entry = NULL; int i; for (i = 0; i < ble_gatts_reg_test_num_entries; i++) { diff --git a/nimble/host/test/src/ble_hs_hci_test.c b/nimble/host/test/src/ble_hs_hci_test.c index 5f72742c63..8dd7c7777c 100644 --- a/nimble/host/test/src/ble_hs_hci_test.c +++ b/nimble/host/test/src/ble_hs_hci_test.c @@ -21,7 +21,7 @@ #include #include #include "nimble/hci_common.h" -#include "nimble/ble_hci_trans.h" +#include "nimble/transport.h" #include "ble_hs_test.h" #include "testutil/testutil.h" #include "ble_hs_test_util.h" @@ -34,7 +34,7 @@ TEST_CASE_SELF(ble_hs_hci_test_event_bad) int rc; /*** Invalid event code. */ - buf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); + buf = ble_transport_alloc_evt(0); TEST_ASSERT_FATAL(buf != NULL); buf[0] = 0xff; diff --git a/nimble/host/test/src/ble_hs_test_util.c b/nimble/host/test/src/ble_hs_test_util.c index 5ee17e7676..f0b26128b0 100644 --- a/nimble/host/test/src/ble_hs_test_util.c +++ b/nimble/host/test/src/ble_hs_test_util.c @@ -24,11 +24,9 @@ #include "testutil/testutil.h" #include "nimble/ble.h" #include "nimble/hci_common.h" -#include "nimble/ble_hci_trans.h" #include "host/ble_hs_adv.h" #include "host/ble_hs_id.h" #include "store/config/ble_store_config.h" -#include "transport/ram/ble_hci_ram.h" #include "ble_hs_test_util.h" /* Our global device address. */ @@ -106,7 +104,7 @@ ble_hs_test_util_prev_tx_dequeue(void) pb = BLE_HCI_DATA_PB(hci_hdr.hdh_handle_pb_bc); TEST_ASSERT_FATAL(pb == BLE_HCI_PB_FIRST_NON_FLUSH); - rc = ble_l2cap_parse_hdr(om, 0, &l2cap_hdr); + rc = ble_l2cap_parse_hdr(om, &l2cap_hdr); TEST_ASSERT_FATAL(rc == 0); os_mbuf_adj(om, BLE_L2CAP_HDR_SZ); @@ -672,36 +670,13 @@ ble_hs_test_util_l2cap_rx(uint16_t conn_handle, struct hci_data_hdr *hci_hdr, struct os_mbuf *om) { - struct ble_hs_conn *conn; - ble_l2cap_rx_fn *rx_cb; - int reject_cid; + uint8_t pb; int rc; - ble_hs_lock(); - - conn = ble_hs_conn_find(conn_handle); - if (conn != NULL) { - rc = ble_l2cap_rx(conn, hci_hdr, om, &rx_cb, &reject_cid); - } else { - rc = os_mbuf_free_chain(om); - TEST_ASSERT_FATAL(rc == 0); - } - - ble_hs_unlock(); - - if (conn == NULL) { - rc = BLE_HS_ENOTCONN; - } else if (rc == 0) { - TEST_ASSERT_FATAL(rx_cb != NULL); - rc = rx_cb(conn->bhc_rx_chan); - ble_l2cap_remove_rx(conn, conn->bhc_rx_chan); - } else if (rc == BLE_HS_EAGAIN) { - /* More fragments on the way. */ + pb = BLE_HCI_DATA_PB(hci_hdr->hdh_handle_pb_bc); + rc = ble_l2cap_rx(conn_handle, pb, om); + if (rc == BLE_HS_EAGAIN) { rc = 0; - } else { - if (reject_cid != -1) { - ble_l2cap_sig_reject_invalid_cid_tx(conn_handle, 0, 0, reject_cid); - } } return rc; @@ -743,7 +718,7 @@ ble_hs_test_util_set_att_mtu(uint16_t conn_handle, uint16_t mtu) ble_hs_lock(); - rc = ble_att_conn_chan_find(conn_handle, &conn, &chan); + rc = ble_att_conn_chan_find(conn_handle, BLE_L2CAP_CID_ATT, &conn, &chan); assert(rc == 0); chan->my_mtu = mtu; chan->peer_mtu = mtu; @@ -774,6 +749,7 @@ ble_hs_test_util_rx_att_mtu_cmd(uint16_t conn_handle, int is_req, uint16_t mtu) int ble_hs_test_util_rx_att_find_info_req(uint16_t conn_handle, + uint16_t cid, uint16_t start_handle, uint16_t end_handle) { @@ -786,7 +762,7 @@ ble_hs_test_util_rx_att_find_info_req(uint16_t conn_handle, ble_att_find_info_req_write(buf, sizeof buf, &req); - rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, + rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, cid, buf, sizeof buf); return rc; @@ -1072,7 +1048,7 @@ ble_hs_test_util_rx_att_indicate_req(uint16_t conn_handle, } void -ble_hs_test_util_rx_att_err_rsp(uint16_t conn_handle, uint8_t req_op, +ble_hs_test_util_rx_att_err_rsp(uint16_t conn_handle, uint16_t cid, uint8_t req_op, uint8_t error_code, uint16_t err_handle) { struct ble_att_error_rsp rsp; @@ -1085,7 +1061,7 @@ ble_hs_test_util_rx_att_err_rsp(uint16_t conn_handle, uint8_t req_op, ble_att_error_rsp_write(buf, sizeof buf, &rsp); - rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, BLE_L2CAP_CID_ATT, + rc = ble_hs_test_util_l2cap_rx_payload_flat(conn_handle, cid, buf, sizeof buf); TEST_ASSERT(rc == 0); } @@ -1788,7 +1764,6 @@ ble_hs_test_util_mbuf_count(const struct ble_hs_test_util_mbuf_params *params) { const struct ble_att_prep_entry *prep; const struct os_mbuf_pkthdr *omp; - const struct ble_l2cap_chan *chan; const struct ble_hs_conn *conn; const struct os_mbuf *om; int count; @@ -1814,9 +1789,7 @@ ble_hs_test_util_mbuf_count(const struct ble_hs_test_util_mbuf_params *params) } if (params->rx_queue) { - SLIST_FOREACH(chan, &conn->bhc_channels, next) { - count += ble_hs_test_util_mbuf_chain_len(chan->rx_buf); - } + count += ble_hs_test_util_mbuf_chain_len(conn->rx_frags); } if (params->prep_list) { @@ -1850,18 +1823,18 @@ ble_hs_test_util_assert_mbufs_freed( TEST_ASSERT(count == ble_hs_test_util_num_mbufs()); } -static int -ble_hs_test_util_pkt_txed(struct os_mbuf *om, void *arg) +int +ble_transport_to_ll_acl_impl(struct os_mbuf *om) { ble_hs_test_util_prev_tx_enqueue(om); return 0; } -static int -ble_hs_test_util_hci_txed(uint8_t *cmdbuf, void *arg) +int +ble_transport_to_ll_cmd_impl(void *buf) { - ble_hs_test_util_hci_out_enqueue(cmdbuf); - ble_hci_trans_buf_free(cmdbuf); + ble_hs_test_util_hci_out_enqueue(buf); + ble_transport_free(buf); return 0; } @@ -2003,9 +1976,6 @@ ble_hs_test_util_init_no_sysinit_no_start(void) ble_hs_hci_set_phony_ack_cb(NULL); - ble_hci_trans_cfg_ll(ble_hs_test_util_hci_txed, NULL, - ble_hs_test_util_pkt_txed, NULL); - ble_hs_test_util_hci_ack_set_startup(); ble_hs_enabled_state = BLE_HS_ENABLED_STATE_OFF; @@ -2046,3 +2016,9 @@ ble_hs_test_util_init(void) /* Clear random address. */ ble_hs_id_rnd_reset(); } + +void +ble_transport_ll_init(void) +{ + /* nothing here */ +} diff --git a/nimble/host/test/src/ble_hs_test_util.h b/nimble/host/test/src/ble_hs_test_util.h index 411443cfdd..6d5d04c05d 100644 --- a/nimble/host/test/src/ble_hs_test_util.h +++ b/nimble/host/test/src/ble_hs_test_util.h @@ -162,6 +162,8 @@ int ble_hs_test_util_l2cap_rx_payload_flat(uint16_t conn_handle, uint16_t cid, const void *data, int len); uint8_t ble_hs_test_util_verify_tx_l2cap_sig(uint16_t opcode, void *cmd, uint16_t cmd_size); +uint8_t ble_hs_test_util_verify_tx_l2cap_discon_rej(uint16_t opcode, void *cmd, + uint16_t cmd_size); int ble_hs_test_util_inject_rx_l2cap_sig(uint16_t conn_handle, uint8_t opcode, uint8_t id, void *cmd, uint16_t cmd_size); void ble_hs_test_util_verify_tx_l2cap(struct os_mbuf *txom); @@ -171,6 +173,7 @@ void ble_hs_test_util_set_att_mtu(uint16_t conn_handle, uint16_t mtu); int ble_hs_test_util_rx_att_mtu_cmd(uint16_t conn_handle, int is_req, uint16_t mtu); int ble_hs_test_util_rx_att_find_info_req(uint16_t conn_handle, + uint16_t cid, uint16_t start_handle, uint16_t end_handle); int ble_hs_test_util_rx_att_find_type_value_req(uint16_t conn_handle, @@ -226,8 +229,9 @@ int ble_hs_test_util_rx_att_indicate_req(uint16_t conn_handle, uint16_t attr_handle, void *attr_val, uint16_t attr_len); -void ble_hs_test_util_rx_att_err_rsp(uint16_t conn_handle, uint8_t req_op, - uint8_t error_code, uint16_t err_handle); +void ble_hs_test_util_rx_att_err_rsp(uint16_t conn_handle, uint16_t cid, + uint8_t req_op, uint8_t error_code, + uint16_t err_handle); void ble_hs_test_util_verify_tx_prep_write(uint16_t attr_handle, uint16_t offset, const void *data, int data_len); diff --git a/nimble/host/test/src/ble_hs_test_util_hci.c b/nimble/host/test/src/ble_hs_test_util_hci.c index a53c5d9fc5..c27af143aa 100644 --- a/nimble/host/test/src/ble_hs_test_util_hci.c +++ b/nimble/host/test/src/ble_hs_test_util_hci.c @@ -20,7 +20,6 @@ #include "testutil/testutil.h" #include "nimble/ble.h" #include "nimble/hci_common.h" -#include "transport/ram/ble_hci_ram.h" #include "ble_hs_test_util.h" #define BLE_HCI_EVENT_CMD_COMPLETE_HDR_LEN (5) @@ -251,6 +250,19 @@ static const struct ble_hs_test_util_hci_ack hci_startup_seq[] = { .evt_params = { 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, .evt_params_len = 8, }, + { + .opcode = ble_hs_hci_util_opcode_join( + BLE_HCI_OGF_INFO_PARAMS, BLE_HCI_OCF_IP_RD_LOC_SUPP_CMD), + .evt_params = { 0x20, 0x00, 0x80, 0x00, 0x00, 0xc0, 0x00, 0x00, + 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x28, 0x22, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, + 0x00, 0xf7, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0xf9, 0xff, 0xff, 0xff, 0xff, 0x07, + 0xe0, 0x63, 0xe0, 0x04, 0x02, 0x00, 0x03, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + .evt_params_len = 64 + }, { .opcode = ble_hs_hci_util_opcode_join( BLE_HCI_OGF_INFO_PARAMS, BLE_HCI_OCF_IP_RD_LOC_SUPP_FEAT), @@ -522,14 +534,13 @@ ble_hs_test_util_hci_rx_evt(uint8_t *evt) totlen = BLE_HCI_EVENT_HDR_LEN + evt[1]; TEST_ASSERT_FATAL(totlen <= UINT8_MAX + BLE_HCI_EVENT_HDR_LEN); - evbuf = ble_hci_trans_buf_alloc( - BLE_HCI_TRANS_BUF_EVT_LO); + evbuf = ble_transport_alloc_evt(1); TEST_ASSERT_FATAL(evbuf != NULL); memcpy(evbuf, evt, totlen); if (os_started()) { - rc = ble_hci_trans_ll_evt_tx(evbuf); + rc = ble_transport_to_hs_evt(evbuf); } else { rc = ble_hs_hci_evt_process((void *)evbuf); } diff --git a/nimble/host/test/src/ble_l2cap_test.c b/nimble/host/test/src/ble_l2cap_test.c index 2b17da06a7..6fd294b82b 100644 --- a/nimble/host/test/src/ble_l2cap_test.c +++ b/nimble/host/test/src/ble_l2cap_test.c @@ -124,7 +124,7 @@ ble_l2cap_test_util_verify_tx_update_conn( } static int -ble_l2cap_test_util_dummy_rx(struct ble_l2cap_chan *chan) +ble_l2cap_test_util_dummy_rx(struct ble_l2cap_chan *chan, struct os_mbuf **om) { return 0; } @@ -220,8 +220,7 @@ ble_l2cap_test_util_verify_first_frag(uint16_t conn_handle, conn = ble_hs_conn_find(conn_handle); TEST_ASSERT_FATAL(conn != NULL); - TEST_ASSERT(conn->bhc_rx_chan != NULL && - conn->bhc_rx_chan->scid == BLE_L2CAP_TEST_CID); + TEST_ASSERT(conn->rx_len && conn->rx_cid == BLE_L2CAP_TEST_CID); ble_hs_unlock(); } @@ -240,8 +239,7 @@ ble_l2cap_test_util_verify_middle_frag(uint16_t conn_handle, conn = ble_hs_conn_find(conn_handle); TEST_ASSERT_FATAL(conn != NULL); - TEST_ASSERT(conn->bhc_rx_chan != NULL && - conn->bhc_rx_chan->scid == BLE_L2CAP_TEST_CID); + TEST_ASSERT(conn->rx_len && conn->rx_cid == BLE_L2CAP_TEST_CID); ble_hs_unlock(); } @@ -260,7 +258,7 @@ ble_l2cap_test_util_verify_last_frag(uint16_t conn_handle, conn = ble_hs_conn_find(conn_handle); TEST_ASSERT_FATAL(conn != NULL); - TEST_ASSERT(conn->bhc_rx_chan == NULL); + TEST_ASSERT(conn->rx_len == 0); ble_hs_unlock(); } @@ -279,7 +277,7 @@ TEST_CASE_SELF(ble_l2cap_test_case_bad_header) NULL, NULL); rc = ble_l2cap_test_util_rx_first_frag(2, 14, 1234, 10); - TEST_ASSERT(rc == BLE_HS_ENOENT); + TEST_ASSERT(rc == BLE_HS_EBADDATA); ble_hs_test_util_assert_mbufs_freed(NULL); } @@ -386,8 +384,7 @@ TEST_CASE_SELF(ble_l2cap_test_case_frag_channels) ble_hs_lock(); conn = ble_hs_conn_find(2); TEST_ASSERT_FATAL(conn != NULL); - TEST_ASSERT(conn->bhc_rx_chan != NULL && - conn->bhc_rx_chan->scid == BLE_L2CAP_TEST_CID); + TEST_ASSERT(conn->rx_len && conn->rx_cid == BLE_L2CAP_TEST_CID); ble_hs_unlock(); /* Receive a starting fragment on a different channel. The first fragment @@ -400,8 +397,7 @@ TEST_CASE_SELF(ble_l2cap_test_case_frag_channels) ble_hs_lock(); conn = ble_hs_conn_find(2); TEST_ASSERT_FATAL(conn != NULL); - TEST_ASSERT(conn->bhc_rx_chan != NULL && - conn->bhc_rx_chan->scid == BLE_L2CAP_CID_ATT); + TEST_ASSERT(conn->rx_len && conn->rx_cid == BLE_L2CAP_CID_ATT); ble_hs_unlock(); /* Terminate the connection. The received fragments should get freed. @@ -415,8 +411,12 @@ TEST_CASE_SELF(ble_l2cap_test_case_frag_channels) TEST_CASE_SELF(ble_l2cap_test_case_frag_timeout) { int32_t ticks_from_now; + uint32_t timeout_ticks; int rc; + timeout_ticks = + ble_npl_time_ms_to_ticks32(MYNEWT_VAL(BLE_L2CAP_RX_FRAG_TIMEOUT)); + ble_l2cap_test_util_init(); ble_l2cap_test_util_create_conn(2, ((uint8_t[]){1,2,3,4,5,6}), @@ -432,10 +432,10 @@ TEST_CASE_SELF(ble_l2cap_test_case_frag_timeout) /* Ensure timer will expire in 30 seconds. */ ticks_from_now = ble_hs_conn_timer(); - TEST_ASSERT(ticks_from_now == MYNEWT_VAL(BLE_L2CAP_RX_FRAG_TIMEOUT)); + TEST_ASSERT(ticks_from_now == timeout_ticks); /* Almost let the timer expire. */ - os_time_advance(MYNEWT_VAL(BLE_L2CAP_RX_FRAG_TIMEOUT) - 1); + os_time_advance(timeout_ticks - 1); ticks_from_now = ble_hs_conn_timer(); TEST_ASSERT(ticks_from_now == 1); @@ -445,11 +445,11 @@ TEST_CASE_SELF(ble_l2cap_test_case_frag_timeout) /* Ensure timer got reset. */ ticks_from_now = ble_hs_conn_timer(); - TEST_ASSERT(ticks_from_now == MYNEWT_VAL(BLE_L2CAP_RX_FRAG_TIMEOUT)); + TEST_ASSERT(ticks_from_now == timeout_ticks); /* Allow the timer to expire. */ ble_hs_test_util_hci_ack_set_disconnect(0); - os_time_advance(MYNEWT_VAL(BLE_L2CAP_RX_FRAG_TIMEOUT)); + os_time_advance(timeout_ticks); ticks_from_now = ble_hs_conn_timer(); TEST_ASSERT(ticks_from_now == BLE_HS_FOREVER); @@ -999,6 +999,46 @@ ble_l2cap_test_coc_disc_by_peer(struct test_data *t) &req, sizeof(req)) == id); } +static void +ble_l2cap_test_coc_disc_by_peer_invalid_dcid(struct test_data *t) +{ + struct ble_l2cap_sig_disc_req req; + struct event *ev = &t->event[t->event_iter++]; + uint8_t id = 10; + int rc; + struct os_mbuf *cmd; + uint16_t rej_err = htole16(BLE_L2CAP_SIG_ERR_INVALID_CID); + req.dcid = htole16(t->chan[0]->dcid + 1); + req.scid = htole16(t->chan[0]->dcid); + + rc = ble_hs_test_util_inject_rx_l2cap_sig(2, BLE_L2CAP_SIG_OP_DISCONN_REQ, + id, &req, sizeof(req)); + TEST_ASSERT(rc == 0); + + /* Ensure callback got NOT called. */ + TEST_ASSERT(!ev->handled); + + struct { + uint16_t local_cid; + uint16_t remote_cid; + } data = { + .local_cid = req.scid, + .remote_cid = req.dcid, + }; + + /* Ensure an we sent back Command Reject response + * Recect command should contain reason and CIDs pair + */ + cmd = os_mbuf_get(&sdu_os_mbuf_pool, 0); + os_mbuf_append(cmd, &rej_err, sizeof(uint16_t)); + os_mbuf_append(cmd, &data, sizeof(data)); + + ble_hs_test_util_verify_tx_l2cap_sig( + BLE_L2CAP_SIG_OP_REJECT, + cmd->om_data, cmd->om_len); + os_mbuf_free_chain(cmd); +} + static void ble_l2cap_test_coc_invalid_disc_by_peer(struct test_data *t) { @@ -1361,6 +1401,29 @@ TEST_CASE_SELF(ble_l2cap_test_case_sig_coc_incoming_disconnect_failed) ble_hs_test_util_assert_mbufs_freed(NULL); } +TEST_CASE_SELF(ble_l2cap_test_case_invalid_cid_in_disconnect_req) +{ + struct test_data t; + + ble_l2cap_test_util_init(); + + ble_l2cap_test_set_chan_test_conf(BLE_L2CAP_TEST_PSM, + BLE_L2CAP_TEST_COC_MTU, &t); + t.expected_num_of_ev = 1; + + t.event[0].type = BLE_L2CAP_EVENT_COC_CONNECTED; + t.event[0].app_status = 0; + t.event[0].l2cap_status = BLE_L2CAP_COC_ERR_CONNECTION_SUCCESS; + t.event[1].type = BLE_L2CAP_EVENT_COC_DISCONNECTED; + + ble_l2cap_test_coc_connect(&t); + ble_l2cap_test_coc_disc_by_peer_invalid_dcid(&t); + + TEST_ASSERT(t.expected_num_of_ev == t.event_cnt); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + TEST_CASE_SELF(ble_l2cap_test_case_coc_send_data_succeed) { struct test_data t; @@ -1493,6 +1556,7 @@ TEST_SUITE(ble_l2cap_test_suite) ble_l2cap_test_case_sig_coc_disconnect_succeed(); ble_l2cap_test_case_sig_coc_incoming_disconnect_succeed(); ble_l2cap_test_case_sig_coc_incoming_disconnect_failed(); + ble_l2cap_test_case_invalid_cid_in_disconnect_req(); ble_l2cap_test_case_coc_send_data_succeed(); ble_l2cap_test_case_coc_send_data_failed_too_big_sdu(); ble_l2cap_test_case_coc_recv_data_succeed(); diff --git a/nimble/host/test/src/ble_os_test.c b/nimble/host/test/src/ble_os_test.c index fa57571b44..6588c67986 100644 --- a/nimble/host/test/src/ble_os_test.c +++ b/nimble/host/test/src/ble_os_test.c @@ -21,7 +21,6 @@ #include "os/os.h" #include "testutil/testutil.h" #include "nimble/hci_common.h" -#include "nimble/ble_hci_trans.h" #include "ble_hs_test.h" #include "host/ble_gap.h" #include "ble_hs_test_util.h" diff --git a/nimble/host/test/src/ble_sm_test.c b/nimble/host/test/src/ble_sm_test.c index be4285fdce..dcdbaf01ed 100644 --- a/nimble/host/test/src/ble_sm_test.c +++ b/nimble/host/test/src/ble_sm_test.c @@ -142,6 +142,99 @@ TEST_CASE_SELF(ble_sm_test_case_g2) ble_hs_test_util_assert_mbufs_freed(NULL); } +TEST_CASE_SELF(ble_sm_test_case_csis_sih) +{ + uint8_t sirk[16] = { 0xcd, 0xcc, 0x72, 0xdd, 0x86, 0x8c, 0xcd, 0xce, + 0x22, 0xfd, 0xa1, 0x21, 0x09, 0x7d, 0x7d, 0x45 }; + uint8_t prand[3] = { 0x63, 0xf5, 0x69 }; + const uint8_t ah_expected[3] = { 0xda, 0x48, 0x19 }; + uint8_t ah_out[3]; + int err; + + err = ble_sm_alg_csis_sih(sirk, prand, ah_out); + TEST_ASSERT_FATAL(err == 0); + TEST_ASSERT(memcmp(ah_out, ah_expected, 3) == 0); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_sm_test_case_csis_sef) +{ + uint8_t sirk[16] = { 0xcd, 0xcc, 0x72, 0xdd, 0x86, 0x8c, 0xcd, 0xce, + 0x22, 0xfd, 0xa1, 0x21, 0x09, 0x7d, 0x7d, 0x45 }; + uint8_t k[16] = { 0xd9, 0xce, 0xe5, 0x3c, 0x22, 0xc6, 0x1e, 0x06, + 0x6f, 0x69, 0x48, 0xd4, 0x9b, 0x1b, 0x6e, 0x67 }; + const uint8_t sef_expected[16] = { 0x46, 0xd3, 0x5f, 0xf2, 0xd5, 0x62, 0x25, 0x7e, + 0xa0, 0x24, 0x35, 0xe1, 0x35, 0x38, 0x0a, 0x17 }; + uint8_t sef_out[16]; + int err; + + err = ble_sm_alg_csis_sef(k, sirk, sef_out); + TEST_ASSERT_FATAL(err == 0); + TEST_ASSERT(memcmp(sef_out, sef_expected, 16) == 0); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_sm_test_case_csis_s1_sirkenc) +{ + const uint8_t s1_expected[16] = { 0x72, 0x45, 0x77, 0x7d, 0x3a, 0x13, 0x7d, 0x3c, + 0x82, 0x9e, 0x14, 0x18, 0x3f, 0x98, 0x01, 0x69 }; + uint8_t s1_out[16]; + int err; + + err = ble_sm_alg_csis_s1((const uint8_t *) "SIRKenc", 7, s1_out); + + TEST_ASSERT_FATAL(err == 0); + TEST_ASSERT(memcmp(s1_out, s1_expected, 16) == 0); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_sm_test_case_csis_k1_csis) +{ + uint8_t k[16] = { 0xd9, 0xce, 0xe5, 0x3c, 0x22, 0xc6, 0x1e, 0x06, + 0x6f, 0x69, 0x48, 0xd4, 0x9b, 0x1b, 0x6e, 0x67 }; + uint8_t k1_expected[16] = { 0x8b, 0x1f, 0x2d, 0x2f, 0x53, 0xee, 0xe8, 0xb0, + 0x82, 0xd9, 0x94, 0xc0, 0x3c, 0x45, 0x77, 0x52 }; + uint8_t k1_out[16]; + uint8_t s1_out[16]; + int err; + + err = ble_sm_alg_csis_s1((const uint8_t *) "SIRKenc", 7, s1_out); + TEST_ASSERT_FATAL(err == 0); + + err = ble_sm_alg_csis_k1(k, 16, s1_out, (const uint8_t *) "csis", 4, k1_out); + + TEST_ASSERT_FATAL(err == 0); + TEST_ASSERT(memcmp(k1_out, k1_expected, 16) == 0); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_sm_test_case_csis_enc_dec_sirk) +{ + uint8_t plaintext_sirk[16] = { 0xcd, 0xcc, 0x72, 0xdd, 0x86, 0x8c, 0xcd, 0xce, + 0x22, 0xfd, 0xa1, 0x21, 0x09, 0x7d, 0x7d, 0x45 }; + uint8_t k[16] = { 0xd9, 0xce, 0xe5, 0x3c, 0x22, 0xc6, 0x1e, 0x06, + 0x6f, 0x69, 0x48, 0xd4, 0x9b, 0x1b, 0x6e, 0x67 }; + uint8_t enc_sirk[16] = {0}; + uint8_t dec_sirk[16] = {0}; + uint8_t rsi[6] = {0x0, 0x0, 0x0, 0xab, 0x34, 0xef}; + int err; + + /* Generate only hash part of rsi, as random part is already hard-coded */ + err = ble_sm_alg_csis_sih(plaintext_sirk, rsi + 3, rsi); + TEST_ASSERT_FATAL(err == 0); + + ble_sm_csis_encrypt_sirk(k, plaintext_sirk, enc_sirk); + TEST_ASSERT_FATAL(err == 0); + + ble_sm_csis_decrypt_sirk(k, enc_sirk, dec_sirk); + TEST_ASSERT_FATAL(err == 0); + TEST_ASSERT(memcmp(dec_sirk, plaintext_sirk, 16) == 0); +} + TEST_CASE_SELF(ble_sm_test_case_conn_broken) { struct ble_hci_ev_disconn_cmp disconn_evt; @@ -322,18 +415,49 @@ TEST_CASE_SELF(ble_sm_test_case_peer_sec_req_inval) fail.reason = BLE_SM_ERR_CMD_NOT_SUPP; ble_sm_test_util_verify_tx_pair_fail(&fail); - /*** Pairing already in progress; ignore security request. */ + /*** Pairing already in progress; ignore security request before pairing + * response was received. */ ble_hs_atomic_conn_set_flags(2, BLE_HS_CONN_F_MASTER, 1); rc = ble_sm_pair_initiate(2); TEST_ASSERT_FATAL(rc == 0); ble_hs_test_util_prev_tx_queue_clear(); - ble_sm_test_util_rx_sec_req(2, &sec_req, BLE_HS_EALREADY); + ble_sm_test_util_rx_sec_req(2, &sec_req, 0); TEST_ASSERT(ble_hs_test_util_prev_tx_queue_sz() == 0); ble_hs_test_util_assert_mbufs_freed(NULL); } +TEST_CASE_SELF(ble_sm_test_case_peer_sec_req_reject) +{ + struct ble_sm_sec_req sec_req; + int rc; + + struct ble_sm_pair_cmd pair_rsp = {0x04, 0, 0x0D, 10, 0x02, 0x02}; + + ble_sm_test_util_init(); + + ble_sm_dbg_set_next_pair_rand(((uint8_t[16]) {0})); + + ble_hs_test_util_create_conn(2, ((uint8_t[6]) {1,2,3,5,6,7}), + ble_sm_test_util_conn_cb, + NULL); + + /*** Pairing already in progress; reject security request after pairing + * response was received. */ + + ble_hs_atomic_conn_set_flags(2, BLE_HS_CONN_F_MASTER, 1); + rc = ble_sm_pair_initiate(2); + TEST_ASSERT_FATAL(rc == 0); + ble_hs_test_util_prev_tx_queue_clear(); + + ble_sm_test_util_rx_pair_rsp(2, &pair_rsp, 0); + ble_sm_test_util_rx_sec_req(2, &sec_req, BLE_HS_EALREADY); + TEST_ASSERT(ble_hs_test_util_prev_tx_queue_sz() != 0); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + /***************************************************************************** * $us * *****************************************************************************/ @@ -403,6 +527,11 @@ TEST_SUITE(ble_sm_gen_test_suite) ble_sm_test_case_f5(); ble_sm_test_case_f6(); ble_sm_test_case_g2(); + ble_sm_test_case_csis_sih(); + ble_sm_test_case_csis_sef(); + ble_sm_test_case_csis_s1_sirkenc(); + ble_sm_test_case_csis_k1_csis(); + ble_sm_test_case_csis_enc_dec_sirk(); ble_sm_test_case_peer_fail_inval(); ble_sm_test_case_peer_lgcy_fail_confirm(); @@ -410,5 +539,6 @@ TEST_SUITE(ble_sm_gen_test_suite) ble_sm_test_case_peer_bonding_bad(); ble_sm_test_case_conn_broken(); ble_sm_test_case_peer_sec_req_inval(); + ble_sm_test_case_peer_sec_req_reject(); } #endif diff --git a/nimble/host/test/src/ble_sm_test_util.c b/nimble/host/test/src/ble_sm_test_util.c index bad473f178..74d40e8b53 100644 --- a/nimble/host/test/src/ble_sm_test_util.c +++ b/nimble/host/test/src/ble_sm_test_util.c @@ -717,7 +717,7 @@ ble_sm_test_util_rx_pair_req(uint16_t conn_handle, req, rx_status); } -static void +void ble_sm_test_util_rx_pair_rsp(uint16_t conn_handle, struct ble_sm_pair_cmd *rsp, int rx_status) { @@ -1671,9 +1671,6 @@ ble_sm_test_util_peer_bonding_good(int send_enc_req, TEST_ASSERT(ble_sm_test_store_obj_type == BLE_STORE_OBJ_TYPE_OUR_SEC); TEST_ASSERT(ble_sm_test_store_key.sec.peer_addr.type == ble_hs_misc_peer_addr_type_to_id(peer_addr_type)); - TEST_ASSERT(ble_sm_test_store_key.sec.ediv_rand_present); - TEST_ASSERT(ble_sm_test_store_key.sec.ediv == ediv); - TEST_ASSERT(ble_sm_test_store_key.sec.rand_num == rand_num); TEST_ASSERT(!conn->bhc_sec_state.encrypted); TEST_ASSERT(ble_sm_num_procs() == 1); @@ -1738,9 +1735,6 @@ ble_sm_test_util_peer_bonding_bad(uint16_t ediv, uint64_t rand_num) /* Ensure the LTK request event got sent to the application. */ TEST_ASSERT(ble_sm_test_store_obj_type == BLE_STORE_OBJ_TYPE_OUR_SEC); - TEST_ASSERT(ble_sm_test_store_key.sec.ediv_rand_present); - TEST_ASSERT(ble_sm_test_store_key.sec.ediv == ediv); - TEST_ASSERT(ble_sm_test_store_key.sec.rand_num == rand_num); TEST_ASSERT(!conn->bhc_sec_state.encrypted); diff --git a/nimble/host/test/src/ble_sm_test_util.h b/nimble/host/test/src/ble_sm_test_util.h index d9aa3805c7..3ddc86c1f1 100644 --- a/nimble/host/test/src/ble_sm_test_util.h +++ b/nimble/host/test/src/ble_sm_test_util.h @@ -96,6 +96,9 @@ void ble_sm_test_util_io_check_post( void ble_sm_test_util_rx_sec_req(uint16_t conn_handle, struct ble_sm_sec_req *cmd, int exp_status); +void ble_sm_test_util_rx_pair_rsp(uint16_t conn_handle, + struct ble_sm_pair_cmd *rsp, + int rx_status); void ble_sm_test_util_verify_tx_pair_fail(struct ble_sm_pair_fail *exp_cmd); void ble_sm_test_util_us_lgcy_good(struct ble_sm_test_params *params); void ble_sm_test_util_peer_fail_inval(int we_are_master, diff --git a/nimble/host/test/src/ble_uuid_test.c b/nimble/host/test/src/ble_uuid_test.c index 786e371ac4..379fd1f441 100644 --- a/nimble/host/test/src/ble_uuid_test.c +++ b/nimble/host/test/src/ble_uuid_test.c @@ -24,8 +24,75 @@ #include "host/ble_uuid.h" #include "ble_hs_test_util.h" -TEST_CASE_SELF(ble_uuid_test) -{ +#define DEBUG 0 + +#if DEBUG +#define DEBUG_PRINT(fmt, ...) printf(fmt, ## __VA_ARGS__) +#else +#define DEBUG_PRINT(fmt, ...) +#endif + +#define TEST_UUID_128_1_STR "0329a25a-c4c4-4923-8039-4bacfa18eb72" +#define TEST_UUID_128_1 \ + 0x72, 0xeb, 0x18, 0xfa, 0xac, 0x4b, 0x39, 0x80, \ + 0x23, 0x49, 0xc4, 0xc4, 0x5a, 0xa2, 0x29, 0x03 + +#define TEST_UUID_128_2_STR "e3ec4966df944981a772985ff8d75dff" +#define TEST_UUID_128_2 \ + 0xff, 0x5d, 0xd7, 0xf8, 0x5f, 0x98, 0x72, 0xa7, \ + 0x81, 0x49, 0x94, 0xdf, 0x66, 0x49, 0xec, 0xe3 + +#define TEST_UUID_128_3_STR "00002a37-0000-1000-8000-00805f9b34fb" +#define TEST_UUID_128_3 \ + 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, \ + 0x00, 0x10, 0x00, 0x00, 0x37, 0x2a, 0x00, 0x00 +#define TEST_UUID_128_3_AS_16 ((uint16_t) 0x2a37) + +#define TEST_32UUID1_STR "0x0329a25a" +#define TEST_32UUID1 ((uint32_t)0x0329a25a) + +#define TEST_32UUID2_STR "e3ec4966" +#define TEST_32UUID2 ((uint32_t)0xe3ec4966) + +#define TEST_16UUID1_STR "0x0329" +#define TEST_16UUID1 ((uint16_t)0x0329) + +#define TEST_16UUID2_STR "e3ec" +#define TEST_16UUID2 ((uint16_t)0xe3ec) + +static const ble_uuid128_t test_uuid128[4] = { + BLE_UUID128_INIT(TEST_UUID_128_1), + BLE_UUID128_INIT(TEST_UUID_128_2), + BLE_UUID128_INIT(TEST_UUID_128_3) +}; + +static const char test_str128[][100] = { + TEST_UUID_128_1_STR, + TEST_UUID_128_2_STR, + TEST_UUID_128_3_STR +}; + +static const ble_uuid32_t test_uuid32[3] = { + BLE_UUID32_INIT(TEST_32UUID1), + BLE_UUID32_INIT(TEST_32UUID2), +}; + +static const char test_str32[][100] = { + TEST_32UUID1_STR, + TEST_32UUID2_STR, +}; + +static const ble_uuid16_t test_uuid16[3] = { + BLE_UUID16_INIT(TEST_16UUID1), + BLE_UUID16_INIT(TEST_16UUID2), +}; + +static const char test_str16[][100] = { + TEST_16UUID1_STR, + TEST_16UUID2_STR, +}; + +TEST_CASE_SELF(ble_uuid_test) { uint8_t buf_16[2] = { 0x00, 0x18 }; uint8_t buf_128[16] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF }; @@ -70,7 +137,161 @@ TEST_CASE_SELF(ble_uuid_test) ble_hs_test_util_assert_mbufs_freed(NULL); } -TEST_SUITE(ble_uuid_test_suite) -{ +TEST_CASE_SELF(ble_uuid_from_string_test) { + int rc; + ble_uuid_any_t uuid128[3]; + ble_uuid_any_t uuid32[3]; + ble_uuid_any_t uuid16[3]; + + for (int i = 0; i < 2; i++) { + DEBUG_PRINT("Test 128bit: %d\n", i); + ble_uuid_from_str((ble_uuid_any_t * ) &uuid128[i], test_str128[i]); + DEBUG_PRINT("Original:\n"); + for (int j = 0; j < 16; j++) { + DEBUG_PRINT("%2x, ", test_uuid128[i].value[j]); + } + DEBUG_PRINT("\nConverted:\n"); + for (int j = 0; j < 16; j++) { + DEBUG_PRINT("%2x, ", uuid128[i].u128.value[j]); + } + DEBUG_PRINT("\n"); + DEBUG_PRINT("The same: %s\n", + ble_uuid_cmp((const ble_uuid_t *) &uuid128[i].u128, + (const ble_uuid_t *) &test_uuid128[i]) == 0 + ? "true" : "false"); + rc = ble_uuid_cmp((const ble_uuid_t *) &uuid128[i].u128, + (const ble_uuid_t *) &test_uuid128[i]); + TEST_ASSERT(rc == 0); + } + + DEBUG_PRINT("\n"); + DEBUG_PRINT("\n"); + + for (int i = 0; i < 2; i++) { + DEBUG_PRINT("Test 32bit: %d\n", i); + ble_uuid_from_str((ble_uuid_any_t * ) &uuid32[i], test_str32[i]); + DEBUG_PRINT("Original:\n"); + DEBUG_PRINT("%x, ", test_uuid32[i].value); + DEBUG_PRINT("\nConverted:\n"); + DEBUG_PRINT("%x, ", uuid32[i].u32.value); + DEBUG_PRINT("\n"); + DEBUG_PRINT("The same: %s\n", + ble_uuid_cmp((const ble_uuid_t *) &uuid32[i].u32, + (const ble_uuid_t *) &test_uuid32[i]) == 0 + ? "true" : "false"); + rc = ble_uuid_cmp((const ble_uuid_t *) &uuid32[i].u32, + (const ble_uuid_t *) &test_uuid32[i]); + TEST_ASSERT(rc == 0); + } + + DEBUG_PRINT("\n"); + DEBUG_PRINT("\n"); + + for (int i = 0; i < 2; i++) { + DEBUG_PRINT("Test 16bit: %d\n", i); + ble_uuid_from_str((ble_uuid_any_t * ) &uuid16[i], test_str16[i]); + DEBUG_PRINT("Original:\n"); + DEBUG_PRINT("%x, ", test_uuid16[i].value); + DEBUG_PRINT("\nConverted:\n"); + DEBUG_PRINT("%x, ", uuid16[i].u16.value); + DEBUG_PRINT("\n"); + DEBUG_PRINT("The same: %s\n", + ble_uuid_cmp((const ble_uuid_t *) &uuid16[i].u16, + (const ble_uuid_t *) &test_uuid16[i]) == 0 + ? "true" : "false"); + rc = ble_uuid_cmp((const ble_uuid_t *) &uuid16[i].u16, + (const ble_uuid_t *) &test_uuid16[i]); + TEST_ASSERT(rc == 0); + } + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_uuid_from_string_sig_test) { + int rc; + ble_uuid_any_t uuid; + + ble_uuid16_t test_uuid = BLE_UUID16_INIT(TEST_UUID_128_3_AS_16); + + DEBUG_PRINT("Test %d\n", 0); + ble_uuid_from_str(&uuid, test_str128[2]); + DEBUG_PRINT("Original:\n"); + for (int j = 0; j < 16; j++) { + DEBUG_PRINT("%2x, ", test_uuid128[2].value[j]); + } + DEBUG_PRINT("\nConverted:\n"); + DEBUG_PRINT("%x\n", uuid.u16.value); + DEBUG_PRINT("The same: %s\n", + ble_uuid_cmp((const ble_uuid_t *) &uuid.u16, + (const ble_uuid_t *) &test_uuid) == 0 ? "true" + : "false"); + rc = ble_uuid_cmp((const ble_uuid_t *)&uuid.u16, + (const ble_uuid_t *)&test_uuid); + TEST_ASSERT(rc == 0); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_uuid_to_str_and_back_test) { + int rc; + ble_uuid128_t uuid = BLE_UUID128_INIT(TEST_UUID_128_1); + ble_uuid_any_t final_uuid; + char uuid_str[100]; + + ble_uuid_to_str((const ble_uuid_t *)&uuid, uuid_str); + + DEBUG_PRINT("String: %s\n", uuid_str); + + rc = ble_uuid_from_str(&final_uuid, (const char *)uuid_str); + TEST_ASSERT(rc == 0); + + rc = ble_uuid_cmp((const ble_uuid_t *)&uuid, (const ble_uuid_t *)&final_uuid.u128); + TEST_ASSERT(rc == 0); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_uuid_to_str_too_short) { + int rc; + ble_uuid_any_t final_uuid; + char uuid_str[4] = "012"; + + DEBUG_PRINT("String: %s\n", uuid_str); + + rc = ble_uuid_from_str(&final_uuid, (const char *)uuid_str); + TEST_ASSERT(rc == BLE_HS_EINVAL); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_CASE_SELF(ble_uuid_to_str_sig_to_16_and_32) { + int rc; + ble_uuid_any_t final_uuid; + char uuid_str16[37] = "0000ffff-0000-1000-8000-00805f9b34fb"; + char uuid_str32[37] = "ffffffff-0000-1000-8000-00805f9b34fb"; + + DEBUG_PRINT("String16: %s\n", uuid_str16); + DEBUG_PRINT("String32: %s\n", uuid_str32); + + rc = ble_uuid_from_str(&final_uuid, (const char *)uuid_str16); + TEST_ASSERT(rc == 0); + TEST_ASSERT(final_uuid.u.type == BLE_UUID_TYPE_16); + TEST_ASSERT(final_uuid.u16.value == UINT16_MAX); + memset(&final_uuid, 0, sizeof(ble_uuid_any_t)); + + rc = ble_uuid_from_str(&final_uuid, (const char *)uuid_str32); + TEST_ASSERT(rc == 0); + TEST_ASSERT(final_uuid.u.type == BLE_UUID_TYPE_32); + TEST_ASSERT(final_uuid.u32.value == UINT32_MAX); + + ble_hs_test_util_assert_mbufs_freed(NULL); +} + +TEST_SUITE(ble_uuid_test_suite) { ble_uuid_test(); + ble_uuid_from_string_test(); + ble_uuid_from_string_sig_test(); + ble_uuid_to_str_and_back_test(); + ble_uuid_to_str_too_short(); + ble_uuid_to_str_sig_to_16_and_32(); } diff --git a/nimble/host/test/syscfg.yml b/nimble/host/test/syscfg.yml index 6307398e4c..dfafb8e76b 100644 --- a/nimble/host/test/syscfg.yml +++ b/nimble/host/test/syscfg.yml @@ -24,8 +24,11 @@ syscfg.vals: BLE_GATT_MAX_PROCS: 16 BLE_SM: 1 BLE_SM_SC: 1 + BLE_SM_CSIS_SIRK: 1 MSYS_1_BLOCK_COUNT: 100 BLE_L2CAP_COC_MAX_NUM: 2 CONFIG_FCB: 1 BLE_VERSION: 52 BLE_L2CAP_ENHANCED_COC: 1 + BLE_TRANSPORT_LL: custom + BLE_EATT_CHAN_NUM: 0 diff --git a/nimble/host/util/src/addr.c b/nimble/host/util/src/addr.c index b3112f1284..830ff02580 100644 --- a/nimble/host/util/src/addr.c +++ b/nimble/host/util/src/addr.c @@ -55,8 +55,13 @@ ble_hs_util_ensure_rand_addr(void) /* Otherwise, try to load a random address. */ rc = ble_hs_util_load_rand_addr(&addr); + if (rc != 0) { - return rc; + /* If it didn't work, generate random address */ + rc = ble_hs_id_gen_rnd(0, &addr); + if (rc != 0) { + return rc; + } } /* Configure nimble to use the random address. */ diff --git a/nimble/include/nimble/ble.h b/nimble/include/nimble/ble.h index 1ddd5773d0..0370f966cd 100644 --- a/nimble/include/nimble/ble.h +++ b/nimble/include/nimble/ble.h @@ -20,6 +20,11 @@ #ifndef H_BLE_ #define H_BLE_ +/** + * @defgroup bt_low_energy Bluetooth Low Energy + * @{ + */ + #include #include #include "syscfg/syscfg.h" @@ -29,15 +34,18 @@ extern "C" { #endif -/* The number of advertising instances */ +/** The number of advertising instances */ #define BLE_ADV_INSTANCES (MYNEWT_VAL(BLE_MULTI_ADV_INSTANCES) + 1) -/* BLE encryption block definitions */ +/** BLE encryption block definitions */ #define BLE_ENC_BLOCK_SIZE (16) -/* 4 byte header + 251 byte payload. */ +/** 4 byte header + 251 byte payload. */ #define BLE_ACL_MAX_PKT_SIZE 255 +/** + * @cond INTERNAL_DOCS + */ struct ble_encryption_block { uint8_t key[BLE_ENC_BLOCK_SIZE]; @@ -88,8 +96,12 @@ struct ble_mbuf_hdr_rxinfo * set for the same PDU (e.g. one use by scanner, other one used by * connection) */ +#define BLE_MBUF_HDR_F_CONNECT_IND_TXD (0x4000) +#define BLE_MBUF_HDR_F_CONNECT_REQ_TXD (0x4000) +#define BLE_MBUF_HDR_F_CONNECT_RSP_RXD (0x0008) #define BLE_MBUF_HDR_F_CONN_CREDIT (0x8000) #define BLE_MBUF_HDR_F_IGNORED (0x8000) +#define BLE_MBUF_HDR_F_CONN_CREDIT_INT (0x4000) #define BLE_MBUF_HDR_F_SCAN_REQ_TXD (0x4000) #define BLE_MBUF_HDR_F_INITA_RESOLVED (0x2000) #define BLE_MBUF_HDR_F_TARGETA_RESOLVED (0x2000) @@ -97,7 +109,7 @@ struct ble_mbuf_hdr_rxinfo #define BLE_MBUF_HDR_F_EXT_ADV (0x0800) #define BLE_MBUF_HDR_F_RESOLVED (0x0400) #define BLE_MBUF_HDR_F_AUX_PTR_WAIT (0x0200) -#define BLE_MBUF_HDR_F_AUX_INVALID (0x0100) +#define BLE_MBUF_HDR_F_AUX_PTR_FAILED (0x0100) #define BLE_MBUF_HDR_F_CRC_OK (0x0080) #define BLE_MBUF_HDR_F_DEVMATCH (0x0040) #define BLE_MBUF_HDR_F_MIC_FAILURE (0x0020) @@ -108,22 +120,46 @@ struct ble_mbuf_hdr_rxinfo /* Transmit info. NOTE: no flags defined */ struct ble_mbuf_hdr_txinfo { - uint8_t flags; + uint8_t num_data_pkt; uint8_t hdr_byte; uint16_t offset; uint16_t pyld_len; }; +struct ble_mbuf_hdr_txiso { + uint16_t packet_seq_num; + uint32_t cpu_timestamp; + uint32_t hci_timestamp; +}; + +/** + * @endcond + */ + +/** Structure representing a BLE mbuf header. */ struct ble_mbuf_hdr { union { + /** RX info for received packets. */ struct ble_mbuf_hdr_rxinfo rxinfo; + + /** TX info for transmitted packets. */ struct ble_mbuf_hdr_txinfo txinfo; + + /** TX ISO info for transmitted isochronous packets. */ + struct ble_mbuf_hdr_txiso txiso; }; + + /** CPU time when the packet processing began. */ uint32_t beg_cputime; + + /** Remaining microseconds for packet processing. */ uint32_t rem_usecs; }; +/** + * @cond INTERNAL_DOCS + */ #define BLE_MBUF_HDR_IGNORED(hdr) \ (!!((hdr)->rxinfo.flags & BLE_MBUF_HDR_F_IGNORED)) @@ -142,9 +178,6 @@ struct ble_mbuf_hdr #define BLE_MBUF_HDR_SCAN_RSP_RXD(hdr) \ (!!((hdr)->rxinfo.flags & BLE_MBUF_HDR_F_SCAN_RSP_RXD)) -#define BLE_MBUF_HDR_AUX_INVALID(hdr) \ - (!!((hdr)->rxinfo.flags & BLE_MBUF_HDR_F_AUX_INVALID)) - #define BLE_MBUF_HDR_WAIT_AUX(hdr) \ (!!((hdr)->rxinfo.flags & BLE_MBUF_HDR_F_AUX_PTR_WAIT)) @@ -180,7 +213,16 @@ struct ble_mbuf_hdr /* Length of host user header. Only contains the peer's connection handle. */ #define BLE_MBUF_HS_HDR_LEN (2) +/** + * @endcond + */ + +/** Length of a Bluetooth Device Address. */ #define BLE_DEV_ADDR_LEN (6) + +/** + * @cond INTERNAL_DOCS + */ extern uint8_t g_dev_addr[BLE_DEV_ADDR_LEN]; extern uint8_t g_random_addr[BLE_DEV_ADDR_LEN]; @@ -265,29 +307,109 @@ enum ble_error_codes #define BLE_HW_ERR_DO_NOT_USE (0) /* XXX: reserve this one for now */ #define BLE_HW_ERR_HCI_SYNC_LOSS (1) -/* Own Bluetooth Device address type */ +/** + * @endcond + */ + +/** + * @defgroup ble_own_address_types Bluetooth Device Own Address Types + * @{ + */ + +/** Bluetooth Device Own Address Type: Public. */ #define BLE_OWN_ADDR_PUBLIC (0x00) + +/** Bluetooth Device Own Address Type: Random. */ #define BLE_OWN_ADDR_RANDOM (0x01) + +/** + * Bluetooth Device Own Address Type: Resolvable Private Address (RPA) + * with Public fallback. + */ #define BLE_OWN_ADDR_RPA_PUBLIC_DEFAULT (0x02) + +/** + * Bluetooth Device Own Address Type: Resolvable Private Address (RPA) + * with Random fallback. + */ #define BLE_OWN_ADDR_RPA_RANDOM_DEFAULT (0x03) -/* Bluetooth Device address type */ +/** @} */ + +/** + * @defgroup ble_address_types Bluetooth Device Address Types + * @{ + */ + +/** Bluetooth Device Address Type: Public. */ #define BLE_ADDR_PUBLIC (0x00) + +/** Bluetooth Device Address Type: Random. */ #define BLE_ADDR_RANDOM (0x01) + +/** + * Bluetooth Device Address Type: Public Identity Address + * (Corresponds to Resolved Private Address). + */ #define BLE_ADDR_PUBLIC_ID (0x02) + +/** + * Bluetooth Device Address Type: Random (Static) Identity Address + * (Corresponds to Resolved Private Address). + */ #define BLE_ADDR_RANDOM_ID (0x03) +/** + * Bluetooth Device Address Type: Anonymous + * (Corresponds to devices sending anonymous advertisements). + */ +#define BLE_ADDR_ANONYMOUS (0xFF) + +/** @} */ + +/** + * @brief A macro representing any BLE address. + * + * This macro initializes a `ble_addr_t` structure to all zeros. + */ #define BLE_ADDR_ANY (&(ble_addr_t) { 0, {0, 0, 0, 0, 0, 0} }) +/** + * Checks if the given address is a Resolvable Private Address (RPA). + * + * @param addr Pointer to the `ble_addr_t` structure. + * @return Non-zero if the address is an RPA, + * zero otherwise. + */ #define BLE_ADDR_IS_RPA(addr) (((addr)->type == BLE_ADDR_RANDOM) && \ ((addr)->val[5] & 0xc0) == 0x40) + +/** + * Checks if the given address is a Non-Resolvable Private Address (NRPA). + * + * @param addr Pointer to the `ble_addr_t` structure. + * @return Non-zero if the address is an NRPA, + * zero otherwise. + */ #define BLE_ADDR_IS_NRPA(addr) (((addr)->type == BLE_ADDR_RANDOM) && \ ((addr)->val[5] & 0xc0) == 0x00) + +/** + * @brief Checks if the given address is a Static Random Address. + * + * @param addr Pointer to the `ble_addr_t` structure. + * @return Non-zero if the address is a Static Random Address, + * zero otherwise. + */ #define BLE_ADDR_IS_STATIC(addr) (((addr)->type == BLE_ADDR_RANDOM) && \ ((addr)->val[5] & 0xc0) == 0xc0) +/** Structure representing a BLE address. */ typedef struct { + /** The type of the address. */ uint8_t type; + + /** The value of the address as an array of 6 bytes. */ uint8_t val[6]; } ble_addr_t; @@ -308,4 +430,6 @@ static inline int ble_addr_cmp(const ble_addr_t *a, const ble_addr_t *b) } #endif +/** @} **/ + #endif /* H_BLE_ */ diff --git a/nimble/include/nimble/ble_hci_trans.h b/nimble/include/nimble/ble_hci_trans.h deleted file mode 100644 index e8d3ec0311..0000000000 --- a/nimble/include/nimble/ble_hci_trans.h +++ /dev/null @@ -1,192 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef H_HCI_TRANSPORT_ -#define H_HCI_TRANSPORT_ - -#include -#include "os/os_mempool.h" - -#ifdef __cplusplus -extern "C" { -#endif - -struct os_mbuf; - -#define BLE_HCI_TRANS_CMD_SZ 260 - -/*** Type of buffers for holding commands and events. */ -/** - * Controller-to-host event buffers. Events have one of two priorities: - * o Low-priority (BLE_HCI_TRANS_BUF_EVT_LO) - * o High-priority (BLE_HCI_TRANS_BUF_EVT_HI) - * - * Low-priority event buffers are only used for advertising reports. If there - * are no free low-priority event buffers, then an incoming advertising report - * will get dropped. - * - * High-priority event buffers are for everything except advertising reports. - * If there are no free high-priority event buffers, a request to allocate one - * will try to allocate a low-priority buffer instead. - * - * If you want all events to be given equal treatment, then you should allocate - * low-priority events only. - * - * Event priorities solve the problem of critical events getting dropped due to - * a flood of advertising reports. This solution is likely temporary: when - * HCI flow control is added, event priorities may become obsolete. - * - * Not all transports distinguish between low and high priority events. If the - * transport does not have separate settings for low and high buffer counts, - * then it treats all events with equal priority. - */ -#define BLE_HCI_TRANS_BUF_EVT_LO 1 -#define BLE_HCI_TRANS_BUF_EVT_HI 2 - -/* Host-to-controller command. */ -#define BLE_HCI_TRANS_BUF_CMD 3 - -/** Callback function types; executed when HCI packets are received. */ -typedef int ble_hci_trans_rx_cmd_fn(uint8_t *cmd, void *arg); -typedef int ble_hci_trans_rx_acl_fn(struct os_mbuf *om, void *arg); - -/** - * Sends an HCI event from the controller to the host. - * - * @param cmd The HCI event to send. This buffer must be - * allocated via ble_hci_trans_buf_alloc(). - * - * @return 0 on success; - * A BLE_ERR_[...] error code on failure. - */ -int ble_hci_trans_ll_evt_tx(uint8_t *hci_ev); - -/** - * Sends ACL data from controller to host. - * - * @param om The ACL data packet to send. - * - * @return 0 on success; - * A BLE_ERR_[...] error code on failure. - */ -int ble_hci_trans_ll_acl_tx(struct os_mbuf *om); - -/** - * Sends an HCI command from the host to the controller. - * - * @param cmd The HCI command to send. This buffer must be - * allocated via ble_hci_trans_buf_alloc(). - * - * @return 0 on success; - * A BLE_ERR_[...] error code on failure. - */ -int ble_hci_trans_hs_cmd_tx(uint8_t *cmd); - -/** - * Sends ACL data from host to controller. - * - * @param om The ACL data packet to send. - * - * @return 0 on success; - * A BLE_ERR_[...] error code on failure. - */ -int ble_hci_trans_hs_acl_tx(struct os_mbuf *om); - -/** - * Allocates a flat buffer of the specified type. - * - * @param type The type of buffer to allocate; one of the - * BLE_HCI_TRANS_BUF_[...] constants. - * - * @return The allocated buffer on success; - * NULL on buffer exhaustion. - */ -uint8_t *ble_hci_trans_buf_alloc(int type); - -/** - * Frees the specified flat buffer. The buffer must have been allocated via - * ble_hci_trans_buf_alloc(). - * - * @param buf The buffer to free. - */ -void ble_hci_trans_buf_free(uint8_t *buf); - -/** - * Configures a callback to get executed whenever an ACL data packet is freed. - * The function is called immediately before the free occurs. - * - * @param cb The callback to configure. - * @param arg An optional argument to pass to the callback. - * - * @return 0 on success; - * BLE_ERR_UNSUPPORTED if the transport does not - * support this operation. - */ -int ble_hci_trans_set_acl_free_cb(os_mempool_put_fn *cb, void *arg); - -/** - * Configures the HCI transport to operate with a controller. The transport - * will execute specified callbacks upon receiving HCI packets from the host. - * - * @param cmd_cb The callback to execute upon receiving an HCI - * command. - * @param cmd_arg Optional argument to pass to the command - * callback. - * @param acl_cb The callback to execute upon receiving ACL - * data. - * @param acl_arg Optional argument to pass to the ACL - * callback. - */ -void ble_hci_trans_cfg_ll(ble_hci_trans_rx_cmd_fn *cmd_cb, - void *cmd_arg, - ble_hci_trans_rx_acl_fn *acl_cb, - void *acl_arg); - -/** - * Configures the HCI transport to operate with a host. The transport will - * execute specified callbacks upon receiving HCI packets from the controller. - * - * @param evt_cb The callback to execute upon receiving an HCI - * event. - * @param evt_arg Optional argument to pass to the event - * callback. - * @param acl_cb The callback to execute upon receiving ACL - * data. - * @param acl_arg Optional argument to pass to the ACL - * callback. - */ -void ble_hci_trans_cfg_hs(ble_hci_trans_rx_cmd_fn *evt_cb, - void *evt_arg, - ble_hci_trans_rx_acl_fn *acl_cb, - void *acl_arg); - -/** - * Resets the HCI module to a clean state. Frees all buffers and reinitializes - * the underlying transport. - * - * @return 0 on success; - * A BLE_ERR_[...] error code on failure. - */ -int ble_hci_trans_reset(void); - -#ifdef __cplusplus -} -#endif - -#endif /* H_HCI_TRANSPORT_ */ diff --git a/nimble/include/nimble/hci_common.h b/nimble/include/nimble/hci_common.h index 92031c3c16..01c3dbc14b 100644 --- a/nimble/include/nimble/hci_common.h +++ b/nimble/include/nimble/hci_common.h @@ -21,13 +21,14 @@ #define H_BLE_HCI_COMMON_ #include "ble.h" +#include "nimble/transport.h" #ifdef __cplusplus extern "C" { #endif -#define BLE_HCI_MAX_DATA_LEN (MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE) - \ - sizeof(struct ble_hci_ev)) +#define BLE_HCI_MAX_DATA_LEN (MYNEWT_VAL(BLE_TRANSPORT_EVT_SIZE) - \ + sizeof(struct ble_hci_ev)) /* Generic command header */ struct ble_hci_cmd { @@ -482,20 +483,20 @@ struct ble_hci_le_rd_resolv_list_size_rp { } __attribute__((packed)); #define BLE_HCI_OCF_LE_RD_PEER_RESOLV_ADDR (0x002B) -struct ble_hci_le_rd_peer_recolv_addr_cp { +struct ble_hci_le_rd_peer_resolv_addr_cp { uint8_t peer_addr_type; uint8_t peer_id_addr[6]; } __attribute__((packed)); -struct ble_hci_le_rd_peer_recolv_addr_rp { +struct ble_hci_le_rd_peer_resolv_addr_rp { uint8_t rpa[6]; } __attribute__((packed)); #define BLE_HCI_OCF_LE_RD_LOCAL_RESOLV_ADDR (0x002C) -struct ble_hci_le_rd_local_recolv_addr_cp { +struct ble_hci_le_rd_local_resolv_addr_cp { uint8_t peer_addr_type; uint8_t peer_id_addr[6]; } __attribute__((packed)); -struct ble_hci_le_rd_local_recolv_addr_rp { +struct ble_hci_le_rd_local_resolv_addr_rp { uint8_t rpa[6]; } __attribute__((packed)); @@ -592,6 +593,7 @@ struct ble_hci_le_set_ext_adv_params_cp { uint8_t sid; uint8_t scan_req_notif; } __attribute__((packed)); + struct ble_hci_le_set_ext_adv_params_rp { int8_t tx_power; } __attribute__((packed)); @@ -708,6 +710,7 @@ struct ble_hci_le_ext_create_conn_cp { #define BLE_HCI_LE_PERIODIC_ADV_CREATE_SYNC_OPT_FILTER 0x01 #define BLE_HCI_LE_PERIODIC_ADV_CREATE_SYNC_OPT_DISABLED 0x02 +#define BLE_HCI_LE_PERIODIC_ADV_CREATE_SYNC_OPT_DUPLICATES 0x04 #define BLE_HCI_OCF_LE_PERIODIC_ADV_CREATE_SYNC (0x0044) struct ble_hci_le_periodic_adv_create_sync_cp { @@ -833,112 +836,105 @@ struct ble_hci_le_set_default_periodic_sync_transfer_params_cp { #define BLE_HCI_OCF_LE_GENERATE_DHKEY_V2 (0x005E) #define BLE_HCI_OCF_LE_MODIFY_SCA (0x005F) -#if MYNEWT_VAL(BLE_ISO) #define BLE_HCI_OCF_LE_READ_ISO_TX_SYNC (0x0061) struct ble_hci_le_read_iso_tx_sync_cp { uint16_t conn_handle; } __attribute__((packed)); - struct ble_hci_le_read_iso_tx_sync_rp { uint16_t conn_handle; uint16_t packet_seq_num; - uint32_t timestamp; - uint8_t timeoffset[3]; + uint32_t tx_timestamp; + uint8_t time_offset[3]; } __attribute__((packed)); -#define BLE_HCI_LE_SET_CIG_CIS_MAX_NUM (0x1F) -#define BLE_HCI_OCF_LE_SET_CIG_PARAM (0x0062) +#define BLE_HCI_OCF_LE_SET_CIG_PARAMS (0x0062) struct ble_hci_le_cis_params { uint8_t cis_id; - uint16_t max_sdu_mtos; - uint16_t max_sdu_stom; - uint8_t phy_mtos; - uint8_t phy_stom; - uint8_t rnt_mtos; - uint8_t rnt_stom; + uint16_t max_sdu_c_to_p; + uint16_t max_sdu_p_to_c; + uint8_t phy_c_to_p; + uint8_t phy_p_to_c; + uint8_t rnt_c_to_p; + uint8_t rnt_p_to_c; } __attribute__((packed)); - struct ble_hci_le_set_cig_params_cp { uint8_t cig_id; - uint8_t sdu_interval_mtos[3]; - uint8_t sdu_interval_stom[3]; - uint8_t sca; + uint8_t sdu_interval_c_to_p[3]; + uint8_t sdu_interval_p_to_c[3]; + uint8_t worst_sca; uint8_t packing; uint8_t framing; - uint16_t max_latency_mtos; - uint16_t max_latency_stom; - uint8_t cis_cnt; - struct ble_hci_le_cis_params cis_params[0]; + uint16_t max_latency_c_to_p; + uint16_t max_latency_p_to_c; + uint8_t cis_count; + struct ble_hci_le_cis_params cis[0]; } __attribute__((packed)); - struct ble_hci_le_set_cig_params_rp { uint8_t cig_id; - uint8_t cis_cnt; - uint16_t cis_handle[0]; + uint8_t cis_count; + uint16_t conn_handle[0]; } __attribute__((packed)); -#if MYNEWT_VAL(BLE_ISO_TEST) -#define BLE_HCI_OCF_LE_SET_CIG_PARAM_TEST (0x0063) +#define BLE_HCI_OCF_LE_SET_CIG_PARAMS_TEST (0x0063) struct ble_hci_le_cis_params_test { uint8_t cis_id; uint8_t nse; - uint16_t max_sdu_mtos; - uint16_t max_sdu_stom; - uint16_t max_pdu_mtos; - uint16_t max_pdu_stom; - uint8_t phy_mtos; - uint8_t phy_stom; - uint8_t bn_mtos; - uint8_t bn_stom; + uint16_t max_sdu_c_to_p; + uint16_t max_sdu_p_to_c; + uint16_t max_pdu_c_to_p; + uint16_t max_pdu_p_to_c; + uint8_t phy_c_to_p; + uint8_t phy_p_to_c; + uint8_t bn_c_to_p; + uint8_t bn_p_to_c; } __attribute__((packed)); - struct ble_hci_le_set_cig_params_test_cp { uint8_t cig_id; - uint8_t sdu_interval_mtos[3]; - uint8_t sdu_interval_stom[3]; - uint8_t ft_mtos; - uint8_t ft_stom; + uint8_t sdu_interval_c_to_p[3]; + uint8_t sdu_interval_p_to_c[3]; + uint8_t ft_c_to_p; + uint8_t ft_p_to_c; uint16_t iso_interval; - uint8_t sca; + uint8_t worst_sca; uint8_t packing; uint8_t framing; - uint8_t cis_cnt; - struct ble_hci_le_cis_params_test cis_params[0]; + uint8_t cis_count; + struct ble_hci_le_cis_params_test cis[0]; +} __attribute__((packed)); +struct ble_hci_le_set_cig_params_test_rp { + uint8_t cig_id; + uint8_t cis_count; + uint16_t conn_handle[0]; } __attribute__((packed)); -#endif -#define BLE_HCI_LE_CREATE_CIS_MAX_CIS_NUM (0x1F) #define BLE_HCI_OCF_LE_CREATE_CIS (0x0064) struct ble_hci_le_create_cis_params { uint16_t cis_handle; uint16_t conn_handle; } __attribute__((packed)); - struct ble_hci_le_create_cis_cp { - uint8_t cis_cnt; - struct ble_hci_le_create_cis_params params[0]; + uint8_t cis_count; + struct ble_hci_le_create_cis_params cis[0]; } __attribute__((packed)); #define BLE_HCI_OCF_LE_REMOVE_CIG (0x0065) struct ble_hci_le_remove_cig_cp { uint8_t cig_id; } __attribute__((packed)); - struct ble_hci_le_remove_cig_rp { uint8_t cig_id; } __attribute__((packed)); #define BLE_HCI_OCF_LE_ACCEPT_CIS_REQ (0x0066) struct ble_hci_le_accept_cis_request_cp { - uint16_t cis_handle; + uint16_t conn_handle; } __attribute__((packed)); #define BLE_HCI_OCF_LE_REJECT_CIS_REQ (0x0067) struct ble_hci_le_reject_cis_request_cp { - uint16_t cis_handle; + uint16_t conn_handle; uint8_t reason; } __attribute__((packed)); - struct ble_hci_le_reject_cis_request_rp { uint16_t conn_handle; } __attribute__((packed)); @@ -947,11 +943,11 @@ struct ble_hci_le_reject_cis_request_rp { struct ble_hci_le_create_big_cp { uint8_t big_handle; uint8_t adv_handle; - uint8_t bis_cnt; + uint8_t num_bis; uint8_t sdu_interval[3]; uint16_t max_sdu; uint16_t max_transport_latency; - uint8_t rnt; + uint8_t rtn; uint8_t phy; uint8_t packing; uint8_t framing; @@ -959,12 +955,11 @@ struct ble_hci_le_create_big_cp { uint8_t broadcast_code[16]; } __attribute__((packed)); -#if MYNEWT_VAL(BLE_ISO_TEST) #define BLE_HCI_OCF_LE_CREATE_BIG_TEST (0x0069) struct ble_hci_le_create_big_test_cp { uint8_t big_handle; uint8_t adv_handle; - uint8_t bis_cnt; + uint8_t num_bis; uint8_t sdu_interval[3]; uint16_t iso_interval; uint8_t nse; @@ -979,7 +974,6 @@ struct ble_hci_le_create_big_test_cp { uint8_t encryption; uint8_t broadcast_code[16]; } __attribute__((packed)); -#endif #define BLE_HCI_OCF_LE_TERMINATE_BIG (0x006a) struct ble_hci_le_terminate_big_cp { @@ -987,86 +981,431 @@ struct ble_hci_le_terminate_big_cp { uint8_t reason; } __attribute__((packed)); -#define BLE_HCI_LE_BIG_CREATE_SYNC_LEN_MIN (25) #define BLE_HCI_OCF_LE_BIG_CREATE_SYNC (0x006b) struct ble_hci_le_big_create_sync_cp { uint8_t big_handle; uint16_t sync_handle; - uint8_t big_cnt; uint8_t encryption; uint8_t broadcast_code[16]; uint8_t mse; - uint16_t timeout; + uint16_t sync_timeout; + uint8_t num_bis; uint8_t bis[0]; } __attribute__((packed)); #define BLE_HCI_OCF_LE_BIG_TERMINATE_SYNC (0x006c) -struct ble_hci_le_terminate_big_sync_cp { +struct ble_hci_le_big_terminate_sync_cp { + uint8_t big_handle; +} __attribute__((packed)); +struct ble_hci_le_big_terminate_sync_rp { uint8_t big_handle; } __attribute__((packed)); -#endif #define BLE_HCI_OCF_LE_REQ_PEER_SCA (0x006d) struct ble_hci_le_request_peer_sca_cp { uint16_t conn_handle; } __attribute__((packed)); -#if MYNEWT_VAL(BLE_ISO) #define BLE_HCI_OCF_LE_SETUP_ISO_DATA_PATH (0x006e) -struct ble_hci_le_iso_setup_data_path_cp { - uint16_t iso_handle; - uint8_t direction; - uint8_t id; +struct ble_hci_le_setup_iso_data_path_cp { + uint16_t conn_handle; + uint8_t data_path_dir; + uint8_t data_path_id; uint8_t codec_id[5]; uint8_t controller_delay[3]; - uint8_t codec_conf_len; - uint8_t codec_conf[0]; + uint8_t codec_config_len; + uint8_t codec_config[0]; +} __attribute__((packed)); +struct ble_hci_le_setup_iso_data_path_rp { + uint16_t conn_handle; } __attribute__((packed)); -#define BLE_HCI_LE_REMOVE_INPUT_DATA_PATH_BIT (0x01) -#define BLE_HCI_LE_REMOVE_OUTPUT_DATA_PATH_BIT (0x02) #define BLE_HCI_OCF_LE_REMOVE_ISO_DATA_PATH (0x006f) -struct ble_hci_le_iso_remove_data_path_cp { - uint16_t iso_handle; - uint8_t direction; +struct ble_hci_le_remove_iso_data_path_cp { + uint16_t conn_handle; + uint8_t data_path_dir; +} __attribute__((packed)); +struct ble_hci_le_remove_iso_data_path_rp { + uint16_t conn_handle; } __attribute__((packed)); -#if MYNEWT_VAL(BLE_ISO_TEST) #define BLE_HCI_OCF_LE_ISO_TRANSMIT_TEST (0x0070) struct ble_hci_le_iso_transmit_test_cp { - uint16_t iso_handle; + uint16_t conn_handle; uint8_t payload_type; } __attribute__((packed)); +struct ble_hci_le_iso_transmit_test_rp { + uint16_t conn_handle; +} __attribute__((packed)); #define BLE_HCI_OCF_LE_ISO_RECEIVE_TEST (0x0071) struct ble_hci_le_iso_receive_test_cp { - uint16_t iso_handle; + uint16_t conn_handle; + uint8_t payload_type; +} __attribute__((packed)); +struct ble_hci_le_iso_receive_test_rp { + uint16_t conn_handle; } __attribute__((packed)); #define BLE_HCI_OCF_LE_ISO_READ_TEST_COUNTERS (0x0072) struct ble_hci_le_iso_read_test_counters_cp { - uint16_t iso_handle; + uint16_t conn_handle; +} __attribute__((packed)); +struct ble_hci_le_iso_read_test_counters_rp { + uint16_t conn_handle; + uint32_t received_sdu_count; + uint32_t missed_sdu_count; + uint32_t failed_sdu_count; } __attribute__((packed)); #define BLE_HCI_OCF_LE_ISO_TEST_END (0x0073) struct ble_hci_le_iso_test_end_cp { - uint16_t iso_handle; + uint16_t conn_handle; +} __attribute__((packed)); +struct ble_hci_le_iso_test_end_rp { + uint16_t conn_handle; + uint32_t received_sdu_count; + uint32_t missed_sdu_count; + uint32_t failed_sdu_count; } __attribute__((packed)); -#endif -#endif -#define BLE_HCI_OCF_LE_SET_HOST_FEAT (0x0074) -struct ble_hci_le_set_host_feat_cp { +#define BLE_HCI_OCF_LE_SET_HOST_FEATURE (0x0074) +struct ble_hci_le_set_host_feature_cp { uint8_t bit_num; - uint8_t val; + uint8_t bit_val; +} __attribute__((packed)); + +#define BLE_HCI_OCF_LE_READ_ISO_LINK_QUALITY (0x0075) +struct ble_hci_le_read_iso_link_quality_cp { + uint16_t conn_handle; +} __attribute__((packed)); +struct ble_hci_le_read_iso_link_quality_rp { + uint16_t conn_handle; + uint32_t tx_unacked_pkts; + uint32_t tx_flushed_pkts; + uint32_t tx_last_subevent_pkts; + uint32_t retransmitted_pkts; + uint32_t crc_error_pkts; + uint32_t rx_unreceived_pkts; + uint32_t duplicate_pkts; +} __attribute__((packed)); + +#define BLE_HCI_OCF_LE_ENH_READ_TRANSMIT_POWER_LEVEL (0x0076) +struct ble_hci_le_enh_read_transmit_power_level_cp { + uint16_t conn_handle; + uint8_t phy; +} __attribute__((packed)); +struct ble_hci_le_enh_read_transmit_power_level_rp { + uint16_t conn_handle; + uint8_t phy; + uint8_t curr_tx_power_level; + uint8_t max_tx_power_level; } __attribute__((packed)); -/* --- Vendor specific commands (OGF 0x00FF) */ -#define BLE_HCI_OCF_VS_RD_STATIC_ADDR (0x0001) +#define BLE_HCI_OCF_LE_READ_REMOTE_TRANSMIT_POWER_LEVEL (0x0077) +struct ble_hci_le_read_remote_transmit_power_level_cp { + uint16_t conn_handle; + uint8_t phy; +} __attribute__((packed)); + +#define BLE_HCI_OCF_LE_SET_PATH_LOSS_REPORT_PARAM (0x0078) +struct ble_hci_le_set_path_loss_report_param_cp { + uint16_t conn_handle; + uint8_t high_threshold; + uint8_t high_hysteresis; + uint8_t low_threshold; + uint8_t low_hysteresis; + uint16_t min_time_spent; +} __attribute__((packed)); + +#define BLE_HCI_OCF_LE_SET_PATH_LOSS_REPORT_ENABLE (0x0079) +struct ble_hci_le_set_path_loss_report_enable_cp { + uint16_t conn_handle; + uint8_t enable; +} __attribute__((packed)); + +#define BLE_HCI_OCF_LE_SET_TRANS_PWR_REPORT_ENABLE (0x007A) +struct ble_hci_le_set_transmit_power_report_enable_cp { + uint16_t conn_handle; + uint8_t local_enable; + uint8_t remote_enable; +} __attribute__((packed)); + +#define BLE_HCI_OCF_LE_SET_DEFAULT_SUBRATE (0x007D) +struct ble_hci_le_set_default_subrate_cp { + uint16_t subrate_min; + uint16_t subrate_max; + uint16_t max_latency; + uint16_t cont_num; + uint16_t supervision_tmo; +} __attribute__((packed)); + +#define BLE_HCI_OCF_LE_SUBRATE_REQ (0x007E) +struct ble_hci_le_subrate_req_cp { + uint16_t conn_handle; + uint16_t subrate_min; + uint16_t subrate_max; + uint16_t max_latency; + uint16_t cont_num; + uint16_t supervision_tmo; +} __attribute__((packed)); + +#define BLE_HCI_OCF_LE_SET_EXT_ADV_PARAM_V2 (0x007F) +struct ble_hci_le_set_ext_adv_params_v2_cp { + struct ble_hci_le_set_ext_adv_params_cp params_v1; + uint8_t pri_phy_opt; + uint8_t sec_phy_opt; +} __attribute__((packed)); + +#define BLE_HCI_OCF_LE_CS_RD_LOC_SUPP_CAP (0x0089) +struct ble_hci_le_cs_rd_loc_supp_cap_rp { + uint8_t num_config_supported; + uint16_t max_consecutive_procedures_supported; + uint8_t num_antennas_supported; + uint8_t max_antenna_paths_supported; + uint8_t roles_supported; + uint8_t optional_modes_supported; + uint8_t rtt_capability; + uint8_t rtt_aa_only_n; + uint8_t rtt_sounding_n; + uint8_t rtt_random_payload_n; + uint16_t optional_nadm_sounding_capability; + uint16_t optional_nadm_random_capability; + uint8_t optional_cs_sync_phys_supported; + uint16_t optional_subfeatures_supported; + uint16_t optional_t_ip1_times_supported; + uint16_t optional_t_ip2_times_supported; + uint16_t optional_t_fcs_times_supported; + uint16_t optional_t_pm_times_supported; + uint8_t t_sw_time_supported; +} __attribute__((packed)); + +#define BLE_HCI_OCF_LE_CS_RD_REM_SUPP_CAP (0x008A) +struct ble_hci_le_cs_rd_rem_supp_cap_cp { + uint16_t conn_handle; +} __attribute__((packed)); + +#define BLE_HCI_OCF_LE_CS_WR_CACHED_REM_SUPP_CAP (0x008B) +struct ble_hci_le_cs_wr_cached_rem_supp_cap_cp { + uint16_t conn_handle; + uint8_t num_config_supported; + uint16_t max_consecutive_procedures_supported; + uint8_t num_antennas_supported; + uint8_t max_antenna_paths_supported; + uint8_t roles_supported; + uint8_t optional_modes_supported; + uint8_t rtt_capability; + uint8_t rtt_aa_only_n; + uint8_t rtt_sounding_n; + uint8_t rtt_random_payload_n; + uint16_t optional_nadm_sounding_capability; + uint16_t optional_nadm_random_capability; + uint8_t optional_cs_sync_phys_supported; + uint16_t optional_subfeatures_supported; + uint16_t optional_t_ip1_times_supported; + uint16_t optional_t_ip2_times_supported; + uint16_t optional_t_fcs_times_supported; + uint16_t optional_t_pm_times_supported; + uint8_t t_sw_time_supported; +} __attribute__((packed)); +struct ble_hci_le_cs_wr_cached_rem_supp_cap_rp { + uint16_t conn_handle; +} __attribute__((packed)); + +#define BLE_HCI_OCF_LE_CS_SEC_ENABLE (0x008C) +struct ble_hci_le_cs_sec_enable_cp { + uint16_t conn_handle; +} __attribute__((packed)); + +#define BLE_HCI_OCF_LE_CS_SET_DEF_SETTINGS (0x008D) +struct ble_hci_le_cs_set_def_settings_cp { + uint16_t conn_handle; + uint8_t role_enable; + uint8_t cs_sync_antenna_selection; + uint8_t max_tx_power; +} __attribute__((packed)); +struct ble_hci_le_cs_set_def_settings_rp { + uint16_t conn_handle; +} __attribute__((packed)); + +#define BLE_HCI_OCF_LE_CS_RD_REM_FAE (0x008E) +struct ble_hci_le_cs_rd_rem_fae_cp { + uint16_t conn_handle; +} __attribute__((packed)); + +#define BLE_HCI_OCF_LE_CS_WR_CACHED_REM_FAE (0x008F) +struct ble_hci_le_cs_wr_cached_rem_fae_cp { + uint16_t conn_handle; + uint8_t remote_fae_table[72]; +} __attribute__((packed)); +struct ble_hci_le_cs_wr_cached_rem_fae_rp { + uint16_t conn_handle; +} __attribute__((packed)); + +#define BLE_HCI_OCF_LE_CS_CREATE_CONFIG (0x0090) +struct ble_hci_le_cs_create_config_cp { + uint16_t conn_handle; + uint8_t config_id; + uint8_t create_context; + uint8_t main_mode_type; + uint8_t sub_mode_type; + uint8_t min_main_mode_steps; + uint8_t max_main_mode_steps; + uint8_t main_mode_repetition; + uint8_t mode_0_steps; + uint8_t role; + uint8_t rtt_type; + uint8_t cs_sync_phy; + uint8_t channel_map[10]; + uint8_t channel_map_repetition; + uint8_t channel_selection_type; + uint8_t ch3c_shape; + uint8_t ch3c_jump; + uint8_t companion_signal_enable; +} __attribute__((packed)); + +#define BLE_HCI_OCF_LE_CS_REMOVE_CONFIG (0x0091) +struct ble_hci_le_cs_remove_config_cp { + uint16_t conn_handle; + uint8_t config_id; +} __attribute__((packed)); + +#define BLE_HCI_OCF_LE_CS_SET_CHAN_CLASS (0x0092) +struct ble_hci_le_cs_set_chan_class_cp { + uint8_t channel_classification[10]; +} __attribute__((packed)); + +#define BLE_HCI_OCF_LE_CS_SET_PROC_PARAMS (0x0093) +struct ble_hci_le_cs_set_proc_params_cp { + uint16_t conn_handle; + uint8_t config_id; + uint16_t max_procedure_len; + uint16_t min_procedure_interval; + uint16_t max_procedure_interval; + uint16_t max_procedure_count; + uint8_t min_subevent_len[3]; + uint8_t max_subevent_len[3]; + uint8_t tone_antenna_config_selection; + uint8_t phy; + uint8_t tx_power_delta; + uint8_t preferred_peer_antenna; + uint8_t snr_control_initiator; + uint8_t snr_control_reflector; +} __attribute__((packed)); +struct ble_hci_le_cs_set_proc_params_rp { + uint16_t conn_handle; +} __attribute__((packed)); + +#define BLE_HCI_OCF_LE_CS_PROC_ENABLE (0x0094) +struct ble_hci_le_cs_proc_enable_cp { + uint16_t conn_handle; + uint8_t config_id; + uint8_t enable; +} __attribute__((packed)); + +#define BLE_HCI_OCF_LE_CS_TEST (0x0095) +struct ble_hci_le_cs_test_cp { + uint8_t main_mode_type; + uint8_t sub_mode_type; + uint8_t main_mode_repetition; + uint8_t mode_0_steps; + uint8_t role; + uint8_t rtt_type; + uint8_t cs_sync_phy; + uint8_t cs_sync_antenna_selection; + uint8_t subevent_len[3]; + uint16_t subevent_interval; + uint8_t transmit_power_level; + uint8_t t_ip1_time; + uint8_t t_ip2_time; + uint8_t t_fcs_time; + uint8_t t_pm_time; + uint8_t t_sw_time; + uint8_t tone_antenna_config_selection; + uint8_t companion_signal_enable; + uint16_t drbg_nonce; + uint16_t override_config; + uint8_t override_parameters_length; + uint8_t override_parameters_data[]; +} __attribute__((packed)); + +#define BLE_HCI_OCF_LE_CS_TEST_END (0x0096) + +/* --- Vendor specific commands (OGF 0x003F) */ +/* Read Random Static Address */ +#define BLE_HCI_OCF_VS_RD_STATIC_ADDR (MYNEWT_VAL(BLE_HCI_VS_OCF_OFFSET) + (0x0001)) struct ble_hci_vs_rd_static_addr_rp { uint8_t addr[6]; } __attribute__((packed)); +/* Set default transmit power. Actual selected TX power is returned + * in reply. Setting 0xff restores controller reset default. + */ +#define BLE_HCI_OCF_VS_SET_TX_PWR (MYNEWT_VAL(BLE_HCI_VS_OCF_OFFSET) + (0x0002)) +struct ble_hci_vs_set_tx_pwr_cp { + int8_t tx_power; +} __attribute__((packed)); +struct ble_hci_vs_set_tx_pwr_rp { + int8_t tx_power; +} __attribute__((packed)); + +#define BLE_HCI_OCF_VS_CSS_CONFIGURE (MYNEWT_VAL(BLE_HCI_VS_OCF_OFFSET) + (0x0003)) +struct ble_hci_vs_css_configure_cp { + uint32_t slot_us; + uint32_t period_slots; +} __attribute__((packed)); +#define BLE_HCI_OCF_VS_CSS_ENABLE (MYNEWT_VAL(BLE_HCI_VS_OCF_OFFSET) + (0x0004)) +struct ble_hci_vs_css_enable_cp { + uint8_t enable; +} __attribute__((packed)); +#define BLE_HCI_OCF_VS_CSS_SET_NEXT_SLOT (MYNEWT_VAL(BLE_HCI_VS_OCF_OFFSET) + (0x0005)) +struct ble_hci_vs_css_set_next_slot_cp { + uint16_t slot_idx; +} __attribute__((packed)); +#define BLE_HCI_OCF_VS_CSS_SET_CONN_SLOT (MYNEWT_VAL(BLE_HCI_VS_OCF_OFFSET) + (0x0006)) +struct ble_hci_vs_css_set_conn_slot_cp { + uint16_t conn_handle; + uint16_t slot_idx; +} __attribute__((packed)); +#define BLE_HCI_OCF_VS_CSS_READ_CONN_SLOT (MYNEWT_VAL(BLE_HCI_VS_OCF_OFFSET) + (0x0007)) +struct ble_hci_vs_css_read_conn_slot_cp { + uint16_t conn_handle; +} __attribute__((packed)); +struct ble_hci_vs_css_read_conn_slot_rp { + uint16_t conn_handle; + uint16_t slot_idx; +} __attribute__((packed)); +#define BLE_HCI_OCF_VS_SET_DATA_LEN (MYNEWT_VAL(BLE_HCI_VS_OCF_OFFSET) + (0x0008)) +struct ble_hci_vs_set_data_len_cp { + uint16_t conn_handle; + uint16_t tx_octets; + uint16_t tx_time; + uint16_t rx_octets; + uint16_t rx_time; +} __attribute__((packed)); +struct ble_hci_vs_set_data_len_rp { + uint16_t conn_handle; +} __attribute__((packed)); +#define BLE_HCI_OCF_VS_SET_ANTENNA (MYNEWT_VAL(BLE_HCI_VS_OCF_OFFSET) + (0x0009)) +struct ble_hci_vs_set_antenna_cp { + uint8_t antenna; +} __attribute__((packed)); +#define BLE_HCI_OCF_VS_SET_LOCAL_IRK (MYNEWT_VAL(BLE_HCI_VS_OCF_OFFSET) + (0x000A)) +struct ble_hci_vs_set_local_irk_cp { + uint8_t own_addr_type; + uint8_t irk[16]; +} __attribute__((packed)); + +#define BLE_HCI_VS_SET_SCAN_CFG_FLAG_NO_LEGACY (0x00000001) +#define BLE_HCI_VS_SET_SCAN_CFG_FLAG_NO_EXT (0x00000002) +#define BLE_HCI_VS_SET_SCAN_CFG_FLAG_RSSI_FILTER (0x00000004) + +#define BLE_HCI_OCF_VS_SET_SCAN_CFG (MYNEWT_VAL(BLE_HCI_VS_OCF_OFFSET) + (0x000B)) +struct ble_hci_vs_set_scan_cfg_cp { + uint32_t flags; + int8_t rssi_threshold; +} __attribute__((packed)); + /* Command Specific Definitions */ /* --- Set controller to host flow control (OGF 0x03, OCF 0x0031) --- */ #define BLE_HCI_CTLR_TO_HOST_FC_OFF (0) @@ -1107,8 +1446,17 @@ struct ble_hci_vs_rd_static_addr_rp { #define BLE_HCI_ADV_PEER_ADDR_MAX (1) /* --- LE advertising channel tx power (OCF 0x0007) */ -#define BLE_HCI_ADV_CHAN_TXPWR_MIN (-20) -#define BLE_HCI_ADV_CHAN_TXPWR_MAX (10) +#if MYNEWT_VAL(BLE_VERSION) == 50 +#define BLE_HCI_ADV_CHAN_TXPWR_MIN (-20) +#define BLE_HCI_ADV_CHAN_TXPWR_MAX (10) +#elif MYNEWT_VAL(BLE_VERSION) == 51 +#define BLE_HCI_ADV_CHAN_TXPWR_MIN (-20) +#define BLE_HCI_ADV_CHAN_TXPWR_MAX (20) +#elif MYNEWT_VAL(BLE_VERSION) >= 52 +#define BLE_HCI_ADV_CHAN_TXPWR_MIN (-127) +#define BLE_HCI_ADV_CHAN_TXPWR_MAX (20) +#endif + /* --- LE set scan enable (OCF 0x000c) */ @@ -1146,17 +1494,21 @@ struct ble_hci_vs_rd_static_addr_rp { #define BLE_HCI_ADV_ITVL_DEF (0x800) /* 1.28 seconds */ #define BLE_HCI_ADV_CHANMASK_DEF (0x7) /* all channels */ +#define BLE_HCI_PERIODIC_ADV_ITVL (1250) /* usecs */ + /* Set scan parameters */ #define BLE_HCI_SCAN_TYPE_PASSIVE (0) #define BLE_HCI_SCAN_TYPE_ACTIVE (1) /* Scan interval and scan window timing */ #define BLE_HCI_SCAN_ITVL (625) /* usecs */ -#define BLE_HCI_SCAN_ITVL_MIN (4) /* units */ -#define BLE_HCI_SCAN_ITVL_MAX (16384) /* units */ +#define BLE_HCI_SCAN_ITVL_MIN (0x0004) /* units */ +#define BLE_HCI_SCAN_ITVL_MAX (0x4000) /* units */ +#define BLE_HCI_SCAN_ITVL_MAX_EXT (0xffff) /* units */ #define BLE_HCI_SCAN_ITVL_DEF (16) /* units */ -#define BLE_HCI_SCAN_WINDOW_MIN (4) /* units */ -#define BLE_HCI_SCAN_WINDOW_MAX (16384) /* units */ +#define BLE_HCI_SCAN_WINDOW_MIN (0x0004) /* units */ +#define BLE_HCI_SCAN_WINDOW_MAX (0x4000) /* units */ +#define BLE_HCI_SCAN_WINDOW_MAX_EXT (0xffff) /* units */ #define BLE_HCI_SCAN_WINDOW_DEF (16) /* units */ /* @@ -1215,6 +1567,12 @@ struct ble_hci_vs_rd_static_addr_rp { #define BLE_HCI_SET_DATALEN_TX_TIME_MIN (0x0148) #define BLE_HCI_SET_DATALEN_TX_TIME_MAX (0x4290) +/* --- LE read/write suggested default data length (OCF 0x0023 and 0x0024) */ +#define BLE_HCI_SUGG_DEF_DATALEN_TX_OCTETS_MIN (0x001b) +#define BLE_HCI_SUGG_DEF_DATALEN_TX_OCTETS_MAX (0x00fb) +#define BLE_HCI_SUGG_DEF_DATALEN_TX_TIME_MIN (0x0148) +#define BLE_HCI_SUGG_DEF_DATALEN_TX_TIME_MAX (0x4290) + /* --- LE read maximum default PHY (OCF 0x0030) */ #define BLE_HCI_LE_PHY_1M (1) #define BLE_HCI_LE_PHY_2M (2) @@ -1289,6 +1647,18 @@ struct ble_hci_vs_rd_static_addr_rp { #define BLE_HCI_PRIVACY_NETWORK (0) #define BLE_HCI_PRIVACY_DEVICE (1) +/* --- LE iso transmit test payload type options (OCF 0x0070) */ +#define BLE_HCI_PAYLOAD_TYPE_ZERO_LENGTH (0x00) +#define BLE_HCI_PAYLOAD_TYPE_VARIABLE_LENGTH (0x01) +#define BLE_HCI_PAYLOAD_TYPE_MAXIMUM_LENGTH (0x02) + +/* --- LE set advertising coded PHY options (OCF 0x007F) */ +#define BLE_HCI_ADVERTISING_PHY_OPT_NO_PREF 0x0 +#define BLE_HCI_ADVERTISING_PHY_OPT_S2_PREF 0x1 +#define BLE_HCI_ADVERTISING_PHY_OPT_S8_PREF 0x2 +#define BLE_HCI_ADVERTISING_PHY_OPT_S2_REQ 0x3 +#define BLE_HCI_ADVERTISING_PHY_OPT_S8_REQ 0x4 + /* Event Codes */ #define BLE_HCI_EVCODE_INQUIRY_CMP (0x01) #define BLE_HCI_EVCODE_INQUIRY_RESULT (0x02) @@ -1444,12 +1814,33 @@ struct ble_hci_ev_auth_pyld_tmo { #define BLE_HCI_EVCODE_SAM_STATUS_CHG (0x58) -#define BLE_HCI_EVCODE_VENDOR_DEBUG (0xFF) -struct ble_hci_ev_vendor_debug { +#define BLE_HCI_EVCODE_VS (0xff) +struct ble_hci_ev_vs { uint8_t id; uint8_t data[0]; } __attribute__((packed)); +#define BLE_HCI_VS_SUBEV_ID_ASSERT (0x01) +#define BLE_HCI_VS_SUBEV_ID_CSS_SLOT_CHANGED (0x02) +struct ble_hci_ev_vs_css_slot_changed { + uint16_t conn_handle; + uint16_t slot_idx; +}; + +#define BLE_HCI_VS_SUBEV_ISO_HCI_FEEDBACK (0x03) +struct feedback_pkt { + uint16_t handle; + uint8_t sdu_per_interval; + int8_t diff; +} __attribute__((packed)); +struct ble_hci_vs_subev_iso_hci_feedback { + uint8_t big_handle; + uint8_t count; + struct feedback_pkt feedback[0]; +} __attribute__((packed)); + +#define BLE_HCI_VS_SUBEV_ID_LLCP_TRACE (0x17) + /* LE sub-event codes */ #define BLE_HCI_LE_SUBEV_CONN_COMPLETE (0x01) struct ble_hci_ev_le_subev_conn_complete { @@ -1680,43 +2071,43 @@ struct ble_hci_ev_le_subev_periodic_adv_sync_transfer { uint8_t aca; } __attribute__((packed)); -#define BLE_HCI_LE_SUBEV_CIS_ESTAB (0x19) +#define BLE_HCI_LE_SUBEV_CIS_ESTABLISHED (0x19) struct ble_hci_ev_le_subev_cis_established { uint8_t subev_code; uint8_t status; - uint16_t cis_handle; + uint16_t conn_handle; uint8_t cig_sync_delay[3]; uint8_t cis_sync_delay[3]; - uint8_t trans_latency_mtos[3]; - uint8_t trans_latency_stom[3]; - uint8_t phy_mtos; - uint8_t phy_stom; + uint8_t transport_latency_c_to_p[3]; + uint8_t transport_latency_p_to_c[3]; + uint8_t phy_c_to_p; + uint8_t phy_p_to_c; uint8_t nse; - uint8_t bn_mtos; - uint8_t bn_stom; - uint8_t ft_mtos; - uint8_t ft_stom; - uint16_t max_pdu_mtos; - uint16_t max_pdu_stom; + uint8_t bn_c_to_p; + uint8_t bn_p_to_c; + uint8_t ft_c_to_p; + uint8_t ft_p_to_c; + uint16_t max_pdu_c_to_p; + uint16_t max_pdu_p_to_c; uint16_t iso_interval; } __attribute__((packed)); #define BLE_HCI_LE_SUBEV_CIS_REQUEST (0x1A) struct ble_hci_ev_le_subev_cis_request { uint8_t subev_code; - uint16_t conn_handle; - uint16_t cis_handle; + uint16_t acl_conn_handle; + uint16_t cis_conn_handle; uint8_t cig_id; uint8_t cis_id; } __attribute__((packed)); -#define BLE_HCI_LE_SUBEV_BIG_COMP (0x1B) -struct ble_hci_ev_le_subev_big_complete { +#define BLE_HCI_LE_SUBEV_CREATE_BIG_COMPLETE (0x1B) +struct ble_hci_ev_le_subev_create_big_complete { uint8_t subev_code; uint8_t status; uint8_t big_handle; uint8_t big_sync_delay[3]; - uint8_t transport_latency[3]; + uint8_t transport_latency_big[3]; uint8_t phy; uint8_t nse; uint8_t bn; @@ -1724,31 +2115,31 @@ struct ble_hci_ev_le_subev_big_complete { uint8_t irc; uint16_t max_pdu; uint16_t iso_interval; - uint8_t bis_cnt; - uint16_t bis[0]; + uint8_t num_bis; + uint16_t conn_handle[0]; } __attribute__((packed)); -#define BLE_HCI_LE_SUBEV_BIG_TERMINATE_COMP (0x1C) -struct ble_hci_ev_le_subev_big_terminate_complete { +#define BLE_HCI_LE_SUBEV_TERMINATE_BIG_COMPLETE (0x1C) +struct ble_hci_ev_le_subev_terminate_big_complete { uint8_t subev_code; uint8_t big_handle; uint8_t reason; } __attribute__((packed)); -#define BLE_HCI_LE_SUBEV_BIG_SYNC_ESTAB (0x1D) +#define BLE_HCI_LE_SUBEV_BIG_SYNC_ESTABLISHED (0x1D) struct ble_hci_ev_le_subev_big_sync_established { uint8_t subev_code; uint8_t status; uint8_t big_handle; - uint8_t transport_latency[3]; + uint8_t transport_latency_big[3]; uint8_t nse; uint8_t bn; uint8_t pto; uint8_t irc; uint16_t max_pdu; uint16_t iso_interval; - uint8_t bis_cnt; - uint16_t bis_handles[0]; + uint8_t num_bis; + uint16_t conn_handle[0]; } __attribute__((packed)); #define BLE_HCI_LE_SUBEV_BIG_SYNC_LOST (0x1E) @@ -1766,6 +2157,26 @@ struct ble_hci_ev_le_subev_peer_sca_complete { uint8_t sca; } __attribute__((packed)); +#define BLE_HCI_LE_SUBEV_PATH_LOSS_THRESHOLD (0x20) +struct ble_hci_ev_le_subev_path_loss_threshold { + uint8_t subev_code; + uint16_t conn_handle; + uint8_t current_path_loss; + uint8_t zone_entered; +} __attribute__((packed)); + +#define BLE_HCI_LE_SUBEV_TRANSMIT_POWER_REPORT (0x21) +struct ble_hci_ev_le_subev_transmit_power_report { + uint8_t subev_code; + uint8_t status; + uint16_t conn_handle; + uint8_t reason; + uint8_t phy; + int8_t transmit_power_level; + uint8_t transmit_power_level_flag; + int8_t delta; +} __attribute__((packed)); + #define BLE_HCI_LE_SUBEV_BIGINFO_ADV_REPORT (0x22) struct ble_hci_ev_le_subev_biginfo_adv_report { uint8_t subev_code; @@ -1784,6 +2195,145 @@ struct ble_hci_ev_le_subev_biginfo_adv_report { uint8_t encryption; } __attribute__((packed)); +#define BLE_HCI_LE_SUBEV_SUBRATE_CHANGE (0x23) +struct ble_hci_ev_le_subev_subrate_change { + uint8_t subev_code; + uint8_t status; + uint16_t conn_handle; + uint16_t subrate_factor; + uint16_t periph_latency; + uint16_t cont_num; + uint16_t supervision_tmo; +} __attribute__((packed)); + +#define BLE_HCI_LE_SUBEV_CS_RD_REM_SUPP_CAP_COMPLETE (0x2C) +struct ble_hci_ev_le_subev_cs_rd_rem_supp_cap_complete { + uint8_t subev_code; + uint8_t status; + uint16_t conn_handle; + uint8_t num_config_supported; + uint16_t max_consecutive_procedures_supported; + uint8_t num_antennas_supported; + uint8_t max_antenna_paths_supported; + uint8_t roles_supported; + uint8_t optional_modes_supported; + uint8_t rtt_capability; + uint8_t rtt_aa_only_n; + uint8_t rtt_sounding_n; + uint8_t rtt_random_payload_n; + uint16_t optional_nadm_sounding_capability; + uint16_t optional_nadm_random_capability; + uint8_t optional_cs_sync_phys_supported; + uint16_t optional_subfeatures_supported; + uint16_t optional_t_ip1_times_supported; + uint16_t optional_t_ip2_times_supported; + uint16_t optional_t_fcs_times_supported; + uint16_t optional_t_pm_times_supported; + uint8_t t_sw_time_supported; +} __attribute__((packed)); + +#define BLE_HCI_LE_SUBEV_CS_RD_REM_FAE_COMPLETE (0x2D) +struct ble_hci_ev_le_subev_cs_rd_rem_fae_complete { + uint8_t subev_code; + uint8_t status; + uint16_t conn_handle; + uint8_t remote_fae_table[72]; +} __attribute__((packed)); + +#define BLE_HCI_LE_SUBEV_CS_SEC_ENABLE_COMPLETE (0x2E) +struct ble_hci_ev_le_subev_cs_sec_enable_complete { + uint8_t subev_code; + uint8_t status; + uint16_t conn_handle; +} __attribute__((packed)); + +#define BLE_HCI_LE_SUBEV_CS_CONFIG_COMPLETE (0x2F) +struct ble_hci_ev_le_subev_cs_config_complete { + uint8_t subev_code; + uint8_t status; + uint16_t conn_handle; + uint8_t config_id; + uint8_t action; + uint8_t main_mode_type; + uint8_t sub_mode_type; + uint8_t min_main_mode_steps; + uint8_t max_main_mode_steps; + uint8_t main_mode_repetition; + uint8_t mode_0_steps; + uint8_t role; + uint8_t rtt_type; + uint8_t cs_sync_phy; + uint8_t channel_map[10]; + uint8_t channel_map_repetition; + uint8_t channel_selection_type; + uint8_t ch3c_shape; + uint8_t ch3c_jump; + uint8_t companion_signal_enable; + uint8_t t_ip1_time; + uint8_t t_ip2_time; + uint8_t t_fcs_time; + uint8_t t_pm_time; +} __attribute__((packed)); + +#define BLE_HCI_LE_SUBEV_CS_PROC_ENABLE_COMPLETE (0x30) +struct ble_hci_ev_le_subev_cs_proc_enable_complete { + uint8_t subev_code; + uint8_t status; + uint16_t conn_handle; + uint8_t config_id; + uint8_t state; + uint8_t tone_antenna_config_selection; + uint8_t selected_tx_power; + uint8_t subevent_len[3]; + uint8_t subevents_per_event; + uint16_t subevent_interval; + uint16_t event_interval; + uint16_t procedure_interval; + uint16_t procedure_count; +} __attribute__((packed)); + +#define BLE_HCI_LE_SUBEV_CS_SUBEVENT_RESULT (0x31) +struct cs_steps_data { + uint8_t mode; + uint8_t channel; + uint8_t data_len; + uint8_t data[]; +} __attribute__((packed)); +struct ble_hci_ev_le_subev_cs_subevent_result { + uint8_t subev_code; + uint16_t conn_handle; + uint8_t config_id; + uint16_t start_acl_conn_event_counter; + uint16_t procedure_counter; + uint16_t frequency_compensation; + uint8_t reference_power_level; + uint8_t procedure_done_status; + uint8_t subevent_done_status; + uint8_t abort_reason; + uint8_t num_antenna_paths; + uint8_t num_steps_reported; + struct cs_steps_data steps[]; +} __attribute__((packed)); + +#define BLE_HCI_LE_SUBEV_CS_SUBEVENT_RESULT_CONTINUE (0x32) +struct ble_hci_ev_le_subev_cs_subevent_result_continue { + uint8_t subev_code; + uint16_t conn_handle; + uint8_t config_id; + uint8_t procedure_done_status; + uint8_t subevent_done_status; + uint8_t abort_reason; + uint8_t num_antenna_paths; + uint8_t num_steps_reported; + struct cs_steps_data steps[]; +} __attribute__((packed)); + +#define BLE_HCI_LE_SUBEV_CS_TEST_END_COMPLETE (0x33) +struct ble_hci_ev_le_subev_cs_test_end_complete { + uint8_t subev_code; + uint8_t status; +} __attribute__((packed)); + /* Data buffer overflow event */ #define BLE_HCI_EVENT_ACL_BUF_OVERFLOW (0x01) @@ -1826,6 +2376,10 @@ struct ble_hci_ev_le_subev_biginfo_adv_report { #define BLE_HCI_VER_BCS_5_0 (9) #define BLE_HCI_VER_BCS_5_1 (10) #define BLE_HCI_VER_BCS_5_2 (11) +#define BLE_HCI_VER_BCS_5_3 (12) +#define BLE_HCI_VER_BCS_5_4 (13) +#define BLE_HCI_VER_BCS_6_0 (14) +#define BLE_HCI_VER_BCS_6_1 (15) #define BLE_LMP_VER_BCS_1_0b (0) #define BLE_LMP_VER_BCS_1_1 (1) @@ -1839,6 +2393,10 @@ struct ble_hci_ev_le_subev_biginfo_adv_report { #define BLE_LMP_VER_BCS_5_0 (9) #define BLE_LMP_VER_BCS_5_1 (10) #define BLE_LMP_VER_BCS_5_2 (11) +#define BLE_LMP_VER_BCS_5_3 (12) +#define BLE_LMP_VER_BCS_5_4 (13) +#define BLE_LMP_VER_BCS_6_0 (14) +#define BLE_LMP_VER_BCS_6_1 (15) /* selected HCI and LMP version */ #if MYNEWT_VAL(BLE_VERSION) == 50 @@ -1850,7 +2408,20 @@ struct ble_hci_ev_le_subev_biginfo_adv_report { #elif MYNEWT_VAL(BLE_VERSION) == 52 #define BLE_HCI_VER_BCS BLE_HCI_VER_BCS_5_2 #define BLE_LMP_VER_BCS BLE_LMP_VER_BCS_5_2 - +#elif MYNEWT_VAL(BLE_VERSION) == 53 +#define BLE_HCI_VER_BCS BLE_HCI_VER_BCS_5_3 +#define BLE_LMP_VER_BCS BLE_LMP_VER_BCS_5_3 +#elif MYNEWT_VAL(BLE_VERSION) == 54 +#define BLE_HCI_VER_BCS BLE_HCI_VER_BCS_5_4 +#define BLE_LMP_VER_BCS BLE_LMP_VER_BCS_5_4 +#elif MYNEWT_VAL(BLE_VERSION) == 60 +#define BLE_HCI_VER_BCS BLE_HCI_VER_BCS_6_0 +#define BLE_LMP_VER_BCS BLE_LMP_VER_BCS_6_0 +#elif MYNEWT_VAL(BLE_VERSION) == 61 +#define BLE_HCI_VER_BCS BLE_HCI_VER_BCS_6_1 +#define BLE_LMP_VER_BCS BLE_LMP_VER_BCS_6_1 +#else +#error Unsupported BLE_VERSION selected #endif #define BLE_HCI_DATA_HDR_SZ 4 @@ -1869,6 +2440,60 @@ struct hci_data_hdr #define BLE_HCI_PB_FIRST_FLUSH 2 #define BLE_HCI_PB_FULL 3 +#define BLE_HCI_ISO_CONN_HANDLE_MASK (0x07ff) +#define BLE_HCI_ISO_PB_FLAG_MASK (0x3000) +#define BLE_HCI_ISO_TS_FLAG_MASK (0x4000) +#define BLE_HCI_ISO_LENGTH_MASK (0x3fff) +#define BLE_HCI_ISO_SDU_LENGTH_MASK (0x0fff) +#define BLE_HCI_ISO_PKT_STATUS_FLAG_MASK (0xC000) + +#define BLE_HCI_ISO_HANDLE(ch, pb, ts) ((ch) | ((pb) << 12) | ((ts) << 14)) + +#define BLE_HCI_ISO_CONN_HANDLE(h) ((h) & BLE_HCI_ISO_CONN_HANDLE_MASK) +#define BLE_HCI_ISO_PB_FLAG(h) (((h) & BLE_HCI_ISO_PB_FLAG_MASK) >> 12) +#define BLE_HCI_ISO_TS_FLAG(h) (((h) & BLE_HCI_ISO_TS_FLAG_MASK) >> 14) +#define BLE_HCI_ISO_LENGTH(l) ((l) & BLE_HCI_ISO_LENGTH_MASK) +#define BLE_HCI_ISO_SDU_LENGTH(l) ((l) & BLE_HCI_ISO_SDU_LENGTH_MASK) +#define BLE_HCI_ISO_PKT_STATUS_FLAG(l) (((l) & BLE_HCI_ISO_PKT_STATUS_FLAG_MASK) >> 14) + +#define BLE_HCI_ISO_PB_FIRST (0) +#define BLE_HCI_ISO_PB_CONTINUATION (1) +#define BLE_HCI_ISO_PB_COMPLETE (2) +#define BLE_HCI_ISO_PB_LAST (3) + +#define BLE_HCI_ISO_PKT_STATUS_VALID 0x00 +#define BLE_HCI_ISO_PKT_STATUS_INVALID 0x01 +#define BLE_HCI_ISO_PKT_STATUS_LOST 0x10 + +#define BLE_HCI_ISO_BIG_HANDLE_MIN 0x00 +#define BLE_HCI_ISO_BIG_HANDLE_MAX 0xEF + +#define BLE_HCI_ISO_BIG_ENCRYPTION_UNENCRYPTED 0x00 +#define BLE_HCI_ISO_BIG_ENCRYPTION_ENCRYPTED 0x01 + +#define BLE_HCI_ISO_DATA_PATH_DIR_INPUT 0x00 +#define BLE_HCI_ISO_DATA_PATH_DIR_OUTPUT 0x01 + +#define BLE_HCI_ISO_DATA_PATH_ID_HCI 0x00 + +#define BLE_HCI_ISO_FRAMING_UNFRAMED 0x00 +#define BLE_HCI_ISO_FRAMING_FRAMED_SEGMENTABLE 0x01 +#define BLE_HCI_ISO_FRAMING_FRAMED_UNSEGMENTED 0x02 + +struct ble_hci_iso { + uint16_t handle; + uint16_t length; + uint8_t data[0]; +} __attribute__((packed)); + +#define BLE_HCI_ISO_HDR_SDU_LENGTH_MASK (0x07ff) + +struct ble_hci_iso_data { + uint16_t packet_seq_num; + uint16_t sdu_len; + uint8_t data[0]; +} __attribute__((packed)); + #ifdef __cplusplus } #endif diff --git a/nimble/include/nimble/nimble_npl_log.h b/nimble/include/nimble/nimble_npl_log.h new file mode 100644 index 0000000000..1b49054aa5 --- /dev/null +++ b/nimble/include/nimble/nimble_npl_log.h @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _NIMBLE_NPL_LOG_H_ +#define _NIMBLE_NPL_LOG_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef BLE_NPL_LOG_MODULE +#error "NPL Logging module not specified" +#endif + +/* helper macros */ +#define _BLE_NPL_LOG_CAT(a, ...) _BLE_NPL_LOG_PRIMITIVE_CAT(a, __VA_ARGS__) +#define _BLE_NPL_LOG_PRIMITIVE_CAT(a, ...) a ## __VA_ARGS__ + +/* used to generate proper log function call (used by stack) */ +#define BLE_NPL_LOG(lvl, ...) _BLE_NPL_LOG_CAT(BLE_NPL_LOG_MODULE, _BLE_NPL_LOG_CAT(_, lvl))(__VA_ARGS__) + +/* Include OS-specific LOG implementation, should provide implementation for + * logging macros used by NiBLE (eg via modlog) or BLE_NPL_LOG_IMPL + * macro implementation that generates required logging functions/macros + */ +#include "nimble/nimble_npl_os_log.h" + +/* generate logging functions for modules, can be macro or function */ +#ifdef BLE_NPL_LOG_IMPL +BLE_NPL_LOG_IMPL(DEBUG); +BLE_NPL_LOG_IMPL(INFO); +BLE_NPL_LOG_IMPL(WARN); +BLE_NPL_LOG_IMPL(ERROR); +BLE_NPL_LOG_IMPL(CRITICAL); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _NIMBLE_NPL_LOG_H_ */ diff --git a/nimble/include/nimble/nimble_opt_auto.h b/nimble/include/nimble/nimble_opt_auto.h index 33a1e2aac9..4663ae8c7c 100644 --- a/nimble/include/nimble/nimble_opt_auto.h +++ b/nimble/include/nimble/nimble_opt_auto.h @@ -77,6 +77,10 @@ extern "C" { #define NIMBLE_BLE_ATT_CLT_READ_MULT \ (MYNEWT_VAL(BLE_GATT_READ_MULT)) +#undef NIMBLE_BLE_ATT_CLT_READ_MULT_VAR +#define NIMBLE_BLE_ATT_CLT_READ_MULT_VAR \ + (MYNEWT_VAL(BLE_GATT_READ_MULT_VAR)) + #undef NIMBLE_BLE_ATT_CLT_READ_GROUP_TYPE #define NIMBLE_BLE_ATT_CLT_READ_GROUP_TYPE \ (MYNEWT_VAL(BLE_GATT_DISC_ALL_SVCS)) @@ -105,6 +109,9 @@ extern "C" { #define NIMBLE_BLE_ATT_CLT_INDICATE \ (MYNEWT_VAL(BLE_GATT_INDICATE)) +#undef NIMBLE_BLE_ATT_CLT_NOTIFY_MULT +#define NIMBLE_BLE_ATT_CLT_NOTIFY_MULT \ + (MYNEWT_VAL(BLE_GATT_NOTIFY_MULTIPLE)) /** Security manager settings. */ #undef NIMBLE_BLE_SM diff --git a/nimble/syscfg.yml b/nimble/syscfg.yml index b5cfc585d6..a1948c65d6 100644 --- a/nimble/syscfg.yml +++ b/nimble/syscfg.yml @@ -67,7 +67,15 @@ syscfg.defs: value: 0 restrictions: - 'BLE_PERIODIC_ADV if 1' - + - '(BLE_ROLE_CENTRAL || BLE_ROLE_PERIPHERAL) if 1' + BLE_PERIODIC_ADV_SYNC_BIGINFO_REPORTS: + description: > + This enables BIGInfo reports. + value: 0 + restrictions: + - 'BLE_PERIODIC_ADV if 1' + - '(BLE_VERSION >= 52) if 1' + experimental: 1 BLE_EXT_ADV_MAX_SIZE: description: > This allows to configure maximum size of advertising data and @@ -79,7 +87,7 @@ syscfg.defs: This allows to configure supported Bluetooth Core version. Some features may not be available if version is too low. Version is integer for easy comparison. - range: 50, 51, 52 + range: 50, 51, 52, 53, 54, 60, 61 value: 50 BLE_ISO: description: > @@ -87,7 +95,19 @@ syscfg.defs: value: 0 restrictions: - '(BLE_VERSION >= 52) if 1' - + - '(BLE_ISO_BROADCAST_SOURCE || BLE_ISO_BROADCAST_SINK) if 1' + BLE_ISO_BROADCAST_SOURCE: + description: > + This enables LE Audio Broadcast Source feature + value: 0 + restrictions: + - '(BLE_VERSION >= 52) if 1' + BLE_ISO_BROADCAST_SINK: + description: > + This enables LE Audio Broadcast Sink feature + value: 0 + restrictions: + - '(BLE_VERSION >= 52) if 1' BLE_ISO_TEST: description: > Enables BLE ISO Testing commands @@ -95,11 +115,50 @@ syscfg.defs: restrictions: - 'BLE_ISO if 1' + BLE_CHANNEL_SOUNDING: + description: > + This enables Channel Sounding feature + value: 0 + BLE_HCI_VS: description: > Enables support for NimBLE specific vendor HCI commands value: 0 + BLE_HCI_VS_OCF_OFFSET: + description: > + This defines starting offset for NimBLE specific vendor HCI commands. + Purpose of this is to improve compatibility with other custom + implementations. + value: 0 + + BLE_POWER_CONTROL: + description: > + This enabled LE Power Control feature + value: 0 + + BLE_CONN_SUBRATING: + description: > + This enables LE Connection Subrating feature + value: 0 + + BLE_PHY_2M: + description: > + This enables support for addtitional 2M PHY + value: 0 + restrictions: + - 'BLE_PHY if 1' + + BLE_PHY_CODED: + description: > + This enables support for addtitional CODED PHY + value: 0 + restrictions: + - 'BLE_PHY if 1' + +syscfg.defs.'BLE_PHY_2M || BLE_PHY_CODED': + BLE_PHY: 1 + # Allow periodic sync transfer only if 5.1 or higher syscfg.restrictions: - "'BLE_PERIODIC_ADV_SYNC_TRANSFER == 0' || 'BLE_VERSION >= 51'" @@ -107,3 +166,6 @@ syscfg.restrictions: # Enable VS HCI by default for combined or standalone controller build syscfg.vals.BLE_CONTROLLER: BLE_HCI_VS: 1 + +syscfg.vals.'BLE_ISO_BROADCAST_SOURCE || BLE_ISO_BROADCAST_SINK': + BLE_ISO: 1 diff --git a/nimble/transport/apollo3/pkg.yml b/nimble/transport/apollo3/pkg.yml new file mode 100644 index 0000000000..6706344380 --- /dev/null +++ b/nimble/transport/apollo3/pkg.yml @@ -0,0 +1,46 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +pkg.name: nimble/transport/apollo3 +pkg.description: > + HCI transport for Ambiq Apollo3 + The BLE subsystem implemented on Apollo3 is a fully integrated system which is accessed + via the BLE interface block, and provides autonomous clock and power management. + The subsystem has a 32-bit core which runs from a 32 MHz oscillator, and is dedicated + to running the lower portion of the BLE stack with a standard Host Controller interface (HCI). + This core does not support user programming, as all user code runs on the main Cortex M4 processor. + Software leverages the fully HCI compliant interface for Bluetooth operation. + A series of proprietary HCI commands are also leveraged to provide additional performance and low power operation. + The BLE controller and host can be configured to support up to seven simultaneous connections on chip revision A1 (4 on chip revision B0). + Secure connections and extended packet length are also supported. + See the Apollo3 Datasheet for a full description of the BLE subsystem. +pkg.author: "Apache Mynewt " +pkg.homepage: "http://mynewt.apache.org/" +pkg.keywords: + - ble + - bluetooth + - apollo3 + +pkg.deps: + - nimble + - nimble/transport/common/hci_h4 + - "@apache-mynewt-core/kernel/os" + +pkg.apis: + - ble_transport diff --git a/nimble/transport/apollo3/src/apollo3_ble_hci.c b/nimble/transport/apollo3/src/apollo3_ble_hci.c new file mode 100644 index 0000000000..2ed3012e90 --- /dev/null +++ b/nimble/transport/apollo3/src/apollo3_ble_hci.c @@ -0,0 +1,342 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#include +#include +#include + +#include "am_mcu_apollo.h" + +#define HCI_CMD_HDR_LEN (3) /*!< \brief Command packet header length */ + +/* Tx power level in dBm. */ +typedef enum { + TX_POWER_LEVEL_MINUS_10P0_dBm = 0x4, + TX_POWER_LEVEL_MINUS_5P0_dBm = 0x5, + TX_POWER_LEVEL_0P0_dBm = 0x8, + TX_POWER_LEVEL_PLUS_3P0_dBm = 0xF, + TX_POWER_LEVEL_INVALID = 0x10, +} txPowerLevel_t; + +/* Structure for holding outgoing HCI packets. */ +typedef struct { + uint32_t len; + uint32_t data[MYNEWT_VAL(BLE_TRANSPORT_APOLLO3_MAX_TX_PACKET) / sizeof(uint32_t)]; +} hci_drv_write_t; + +uint32_t g_read_buf[MYNEWT_VAL(BLE_TRANSPORT_APOLLO3_MAX_RX_PACKET) / sizeof(uint32_t)]; + +/* BLE module handle for Ambiq HAL functions */ +void *ble_handle; + +uint8_t g_ble_mac_address[6] = {0}; + +static struct hci_h4_sm hci_apollo3_h4sm; + +static void +apollo3_ble_hci_trans_rx_process(void) +{ + uint32_t len; + int rlen; + uint8_t *buf = (uint8_t *)g_read_buf; + + am_hal_ble_blocking_hci_read(ble_handle, (uint32_t *)buf, &len); + + /* NOTE: Ambiq Apollo3 controller does not have local supported lmp features implemented + * The command will always return 0 so we overwrite the buffer here + */ + if(buf[4] == 0x03 && buf[5] == 0x10 && len == 15) { + memset(&buf[11], 0x60, sizeof(uint8_t)); + } + + rlen = hci_h4_sm_rx(&hci_apollo3_h4sm, buf, len); + assert(rlen >= 0); +} + +/* Interrupt handler that looks for BLECIRQ. This gets set by BLE core when there is something to read */ +static void +apollo3_hci_int(void) +{ + uint32_t int_status; + + /* Read and clear the interrupt status. */ + int_status = am_hal_ble_int_status(ble_handle, true); + am_hal_ble_int_clear(ble_handle, int_status); + + /* Handle any DMA or Command Complete interrupts. */ + am_hal_ble_int_service(ble_handle, int_status); + + /* If this was a BLEIRQ interrupt, attempt to start a read operation. */ + if (int_status & AM_HAL_BLE_INT_BLECIRQ) + { + /* Lower WAKE */ + am_hal_ble_wakeup_set(ble_handle, 0); + + /* Call read function to pull in data from controller */ + apollo3_ble_hci_trans_rx_process(); + } + else { + assert(0); + } +} + +/* Boot the radio. */ +uint32_t +apollo3_hci_radio_boot(bool is_cold_boot) +{ + uint32_t xtal_retry_cnt = 0; + uint32_t am_boot_status; + am_hal_mcuctrl_device_t device_info; + am_hal_ble_config_t ble_config = + { + /* Configure the HCI interface clock for 6 MHz */ + .ui32SpiClkCfg = AM_HAL_BLE_HCI_CLK_DIV8, + + /* Set HCI read and write thresholds to 32 bytes each. */ + .ui32ReadThreshold = 32, + .ui32WriteThreshold = 32, + + /* The MCU will supply the clock to the BLE core. */ + .ui32BleClockConfig = AM_HAL_BLE_CORE_MCU_CLK, + + /* Note: These settings only apply to Apollo3 A1/A2 silicon, not B0 silicon. + * Default settings for expected BLE clock drift (measured in PPM). + */ + .ui32ClockDrift = 0, + .ui32SleepClockDrift = 50, + + /* Default setting - AGC Enabled */ + .bAgcEnabled = true, + + /* Default setting - Sleep Algo enabled */ + .bSleepEnabled = true, + + /* Apply the default patches when am_hal_ble_boot() is called. */ + .bUseDefaultPatches = true, + }; + + /* Configure and enable the BLE interface. */ + am_boot_status = AM_HAL_STATUS_FAIL; + while (am_boot_status != AM_HAL_STATUS_SUCCESS) { + am_hal_pwrctrl_low_power_init(); + am_hal_ble_initialize(0, &ble_handle); + am_hal_ble_power_control(ble_handle, AM_HAL_BLE_POWER_ACTIVE); + + am_hal_ble_config(ble_handle, &ble_config); + + /* + * Delay 1s for 32768Hz clock stability. This isn't required unless this is + * our first run immediately after a power-up. + */ + if (is_cold_boot) { + os_time_delay(OS_TICKS_PER_SEC); + } + + /* Attempt to boot the radio. */ + am_boot_status = am_hal_ble_boot(ble_handle); + + /* Check our status, exit if radio is running */ + if (am_boot_status == AM_HAL_STATUS_SUCCESS) { + break; + } + else if (am_boot_status == AM_HAL_BLE_32K_CLOCK_UNSTABLE) { + /* If the radio is running, but the clock looks bad, we can try to restart. */ + am_hal_ble_power_control(ble_handle, AM_HAL_BLE_POWER_OFF); + am_hal_ble_deinitialize(ble_handle); + + /* We won't restart forever. After we hit the maximum number of retries, we'll just return with failure. */ + if (xtal_retry_cnt++ < MYNEWT_VAL(BLE_TRANSPORT_APOLLO3_MAX_XTAL_RETRIES)) { + os_time_delay(OS_TICKS_PER_SEC); + } + else { + return SYS_EUNKNOWN; + } + } + else { + am_hal_ble_power_control(ble_handle, AM_HAL_BLE_POWER_OFF); + am_hal_ble_deinitialize(ble_handle); + /* + * If the radio failed for some reason other than 32K Clock + * instability, we should just report the failure and return. + */ + return SYS_EUNKNOWN; + } + } + + /* Set the BLE TX Output power to 0dBm. */ + am_hal_ble_tx_power_set(ble_handle, TX_POWER_LEVEL_0P0_dBm); + + /* Enable interrupts for the BLE module. */ + am_hal_ble_int_clear(ble_handle, (AM_HAL_BLE_INT_CMDCMP | + AM_HAL_BLE_INT_DCMP | + AM_HAL_BLE_INT_BLECIRQ)); + + am_hal_ble_int_enable(ble_handle, (AM_HAL_BLE_INT_CMDCMP | + AM_HAL_BLE_INT_DCMP | + AM_HAL_BLE_INT_BLECIRQ)); + + /* When it's is_cold_boot, it will use Apollo's Device ID to form Bluetooth address. */ + if (is_cold_boot) { + am_hal_mcuctrl_info_get(AM_HAL_MCUCTRL_INFO_DEVICEID, &device_info); + + /* Bluetooth address formed by ChipID1 (32 bits) and ChipID0 (8-23 bits). */ + memcpy(g_ble_mac_address, &device_info.ui32ChipID1, sizeof(device_info.ui32ChipID1)); + + /* ui32ChipID0 bit 8-31 is test time during chip manufacturing */ + g_ble_mac_address[4] = (device_info.ui32ChipID0 >> 8) & 0xFF; + g_ble_mac_address[5] = (device_info.ui32ChipID0 >> 16) & 0xFF; + } + + NVIC_EnableIRQ(BLE_IRQn); + + return 0; +} + +/* Wake update helper function */ +static void +apollo3_update_wake(void) +{ + AM_CRITICAL_BEGIN; + + /* Set WAKE if there's something in the write queue, but not if SPISTATUS or IRQ is high. */ + if ((BLEIFn(0)->BSTATUS_b.SPISTATUS == 0) && (BLEIF->BSTATUS_b.BLEIRQ == false)) { + am_hal_ble_wakeup_set(ble_handle, 1); + + /* If we've set wakeup, but IRQ came up at the same time, we should just lower WAKE again. */ + if (BLEIF->BSTATUS_b.BLEIRQ == true) { + am_hal_ble_wakeup_set(ble_handle, 0); + } + } + + AM_CRITICAL_END; +} + +/* + * Function used by the BLE stack to send HCI messages to the BLE controller. + * The payload is placed into a queue and the controller is turned on. When it is ready + * an interrupt will fire to handle sending a message + */ +static int +apollo3_hci_write(hci_drv_write_t *write_buf) +{ + /* Wake up the BLE controller. */ + apollo3_update_wake(); + + /* Wait on SPI status before writing */ + while (BLEIFn(0)->BSTATUS_b.SPISTATUS) { + os_time_delay(1); + } + + if (AM_HAL_STATUS_SUCCESS != + am_hal_ble_blocking_hci_write(ble_handle, AM_HAL_BLE_RAW, write_buf->data, write_buf->len)) { + return -1; + } + + return 0; +} + +static int +apollo3_ble_hci_acl_tx(struct os_mbuf *om) +{ + int rc = 0; + hci_drv_write_t write_buf; + uint8_t *ptr = (uint8_t *)write_buf.data; + + *ptr = HCI_H4_ACL; + ptr++; + write_buf.len = 1; + + os_mbuf_copydata(om, 0, OS_MBUF_PKTLEN(om), ptr); + write_buf.len += OS_MBUF_PKTLEN(om); + + rc = apollo3_hci_write(&write_buf); + + os_mbuf_free_chain(om); + + return (rc < 0) ? BLE_ERR_MEM_CAPACITY : 0; +} + +static int +apollo3_ble_hci_frame_cb(uint8_t pkt_type, void *data) +{ + int rc; + + switch (pkt_type) { + case HCI_H4_ACL: + rc = ble_transport_to_hs_acl(data); + break; + case HCI_H4_EVT: + rc = ble_transport_to_hs_evt(data); + break; + default: + assert(0); + break; + } + + return rc; +} + +static void +apollo3_ble_hci_init(void) +{ + SYSINIT_ASSERT_ACTIVE(); + + /* Enable interrupt to handle read based on BLECIRQ */ + NVIC_SetVector(BLE_IRQn, (uint32_t)apollo3_hci_int); + + /* Initial coldboot configuration */ + apollo3_hci_radio_boot(1); +} + +int +ble_transport_to_ll_cmd_impl(void *buf) +{ + int rc; + uint8_t *cmd = buf; + hci_drv_write_t write_buf; + uint8_t *ptr = (uint8_t *)write_buf.data; + + *ptr = HCI_H4_CMD; + ptr++; + write_buf.len = HCI_CMD_HDR_LEN + cmd[2] + 1; + memcpy(ptr, cmd, write_buf.len - 1); + + rc = apollo3_hci_write(&write_buf); + + ble_transport_free(cmd); + + return (rc < 0) ? BLE_ERR_MEM_CAPACITY : 0; +} + +int +ble_transport_to_ll_acl_impl(struct os_mbuf *om) +{ + return apollo3_ble_hci_acl_tx(om); +} + +void +ble_transport_ll_init(void) +{ + hci_h4_sm_init(&hci_apollo3_h4sm, &hci_h4_allocs_from_ll, + apollo3_ble_hci_frame_cb); + apollo3_ble_hci_init(); +} \ No newline at end of file diff --git a/nimble/transport/apollo3/syscfg.yml b/nimble/transport/apollo3/syscfg.yml new file mode 100644 index 0000000000..82e9f545de --- /dev/null +++ b/nimble/transport/apollo3/syscfg.yml @@ -0,0 +1,37 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +syscfg.defs: + BLE_TRANSPORT_APOLLO3_MAX_TX_PACKET: + description: > + Maximum TX packet size to controller in bytes. + value: 256 + + BLE_TRANSPORT_APOLLO3_MAX_RX_PACKET: + description: > + Maximum RX packet size from controller in bytes. + value: 256 + + BLE_TRANSPORT_APOLLO3_MAX_XTAL_RETRIES: + description: > + Maximum number of retries to boot radio when clock is found to be unstable. + value: 10 + +syscfg.restrictions: + - '!BLE_CONTROLLER' + - '!BLE_HS_FLOW_CTRL' diff --git a/nimble/transport/da1469x/pkg.yml b/nimble/transport/cdc/pkg.yml similarity index 72% rename from nimble/transport/da1469x/pkg.yml rename to nimble/transport/cdc/pkg.yml index 5d9b533cfb..3620ee1426 100644 --- a/nimble/transport/da1469x/pkg.yml +++ b/nimble/transport/cdc/pkg.yml @@ -6,7 +6,7 @@ # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at -# +# # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, @@ -17,22 +17,18 @@ # under the License. # -pkg.name: nimble/transport/da1469x -pkg.description: HCI transport for DA1469x +pkg.name: nimble/transport/cdc +pkg.description: HCI H4 transport over CDC pkg.author: "Apache Mynewt " -pkg.homepage: "http://mynewt.apache.org/" -pkg.keywords: - - ble - - bluetooth +pkg.homepage: "https://mynewt.apache.org/" pkg.deps: - - "@apache-mynewt-nimble/nimble" - - "@apache-mynewt-nimble/nimble/transport/da1469x/cmac_driver" + - "@apache-mynewt-core/hw/hal" - "@apache-mynewt-core/kernel/os" + - nimble + - nimble/transport/common/hci_h4 + - "@apache-mynewt-core/hw/usb/tinyusb" + - "@apache-mynewt-core/hw/usb/tinyusb/cdc" pkg.apis: - ble_transport - -pkg.init: - da1469x_ble_hci_init: 100 - da1469x_ble_hci_cmac_init: 201 diff --git a/nimble/transport/cdc/src/cdc_hci.c b/nimble/transport/cdc/src/cdc_hci.c new file mode 100644 index 0000000000..08c8f984a0 --- /dev/null +++ b/nimble/transport/cdc/src/cdc_hci.c @@ -0,0 +1,432 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define CDC_HCI_LOG_LEVEL 2 + +/* State machine for assembling packets from HOST (commands and ALCs) */ +static struct hci_h4_sm cdc_hci_h4sm; + +static const struct cdc_callbacks cdc_hci_callback; + +struct usb_in_packet; +struct usb_in_queue { + STAILQ_HEAD(, usb_in_packet) queue; +}; + +static struct os_mempool usb_in_packet_pool; + +#define USB_IN_PACKET_COUNT (MYNEWT_VAL(BLE_TRANSPORT_ACL_FROM_LL_COUNT) + \ + MYNEWT_VAL(BLE_TRANSPORT_EVT_COUNT) + \ + MYNEWT_VAL(BLE_TRANSPORT_EVT_DISCARDABLE_COUNT) + 1) + +typedef struct cdc_hci_itf { + /* CDC Interface */ + cdc_itf_t cdc_itf; + /* ACL or Evnet packet that is currently transferred over USB */ + struct usb_in_packet *current_in_packet; + int current_in_packet_offset; + /* ACL and Event packets that are waiting to be transmitted */ + struct usb_in_queue usb_in_queue; + uint8_t rx_buffer[USBD_CDC_DATA_EP_SIZE]; +} cdc_hci_itf_t; + +static cdc_hci_itf_t cdc_hci_itf = { + .cdc_itf.callbacks = &cdc_hci_callback, + .usb_in_queue = {STAILQ_HEAD_INITIALIZER(cdc_hci_itf.usb_in_queue.queue)}, +}; + +struct usb_packet_ops { + void (*packet_free)(struct usb_in_packet *packet); + int (*packet_write)(struct usb_in_packet *packet, size_t offset); + int (*packet_size)(struct usb_in_packet *packet); +}; + +struct usb_in_packet { + STAILQ_ENTRY(usb_in_packet) next; + const struct usb_packet_ops *ops; + void *data; +}; + +static uint8_t usb_in_packet_pool_mem[OS_MEMPOOL_BYTES(USB_IN_PACKET_COUNT, sizeof(struct usb_in_packet))]; + +static void +cdc_hci_rx_cb(cdc_itf_t *itf) +{ + int ret; + uint8_t cdc_num = itf->cdc_num; + uint32_t available = tud_cdc_n_available(cdc_num); + uint32_t received = 0; + int consumed = 0; + + while ((available > 0) || (received > consumed)) { + if (consumed == received) { + consumed = 0; + received = tud_cdc_n_read(cdc_num, cdc_hci_itf.rx_buffer, min(available, sizeof(cdc_hci_itf.rx_buffer))); + available = tud_cdc_n_available(cdc_num); + } + ret = hci_h4_sm_rx(&cdc_hci_h4sm, cdc_hci_itf.rx_buffer + consumed, received - consumed); + if (ret < 0) { + tud_cdc_n_read_flush(cdc_num); + break; + } + consumed += ret; + } +} + +static void +usb_in_packet_free(struct usb_in_packet *pkt) +{ + if (pkt) { + pkt->ops->packet_free(pkt); + os_memblock_put(&usb_in_packet_pool, pkt); + } +} + +static int +usb_in_packet_write(struct usb_in_packet *pkt, int offset) +{ + return pkt->ops->packet_write(pkt, offset); +} + +static int +usb_in_packet_size(struct usb_in_packet *pkt) +{ + if (pkt) { + return pkt->ops->packet_size(pkt); + } else { + return 0; + } +} + +static void +cdc_hci_send_next_in_packet(void) +{ + int sr; + struct usb_in_packet *last_packet; + + if (cdc_hci_itf.current_in_packet == NULL || + cdc_hci_itf.current_in_packet_offset == usb_in_packet_size(cdc_hci_itf.current_in_packet)) { + OS_ENTER_CRITICAL(sr); + last_packet = cdc_hci_itf.current_in_packet; + cdc_hci_itf.current_in_packet_offset = 0; + cdc_hci_itf.current_in_packet = STAILQ_FIRST(&cdc_hci_itf.usb_in_queue.queue); + if (cdc_hci_itf.current_in_packet) { + STAILQ_REMOVE_HEAD(&cdc_hci_itf.usb_in_queue.queue, next); + } + OS_EXIT_CRITICAL(sr); + usb_in_packet_free(last_packet); + } + if (cdc_hci_itf.current_in_packet != NULL && + cdc_hci_itf.current_in_packet_offset < usb_in_packet_size(cdc_hci_itf.current_in_packet)) { + cdc_hci_itf.current_in_packet_offset += usb_in_packet_write(cdc_hci_itf.current_in_packet, + cdc_hci_itf.current_in_packet_offset); + } +} + +static void +cdc_hci_tx_complete_cb(cdc_itf_t *itf) +{ + (void)itf; + + cdc_hci_send_next_in_packet(); +} + +static void +cdc_hci_line_state_cb(cdc_itf_t *itf, bool dtr, bool rts) +{ + (void)itf; + (void)rts; + + if (dtr) { + cdc_hci_send_next_in_packet(); + } +} + +static struct usb_in_packet * +cdc_hci_get_usb_in_packet(void) +{ + struct usb_in_packet *packet = (struct usb_in_packet *)os_memblock_get(&usb_in_packet_pool); + if (packet) { + packet->data = NULL; + } + return packet; +} + +static void +cdc_hci_send_next_in_packet_from_usbd_task(void *dummy) +{ + (void)dummy; + cdc_hci_send_next_in_packet(); +} + +static void +cdc_hci_usb_in_enqueue_packet(struct usb_in_packet *pkt) +{ + int sr; + + /* Add to IN queue */ + OS_ENTER_CRITICAL(sr); + STAILQ_INSERT_TAIL(&cdc_hci_itf.usb_in_queue.queue, pkt, next); + OS_EXIT_CRITICAL(sr); + + usbd_defer_func(cdc_hci_send_next_in_packet_from_usbd_task, NULL, true); +} + + +/* + * Returns packet size as seen over USB + */ +static int +cdc_hci_event_packet_size(struct usb_in_packet *packet) +{ + struct ble_hci_ev *event = packet->data; + return event->length + 2 /* opcode + length */ + 1 /* H4 header */; +} + +/* + * Free Event packet that BLE stack provided to USB stack. + * Function is called once all data was sent over USB IN endpoint. + */ +static void +cdc_hci_event_packet_free(struct usb_in_packet *packet) +{ + ble_transport_free(packet->data); +} + +/* + * Write Event packed from BLE stack to USB IN endpoint. + * Flush will be called separately. + */ +static int +cdc_hci_event_packet_write(struct usb_in_packet *packet, size_t offset) +{ + uint8_t cdc_num = cdc_hci_itf.cdc_itf.cdc_num; + const uint8_t *buf = ((const uint8_t *)packet->data) - 1; + const struct ble_hci_ev *hci_ev = packet->data; + size_t h4_event_size = hci_ev->length + sizeof(struct ble_hci_ev) + 1; + size_t new_offset = offset; + + /* Write H4 Event type */ + if (new_offset == 0) { + new_offset = tud_cdc_n_write_char(cdc_num, HCI_H4_EVT); + } + /* If first byte was not written rest of the event has to wait as well */ + if (new_offset > 0) { + new_offset += tud_cdc_n_write(cdc_num, buf + new_offset, h4_event_size - new_offset); + tud_cdc_n_write_flush(cdc_num); + } + + return (int)(new_offset - offset); +} + +/* + * USB IN endpoint packet handling functions for Events + */ +static const struct usb_packet_ops event_packet_ops = { + .packet_free = cdc_hci_event_packet_free, + .packet_write = cdc_hci_event_packet_write, + .packet_size = cdc_hci_event_packet_size, +}; + +/* + * Returns packet size as seen over USB + */ +static int +cdc_hci_acl_packet_size(struct usb_in_packet *packet) +{ + struct os_mbuf *om = (struct os_mbuf *)packet->data; + /* Data size of mbuf plus one for H4 header (2) */ + return os_mbuf_len(om) + 1; +} + +/* + * Free ACL data packet that BLE stack provided to USB stack. + * Function is called once all data was sent over USB IN endpoint. + */ +static void +cdc_hci_acl_packet_free(struct usb_in_packet *packet) +{ + struct os_mbuf *om = (struct os_mbuf *)packet->data; + + os_mbuf_free_chain(om); +} + +/* + * Write ACL packed from BLE stack to USB IN endpoint. + * Code traverses mbuf to send all data. + * Flush will be called separately. + */ +static int +cdc_hci_acl_packet_write(struct usb_in_packet *packet, size_t offset) +{ + uint8_t cdc_num = cdc_hci_itf.cdc_itf.cdc_num; + struct os_mbuf *om = (struct os_mbuf *)packet->data; + struct os_mbuf *mb; + size_t new_offset = offset; + uint16_t mbuf_offset; + size_t write_size; + size_t written; + + if (om) { + if (new_offset == 0) { + /* Write H4 ACL type */ + new_offset += tud_cdc_n_write_char(cdc_num, HCI_H4_ACL); + } + + for (;;) { + mb = os_mbuf_off(om, (int)new_offset - 1, &mbuf_offset); + assert(mb); + /* mbuf_offset is == om_len when new_offset reached end of mbuf data */ + if (mb->om_len == mbuf_offset) { + break; + } + /* Chunk in current mbuf */ + write_size = mb->om_len - mbuf_offset; + written = tud_cdc_n_write(cdc_num, mb->om_data + mbuf_offset, write_size); + new_offset += written; + /* USB FIFO did not have enough space for whole mbuf, stop write for now */ + if (written < write_size) { + break; + } + } + tud_cdc_n_write_flush(cdc_num); + } + + return (int)(new_offset - offset); +} + +/* + * USB IN endpoint packet handling functions for ACL data + */ +static const struct usb_packet_ops cdc_hci_acl_packet_ops = { + .packet_free = cdc_hci_acl_packet_free, + .packet_write = cdc_hci_acl_packet_write, + .packet_size = cdc_hci_acl_packet_size, +}; + +static int +cdc_hci_frame_cb(uint8_t pkt_type, void *data) +{ + switch (pkt_type) { + case HCI_H4_CMD: + return ble_transport_to_ll_cmd(data); + case HCI_H4_ACL: + return ble_transport_to_ll_acl(data); + default: + assert(0); + break; + } + + return -1; +} + +/* + * BLE stack callback with Event to be dispatched to USB IN endpoint. + */ +int +ble_transport_to_hs_evt_impl(void *buf) +{ + struct usb_in_packet *pkt; + + assert(buf != NULL); + + pkt = cdc_hci_get_usb_in_packet(); + if (pkt == NULL) { + ble_transport_free(buf); + return BLE_ERR_MEM_CAPACITY; + } + + pkt->data = buf; + pkt->ops = &event_packet_ops; + cdc_hci_usb_in_enqueue_packet(pkt); + + return 0; +} + +/* + * BLE stack callback with ACL data to be dispatched to USB IN endpoint. + */ +int +ble_transport_to_hs_acl_impl(struct os_mbuf *om) +{ + struct usb_in_packet *pkt; + + /* If this packet is zero length, just free it */ + if (OS_MBUF_PKTLEN(om) == 0) { + os_mbuf_free_chain(om); + return 0; + } + + pkt = cdc_hci_get_usb_in_packet(); + if (pkt == NULL) { + assert(0); + return -ENOMEM; + } + + pkt->data = om; + pkt->ops = &cdc_hci_acl_packet_ops; + cdc_hci_usb_in_enqueue_packet(pkt); + + return 0; +} + +void +ble_transport_hs_init(void) +{ + int rc; + + SYSINIT_ASSERT_ACTIVE(); + + rc = os_mempool_init(&usb_in_packet_pool, + USB_IN_PACKET_COUNT, + sizeof(struct usb_in_packet), + usb_in_packet_pool_mem, + "usb_in_packet_pool"); + + SYSINIT_PANIC_ASSERT(rc == 0); + + cdc_itf_add(&cdc_hci_itf.cdc_itf); + + hci_h4_sm_init(&cdc_hci_h4sm, &hci_h4_allocs_from_hs, cdc_hci_frame_cb); +} + +static const struct cdc_callbacks cdc_hci_callback = { + .cdc_rx_cb = cdc_hci_rx_cb, + .cdc_line_coding_cb = NULL, + .cdc_line_state_cb = cdc_hci_line_state_cb, + .cdc_rx_wanted_cb = NULL, + .cdc_send_break_cb = NULL, + .cdc_tx_complete_cb = cdc_hci_tx_complete_cb, +}; + diff --git a/nimble/transport/cdc/syscfg.yml b/nimble/transport/cdc/syscfg.yml new file mode 100644 index 0000000000..0336625093 --- /dev/null +++ b/nimble/transport/cdc/syscfg.yml @@ -0,0 +1,27 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +syscfg.defs: + USBD_CDC_HCI_DESCRIPTOR_STRING: + description: String for CDC/HCI interface + value: + + USBD_CDC_HCI: + description: Constant value indicating package usage + value: 1 + diff --git a/nimble/transport/common/hci_h4/include/nimble/transport/hci_h4.h b/nimble/transport/common/hci_h4/include/nimble/transport/hci_h4.h new file mode 100644 index 0000000000..6ad083a05f --- /dev/null +++ b/nimble/transport/common/hci_h4/include/nimble/transport/hci_h4.h @@ -0,0 +1,70 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _HCI_H4_H_ +#define _HCI_H4_H_ + +#include + +#define HCI_H4_NONE 0x00 +#define HCI_H4_CMD 0x01 +#define HCI_H4_ACL 0x02 +#define HCI_H4_EVT 0x04 +#define HCI_H4_ISO 0x05 + +typedef void *(hci_h4_alloc_cmd)(void); +typedef void *(hci_h4_alloc_evt)(int); +typedef struct os_mbuf *(hci_h4_alloc_acl)(void); +typedef struct os_mbuf *(hci_h4_alloc_iso)(void); + +struct hci_h4_allocators { + hci_h4_alloc_cmd *cmd; + hci_h4_alloc_acl *acl; + hci_h4_alloc_evt *evt; + hci_h4_alloc_iso *iso; +}; + +extern const struct hci_h4_allocators hci_h4_allocs_from_ll; +extern const struct hci_h4_allocators hci_h4_allocs_from_hs; + +typedef int (hci_h4_frame_cb)(uint8_t pkt_type, void *data); + +struct hci_h4_sm { + uint8_t state; + uint8_t pkt_type; + uint8_t min_len; + uint16_t len; + uint16_t exp_len; + uint8_t hdr[4]; + union { + uint8_t *buf; + struct os_mbuf *om; + }; + + const struct hci_h4_allocators *allocs; + hci_h4_frame_cb *frame_cb; +}; + +void hci_h4_sm_init(struct hci_h4_sm *h4sm, + const struct hci_h4_allocators *allocs, + hci_h4_frame_cb *frame_cb); + +int hci_h4_sm_rx(struct hci_h4_sm *h4sm, const uint8_t *buf, uint16_t len); + +#endif /* _HCI_H4_H_ */ diff --git a/nimble/transport/common/hci_h4/pkg.yml b/nimble/transport/common/hci_h4/pkg.yml new file mode 100644 index 0000000000..24c4b58071 --- /dev/null +++ b/nimble/transport/common/hci_h4/pkg.yml @@ -0,0 +1,26 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +pkg.name: nimble/transport/common/hci_h4 +pkg.description: HCI H4 protocol +pkg.author: "Apache Mynewt " +pkg.homepage: "https://mynewt.apache.org/" + +pkg.deps: + - nimble diff --git a/nimble/transport/common/hci_h4/src/hci_h4.c b/nimble/transport/common/hci_h4/src/hci_h4.c new file mode 100644 index 0000000000..fd89154a34 --- /dev/null +++ b/nimble/transport/common/hci_h4/src/hci_h4.c @@ -0,0 +1,339 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef min +#define min(a, b) ((a) < (b) ? (a) : (b)) +#endif + +#ifndef max +#define max(a, b) ((a) > (b) ? (a) : (b)) +#endif + +#define HCI_H4_SM_W4_PKT_TYPE 0 +#define HCI_H4_SM_W4_HEADER 1 +#define HCI_H4_SM_W4_PAYLOAD 2 +#define HCI_H4_SM_COMPLETED 3 + +const struct hci_h4_allocators hci_h4_allocs_from_ll = { + .acl = ble_transport_alloc_acl_from_ll, + .evt = ble_transport_alloc_evt, +}; +const struct hci_h4_allocators hci_h4_allocs_from_hs = { + .cmd = ble_transport_alloc_cmd, + .acl = ble_transport_alloc_acl_from_hs, + .iso = ble_transport_alloc_iso_from_hs, +}; + +struct hci_h4_input_buffer { + const uint8_t *buf; + uint16_t len; +}; + +static void +hci_h4_frame_start(struct hci_h4_sm *rxs, uint8_t pkt_type) +{ + rxs->pkt_type = pkt_type; + rxs->len = 0; + rxs->exp_len = 0; + + switch (rxs->pkt_type) { + case HCI_H4_CMD: + rxs->min_len = 3; + break; + case HCI_H4_ACL: + case HCI_H4_ISO: + rxs->min_len = 4; + break; + case HCI_H4_EVT: + rxs->min_len = 2; + break; + default: + /* XXX sync loss */ + assert(0); + break; + } +} + +static int +hci_h4_ib_consume(struct hci_h4_input_buffer *ib, uint16_t len) +{ + assert(ib->len >= len); + + ib->buf += len; + ib->len -= len; + + return len; +} + +static int +hci_h4_ib_pull_min_len(struct hci_h4_sm *rxs, + struct hci_h4_input_buffer *ib) +{ + uint16_t len; + + len = min(ib->len, rxs->min_len - rxs->len); + memcpy(&rxs->hdr[rxs->len], ib->buf, len); + + rxs->len += len; + hci_h4_ib_consume(ib, len); + + return rxs->len != rxs->min_len; +} + +static int +hci_h4_sm_w4_header(struct hci_h4_sm *h4sm, struct hci_h4_input_buffer *ib) +{ + int rc; + + rc = hci_h4_ib_pull_min_len(h4sm, ib); + if (rc) { + /* need more data */ + return 1; + } + + switch (h4sm->pkt_type) { + case HCI_H4_CMD: + assert(h4sm->allocs && h4sm->allocs->cmd); + h4sm->buf = h4sm->allocs->cmd(); + if (!h4sm->buf) { + return -1; + } + + memcpy(h4sm->buf, h4sm->hdr, h4sm->len); + h4sm->exp_len = h4sm->hdr[2] + 3; + break; + case HCI_H4_ACL: + assert(h4sm->allocs && h4sm->allocs->acl); + h4sm->om = h4sm->allocs->acl(); + if (!h4sm->om) { + return -1; + } + + os_mbuf_append(h4sm->om, h4sm->hdr, h4sm->len); + h4sm->exp_len = get_le16(&h4sm->hdr[2]) + 4; + break; + case HCI_H4_EVT: + if (h4sm->hdr[0] == BLE_HCI_EVCODE_LE_META) { + /* For LE Meta event we need 3 bytes to parse header */ + h4sm->min_len = 3; + rc = hci_h4_ib_pull_min_len(h4sm, ib); + if (rc) { + /* need more data */ + return 1; + } + } + + assert(h4sm->allocs && h4sm->allocs->evt); + + /* We can drop legacy advertising events if there's no free buffer in + * discardable pool. + */ + if (h4sm->hdr[2] == BLE_HCI_LE_SUBEV_ADV_RPT) { + h4sm->buf = h4sm->allocs->evt(1); + } else { + h4sm->buf = h4sm->allocs->evt(0); + if (!h4sm->buf) { + return -1; + } + } + + if (h4sm->buf) { + memcpy(h4sm->buf, h4sm->hdr, h4sm->len); + } + + h4sm->exp_len = h4sm->hdr[1] + 2; + if (h4sm->exp_len > MYNEWT_VAL(BLE_TRANSPORT_EVT_SIZE)) { + return -1; + } + break; + case HCI_H4_ISO: + assert(h4sm->allocs && h4sm->allocs->iso); + h4sm->om = h4sm->allocs->iso(); + if (!h4sm->om) { + return -1; + } + + os_mbuf_append(h4sm->om, h4sm->hdr, h4sm->len); + h4sm->exp_len = BLE_HCI_ISO_LENGTH(get_le16(&h4sm->hdr[2])) + 4; + break; + default: + assert(0); + break; + } + + return 0; +} + +static int +hci_h4_sm_w4_payload(struct hci_h4_sm *h4sm, + struct hci_h4_input_buffer *ib) +{ + uint16_t mbuf_len; + uint16_t len; + int rc; + + len = min(ib->len, h4sm->exp_len - h4sm->len); + + switch (h4sm->pkt_type) { + case HCI_H4_CMD: + case HCI_H4_EVT: + if (h4sm->buf) { + memcpy(&h4sm->buf[h4sm->len], ib->buf, len); + } + break; + case HCI_H4_ACL: + case HCI_H4_ISO: + assert(h4sm->om); + + mbuf_len = OS_MBUF_PKTLEN(h4sm->om); + rc = os_mbuf_append(h4sm->om, ib->buf, len); + if (rc) { + /* Some data may already be appended so need to adjust h4sm only by + * the size of appended data. + */ + len = OS_MBUF_PKTLEN(h4sm->om) - mbuf_len; + h4sm->len += len; + hci_h4_ib_consume(ib, len); + + return -1; + } + break; + default: + assert(0); + break; + } + + h4sm->len += len; + hci_h4_ib_consume(ib, len); + + /* return 1 if need more data */ + return h4sm->len != h4sm->exp_len; +} + +static void +hci_h4_sm_completed(struct hci_h4_sm *h4sm) +{ + int rc; + + switch (h4sm->pkt_type) { + case HCI_H4_CMD: + case HCI_H4_EVT: + if (h4sm->buf) { + assert(h4sm->frame_cb); + rc = h4sm->frame_cb(h4sm->pkt_type, h4sm->buf); + if (rc != 0) { + ble_transport_free(h4sm->buf); + } + h4sm->buf = NULL; + } + break; + case HCI_H4_ACL: + case HCI_H4_ISO: + if (h4sm->om) { + assert(h4sm->frame_cb); + rc = h4sm->frame_cb(h4sm->pkt_type, h4sm->om); + if (rc != 0) { + os_mbuf_free_chain(h4sm->om); + } + h4sm->om = NULL; + } + break; + default: + assert(0); + break; + } +} + +int +hci_h4_sm_rx(struct hci_h4_sm *h4sm, const uint8_t *buf, uint16_t len) +{ + struct hci_h4_input_buffer ib = { + .buf = buf, + .len = len, + }; + + int rc = 0; + while (ib.len && (rc >= 0)) { + rc = 0; + switch (h4sm->state) { + case HCI_H4_SM_W4_PKT_TYPE: + hci_h4_frame_start(h4sm, ib.buf[0]); + hci_h4_ib_consume(&ib, 1); + h4sm->state = HCI_H4_SM_W4_HEADER; + /* no break */ + case HCI_H4_SM_W4_HEADER: + rc = hci_h4_sm_w4_header(h4sm, &ib); + assert(rc >= 0); + if (rc) { + break; + } + h4sm->state = HCI_H4_SM_W4_PAYLOAD; + /* no break */ + case HCI_H4_SM_W4_PAYLOAD: + rc = hci_h4_sm_w4_payload(h4sm, &ib); + assert(rc >= 0); + if (rc) { + break; + } + h4sm->state = HCI_H4_SM_COMPLETED; + /* no break */ + case HCI_H4_SM_COMPLETED: + hci_h4_sm_completed(h4sm); + h4sm->state = HCI_H4_SM_W4_PKT_TYPE; + break; + default: + assert(0); + break; + } + } + + /* Calculate consumed bytes + * + * Note: we should always consume some bytes unless there is an oom error. + * It's also possible that we have an oom error but already consumed some + * data, in such case just return success and error will be returned on next + * pass. + */ + len = len - ib.len; + if (len == 0) { + assert(rc < 0); + return -1; + } + + return len; +} + +void +hci_h4_sm_init(struct hci_h4_sm *h4sm, const struct hci_h4_allocators *allocs, + hci_h4_frame_cb *frame_cb) +{ + memset(h4sm, 0, sizeof(*h4sm)); + h4sm->allocs = allocs; + h4sm->frame_cb = frame_cb; +} diff --git a/nimble/transport/common/hci_ipc/include/nimble/transport/hci_ipc.h b/nimble/transport/common/hci_ipc/include/nimble/transport/hci_ipc.h new file mode 100644 index 0000000000..551fb93d4c --- /dev/null +++ b/nimble/transport/common/hci_ipc/include/nimble/transport/hci_ipc.h @@ -0,0 +1,99 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _HCI_IPC_H_ +#define _HCI_IPC_H_ + +#include + +#define HCI_IPC_TYPE_CMD 0x01 +#define HCI_IPC_TYPE_ACL 0x02 +#define HCI_IPC_TYPE_EVT 0x04 +#define HCI_IPC_TYPE_EVT_DISCARDABLE 0x05 +#define HCI_IPC_TYPE_EVT_IN_CMD 0x06 +#define HCI_IPC_TYPE_ISO 0x07 + +struct __attribute__((packed)) hci_ipc_hdr { + uint8_t type; + uint16_t length; +}; + +struct hci_ipc_sm { + struct hci_ipc_hdr hdr; + uint8_t hdr_len; + uint16_t rem_len; + uint16_t buf_len; + + union { + uint8_t *buf; + struct os_mbuf *om; + }; +}; + +struct hci_ipc_shm { + uint16_t n2a_num_acl; + uint16_t n2a_num_evt; + uint16_t n2a_num_evt_disc; +}; + +void hci_ipc_init(volatile struct hci_ipc_shm *shm, struct hci_ipc_sm *sm); +int hci_ipc_rx(struct hci_ipc_sm *sm, const uint8_t *buf, uint16_t len); + +extern void hci_ipc_atomic_put(volatile uint16_t *num); +extern uint16_t hci_ipc_atomic_get(volatile uint16_t *num); + +/* Just to optimize static inlines below, do not use directly! */ +extern volatile struct hci_ipc_shm *g_ipc_shm; + +static inline int +hci_ipc_get(uint8_t type) +{ + volatile struct hci_ipc_shm *shm = g_ipc_shm; + + switch (type) { + case HCI_IPC_TYPE_ACL: + return hci_ipc_atomic_get(&shm->n2a_num_acl); + case HCI_IPC_TYPE_EVT: + return hci_ipc_atomic_get(&shm->n2a_num_evt); + case HCI_IPC_TYPE_EVT_DISCARDABLE: + return hci_ipc_atomic_get(&shm->n2a_num_evt_disc); + } + + return 0; +} + +static inline void +hci_ipc_put(uint8_t type) +{ + volatile struct hci_ipc_shm *shm = g_ipc_shm; + + switch (type) { + case HCI_IPC_TYPE_ACL: + hci_ipc_atomic_put(&shm->n2a_num_acl); + break; + case HCI_IPC_TYPE_EVT: + hci_ipc_atomic_put(&shm->n2a_num_evt); + break; + case HCI_IPC_TYPE_EVT_DISCARDABLE: + hci_ipc_atomic_put(&shm->n2a_num_evt_disc); + break; + } +} + +#endif /* _HCI_IPC_H_ */ diff --git a/nimble/transport/common/hci_ipc/pkg.yml b/nimble/transport/common/hci_ipc/pkg.yml new file mode 100644 index 0000000000..b66a332090 --- /dev/null +++ b/nimble/transport/common/hci_ipc/pkg.yml @@ -0,0 +1,26 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +pkg.name: nimble/transport/common/hci_ipc +pkg.description: Custom HCI IPC protocol +pkg.author: "Apache Mynewt " +pkg.homepage: "https://mynewt.apache.org/" + +pkg.deps: + - nimble diff --git a/nimble/transport/common/hci_ipc/src/hci_ipc.c b/nimble/transport/common/hci_ipc/src/hci_ipc.c new file mode 100644 index 0000000000..f1ebbd8953 --- /dev/null +++ b/nimble/transport/common/hci_ipc/src/hci_ipc.c @@ -0,0 +1,242 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef min +#define min(a, b) ((a) < (b) ? (a) : (b)) +#endif + +#ifndef max +#define max(a, b) ((a) > (b) ? (a) : (b)) +#endif + +volatile struct hci_ipc_shm *g_ipc_shm; + +static void +hci_ipc_alloc(struct hci_ipc_sm *sm) +{ + assert(sm->hdr.type); + assert(sm->buf == NULL); + + switch (sm->hdr.type) { +#if MYNEWT_VAL(BLE_CONTROLLER) + case HCI_IPC_TYPE_CMD: + sm->buf = ble_transport_alloc_cmd(); + break; +#endif + case HCI_IPC_TYPE_ACL: +#if MYNEWT_VAL(BLE_CONTROLLER) + sm->om = ble_transport_alloc_acl_from_hs(); +#else + sm->om = ble_transport_alloc_acl_from_ll(); +#endif + break; +#if !MYNEWT_VAL(BLE_CONTROLLER) + case HCI_IPC_TYPE_EVT: + sm->buf = ble_transport_alloc_evt(0); + break; + case HCI_IPC_TYPE_EVT_DISCARDABLE: + sm->buf = ble_transport_alloc_evt(1); + break; + case HCI_IPC_TYPE_EVT_IN_CMD: + sm->buf = ble_transport_alloc_cmd(); + break; +#endif + case HCI_IPC_TYPE_ISO: +#if MYNEWT_VAL(BLE_CONTROLLER) + sm->om = ble_transport_alloc_iso_from_hs(); +#else + sm->om = ble_transport_alloc_iso_from_ll(); +#endif + break; + default: + assert(0); + break; + } + + assert(sm->buf); + + sm->rem_len = sm->hdr.length; + sm->buf_len = 0; +} + +static bool +hci_ipc_has_hdr(struct hci_ipc_sm *sm) +{ + return sm->hdr_len == sizeof(sm->hdr); +} + +static void +hci_ipc_frame(struct hci_ipc_sm *sm) +{ + assert(sm->hdr.type); + assert(sm->buf); + assert(sm->rem_len == 0); + + switch (sm->hdr.type) { +#if MYNEWT_VAL(BLE_CONTROLLER) + case HCI_IPC_TYPE_CMD: + ble_transport_to_ll_cmd(sm->buf); + break; +#endif + case HCI_IPC_TYPE_ACL: +#if MYNEWT_VAL(BLE_CONTROLLER) + ble_transport_to_ll_acl(sm->om); +#else + ble_transport_to_hs_acl(sm->om); +#endif + break; +#if !MYNEWT_VAL(BLE_CONTROLLER) + case HCI_IPC_TYPE_EVT: + case HCI_IPC_TYPE_EVT_DISCARDABLE: + case HCI_IPC_TYPE_EVT_IN_CMD: + ble_transport_to_hs_evt(sm->buf); + break; +#endif + case HCI_IPC_TYPE_ISO: +#if MYNEWT_VAL(BLE_CONTROLLER) + ble_transport_to_ll_iso(sm->om); +#else + ble_transport_to_hs_iso(sm->om); +#endif + break; + default: + assert(0); + break; + } + + sm->hdr.type = 0; + sm->hdr.length = 0; + sm->hdr_len = 0; + sm->buf_len = 0; + sm->rem_len = 0; + sm->buf = NULL; +} + +static uint16_t +hci_ipc_copy_to_hdr(struct hci_ipc_sm *sm, const uint8_t *buf, uint16_t len) +{ + uint16_t rem_hdr_len; + uint8_t *p; + + if (hci_ipc_has_hdr(sm)) { + return 0; + } + + rem_hdr_len = sizeof(sm->hdr) - sm->hdr_len; + len = min(len, rem_hdr_len); + + p = (void *)&sm->hdr; + memcpy(p + sm->hdr_len, buf, len); + + sm->hdr_len += len; + + if (hci_ipc_has_hdr(sm)) { + hci_ipc_alloc(sm); + } + + return len; +} + +static uint16_t +hci_ipc_copy_to_buf(struct hci_ipc_sm *sm, const uint8_t *buf, uint16_t len) +{ + int rc; + + assert(sm->hdr.type); + assert(sm->buf); + + len = min(len, sm->rem_len); + + switch (sm->hdr.type) { +#if MYNEWT_VAL(BLE_CONTROLLER) + case HCI_IPC_TYPE_CMD: +#else + case HCI_IPC_TYPE_EVT: + case HCI_IPC_TYPE_EVT_DISCARDABLE: + case HCI_IPC_TYPE_EVT_IN_CMD: +#endif + memcpy(sm->buf + sm->buf_len, buf, len); + break; + case HCI_IPC_TYPE_ACL: + case HCI_IPC_TYPE_ISO: + rc = os_mbuf_append(sm->om, buf, len); + assert(rc == 0); + break; + default: + assert(0); + break; + } + + sm->rem_len -= len; + sm->buf_len += len; + + if (sm->rem_len == 0) { + hci_ipc_frame(sm); + } + + return len; +} + +int +hci_ipc_rx(struct hci_ipc_sm *sm, const uint8_t *buf, uint16_t len) +{ + uint16_t rem_len = len; + uint16_t copy_len; + + while (rem_len) { + if (hci_ipc_has_hdr(sm)) { + copy_len = hci_ipc_copy_to_buf(sm, buf, rem_len); + } else { + copy_len = hci_ipc_copy_to_hdr(sm, buf, rem_len); + } + + rem_len -= copy_len; + buf += copy_len; + } + + return len; +} + +void +hci_ipc_init(volatile struct hci_ipc_shm *shm, struct hci_ipc_sm *sm) +{ + assert(g_ipc_shm == NULL); + + g_ipc_shm = shm; + memset(sm, 0, sizeof(*sm)); + +#if MYNEWT_VAL(BLE_CONTROLLER) + while (shm->n2a_num_evt_disc == 0) { + /* Wait until app side initializes credits */ + } +#else + shm->n2a_num_acl = MYNEWT_VAL(BLE_TRANSPORT_ACL_FROM_LL_COUNT); + shm->n2a_num_evt = MYNEWT_VAL(BLE_TRANSPORT_EVT_COUNT); + shm->n2a_num_evt_disc = MYNEWT_VAL(BLE_TRANSPORT_EVT_DISCARDABLE_COUNT); +#endif +} diff --git a/nimble/transport/da1469x/.gitignore b/nimble/transport/da1469x/.gitignore deleted file mode 100644 index bba9f995af..0000000000 --- a/nimble/transport/da1469x/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/src/libble_stack_da1469x.a - diff --git a/nimble/transport/da1469x/README b/nimble/transport/da1469x/README deleted file mode 100644 index b30a01c48a..0000000000 --- a/nimble/transport/da1469x/README +++ /dev/null @@ -1,13 +0,0 @@ -Integrated BLE Controller (CMAC) requires a binary firmware to be loaded. Such -firmware is distributed by Dialog Semiconductor in SDK package which has to be -obtained separately, see: -https://www.dialog-semiconductor.com/products/da1469x-product-family - -Firmware is available as part of following library in SDK package: -sdk/interfaces/ble/binaries/DA1469x-Release/libble_stack_da1469x.a - -By default, CMAC driver will look for this file in its package root directory -(i.e. nimble/transport/da1469x/cmac_driver) but this can be changed using -CMAC_IMAGE_FILE_NAME syscfg variable. - -Current version of CMAC driver was tested with SDK version 10.0.4.66. diff --git a/nimble/transport/da1469x/cmac_driver/scripts/build_libcmac.sh b/nimble/transport/da1469x/cmac_driver/scripts/build_libcmac.sh deleted file mode 100755 index 659c2b9f34..0000000000 --- a/nimble/transport/da1469x/cmac_driver/scripts/build_libcmac.sh +++ /dev/null @@ -1,51 +0,0 @@ -#!/bin/bash - -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - -if [ ! -f ${MYNEWT_VAL_CMAC_IMAGE_FILE_NAME} ]; then - >&2 echo ERROR: BLE stack library not found. Please check nimble/transport/da1469x/README for details. - exit 1 -fi - -OBJCOPY=${MYNEWT_OBJCOPY_PATH} -AR=${MYNEWT_AR_PATH} -LIBBLE_A=$(readlink -e ${MYNEWT_VAL_CMAC_IMAGE_FILE_NAME}) -LIBCMAC_A=${MYNEWT_USER_SRC_DIR}/libcmac.a - -BASENAME_ROM=cmac.rom -BASENAME_RAM=cmac.ram - -cd ${MYNEWT_USER_WORK_DIR} - -# Extract firmware binary from .a since we do not need to link all other -# objects with our image. -${AR} x ${LIBBLE_A} cmac_fw.c.obj -${OBJCOPY} -O binary --only-section=.cmi_fw_area cmac_fw.c.obj cmac.bin - -# We need separate copies for RAM and ROM image since section names are derived -# from file names. For now files are the same, but it would be possible to -# link ROM image without data and shared sections which contains zeroes anyway. -cp cmac.bin ${BASENAME_ROM}.bin -cp cmac.bin ${BASENAME_RAM}.bin - -# Convert both binaries to objects and create archive to link -${OBJCOPY} -I binary -O elf32-littlearm -B armv8-m.main \ - --rename-section .data=.libcmac.rom ${BASENAME_ROM}.bin ${BASENAME_ROM}.o -${OBJCOPY} -I binary -O elf32-littlearm -B armv8-m.main \ - --rename-section .data=.libcmac.ram ${BASENAME_RAM}.bin ${BASENAME_RAM}.o -${AR} -rcs ${LIBCMAC_A} ${BASENAME_ROM}.o ${BASENAME_RAM}.o diff --git a/nimble/transport/da1469x/cmac_driver/src/cmac_host.c b/nimble/transport/da1469x/cmac_driver/src/cmac_host.c deleted file mode 100644 index 0bfb715e55..0000000000 --- a/nimble/transport/da1469x/cmac_driver/src/cmac_host.c +++ /dev/null @@ -1,326 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#include -#include -#include -#include -#include "os/os.h" -#include "mcu/cmsis_nvic.h" -#include "mcu/da1469x_lpclk.h" -#include "mcu/da1469x_hal.h" -#include "mcu/da1469x_pdc.h" -#include "mcu/mcu.h" -#include "cmac_driver/cmac_host.h" - -#define CMAC_SYM_CONFIG ((void *)(0x00818f20 + MEMCTRL->CMI_CODE_BASE_REG)) -#define CMAC_SYM_CONFIG_DYN ((void *)(0x00821af8 + MEMCTRL->CMI_CODE_BASE_REG)) -#define CMAC_SYM_MBOX_RX ((void *)(0x008216b0 + MEMCTRL->CMI_CODE_BASE_REG)) -#define CMAC_SYM_MBOX_TX ((void *)(0x008218b0 + MEMCTRL->CMI_CODE_BASE_REG)) - -#define CMAC_MBOX_SIZE 504 -#define CMAC_MBOX_F_RESET 0x0008 -#define CMAC_MBOX_F_WRITEPENDING 0x0010 - -struct cmac_config { - uint8_t bdaddr[6]; /* Device address */ - - uint8_t rf_calibration_delay; - - uint8_t lp_clock_freq; /* Sleep clock frequency (0 = 32768Hz, 1 = 32000Hz) */ - uint16_t lp_clock_sca; /* Sleep clock accuracy [ppm] */ - - uint16_t rx_buf_len; /* RX buffer size */ - uint16_t tx_buf_len; /* TX buffer size */ - bool initial_length_req; - - /* Channel assessment algorithm settings */ - uint16_t chan_assess_itvl; - uint8_t chan_assess_itvl_mult; - int8_t chan_assess_min_rssi; - uint16_t chan_assess_pkt_num; - uint16_t chan_assess_bad_pkt_num; - - /* Calibration settings */ - uint8_t system_tcs_length; - uint8_t synth_tcs_length; - uint8_t rfcu_tcs_length; - - uint8_t default_tx_power; /* Default TX power for connection/advertising */ - bool filter_dup_ov_discard; /* Discard unknown devices when filter buffer is full */ - bool use_hp_1m; - bool use_hp_2m; -}; - -struct cmac_config_dynamic { - bool enable_sleep; /* Enable sleep */ - - /* More options here, don't care now */ -}; - -struct cmac_mbox { - volatile uint16_t magic; - volatile uint16_t flags; - volatile uint16_t wr_off; - volatile uint16_t rd_off; - uint8_t data[CMAC_MBOX_SIZE]; -}; - -/* CMAC data */ -extern char _binary_cmac_rom_bin_start[]; -extern char _binary_cmac_rom_bin_end; -extern char _binary_cmac_ram_bin_start[]; -extern char _binary_cmac_ram_bin_end; - -struct cmac_image_info { - uint32_t _dummy1; - uint32_t size_rom; - uint32_t _dummy2; - uint32_t magic; - uint32_t _dummy3[5]; -}; - -/* Mailboxes for SYS<->CMAC communication */ -static struct cmac_mbox *cmac_mbox_rx; -static struct cmac_mbox *cmac_mbox_tx; - -/* PDC entry for waking up CMAC */ -static int8_t g_cmac_host_pdc_sys2cmac; -/* PDC entry for waking up M33 */ -static int8_t g_cmac_host_pdc_cmac2sys; -/* Callback for data ready from CMAC */ -static cmac_mbox_read_cb g_cmac_mbox_read_cb; - -static inline void -cmac_host_signal2cmac(void) -{ - da1469x_pdc_set(g_cmac_host_pdc_sys2cmac); -} - -static void -cmac2sys_isr(void) -{ - uint16_t wr_off; - uint16_t rd_off; - uint16_t chunk; - uint16_t len; - - os_trace_isr_enter(); - - /* Clear CMAC2SYS interrupt */ - *(volatile uint32_t *)0x40002000 = 2; - - if (*(volatile uint32_t *)0x40002000 & 0x1c00) { - /* XXX CMAC is in error state, need to recover */ - assert(0); - } - - if (cmac_mbox_rx->flags & CMAC_MBOX_F_RESET) { - cmac_mbox_rx->flags &= ~CMAC_MBOX_F_RESET; - goto done; - } - - if (!g_cmac_mbox_read_cb) { - cmac_mbox_rx->rd_off = cmac_mbox_rx->wr_off; - goto done; - } - - do { - rd_off = cmac_mbox_rx->rd_off; - wr_off = cmac_mbox_rx->wr_off; - - if (rd_off <= wr_off) { - chunk = wr_off - rd_off; - } else { - chunk = CMAC_MBOX_SIZE - rd_off; - } - - while (chunk) { - len = g_cmac_mbox_read_cb(&cmac_mbox_rx->data[rd_off], chunk); - - rd_off += len; - chunk -= len; - }; - - cmac_mbox_rx->rd_off = rd_off % CMAC_MBOX_SIZE; - } while (cmac_mbox_rx->rd_off != cmac_mbox_rx->wr_off); - -done: - - if (cmac_mbox_rx->flags & CMAC_MBOX_F_WRITEPENDING) { - cmac_host_signal2cmac(); - } - - os_trace_isr_exit(); -} - -static void -cmac_host_lpclk_cb(uint32_t freq) -{ - struct cmac_config_dynamic *cmac_config_dyn; - - cmac_config_dyn = CMAC_SYM_CONFIG_DYN; - cmac_config_dyn->enable_sleep = freq == 32768; -} - -void -cmac_mbox_write(const uint8_t *buf, size_t len) -{ - uint16_t wr_off; - uint16_t rd_off; - uint16_t chunk; - uint32_t primask; - - __HAL_DISABLE_INTERRUPTS(primask); - - while (len) { - rd_off = cmac_mbox_tx->rd_off; - wr_off = cmac_mbox_tx->wr_off; - - if (rd_off > wr_off) { - chunk = min(len, rd_off - wr_off); - } else { - chunk = min(len, CMAC_MBOX_SIZE - wr_off); - } - - if (chunk == 0) { - continue; - } - - memcpy(&cmac_mbox_tx->data[wr_off], buf, chunk); - - wr_off += chunk; - cmac_mbox_tx->wr_off = wr_off % CMAC_MBOX_SIZE; - - cmac_host_signal2cmac(); - - len -= chunk; - buf += chunk; - } - - __HAL_ENABLE_INTERRUPTS(primask); -} - -void -cmac_mbox_set_read_cb(cmac_mbox_read_cb cb) -{ - g_cmac_mbox_read_cb = cb; -} - -void -cmac_host_init(void) -{ - struct cmac_image_info ii; - uint32_t cmac_rom_size; - uint32_t cmac_ram_size; - struct cmac_config *cmac_config; - struct cmac_config_dynamic *cmac_config_dyn; - - /* Add PDC entry to wake up CMAC from M33 */ - g_cmac_host_pdc_sys2cmac = da1469x_pdc_add(MCU_PDC_TRIGGER_MAC_TIMER, - MCU_PDC_MASTER_CMAC, - MCU_PDC_EN_XTAL); - da1469x_pdc_set(g_cmac_host_pdc_sys2cmac); - da1469x_pdc_ack(g_cmac_host_pdc_sys2cmac); - - /* Add PDC entry to wake up M33 from CMAC, if does not exist yet */ - g_cmac_host_pdc_cmac2sys = da1469x_pdc_find(MCU_PDC_TRIGGER_COMBO, - MCU_PDC_MASTER_M33, 0); - if (g_cmac_host_pdc_cmac2sys < 0) { - g_cmac_host_pdc_cmac2sys = da1469x_pdc_add(MCU_PDC_TRIGGER_COMBO, - MCU_PDC_MASTER_M33, - MCU_PDC_EN_XTAL); - da1469x_pdc_set(g_cmac_host_pdc_cmac2sys); - da1469x_pdc_ack(g_cmac_host_pdc_cmac2sys); - } - - /* Enable Radio LDO */ - CRG_TOP->POWER_CTRL_REG |= CRG_TOP_POWER_CTRL_REG_LDO_RADIO_ENABLE_Msk; - - /* Enable CMAC, but keep it in reset */ - CRG_TOP->CLK_RADIO_REG = (1 << CRG_TOP_CLK_RADIO_REG_RFCU_ENABLE_Pos) | - (1 << CRG_TOP_CLK_RADIO_REG_CMAC_SYNCH_RESET_Pos) | - (0 << CRG_TOP_CLK_RADIO_REG_CMAC_CLK_SEL_Pos) | - (1 << CRG_TOP_CLK_RADIO_REG_CMAC_CLK_ENABLE_Pos) | - (0 << CRG_TOP_CLK_RADIO_REG_CMAC_DIV_Pos); - - /* Calculate size of ROM and RAM area (for now they should be the same) */ - cmac_rom_size = &_binary_cmac_rom_bin_end - &_binary_cmac_rom_bin_start[0]; - cmac_ram_size = &_binary_cmac_ram_bin_end - &_binary_cmac_ram_bin_start[0]; - assert(cmac_rom_size == cmac_ram_size); - - /* Load image header and check if image can be loaded */ - memcpy(&ii, &_binary_cmac_rom_bin_start, sizeof(ii)); - assert(ii.magic == 0x43414d43); /* "CMAC" */ - - /* Copy CMAC image to RAM */ - memset(&_binary_cmac_ram_bin_start, 0, cmac_ram_size); - memcpy(&_binary_cmac_ram_bin_start, &_binary_cmac_rom_bin_start[sizeof(ii)], - ii.size_rom); - - /* - * Setup memory controller for CMAC - * Code and data are set to the same address initially since CMAC will - * update data address on init. Also shared address is updated on init. - */ - MEMCTRL->CMI_CODE_BASE_REG = (uint32_t)&_binary_cmac_ram_bin_start; - MEMCTRL->CMI_DATA_BASE_REG = MEMCTRL->CMI_CODE_BASE_REG; - MEMCTRL->CMI_SHARED_BASE_REG = 0; - MEMCTRL->CMI_END_REG = (uint32_t)&_binary_cmac_ram_bin_end; - - /* Symbols below are in shared memory, can update them now */ - cmac_config = CMAC_SYM_CONFIG; - cmac_config_dyn = CMAC_SYM_CONFIG_DYN; - cmac_mbox_rx = CMAC_SYM_MBOX_RX; - cmac_mbox_tx = CMAC_SYM_MBOX_TX; - - /* Update CMAC configuration */ - cmac_config->lp_clock_freq = 0; - cmac_config->lp_clock_sca = 50; - cmac_config->rx_buf_len = 251 + 11; - cmac_config->tx_buf_len = 251 + 11; - cmac_config->initial_length_req = 0; - cmac_config->system_tcs_length = 0; - cmac_config->synth_tcs_length = 0; - cmac_config->rfcu_tcs_length = 0; - cmac_config->default_tx_power = 4; - cmac_config_dyn->enable_sleep = false; - - /* Release CMAC from reset */ - CRG_TOP->CLK_RADIO_REG &= ~CRG_TOP_CLK_RADIO_REG_CMAC_SYNCH_RESET_Msk; - - /* Wait for CMAC to update registers */ - while (MEMCTRL->CMI_DATA_BASE_REG == MEMCTRL->CMI_CODE_BASE_REG); - while (MEMCTRL->CMI_SHARED_BASE_REG != (MEMCTRL->CMI_END_REG & 0xfffffc00)); - - /* Initialize mailboxes and sync with CMAC */ - cmac_mbox_tx->flags = CMAC_MBOX_F_RESET; - cmac_mbox_tx->wr_off = 0; - cmac_mbox_tx->rd_off = 0; - cmac_mbox_tx->magic = 0xa55a; - while (cmac_mbox_rx->magic != 0xa55a); - - NVIC_SetVector(CMAC2SYS_IRQn, (uint32_t)cmac2sys_isr); - NVIC_SetPriority(CMAC2SYS_IRQn, 0); - NVIC_EnableIRQ(CMAC2SYS_IRQn); - - cmac_host_signal2cmac(); - - da1469x_lpclk_register_cmac_cb(cmac_host_lpclk_cb); -} diff --git a/nimble/transport/da1469x/src/da1469x_ble_hci.c b/nimble/transport/da1469x/src/da1469x_ble_hci.c deleted file mode 100644 index 971d0cd047..0000000000 --- a/nimble/transport/da1469x/src/da1469x_ble_hci.c +++ /dev/null @@ -1,368 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#include -#include -#include "os/mynewt.h" -#include "nimble/ble.h" -#include "nimble/ble_hci_trans.h" -#include "nimble/hci_common.h" -#include "cmac_driver/cmac_host.h" - -#define HCI_PKT_NONE 0x00 -#define HCI_PKT_CMD 0x01 -#define HCI_PKT_ACL 0x02 -#define HCI_PKT_EVT 0x04 - -#define POOL_ACL_BLOCK_SIZE \ - OS_ALIGN(MYNEWT_VAL(BLE_ACL_BUF_SIZE) + \ - BLE_MBUF_MEMBLOCK_OVERHEAD + \ - BLE_HCI_DATA_HDR_SZ, OS_ALIGNMENT) - -struct da1469x_ble_hci_host_api { - ble_hci_trans_rx_cmd_fn *evt_cb; - void *evt_arg; - ble_hci_trans_rx_acl_fn *acl_cb; - void *acl_arg; -}; - -struct da1469x_ble_hci_rx_data { - uint8_t type; - uint8_t hdr[4]; - uint8_t min_len; - uint16_t len; - uint16_t expected_len; - union { - uint8_t *buf; - struct os_mbuf *om; - }; -}; - -struct da1469x_ble_hci_pool_cmd { - uint8_t cmd[BLE_HCI_TRANS_CMD_SZ]; - bool allocated; -}; - -/* (Pseudo)pool for HCI commands */ -static struct da1469x_ble_hci_pool_cmd da1469x_ble_hci_pool_cmd; - -/* Pools for HCI events (high and low priority) */ -static uint8_t da1469x_ble_hci_pool_evt_hi_buf[ OS_MEMPOOL_BYTES( - MYNEWT_VAL(BLE_HCI_EVT_HI_BUF_COUNT), - MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE)) ]; -static struct os_mempool da1469x_ble_hci_pool_evt_hi; -static uint8_t da1469x_ble_hci_pool_evt_lo_buf[ OS_MEMPOOL_BYTES( - MYNEWT_VAL(BLE_HCI_EVT_LO_BUF_COUNT), - MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE)) ]; -static struct os_mempool da1469x_ble_hci_pool_evt_lo; - -/* Pool for ACL data */ -static uint8_t da1469x_ble_hci_pool_acl_buf[ OS_MEMPOOL_BYTES( - MYNEWT_VAL(BLE_ACL_BUF_COUNT), - POOL_ACL_BLOCK_SIZE) ]; -static struct os_mempool da1469x_ble_hci_pool_acl; -static struct os_mbuf_pool da1469x_ble_hci_pool_acl_mbuf; - -/* Interface to host */ -static struct da1469x_ble_hci_host_api da1469x_ble_hci_host_api; - -/* State of RX currently in progress (needs to reassemble frame) */ -static struct da1469x_ble_hci_rx_data da1469x_ble_hci_rx_data; - -int -ble_hci_trans_reset(void) -{ - /* XXX Should we do something with RF and/or BLE core? */ - return 0; -} - -void -ble_hci_trans_cfg_hs(ble_hci_trans_rx_cmd_fn *evt_cb, void *evt_arg, - ble_hci_trans_rx_acl_fn *acl_cb, void *acl_arg) -{ - da1469x_ble_hci_host_api.evt_cb = evt_cb; - da1469x_ble_hci_host_api.evt_arg = evt_arg; - da1469x_ble_hci_host_api.acl_cb = acl_cb; - da1469x_ble_hci_host_api.acl_arg = acl_arg; -} - -uint8_t * -ble_hci_trans_buf_alloc(int type) -{ - uint8_t *buf; - - switch (type) { - case BLE_HCI_TRANS_BUF_CMD: - assert(!da1469x_ble_hci_pool_cmd.allocated); - da1469x_ble_hci_pool_cmd.allocated = 1; - buf = da1469x_ble_hci_pool_cmd.cmd; - break; - case BLE_HCI_TRANS_BUF_EVT_HI: - buf = os_memblock_get(&da1469x_ble_hci_pool_evt_hi); - if (buf) { - break; - } - /* no break */ - case BLE_HCI_TRANS_BUF_EVT_LO: - buf = os_memblock_get(&da1469x_ble_hci_pool_evt_lo); - break; - default: - assert(0); - buf = NULL; - } - - return buf; -} - -void -ble_hci_trans_buf_free(uint8_t *buf) -{ - int rc; - - if (buf == da1469x_ble_hci_pool_cmd.cmd) { - assert(da1469x_ble_hci_pool_cmd.allocated); - da1469x_ble_hci_pool_cmd.allocated = 0; - } else if (os_memblock_from(&da1469x_ble_hci_pool_evt_hi, buf)) { - rc = os_memblock_put(&da1469x_ble_hci_pool_evt_hi, buf); - assert(rc == 0); - } else { - assert(os_memblock_from(&da1469x_ble_hci_pool_evt_lo, buf)); - rc = os_memblock_put(&da1469x_ble_hci_pool_evt_lo, buf); - assert(rc == 0); - } -} - -int -ble_hci_trans_hs_cmd_tx(uint8_t *cmd) -{ - uint8_t ind = HCI_PKT_CMD; - int len = 3 + cmd[2]; - - cmac_mbox_write(&ind, 1); - cmac_mbox_write(cmd, len); - - ble_hci_trans_buf_free(cmd); - - return 0; -} - -int -ble_hci_trans_hs_acl_tx(struct os_mbuf *om) -{ - uint8_t ind = HCI_PKT_ACL; - struct os_mbuf *x; - - cmac_mbox_write(&ind, 1); - - x = om; - while (x) { - cmac_mbox_write(x->om_data, x->om_len); - x = SLIST_NEXT(x, om_next); - } - - os_mbuf_free_chain(om); - - return 0; -} - -static int -da1469x_ble_hci_trans_ll_rx(const uint8_t *buf, uint16_t len) -{ - struct da1469x_ble_hci_rx_data *rxd = &da1469x_ble_hci_rx_data; - void *data; - int pool = BLE_HCI_TRANS_BUF_EVT_HI; - int rc; - - assert(len); - - if (rxd->type == HCI_PKT_NONE) { - rxd->type = buf[0]; - rxd->len = 0; - rxd->expected_len = 0; - - switch (rxd->type) { - case HCI_PKT_ACL: - rxd->min_len = 4; - break; - case HCI_PKT_EVT: - rxd->min_len = 2; - break; - default: - assert(0); - break; - } - - return 1; - } - - /* Ensure we have minimum length of bytes required to process header */ - if (rxd->len < rxd->min_len) { - len = min(len, rxd->min_len - rxd->len); - memcpy(&rxd->hdr[rxd->len], buf, len); - rxd->len += len; - return len; - } - - /* Parse header and allocate proper buffer if not done yet */ - if (rxd->expected_len == 0) { - switch (rxd->type) { - case HCI_PKT_ACL: - data = os_mbuf_get_pkthdr(&da1469x_ble_hci_pool_acl_mbuf, - sizeof(struct ble_mbuf_hdr)); - if (!data) { - return 0; - } - - rxd->om = data; - os_mbuf_append(rxd->om, rxd->hdr, rxd->len); - rxd->expected_len = get_le16(&rxd->hdr[2]) + 4; - break; - case HCI_PKT_EVT: - if (rxd->hdr[0] == BLE_HCI_EVCODE_LE_META) { - /* For LE Meta event we need 3 bytes to parse header */ - if (rxd->min_len < 3) { - rxd->min_len = 3; - return 0; - } - - /* Advertising reports shall be allocated from low-prio pool */ - if ((rxd->hdr[2] == BLE_HCI_LE_SUBEV_ADV_RPT) || - (rxd->hdr[2] == BLE_HCI_LE_SUBEV_EXT_ADV_RPT)) { - pool = BLE_HCI_TRANS_BUF_EVT_LO; - } - } - - data = ble_hci_trans_buf_alloc(pool); - if (!data) { - /* - * Only care about valid buffer when shall be allocated from - * high-prio pool, otherwise NULL is fine and we'll just skip - * this event. - */ - if (pool != BLE_HCI_TRANS_BUF_EVT_LO) { - data = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_LO); - if (!data) { - return 0; - } - } - } - - rxd->buf = data; - memcpy(rxd->buf, rxd->hdr, rxd->len); - rxd->expected_len = rxd->hdr[1] + 2; - break; - default: - assert(0); - return len; - } - } - - len = min(len, rxd->expected_len - rxd->len); - - switch (rxd->type) { - case HCI_PKT_ACL: - os_mbuf_append(rxd->om, buf, len); - rxd->len += len; - - if (rxd->len == rxd->expected_len) { - rc = da1469x_ble_hci_host_api.acl_cb(rxd->om, - da1469x_ble_hci_host_api.acl_arg); - if (rc != 0) { - os_mbuf_free_chain(rxd->om); - } - rxd->type = HCI_PKT_NONE; - } - break; - case HCI_PKT_EVT: - if (rxd->buf) { - memcpy(&rxd->buf[rxd->len], buf, len); - } - rxd->len += len; - - if (rxd->len == rxd->expected_len) { - /* - * XXX for unknown reason at startup controller sends command - * complete for a vendor specific command which we never sent - * and this messes up with our ack code - just discard this - * event - */ - if ((rxd->buf[0] == 0x0E) && (get_le16(&rxd->buf[3]) == 0xfc11)) { - ble_hci_trans_buf_free(rxd->buf); - } else if (rxd->buf) { - rc = da1469x_ble_hci_host_api.evt_cb(rxd->buf, - da1469x_ble_hci_host_api.evt_arg); - if (rc != 0) { - ble_hci_trans_buf_free(rxd->buf); - } - } - rxd->type = HCI_PKT_NONE; - } - break; - default: - assert(0); - break; - } - - return len; -} - -static int -da1469x_ble_hci_read_cb(const uint8_t *buf, uint16_t len) -{ - return da1469x_ble_hci_trans_ll_rx(buf, len); -} - -void -da1469x_ble_hci_init(void) -{ - int rc; - - SYSINIT_ASSERT_ACTIVE(); - - rc = os_mempool_init(&da1469x_ble_hci_pool_acl, MYNEWT_VAL(BLE_ACL_BUF_COUNT), - POOL_ACL_BLOCK_SIZE, da1469x_ble_hci_pool_acl_buf, - "da1469x_ble_hci_pool_acl"); - SYSINIT_PANIC_ASSERT(rc == 0); - - rc = os_mbuf_pool_init(&da1469x_ble_hci_pool_acl_mbuf, - &da1469x_ble_hci_pool_acl, POOL_ACL_BLOCK_SIZE, - MYNEWT_VAL(BLE_ACL_BUF_COUNT)); - SYSINIT_PANIC_ASSERT(rc == 0); - - rc = os_mempool_init(&da1469x_ble_hci_pool_evt_hi, - MYNEWT_VAL(BLE_HCI_EVT_HI_BUF_COUNT), - MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE), - da1469x_ble_hci_pool_evt_hi_buf, - "da1469x_ble_hci_pool_evt_hi"); - SYSINIT_PANIC_ASSERT(rc == 0); - - rc = os_mempool_init(&da1469x_ble_hci_pool_evt_lo, - MYNEWT_VAL(BLE_HCI_EVT_LO_BUF_COUNT), - MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE), - da1469x_ble_hci_pool_evt_lo_buf, - "da1469x_ble_hci_pool_evt_lo"); - SYSINIT_PANIC_ASSERT(rc == 0); -} - -void -da1469x_ble_hci_cmac_init(void) -{ - cmac_mbox_set_read_cb(da1469x_ble_hci_read_cb); - cmac_host_init(); -} diff --git a/nimble/transport/dialog_cmac/.gitignore b/nimble/transport/dialog_cmac/.gitignore deleted file mode 100644 index bba9f995af..0000000000 --- a/nimble/transport/dialog_cmac/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/src/libble_stack_da1469x.a - diff --git a/nimble/transport/dialog_cmac/cmac_driver/diag/src/cmac_diag.c b/nimble/transport/dialog_cmac/cmac_driver/diag/src/cmac_diag.c deleted file mode 100644 index 4f75470654..0000000000 --- a/nimble/transport/dialog_cmac/cmac_driver/diag/src/cmac_diag.c +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#include "syscfg/syscfg.h" -#include "mcu/mcu.h" - -#if MYNEWT_VAL(BLE_HOST) -void -cmac_diag_setup_host(void) -{ - /* Setup pins for diagnostic signals */ - mcu_gpio_set_pin_function(42, MCU_GPIO_MODE_OUTPUT, MCU_GPIO_FUNC_CMAC_DIAG0); /* DIAG_0 @ P1.10 */ - mcu_gpio_set_pin_function(43, MCU_GPIO_MODE_OUTPUT, MCU_GPIO_FUNC_CMAC_DIAG1); /* DIAG_1 @ P1.11 */ - mcu_gpio_set_pin_function(44, MCU_GPIO_MODE_OUTPUT, MCU_GPIO_FUNC_CMAC_DIAG2); /* DIAG_2 @ P1.12 */ - mcu_gpio_set_pin_function(24, MCU_GPIO_MODE_OUTPUT, MCU_GPIO_FUNC_CMAC_DIAGX); /* DIAG_3 @ P0.24 */ - mcu_gpio_set_pin_function(21, MCU_GPIO_MODE_OUTPUT, MCU_GPIO_FUNC_CMAC_DIAGX); /* DIAG_4 @ P0.21 */ - mcu_gpio_set_pin_function(20, MCU_GPIO_MODE_OUTPUT, MCU_GPIO_FUNC_CMAC_DIAGX); /* DIAG_5 @ P0.20 */ - mcu_gpio_set_pin_function(19, MCU_GPIO_MODE_OUTPUT, MCU_GPIO_FUNC_CMAC_DIAGX); /* DIAG_6 @ P0.19 */ - mcu_gpio_set_pin_function(18, MCU_GPIO_MODE_OUTPUT, MCU_GPIO_FUNC_CMAC_DIAGX); /* DIAG_7 @ P0.18 */ - mcu_gpio_set_pin_function(31, MCU_GPIO_MODE_OUTPUT, MCU_GPIO_FUNC_CMAC_DIAGX); /* DIAG_8 @ P0.31 */ - mcu_gpio_set_pin_function(30, MCU_GPIO_MODE_OUTPUT, MCU_GPIO_FUNC_CMAC_DIAGX); /* DIAG_9 @ P0.30 */ - mcu_gpio_set_pin_function(29, MCU_GPIO_MODE_OUTPUT, MCU_GPIO_FUNC_CMAC_DIAGX); /* DIAG_10 @ P0.29 */ - mcu_gpio_set_pin_function(28, MCU_GPIO_MODE_OUTPUT, MCU_GPIO_FUNC_CMAC_DIAGX); /* DIAG_11 @ P0.28 */ - mcu_gpio_set_pin_function(27, MCU_GPIO_MODE_OUTPUT, MCU_GPIO_FUNC_CMAC_DIAGX); /* DIAG_12 @ P0.27 */ - mcu_gpio_set_pin_function(26, MCU_GPIO_MODE_OUTPUT, MCU_GPIO_FUNC_CMAC_DIAGX); /* DIAG_13 @ P0.26 */ - mcu_gpio_set_pin_function(38, MCU_GPIO_MODE_OUTPUT, MCU_GPIO_FUNC_CMAC_DIAGX); /* DIAG_14 @ P1.06 */ - mcu_gpio_set_pin_function(41, MCU_GPIO_MODE_OUTPUT, MCU_GPIO_FUNC_CMAC_DIAGX); /* DIAG_15 @ P1.09 */ -} -#endif - -#if MYNEWT_VAL(BLE_CONTROLLER) -void -cmac_diag_setup_cmac(void) -{ - MCU_DIAG_MAP( 0, 4, DSER); - MCU_DIAG_MAP( 1, 6, CMAC_ON_ERROR); - MCU_DIAG_MAP( 2, 2, PHY_TX_EN); - MCU_DIAG_MAP( 3, 2, PHY_RX_EN); - MCU_DIAG_MAP( 4, 2, PHY_TXRX_DATA_COMB); - MCU_DIAG_MAP( 5, 2, PHY_TXRX_DATA_EN_COMB); - MCU_DIAG_MAP( 6, 5, EV1US_FRAME_START); - MCU_DIAG_MAP( 7, 5, EV_BS_START); - MCU_DIAG_MAP( 8, 5, EV1C_BS_STOP); - MCU_DIAG_MAP( 9, 5, EV1US_PHY_TO_IDLE); - MCU_DIAG_MAP(10, 9, CALLBACK_IRQ); - MCU_DIAG_MAP(11, 9, FIELD_IRQ); - MCU_DIAG_MAP(12, 9, FRAME_IRQ); - MCU_DIAG_MAP(13, 3, SLP_TIMER_ACTIVE); - MCU_DIAG_MAP(14, 4, SLEEPING); - MCU_DIAG_MAP(15, 8, LL_TIMER1_00); -} -#endif diff --git a/nimble/transport/dialog_cmac/cmac_driver/include/cmac_driver/cmac_shared.h b/nimble/transport/dialog_cmac/cmac_driver/include/cmac_driver/cmac_shared.h deleted file mode 100644 index 90b5827dd4..0000000000 --- a/nimble/transport/dialog_cmac/cmac_driver/include/cmac_driver/cmac_shared.h +++ /dev/null @@ -1,193 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef __MCU_CMAC_SHARED_H_ -#define __MCU_CMAC_SHARED_H_ - -#include -#include "syscfg/syscfg.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define CMAC_SHARED_MAGIC_CMAC (0x4C6C) /* "lL" */ -#define CMAC_SHARED_MAGIC_SYS (0x5368) /* "hS" */ - -#define CMAC_SHARED_F_SYS_LPCLK_AVAILABLE (0x0001) - -/* - * Simple circular buffer for storing random numbers generated by M33 - * Empty: cmr_in = cmr_out = 0; - * Full: cmr_in + 1 = cmr_out - * - * cmr_in: used by the M33 to add random numbers to the circular buffer. - * cmr_out: used by CMAC to retrieve random numbers - * - * NOTE: cmr_in and cmr_out are indices. - */ -#define CMAC_RAND_BUF_ELEMS (16) - -struct cmac_rand { - int cmr_active; - int cmr_in; - int cmr_out; - uint32_t cmr_buf[CMAC_RAND_BUF_ELEMS]; -}; - -struct cmac_mbox { - uint16_t rd_off; - uint16_t wr_off; -}; - -struct cmac_dcdc { - uint8_t enabled; - uint32_t v18; - uint32_t v18p; - uint32_t vdd; - uint32_t v14; - uint32_t ctrl1; -}; - -struct cmac_trim { - uint8_t rfcu_len; - uint8_t rfcu_mode1_len; - uint8_t rfcu_mode2_len; - uint8_t synth_len; - uint32_t rfcu[ MYNEWT_VAL(CMAC_TRIM_SIZE_RFCU) ]; - uint32_t rfcu_mode1[2]; - uint32_t rfcu_mode2[2]; - uint32_t synth[ MYNEWT_VAL(CMAC_TRIM_SIZE_SYNTH) ]; -}; - -#if MYNEWT_VAL(CMAC_DEBUG_DATA_ENABLE) -struct cmac_debug { - int8_t last_rx_rssi; - int8_t tx_power_override; - - uint32_t cal_res_1; - uint32_t cal_res_2; - uint32_t trim_val1_tx_1; - uint32_t trim_val1_tx_2; - uint32_t trim_val2_tx; - uint32_t trim_val2_rx; -}; -#endif - -#if MYNEWT_VAL(CMAC_DEBUG_COREDUMP_ENABLE) -struct cmac_coredump { - uint32_t lr; - uint32_t pc; - uint32_t assert; - const char *assert_file; - uint32_t assert_line; - - uint32_t CM_STAT_REG; - uint32_t CM_LL_TIMER1_36_10_REG; - uint32_t CM_LL_TIMER1_9_0_REG; - uint32_t CM_ERROR_REG; - uint32_t CM_EXC_STAT_REG; -}; -#endif - -#define CMAC_PENDING_OP_LP_CLK 0x0001 -#define CMAC_PENDING_OP_RF_CAL 0x0002 - -struct cmac_shared_data { - uint16_t magic_cmac; - uint16_t magic_sys; - uint16_t pending_ops; - uint16_t lp_clock_freq; /* LP clock frequency */ - uint32_t xtal32m_settle_us;/* XTAL32M settling time */ - struct cmac_mbox mbox_s2c; /* SYS2CMAC mailbox */ - struct cmac_mbox mbox_c2s; /* CMAC2SYS mailbox */ - struct cmac_dcdc dcdc; /* DCDC settings */ - struct cmac_trim trim; /* Trim data */ - struct cmac_rand rand; /* Random numbers */ -#if MYNEWT_VAL(CMAC_DEBUG_DATA_ENABLE) - struct cmac_debug debug; /* Extra debug data */ -#endif -#if MYNEWT_VAL(CMAC_DEBUG_COREDUMP_ENABLE) - struct cmac_coredump coredump; -#endif - - uint8_t mbox_s2c_buf[ MYNEWT_VAL(CMAC_MBOX_SIZE_S2C) ]; - uint8_t mbox_c2s_buf[ MYNEWT_VAL(CMAC_MBOX_SIZE_C2S) ]; -}; - -#if MYNEWT_VAL(BLE_HOST) -extern volatile struct cmac_shared_data *g_cmac_shared_data; -#elif MYNEWT_VAL(BLE_CONTROLLER) -extern volatile struct cmac_shared_data g_cmac_shared_data; -#endif - -/* cmac_mbox */ -typedef int (cmac_mbox_read_cb)(const void *data, uint16_t len); -typedef void (cmac_mbox_write_notif_cb)(void); -void cmac_mbox_set_read_cb(cmac_mbox_read_cb *cb); -void cmac_mbox_set_write_notif_cb(cmac_mbox_write_notif_cb *cb); -int cmac_mbox_read(void); -int cmac_mbox_write(const void *data, uint16_t len); - -/* cmac_rand */ -typedef void (*cmac_rand_isr_cb_t)(uint8_t rnum); -void cmac_rand_start(void); -void cmac_rand_stop(void); -void cmac_rand_read(void); -void cmac_rand_write(void); -void cmac_rand_chk_fill(void); -int cmac_rand_get_next(void); -int cmac_rand_is_active(void); -int cmac_rand_is_full(void); -void cmac_rand_fill(uint32_t *buf, int num_words); -void cmac_rand_set_isr_cb(cmac_rand_isr_cb_t cb); - -void cmac_shared_init(void); -void cmac_shared_sync(void); - -#if MYNEWT_VAL(BLE_HOST) -#define CMAC_SHARED_LOCK_VAL 0x40000000 -#elif MYNEWT_VAL(BLE_CONTROLLER) -#define CMAC_SHARED_LOCK_VAL 0xc0000000 -#endif - -static inline void -cmac_shared_lock(void) -{ - volatile uint32_t *bsr_set = (void *)0x50050074; - volatile uint32_t *bsr_stat = (void *)0x5005007c; - - while ((*bsr_stat & 0xc0000000) != CMAC_SHARED_LOCK_VAL) { - *bsr_set = CMAC_SHARED_LOCK_VAL; - } -} - -static inline void -cmac_shared_unlock(void) -{ - volatile uint32_t *bsr_reset = (void *)0x50050078; - - *bsr_reset = CMAC_SHARED_LOCK_VAL; -} - -#ifdef __cplusplus -} -#endif - -#endif /* __MCU_CMAC_SHARED_H_ */ diff --git a/nimble/transport/dialog_cmac/cmac_driver/scripts/build_libcmac.sh b/nimble/transport/dialog_cmac/cmac_driver/scripts/build_libcmac.sh deleted file mode 100755 index bbc822aa5f..0000000000 --- a/nimble/transport/dialog_cmac/cmac_driver/scripts/build_libcmac.sh +++ /dev/null @@ -1,45 +0,0 @@ -#!/bin/bash - -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - -NEWT=${MYNEWT_NEWT_PATH} -OBJCOPY=${MYNEWT_OBJCOPY_PATH} -AR=${MYNEWT_AR_PATH} -LIBCMAC_A=${MYNEWT_USER_SRC_DIR}/libcmac.a - -export WORK_DIR=${MYNEWT_USER_WORK_DIR} -export BASENAME_ROM=cmac.rom -export BASENAME_RAM=cmac.ram - -if [ ${MYNEWT_VAL_CMAC_IMAGE_SINGLE} -eq 0 ]; then - # Create empty binary for ROM image (1 byte required for objcopy) - truncate -s 1 ${WORK_DIR}/${BASENAME_ROM}.bin - # Create fixed size RAM image - truncate -s ${MYNEWT_VAL_CMAC_IMAGE_RAM_SIZE} ${WORK_DIR}/${BASENAME_RAM}.bin -else - ${NEWT} build ${MYNEWT_VAL_CMAC_IMAGE_TARGET_NAME} -fi - -cd ${WORK_DIR} - -# Convert both binaries to objects and create archive to link -${OBJCOPY} -I binary -O elf32-littlearm -B armv8-m.main \ - --rename-section .data=.libcmac.rom ${BASENAME_ROM}.bin ${BASENAME_ROM}.o -${OBJCOPY} -I binary -O elf32-littlearm -B armv8-m.main \ - --rename-section .data=.libcmac.ram ${BASENAME_RAM}.bin ${BASENAME_RAM}.o -${AR} -rcs ${LIBCMAC_A} ${BASENAME_ROM}.o ${BASENAME_RAM}.o diff --git a/nimble/transport/dialog_cmac/cmac_driver/src/cmac_host.c b/nimble/transport/dialog_cmac/cmac_driver/src/cmac_host.c deleted file mode 100644 index df81c582bb..0000000000 --- a/nimble/transport/dialog_cmac/cmac_driver/src/cmac_host.c +++ /dev/null @@ -1,326 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#include -#include -#include -#include -#include "syscfg/syscfg.h" -#include "sysflash/sysflash.h" -#include "os/os.h" -#include "mcu/mcu.h" -#include "mcu/cmsis_nvic.h" -#include "mcu/da1469x_hal.h" -#include "mcu/da1469x_lpclk.h" -#include "mcu/da1469x_clock.h" -#include "mcu/da1469x_trimv.h" -#include "mcu/da1469x_pdc.h" -#include "cmac_driver/cmac_host.h" -#include "cmac_driver/cmac_shared.h" -#include "cmac_driver/cmac_diag.h" -#include "trng/trng.h" -#if MYNEWT_VAL(CMAC_DEBUG_COREDUMP_ENABLE) -#include "console/console.h" -#endif - -/* CMAC data */ -extern char _binary_cmac_rom_bin_start[]; -extern char _binary_cmac_rom_bin_end; -extern char _binary_cmac_ram_bin_start[]; -extern char _binary_cmac_ram_bin_end; - -struct cmac_image_info { - uint32_t magic; - uint32_t size_rom; - uint32_t size_ram; - uint32_t offset_data; - uint32_t offset_shared; -}; - -/* PDC entry for waking up CMAC */ -static int8_t g_cmac_host_pdc_sys2cmac; -/* PDC entry for waking up M33 */ -static int8_t g_cmac_host_pdc_cmac2sys; - -static void cmac_host_rand_fill(struct os_event *ev); -static struct os_event g_cmac_host_rand_ev = { - .ev_cb = cmac_host_rand_fill -}; - -static void cmac_host_rand_chk_fill(void); - -static void -cmac2sys_isr(void) -{ -#if MYNEWT_VAL(CMAC_DEBUG_COREDUMP_ENABLE) - volatile struct cmac_coredump *cd = &g_cmac_shared_data->coredump; - const char *assert_file; -#endif - - os_trace_isr_enter(); - - /* Clear CMAC2SYS interrupt */ - *(volatile uint32_t *)0x40002000 = 2; - - cmac_mbox_read(); - - if (*(volatile uint32_t *)0x40002000 & 0x1c00) { -#if MYNEWT_VAL(CMAC_DEBUG_COREDUMP_ENABLE) - console_blocking_mode(); - console_printf("CMAC error (0x%08lx)\n", *(volatile uint32_t *)0x40002000); - console_printf(" lr:0x%08lx pc:0x%08lx\n", cd->lr, cd->pc); - if (cd->assert) { - console_printf(" assert:0x%08lx\n", cd->assert); - if (cd->assert_file) { - /* Need to translate pointer from M0 code segment to M33 data */ - assert_file = cd->assert_file + MCU_MEM_SYSRAM_START_ADDRESS + - MEMCTRL->CMI_CODE_BASE_REG; - console_printf(" %s:%d\n", - assert_file, (unsigned)cd->assert_line); - } - } - console_printf(" 0x%08lx CM_ERROR_REG\n", cd->CM_ERROR_REG); - console_printf(" 0x%08lx CM_EXC_STAT_REG\n", cd->CM_EXC_STAT_REG); - console_printf(" 0x%08lx CM_LL_TIMER1_36_10_REG\n", cd->CM_LL_TIMER1_36_10_REG); - console_printf(" 0x%08lx CM_LL_TIMER1_9_0_REG\n", cd->CM_LL_TIMER1_9_0_REG); - - /* Spin if debugger is connected to CMAC to avoid resetting it */ - if (cd->CM_STAT_REG & 0x20) { - for (;;); - } -#endif - /* XXX CMAC is in error state, need to recover */ - assert(0); - return; - } - - cmac_host_rand_chk_fill(); - - os_trace_isr_exit(); -} - -static void -cmac_host_rand_fill(struct os_event *ev) -{ - size_t num_bytes; - struct trng_dev *trng; - uint32_t *rnum; - uint32_t rnums[CMAC_RAND_BUF_ELEMS]; - - /* Check if full */ - if (!cmac_rand_is_active() || cmac_rand_is_full()) { - return; - } - - assert(ev->ev_arg != NULL); - - /* Fill buffer with random numbers even though we may not use all of them */ - trng = ev->ev_arg; - rnum = &rnums[0]; - num_bytes = trng_read(trng, rnum, CMAC_RAND_BUF_ELEMS * sizeof(uint32_t)); - - cmac_rand_fill(rnum, num_bytes / 4); - cmac_host_signal2cmac(); -} - -static void -cmac_host_rand_chk_fill(void) -{ - if (cmac_rand_is_active() && !cmac_rand_is_full()) { - os_eventq_put(os_eventq_dflt_get(), &g_cmac_host_rand_ev); - } -} - -void -cmac_host_signal2cmac(void) -{ - da1469x_pdc_set(g_cmac_host_pdc_sys2cmac); -} - -static void -cmac_host_lpclk_cb(uint32_t freq) -{ - /* No need to wakeup CMAC if LP clock frequency did not change */ - if (g_cmac_shared_data->lp_clock_freq == freq) { - return; - } - - cmac_shared_lock(); - g_cmac_shared_data->lp_clock_freq = freq; - g_cmac_shared_data->pending_ops |= CMAC_PENDING_OP_LP_CLK; - cmac_shared_unlock(); - - cmac_host_signal2cmac(); -} - -#if MYNEWT_VAL(CMAC_DEBUG_HOST_PRINT_ENABLE) -static void -cmac_host_print_trim(const char *name, const uint32_t *tv, unsigned len) -{ - console_printf("[CMAC] Trim values for '%s'\n", name); - - while (len) { - console_printf(" 0x%08x = 0x%08x\n", (unsigned)tv[0], (unsigned)tv[1]); - len -= 2; - tv += 2; - } -} -#endif - -void -cmac_host_rf_calibrate(void) -{ - cmac_shared_lock(); - g_cmac_shared_data->pending_ops |= CMAC_PENDING_OP_RF_CAL; - cmac_shared_unlock(); - - cmac_host_signal2cmac(); -} - -void -cmac_host_init(void) -{ - struct trng_dev *trng; - struct cmac_image_info ii; - uint32_t cmac_rom_size; - uint32_t cmac_ram_size; -#if !MYNEWT_VAL(CMAC_IMAGE_SINGLE) - const struct flash_area *fa; - int rc; -#endif - struct cmac_trim *trim; - - /* Get trng os device */ - trng = (struct trng_dev *) os_dev_open("trng", OS_TIMEOUT_NEVER, NULL); - assert(trng); - g_cmac_host_rand_ev.ev_arg = trng; - -#if MYNEWT_VAL(CMAC_DEBUG_DIAG_ENABLE) - cmac_diag_setup_host(); -#endif - -#if MYNEWT_VAL(CMAC_DEBUG_SWD_ENABLE) - /* Enable CMAC debugger */ - CRG_TOP->SYS_CTRL_REG |= 0x40; /* CRG_TOP_SYS_CTRL_REG_CMAC_DEBUGGER_ENABLE_Msk */ -#endif - - /* - * Add PDC entry to wake up CMAC from M33 - * - * XXX if MCU_DEBUG_GPIO_DEEP_SLEEP is enabled on CMAC, this should also - * enable PD_COM so CMAC can access GPIOs after wake up - */ - g_cmac_host_pdc_sys2cmac = da1469x_pdc_add(MCU_PDC_TRIGGER_MAC_TIMER, - MCU_PDC_MASTER_CMAC, - MCU_PDC_EN_XTAL); - da1469x_pdc_set(g_cmac_host_pdc_sys2cmac); - da1469x_pdc_ack(g_cmac_host_pdc_sys2cmac); - - /* Add PDC entry to wake up M33 from CMAC, if does not exist yet */ - g_cmac_host_pdc_cmac2sys = da1469x_pdc_find(MCU_PDC_TRIGGER_COMBO, - MCU_PDC_MASTER_M33, 0); - if (g_cmac_host_pdc_cmac2sys < 0) { - g_cmac_host_pdc_cmac2sys = da1469x_pdc_add(MCU_PDC_TRIGGER_COMBO, - MCU_PDC_MASTER_M33, - MCU_PDC_EN_XTAL); - da1469x_pdc_set(g_cmac_host_pdc_cmac2sys); - da1469x_pdc_ack(g_cmac_host_pdc_cmac2sys); - } - - /* Setup CMAC2SYS interrupt */ - NVIC_SetVector(CMAC2SYS_IRQn, (uint32_t)cmac2sys_isr); - NVIC_SetPriority(CMAC2SYS_IRQn, MYNEWT_VAL(CMAC_CMAC2SYS_IRQ_PRIORITY)); - NVIC_DisableIRQ(CMAC2SYS_IRQn); - - /* Enable Radio LDO */ - CRG_TOP->POWER_CTRL_REG |= CRG_TOP_POWER_CTRL_REG_LDO_RADIO_ENABLE_Msk; - - /* Enable CMAC, but keep it in reset */ - CRG_TOP->CLK_RADIO_REG = (1 << CRG_TOP_CLK_RADIO_REG_RFCU_ENABLE_Pos) | - (1 << CRG_TOP_CLK_RADIO_REG_CMAC_SYNCH_RESET_Pos) | - (0 << CRG_TOP_CLK_RADIO_REG_CMAC_CLK_SEL_Pos) | - (1 << CRG_TOP_CLK_RADIO_REG_CMAC_CLK_ENABLE_Pos) | - (0 << CRG_TOP_CLK_RADIO_REG_CMAC_DIV_Pos); - - /* Calculate size of ROM and RAM area */ - cmac_rom_size = &_binary_cmac_rom_bin_end - &_binary_cmac_rom_bin_start[0]; - cmac_ram_size = &_binary_cmac_ram_bin_end - &_binary_cmac_ram_bin_start[0]; - - /* Load image header and check if image can be loaded */ -#if MYNEWT_VAL(CMAC_IMAGE_SINGLE) - memcpy(&ii, &_binary_cmac_rom_bin_start[128], sizeof(ii)); -#else - rc = flash_area_open(FLASH_AREA_IMAGE_1, &fa); - assert(rc == 0); - rc = flash_area_read(fa, 128, &ii, sizeof(ii)); - assert(rc == 0); -#endif - - assert(ii.magic == 0xC3ACC3AC); - assert(ii.size_rom == cmac_rom_size); - assert(ii.size_ram <= cmac_ram_size); - - /* Copy CMAC image to RAM */ -#if MYNEWT_VAL(CMAC_IMAGE_SINGLE) - memset(&_binary_cmac_ram_bin_start, 0xaa, cmac_ram_size); - memcpy(&_binary_cmac_ram_bin_start, &_binary_cmac_rom_bin_start, ii.size_rom); -#else - memset(&_binary_cmac_ram_bin_start, 0xaa, cmac_ram_size); - rc = flash_area_read(fa, 0, &_binary_cmac_ram_bin_start, ii.size_rom); - assert(rc == 0); -#endif - - /* Setup CMAC memory addresses */ - MEMCTRL->CMI_CODE_BASE_REG = (uint32_t)&_binary_cmac_ram_bin_start; - MEMCTRL->CMI_DATA_BASE_REG = MEMCTRL->CMI_CODE_BASE_REG + ii.offset_data; - MEMCTRL->CMI_SHARED_BASE_REG = MEMCTRL->CMI_CODE_BASE_REG + ii.offset_shared; - MEMCTRL->CMI_END_REG = MEMCTRL->CMI_CODE_BASE_REG + ii.size_ram - 1; - - /* Initialize shared memory */ - cmac_shared_init(); - - trim = (struct cmac_trim *)&g_cmac_shared_data->trim; - trim->rfcu_len = da1469x_trimv_group_read(6, trim->rfcu, ARRAY_SIZE(trim->rfcu)); - trim->rfcu_mode1_len = da1469x_trimv_group_read(8, trim->rfcu_mode1, ARRAY_SIZE(trim->rfcu_mode1)); - trim->rfcu_mode2_len = da1469x_trimv_group_read(10, trim->rfcu_mode2, ARRAY_SIZE(trim->rfcu_mode2)); - trim->synth_len = da1469x_trimv_group_read(7, trim->synth, ARRAY_SIZE(trim->synth)); - -#if MYNEWT_VAL(CMAC_DEBUG_HOST_PRINT_ENABLE) - cmac_host_print_trim("rfcu", trim->rfcu, trim->rfcu_len); - cmac_host_print_trim("rfcu_mode1", trim->rfcu_mode1, trim->rfcu_mode1_len); - cmac_host_print_trim("rfcu_mode2", trim->rfcu_mode2, trim->rfcu_mode2_len); - cmac_host_print_trim("synth", trim->synth, trim->synth_len); -#endif - - /* Release CMAC from reset and sync */ - CRG_TOP->CLK_RADIO_REG &= ~CRG_TOP_CLK_RADIO_REG_CMAC_SYNCH_RESET_Msk; - cmac_shared_sync(); - - da1469x_lpclk_register_cmac_cb(cmac_host_lpclk_cb); - -#if MYNEWT_VAL(CMAC_DEBUG_HOST_PRINT_ENABLE) && MYNEWT_VAL(CMAC_DEBUG_DATA_ENABLE) - /* Trim values are calculated on RF init, so are valid after synced with CMAC */ - console_printf("[CMAC] Calculated trim_val1: 1=0x%08x 2=0x%08x\n", - (unsigned)g_cmac_shared_data->debug.trim_val1_tx_1, - (unsigned)g_cmac_shared_data->debug.trim_val1_tx_2); - console_printf("[CMAC] Calculated trim_val2: tx=0x%08x rx=0x%08x\n", - (unsigned)g_cmac_shared_data->debug.trim_val2_tx, - (unsigned)g_cmac_shared_data->debug.trim_val2_rx); -#endif -} diff --git a/nimble/transport/dialog_cmac/cmac_driver/src/cmac_mbox.c b/nimble/transport/dialog_cmac/cmac_driver/src/cmac_mbox.c deleted file mode 100644 index 9594dbe900..0000000000 --- a/nimble/transport/dialog_cmac/cmac_driver/src/cmac_mbox.c +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#include -#include -#include -#include -#include -#include "syscfg/syscfg.h" -#include "mcu/mcu.h" -#include "os/os_arch.h" -#include "os/os.h" - -#ifndef min -#define min(_a, _b) ((_a) < (_b) ? (_a) : (_b)) -#endif - -static cmac_mbox_read_cb *g_cmac_mbox_read_cb; -static cmac_mbox_write_notif_cb *g_cmac_mbox_write_notif_cb; - -void -cmac_mbox_set_read_cb(cmac_mbox_read_cb *cb) -{ - g_cmac_mbox_read_cb = cb; -} - -void -cmac_mbox_set_write_notif_cb(cmac_mbox_write_notif_cb *cb) -{ - g_cmac_mbox_write_notif_cb = cb; -} - -int -cmac_mbox_read(void) -{ -#if MYNEWT_VAL(BLE_HOST) - volatile struct cmac_mbox *mbox = &g_cmac_shared_data->mbox_c2s; - uint8_t *mbox_buf = (uint8_t *)&g_cmac_shared_data->mbox_c2s_buf; - const uint16_t mbox_size = MYNEWT_VAL(CMAC_MBOX_SIZE_C2S); -#else - volatile struct cmac_mbox *mbox = &g_cmac_shared_data.mbox_s2c; - uint8_t *mbox_buf = (uint8_t *)&g_cmac_shared_data.mbox_s2c_buf; - const uint16_t mbox_size = MYNEWT_VAL(CMAC_MBOX_SIZE_S2C); -#endif - uint16_t rd_off; - uint16_t wr_off; - uint16_t chunk; - int len = 0; - - if (!g_cmac_mbox_read_cb) { - return 0; - } - - do { - rd_off = mbox->rd_off; - wr_off = mbox->wr_off; - - if (rd_off <= wr_off) { - chunk = wr_off - rd_off; - } else { - chunk = mbox_size - rd_off; - } - - while (chunk) { - len = g_cmac_mbox_read_cb(&mbox_buf[rd_off], chunk); - if (len < 0) { - break; - } - - rd_off += len; - chunk -= len; - } - - mbox->rd_off = rd_off == mbox_size ? 0 : rd_off; - } while ((mbox->rd_off != mbox->wr_off) && (len >= 0)); - - return 0; -} - -int -cmac_mbox_write(const void *data, uint16_t len) -{ -#if MYNEWT_VAL(BLE_HOST) - volatile struct cmac_mbox *mbox = &g_cmac_shared_data->mbox_s2c; - uint8_t *mbox_buf = (uint8_t *)&g_cmac_shared_data->mbox_s2c_buf; - const uint16_t mbox_size = MYNEWT_VAL(CMAC_MBOX_SIZE_S2C); -#else - volatile struct cmac_mbox *mbox = &g_cmac_shared_data.mbox_c2s; - uint8_t *mbox_buf = (uint8_t *)&g_cmac_shared_data.mbox_c2s_buf; - const uint16_t mbox_size = MYNEWT_VAL(CMAC_MBOX_SIZE_C2S); -#endif - uint16_t rd_off; - uint16_t wr_off; - uint16_t max_wr; - uint16_t chunk; - - while (len) { - rd_off = mbox->rd_off; - wr_off = mbox->wr_off; - - /* - * Calculate maximum length to write, i.e. up to end of buffer or stop - * before rd_off to be able to detect full queue. - */ - if (rd_off > wr_off) { - /* - * |0|1|2|3|4|5|6|7| - * | | | |W| | |R| | - * `---^ - */ - max_wr = rd_off - wr_off - 1; - } else if (rd_off == 0) { - /* - * |0|1|2|3|4|5|6|7| - * |R| | |W| | | | | - * `-------^ - */ - max_wr = mbox_size - wr_off - 1; - } else { - /* - * |0|1|2|3|4|5|6|7| - * | |R| |W| | | | | - * `---------^ - */ - max_wr = mbox_size - wr_off; - } - - chunk = min(len, max_wr); - - if (chunk == 0) { - continue; - } - - memcpy(&mbox_buf[wr_off], data, chunk); - - wr_off += chunk; - mbox->wr_off = wr_off == mbox_size ? 0 : wr_off; - - g_cmac_mbox_write_notif_cb(); - - len -= chunk; - data = (uint8_t *)data + chunk; - } - - return 0; -} diff --git a/nimble/transport/dialog_cmac/cmac_driver/src/cmac_rand.c b/nimble/transport/dialog_cmac/cmac_driver/src/cmac_rand.c deleted file mode 100644 index 67a315f96e..0000000000 --- a/nimble/transport/dialog_cmac/cmac_driver/src/cmac_rand.c +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#include -#include -#include -#include -#include "syscfg/syscfg.h" -#include "mcu/mcu.h" -#include "os/os_arch.h" -#include "os/os.h" - -#if MYNEWT_VAL(BLE_HOST) -int -cmac_rand_is_active(void) -{ - return g_cmac_shared_data->rand.cmr_active; -} - -int -cmac_rand_is_full(void) -{ - int next; - bool rc; - - next = cmac_rand_get_next(); - if (next == g_cmac_shared_data->rand.cmr_out) { - rc = 1; - } else { - rc = 0; - } - return rc; -} - -int -cmac_rand_get_next(void) -{ - int next; - - /* If active and not full, put event on queue to get random numbers */ - next = g_cmac_shared_data->rand.cmr_in + 1; - if (next == CMAC_RAND_BUF_ELEMS) { - next = 0; - } - return next; -} - -void -cmac_rand_fill(uint32_t *buf, int num_words) -{ - int next; - - /* XXX: if words is 0, is it possible we could get into a state - where we are waiting for random numbers but M33 does not know it - has to fill any? */ - - /* NOTE: we already know the buffer is not full first time through */ - next = g_cmac_shared_data->rand.cmr_in; - while (num_words) { - g_cmac_shared_data->rand.cmr_buf[next] = buf[0]; - next = cmac_rand_get_next(); - g_cmac_shared_data->rand.cmr_in = next; - next = cmac_rand_get_next(); - if (next == g_cmac_shared_data->rand.cmr_out) { - break; - } - --num_words; - ++buf; - } -} -#endif - -#if MYNEWT_VAL(BLE_CONTROLLER) -static cmac_rand_isr_cb_t g_cmac_rand_isr_cb; - -void -cmac_rand_set_isr_cb(cmac_rand_isr_cb_t cb) -{ - g_cmac_rand_isr_cb = cb; -} - -void -cmac_rand_start(void) -{ - g_cmac_shared_data.rand.cmr_active = 1; -} - -void -cmac_rand_stop(void) -{ - g_cmac_shared_data.rand.cmr_active = 0; -} - -/** - * cmac rnum read - * - * Called during the system to cmac isr to take random numbers - * from shared memory into the BLE stack. - */ -void -cmac_rand_read(void) -{ - uint8_t bytes_left; - uint32_t rnum; - - /* Just leave if no callback. */ - if (g_cmac_rand_isr_cb == NULL) { - return; - } - - bytes_left = 0; - while (g_cmac_shared_data.rand.cmr_active) { - if (bytes_left) { - --bytes_left; - rnum >>= 8; - } else if (g_cmac_shared_data.rand.cmr_out != g_cmac_shared_data.rand.cmr_in) { - bytes_left = 3; - rnum = g_cmac_shared_data.rand.cmr_buf[g_cmac_shared_data.rand.cmr_out]; - ++g_cmac_shared_data.rand.cmr_out; - if (g_cmac_shared_data.rand.cmr_out == CMAC_RAND_BUF_ELEMS) { - g_cmac_shared_data.rand.cmr_out = 0; - } - } else { - break; - } - (*g_cmac_rand_isr_cb)((uint8_t)rnum); - } -} -#endif diff --git a/nimble/transport/dialog_cmac/cmac_driver/src/cmac_shared.c b/nimble/transport/dialog_cmac/cmac_driver/src/cmac_shared.c deleted file mode 100644 index 24640ca475..0000000000 --- a/nimble/transport/dialog_cmac/cmac_driver/src/cmac_shared.c +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#include "syscfg/syscfg.h" -#if MYNEWT_VAL(BLE_CONTROLLER) && !MYNEWT_VAL(MCU_DEBUG_DSER_CMAC_SHARED) -#define MCU_DIAG_SER_DISABLE -#endif - -#include -#include -#include -#include "mcu/mcu.h" -#include -#include "os/os_arch.h" -#include "os/os.h" - -#ifndef min -#define min(_a, _b) ((_a) < (_b) ? (_a) : (_b)) -#endif - -#if MYNEWT_VAL(BLE_HOST) -volatile struct cmac_shared_data *g_cmac_shared_data; -#include "mcu/da1469x_clock.h" -#define MCU_DIAG_SER(_x) -#elif MYNEWT_VAL(BLE_CONTROLLER) -volatile struct cmac_shared_data g_cmac_shared_data __attribute__((section(".shdata"))); -#endif - -void -cmac_shared_init(void) -{ -#if MYNEWT_VAL(BLE_HOST) - g_cmac_shared_data = (void *)(MCU_MEM_SYSRAM_START_ADDRESS + - MEMCTRL->CMI_SHARED_BASE_REG); - - memset((void *)g_cmac_shared_data, 0, sizeof(*g_cmac_shared_data)); - - g_cmac_shared_data->xtal32m_settle_us = MYNEWT_VAL(MCU_CLOCK_XTAL32M_SETTLE_TIME_US); - - g_cmac_shared_data->dcdc.enabled = DCDC->DCDC_CTRL1_REG & DCDC_DCDC_CTRL1_REG_DCDC_ENABLE_Msk; - if (g_cmac_shared_data->dcdc.enabled) { - g_cmac_shared_data->dcdc.v18 = DCDC->DCDC_V18_REG; - g_cmac_shared_data->dcdc.v18p = DCDC->DCDC_V18P_REG; - g_cmac_shared_data->dcdc.vdd = DCDC->DCDC_VDD_REG; - g_cmac_shared_data->dcdc.v14 = DCDC->DCDC_V14_REG; - g_cmac_shared_data->dcdc.ctrl1 = DCDC->DCDC_CTRL1_REG; - } - -#if MYNEWT_VAL(CMAC_DEBUG_DATA_ENABLE) - g_cmac_shared_data->debug.tx_power_override = INT8_MAX; -#endif -#endif -} - - -void -cmac_shared_sync(void) -{ - /* - * We need to guarantee proper order of initialization here, i.e. SYS has - * to wait until CMAC finished initialization as otherwise host may start - * sending HCI packets which will timeout as there is no one to read them. - */ -#if MYNEWT_VAL(BLE_HOST) - assert(g_cmac_shared_data->magic_sys == 0); - - while (g_cmac_shared_data->magic_cmac != CMAC_SHARED_MAGIC_CMAC); - g_cmac_shared_data->magic_sys = CMAC_SHARED_MAGIC_SYS; - - NVIC_EnableIRQ(CMAC2SYS_IRQn); -#endif - -#if MYNEWT_VAL(BLE_CONTROLLER) - assert(g_cmac_shared_data.magic_cmac == 0); - - g_cmac_shared_data.magic_cmac = CMAC_SHARED_MAGIC_CMAC; - while (g_cmac_shared_data.magic_sys != CMAC_SHARED_MAGIC_SYS); - - NVIC_SetPriority(SYS2CMAC_IRQn, 3); - NVIC_EnableIRQ(SYS2CMAC_IRQn); -#endif -} diff --git a/nimble/transport/dialog_cmac/cmac_driver/syscfg.yml b/nimble/transport/dialog_cmac/cmac_driver/syscfg.yml deleted file mode 100644 index a382c42447..0000000000 --- a/nimble/transport/dialog_cmac/cmac_driver/syscfg.yml +++ /dev/null @@ -1,104 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# - -syscfg.defs: - CMAC_MBOX_SIZE_S2C: - description: > - Size of mailbox for SYS to CMAC data. The size - value should be power of 2 to allow for better - code optimization. - value: 128 - CMAC_MBOX_SIZE_C2S: - description: > - Size of mailbox for CMAC to SYS data. The size - value should be power of 2 to allow for better - code optimization. - value: 128 - - CMAC_TRIM_SIZE_RFCU: - description: > - Size of trim values for RFCU. This is maximum - number of trim values that can be read from - OTP and applied, all excessive values will be - discarded. - value: 10 - CMAC_TRIM_SIZE_SYNTH: - description: > - Size of trim values for RFCU. This is maximum - number of trim values that can be read from - OTP and applied, all excessive values will be - discarded. - value: 10 - - CMAC_DEBUG_SWD_ENABLE: - description: > - Enable CMAC SWD interface. - value: 0 - CMAC_DEBUG_DIAG_ENABLE: - description: > - Enable CMAC diagnostic lines. - value: 0 - CMAC_DEBUG_DATA_ENABLE: - description: > - Enable extra debugging data in shared segment. - value: 0 - CMAC_DEBUG_COREDUMP_ENABLE: - description: > - Enable dumping CMAC registers to shared segment - on fault. - value: 1 - CMAC_DEBUG_HOST_PRINT_ENABLE: - description: > - Enable some debug printouts to console from host side. - This will dump some settings during startup, useful to - check what is loaded to CMAC via shared data. - value: 0 - - CMAC_IMAGE_SINGLE: - description: > - When enable, CMAC binary is linked with application image - creating a single image build. See CMAC_IMAGE_TARGET_NAME. - When disabled, CMAC binary is built and flashed separately - to flash partition. See CMAC_IMAGE_PARTITION. - value: 1 - CMAC_IMAGE_TARGET_NAME: - description: > - Target name to build for CMAC binary for single image build. - value: "@apache-mynewt-nimble/targets/dialog_cmac" - CMAC_IMAGE_PARTITION: - description: > - Flash partition to load CMAC binary from if single image build - is disabled. - value: FLASH_AREA_IMAGE_1 - CMAC_IMAGE_RAM_SIZE: - description: > - Size of RAM area in bytes reserved for CMAC if single image - build is disabled. Unit suffix (K, M) is allowed. - Note: for single image build this setting is not applicable - since proper RAM area size is automatically calculated from - CMAC binary. - value: 128K - - CMAC_CMAC2SYS_IRQ_PRIORITY: - description: > - The priority of the CMAC2SYS IRQ. Default is 0, or highest - priority. - value: 0 - -syscfg.restrictions.BLE_HOST: - - TRNG diff --git a/nimble/transport/dialog_cmac/pkg.yml b/nimble/transport/dialog_cmac/pkg.yml index ef8fc1ee43..40de98fe99 100644 --- a/nimble/transport/dialog_cmac/pkg.yml +++ b/nimble/transport/dialog_cmac/pkg.yml @@ -18,19 +18,16 @@ # pkg.name: nimble/transport/dialog_cmac -pkg.description: HCI H4 transport for Dialog CMAC +pkg.description: IPC transport for Dialog CMAC pkg.author: "Apache Mynewt " -pkg.homepage: "http://mynewt.apache.org/" +pkg.homepage: "https://mynewt.apache.org/" pkg.keywords: - ble - bluetooth pkg.deps: - - nimble - - nimble/transport/dialog_cmac/cmac_driver + - nimble/transport/common/hci_h4 + - "@apache-mynewt-core/hw/drivers/ipc_cmac" pkg.apis: - ble_transport - -pkg.init: - ble_hci_cmac_init: 100 diff --git a/nimble/transport/dialog_cmac/src/ble_hci_cmac_common.c b/nimble/transport/dialog_cmac/src/ble_hci_cmac_common.c deleted file mode 100644 index 665b62166b..0000000000 --- a/nimble/transport/dialog_cmac/src/ble_hci_cmac_common.c +++ /dev/null @@ -1,194 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#include -#include - -#include "syscfg/syscfg.h" -#include "os/mynewt.h" -#include "nimble/ble.h" -#include "nimble/ble_hci_trans.h" -#include "nimble/hci_common.h" -#include "ble_hci_cmac_priv.h" - -/* - * If controller-to-host flow control is enabled we need to hold an extra command - * buffer for HCI_Host_Number_Of_Completed_Packets which can be sent at any time. - */ -#if MYNEWT_VAL(BLE_HS_FLOW_CTRL) || MYNEWT_VAL(BLE_LL_CFG_FEAT_CTRL_TO_HOST_FLOW_CONTROL) -#define HCI_CMD_COUNT 2 -#else -#define HCI_CMD_COUNT 1 -#endif - -#define POOL_ACL_BLOCK_SIZE OS_ALIGN(MYNEWT_VAL(BLE_ACL_BUF_SIZE) + \ - BLE_MBUF_MEMBLOCK_OVERHEAD + \ - BLE_HCI_DATA_HDR_SZ, OS_ALIGNMENT) - -static uint8_t ble_hci_pool_cmd_mempool_buf[ - OS_MEMPOOL_BYTES(HCI_CMD_COUNT, BLE_HCI_TRANS_CMD_SZ)]; -static struct os_mempool ble_hci_pool_cmd_mempool; - -static uint8_t ble_hci_pool_evt_hi_mempool_buf[ - OS_MEMPOOL_BYTES(MYNEWT_VAL(BLE_HCI_EVT_HI_BUF_COUNT), - MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE))]; -static struct os_mempool ble_hci_pool_evt_hi_mempool; - -static uint8_t ble_hci_pool_evt_lo_mempool_buf[ - OS_MEMPOOL_BYTES(MYNEWT_VAL(BLE_HCI_EVT_LO_BUF_COUNT), - MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE))]; -static struct os_mempool ble_hci_pool_evt_lo_mempool; - -static uint8_t ble_hci_pool_acl_mempool_buf[ - OS_MEMPOOL_BYTES(MYNEWT_VAL(BLE_ACL_BUF_COUNT), - POOL_ACL_BLOCK_SIZE)]; -static struct os_mempool_ext ble_hci_pool_acl_mempool; -static struct os_mbuf_pool ble_hci_pool_acl_mbuf_pool; - -__attribute__((weak)) void ble_hci_trans_notify_free(void); - -static os_mempool_put_fn *g_ble_hci_pool_acl_mempool_put_cb; -static void *g_ble_hci_pool_acl_mempool_put_arg; - -int -ble_hci_trans_reset(void) -{ - return 0; -} - -uint8_t * -ble_hci_trans_buf_alloc(int type) -{ - uint8_t *buf; - - switch (type) { - case BLE_HCI_TRANS_BUF_CMD: - buf = os_memblock_get(&ble_hci_pool_cmd_mempool); - break; - case BLE_HCI_TRANS_BUF_EVT_HI: - buf = os_memblock_get(&ble_hci_pool_evt_hi_mempool); - if (buf) { - break; - } - /* no break */ - case BLE_HCI_TRANS_BUF_EVT_LO: - buf = os_memblock_get(&ble_hci_pool_evt_lo_mempool); - break; - default: - assert(0); - buf = NULL; - } - - return buf; -} - -void -ble_hci_trans_buf_free(uint8_t *buf) -{ - int rc; - - if (os_memblock_from(&ble_hci_pool_cmd_mempool, buf)) { - rc = os_memblock_put(&ble_hci_pool_cmd_mempool, buf); - assert(rc == 0); - } else if (os_memblock_from(&ble_hci_pool_evt_hi_mempool, buf)) { - rc = os_memblock_put(&ble_hci_pool_evt_hi_mempool, buf); - assert(rc == 0); - } else { - assert(os_memblock_from(&ble_hci_pool_evt_lo_mempool, buf)); - rc = os_memblock_put(&ble_hci_pool_evt_lo_mempool, buf); - assert(rc == 0); - } - - ble_hci_trans_notify_free(); -} - -struct os_mbuf * -ble_hci_cmac_alloc_acl_mbuf(void) -{ - return os_mbuf_get_pkthdr(&ble_hci_pool_acl_mbuf_pool, - sizeof(struct ble_mbuf_hdr)); -} - -static os_error_t -ble_hci_cmac_free_acl_cb(struct os_mempool_ext *mpe, void *data, void *arg) -{ - int rc; - - if (g_ble_hci_pool_acl_mempool_put_cb) { - rc = g_ble_hci_pool_acl_mempool_put_cb(mpe, data, - g_ble_hci_pool_acl_mempool_put_arg); - } else { - rc = os_memblock_put_from_cb(&mpe->mpe_mp, data); - } - - if (rc != 0) { - return rc; - } - - ble_hci_trans_notify_free(); - - return 0; -} - - -int -ble_hci_trans_set_acl_free_cb(os_mempool_put_fn *cb, void *arg) -{ - g_ble_hci_pool_acl_mempool_put_cb = cb; - g_ble_hci_pool_acl_mempool_put_arg = arg; - - return 0; -} - -void -ble_hci_cmac_init(void) -{ - int rc; - - SYSINIT_ASSERT_ACTIVE(); - - rc = os_mempool_init(&ble_hci_pool_cmd_mempool, - HCI_CMD_COUNT, BLE_HCI_TRANS_CMD_SZ, - ble_hci_pool_cmd_mempool_buf, "ble_hci_cmd"); - SYSINIT_PANIC_ASSERT(rc == 0); - - rc = os_mempool_init(&ble_hci_pool_evt_hi_mempool, - MYNEWT_VAL(BLE_HCI_EVT_HI_BUF_COUNT), - MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE), - ble_hci_pool_evt_hi_mempool_buf, "ble_hci_evt_hi"); - SYSINIT_PANIC_ASSERT(rc == 0); - - rc = os_mempool_init(&ble_hci_pool_evt_lo_mempool, - MYNEWT_VAL(BLE_HCI_EVT_LO_BUF_COUNT), - MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE), - ble_hci_pool_evt_lo_mempool_buf, "ble_hci_evt_lo"); - SYSINIT_PANIC_ASSERT(rc == 0); - - rc = os_mempool_ext_init(&ble_hci_pool_acl_mempool, - MYNEWT_VAL(BLE_ACL_BUF_COUNT), POOL_ACL_BLOCK_SIZE, - ble_hci_pool_acl_mempool_buf, "ble_hci_acl"); - SYSINIT_PANIC_ASSERT(rc == 0); - - rc = os_mbuf_pool_init(&ble_hci_pool_acl_mbuf_pool, - &ble_hci_pool_acl_mempool.mpe_mp, POOL_ACL_BLOCK_SIZE, - MYNEWT_VAL(BLE_ACL_BUF_COUNT)); - SYSINIT_PANIC_ASSERT(rc == 0); - - ble_hci_pool_acl_mempool.mpe_put_cb = ble_hci_cmac_free_acl_cb; -} diff --git a/nimble/transport/dialog_cmac/src/ble_hci_cmac_hs.c b/nimble/transport/dialog_cmac/src/ble_hci_cmac_hs.c deleted file mode 100644 index 1164fe7186..0000000000 --- a/nimble/transport/dialog_cmac/src/ble_hci_cmac_hs.c +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#include -#include -#include "syscfg/syscfg.h" - -#if MYNEWT_VAL(BLE_HOST) - -#include "cmac_driver/cmac_shared.h" -#include "cmac_driver/cmac_host.h" -#include "nimble/ble_hci_trans.h" -#include "os/os_mbuf.h" -#include "ble_hci_trans_h4.h" -#include "ble_hci_cmac_priv.h" - -struct ble_hci_cmac_hs_api { - ble_hci_trans_rx_cmd_fn *evt_cb; - void *evt_arg; - ble_hci_trans_rx_acl_fn *acl_cb; - void *acl_arg; -}; - -static struct ble_hci_cmac_hs_api g_ble_hci_cmac_hs_api; -static struct ble_hci_trans_h4_rx_state g_ble_hci_cmac_hs_rx_state; -static bool g_ble_hci_cmac_hs_read_err; - -static int -ble_hci_cmac_hs_frame_cb(uint8_t pkt_type, void *data) -{ - int rc; - - switch (pkt_type) { - case BLE_HCI_TRANS_H4_PKT_TYPE_ACL: - rc = g_ble_hci_cmac_hs_api.acl_cb(data, g_ble_hci_cmac_hs_api.acl_arg); - break; - case BLE_HCI_TRANS_H4_PKT_TYPE_EVT: - rc = g_ble_hci_cmac_hs_api.evt_cb(data, g_ble_hci_cmac_hs_api.evt_arg); - break; - default: - assert(0); - break; - } - - return rc; -} - -static int -ble_hci_cmac_hs_mbox_read_cb(const void *data, uint16_t len) -{ - int rlen; - os_sr_t sr; - - rlen = ble_hci_trans_h4_rx(&g_ble_hci_cmac_hs_rx_state, data, len, - ble_hci_cmac_hs_frame_cb); - if (rlen < 0) { - /* - * There was oom error, we need to wait for buffer to be freed and - * trigger another read. - */ - OS_ENTER_CRITICAL(sr); - g_ble_hci_cmac_hs_read_err = true; - OS_EXIT_CRITICAL(sr); - } - - return rlen; -} - -static void -ble_hci_cmac_hs_mbox_write_notif_cb(void) -{ - cmac_host_signal2cmac(); -} - -int -ble_hci_trans_hs_cmd_tx(uint8_t *cmd) -{ - uint8_t pkt_type = BLE_HCI_TRANS_H4_PKT_TYPE_CMD; - - cmac_mbox_write(&pkt_type, sizeof(pkt_type)); - cmac_mbox_write(cmd, cmd[2] + 3); - - ble_hci_trans_buf_free(cmd); - - return 0; -} - -int -ble_hci_trans_hs_acl_tx(struct os_mbuf *om) -{ - uint8_t pkt_type = BLE_HCI_TRANS_H4_PKT_TYPE_ACL; - struct os_mbuf *om_next; - - cmac_mbox_write(&pkt_type, sizeof(pkt_type)); - - while (om) { - om_next = SLIST_NEXT(om, om_next); - - cmac_mbox_write(om->om_data, om->om_len); - - os_mbuf_free(om); - om = om_next; - } - - return 0; -} - -void -ble_hci_trans_notify_free(void) -{ - os_sr_t sr; - - OS_ENTER_CRITICAL(sr); - if (g_ble_hci_cmac_hs_read_err) { - g_ble_hci_cmac_hs_read_err = false; - /* Just trigger an interrupt, it will trigger read */ - NVIC_SetPendingIRQ(CMAC2SYS_IRQn); - } - OS_EXIT_CRITICAL(sr); -} - -void -ble_hci_trans_cfg_hs(ble_hci_trans_rx_cmd_fn *evt_cb, void *evt_arg, - ble_hci_trans_rx_acl_fn *acl_cb, void *acl_arg) -{ - g_ble_hci_cmac_hs_api.evt_cb = evt_cb; - g_ble_hci_cmac_hs_api.evt_arg = evt_arg; - g_ble_hci_cmac_hs_api.acl_cb = acl_cb; - g_ble_hci_cmac_hs_api.acl_arg = acl_arg; - - /* We can now handle data from CMAC, initialize it */ - cmac_mbox_set_read_cb(ble_hci_cmac_hs_mbox_read_cb); - cmac_mbox_set_write_notif_cb(ble_hci_cmac_hs_mbox_write_notif_cb); - cmac_host_init(); -} - -#endif diff --git a/nimble/transport/dialog_cmac/src/ble_hci_cmac_ll.c b/nimble/transport/dialog_cmac/src/ble_hci_cmac_ll.c deleted file mode 100644 index 6b49158ad9..0000000000 --- a/nimble/transport/dialog_cmac/src/ble_hci_cmac_ll.c +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#include "syscfg/syscfg.h" - -#if MYNEWT_VAL(BLE_CONTROLLER) - -#if !MYNEWT_VAL(MCU_DEBUG_DSER_BLE_HCI_CMAC_LL) -#define MCU_DIAG_SER_DISABLE -#endif - -#include -#include -#include "mcu/mcu.h" -#include "cmac_driver/cmac_shared.h" -#include "nimble/ble_hci_trans.h" -#include "os/os_mbuf.h" -#include "ble_hci_trans_h4.h" -#include "ble_hci_cmac_priv.h" - -struct ble_hci_cmac_ll_api { - ble_hci_trans_rx_cmd_fn *cmd_cb; - void *cmd_arg; - ble_hci_trans_rx_acl_fn *acl_cb; - void *acl_arg; -}; - -static struct ble_hci_cmac_ll_api g_ble_hci_cmac_ll_api; -static struct ble_hci_trans_h4_rx_state g_ble_hci_cmac_ll_rx_state; - -static int -ble_hci_cmac_ll_frame_cb(uint8_t pkt_type, void *data) -{ - int rc; - - MCU_DIAG_SER('F'); - - switch (pkt_type) { - case BLE_HCI_TRANS_H4_PKT_TYPE_CMD: - rc = g_ble_hci_cmac_ll_api.cmd_cb(data, g_ble_hci_cmac_ll_api.cmd_arg); - break; - case BLE_HCI_TRANS_H4_PKT_TYPE_ACL: - rc = g_ble_hci_cmac_ll_api.acl_cb(data, g_ble_hci_cmac_ll_api.acl_arg); - break; - default: - assert(0); - break; - } - - return rc; -} - -static int -ble_hci_cmac_ll_mbox_read_cb(const void *data, uint16_t len) -{ - int rlen; - - MCU_DIAG_SER('R'); - rlen = ble_hci_trans_h4_rx(&g_ble_hci_cmac_ll_rx_state, data, len, - ble_hci_cmac_ll_frame_cb); - - /* There should be no oom on LL side due to flow control used */ - assert(rlen >= 0); - - return rlen; -} - -static void -ble_hci_cmac_ll_mbox_write_notif_cb(void) -{ - MCU_DIAG_SER('W'); - CMAC->CM_EV_SET_REG = CMAC_CM_EV_SET_REG_EV1C_CMAC2SYS_IRQ_SET_Msk; -} - -int -ble_hci_trans_ll_evt_tx(uint8_t *evt) -{ - uint8_t pkt_type = BLE_HCI_TRANS_H4_PKT_TYPE_EVT; - os_sr_t sr; - - OS_ENTER_CRITICAL(sr); - - cmac_mbox_write(&pkt_type, sizeof(pkt_type)); - cmac_mbox_write(evt, evt[1] + 2); - - ble_hci_trans_buf_free(evt); - - OS_EXIT_CRITICAL(sr); - - return 0; -} - -int -ble_hci_trans_ll_acl_tx(struct os_mbuf *om) -{ - uint8_t pkt_type = BLE_HCI_TRANS_H4_PKT_TYPE_ACL; - struct os_mbuf *om_next; - - cmac_mbox_write(&pkt_type, sizeof(pkt_type)); - - while (om) { - om_next = SLIST_NEXT(om, om_next); - - cmac_mbox_write(om->om_data, om->om_len); - - os_mbuf_free(om); - om = om_next; - } - - return 0; -} - -void -ble_hci_trans_cfg_ll(ble_hci_trans_rx_cmd_fn *cmd_cb, void *cmd_arg, - ble_hci_trans_rx_acl_fn *acl_cb, void *acl_arg) -{ - g_ble_hci_cmac_ll_api.cmd_cb = cmd_cb; - g_ble_hci_cmac_ll_api.cmd_arg = cmd_arg; - g_ble_hci_cmac_ll_api.acl_cb = acl_cb; - g_ble_hci_cmac_ll_api.acl_arg = acl_arg; - - /* Setup callbacks for mailboxes */ - cmac_mbox_set_read_cb(ble_hci_cmac_ll_mbox_read_cb); - cmac_mbox_set_write_notif_cb(ble_hci_cmac_ll_mbox_write_notif_cb); - - /* Synchronize with SYS */ - cmac_shared_sync(); -} - -#endif diff --git a/nimble/transport/dialog_cmac/src/ble_hci_trans_h4.c b/nimble/transport/dialog_cmac/src/ble_hci_trans_h4.c deleted file mode 100644 index 74da391239..0000000000 --- a/nimble/transport/dialog_cmac/src/ble_hci_trans_h4.c +++ /dev/null @@ -1,332 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#include -#include -#include -#include "syscfg/syscfg.h" -#include "os/os_mbuf.h" -#include "nimble/ble_hci_trans.h" -#include "nimble/hci_common.h" -#include "ble_hci_trans_h4.h" -#include "ble_hci_cmac_priv.h" - -#define RXS_STATE_W4_PKT_TYPE 0 -#define RXS_STATE_W4_HEADER 1 -#define RXS_STATE_W4_PAYLOAD 2 -#define RXS_STATE_COMPLETED 3 - -struct input_buffer { - const uint8_t *buf; - uint16_t len; -}; - -static int -ble_hci_trans_h4_ib_adjust(struct input_buffer *ib, uint16_t len) -{ - assert(ib->len >= len); - - ib->buf += len; - ib->len -= len; - - return len; -} - -static void -ble_hci_trans_h4_rxs_start(struct ble_hci_trans_h4_rx_state *rxs, uint8_t pkt_type) -{ - rxs->pkt_type = pkt_type; - rxs->len = 0; - rxs->expected_len = 0; - - switch (rxs->pkt_type) { -#if MYNEWT_VAL(BLE_CONTROLLER) - case BLE_HCI_TRANS_H4_PKT_TYPE_CMD: - rxs->min_len = 3; - break; -#endif - case BLE_HCI_TRANS_H4_PKT_TYPE_ACL: - rxs->min_len = 4; - break; -#if MYNEWT_VAL(BLE_HOST) - case BLE_HCI_TRANS_H4_PKT_TYPE_EVT: - rxs->min_len = 2; - break; -#endif - default: - /* XXX sync loss */ - assert(0); - break; - } -} - -static int -ble_hci_trans_h4_pull_min_len(struct ble_hci_trans_h4_rx_state *rxs, - struct input_buffer *ib) -{ - uint16_t len; - - len = min(ib->len, rxs->min_len - rxs->len); - memcpy(&rxs->hdr[rxs->len], ib->buf, len); - - rxs->len += len; - ble_hci_trans_h4_ib_adjust(ib, len); - - return rxs->len != rxs->min_len; -} - -static int -ble_hci_trans_h4_rx_state_w4_header(struct ble_hci_trans_h4_rx_state *rxs, - struct input_buffer *ib) -{ -#if MYNEWT_VAL(BLE_HOST) - int pool; -#endif - int rc; - - rc = ble_hci_trans_h4_pull_min_len(rxs, ib); - if (rc) { - /* need more data */ - return 1; - } - - switch (rxs->pkt_type) { -#if MYNEWT_VAL(BLE_CONTROLLER) - case BLE_HCI_TRANS_H4_PKT_TYPE_CMD: - rxs->buf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_CMD); - if (!rxs->buf) { - return -1; - } - - memcpy(rxs->buf, rxs->hdr, rxs->len); - rxs->expected_len = rxs->hdr[2] + 3; - break; -#endif - case BLE_HCI_TRANS_H4_PKT_TYPE_ACL: - rxs->om = ble_hci_cmac_alloc_acl_mbuf(); - if (!rxs->om) { - return -1; - } - - os_mbuf_append(rxs->om, rxs->hdr, rxs->len); - rxs->expected_len = get_le16(&rxs->hdr[2]) + 4; - break; -#if MYNEWT_VAL(BLE_HOST) - case BLE_HCI_TRANS_H4_PKT_TYPE_EVT: - pool = BLE_HCI_TRANS_BUF_EVT_HI; - if (rxs->hdr[0] == BLE_HCI_EVCODE_LE_META) { - /* For LE Meta event we need 3 bytes to parse header */ - rxs->min_len = 3; - rc = ble_hci_trans_h4_pull_min_len(rxs, ib); - if (rc) { - /* need more data */ - return 1; - } - - /* Advertising reports shall be allocated from low-prio pool */ - if ((rxs->hdr[2] == BLE_HCI_LE_SUBEV_ADV_RPT) || - (rxs->hdr[2] == BLE_HCI_LE_SUBEV_EXT_ADV_RPT)) { - pool = BLE_HCI_TRANS_BUF_EVT_LO; - } - } - - /* - * XXX Events originally allocated from hi-pool can use lo-pool as - * fallback and cannot be dropped. Events allocated from lo-pool - * can be dropped to avoid oom while scanning which means that - * any advertising or extended advertising report can be silently - * discarded by transport. While this is perfectly fine for legacy - * advertising, for extended advertising it means we can drop start - * or end of chain report and host won't be able to reassemble - * chain properly... so just need to make sure pool on host side is - * large enough to catch up with controller. - */ - rxs->buf = ble_hci_trans_buf_alloc(pool); - if (!rxs->buf && pool == BLE_HCI_TRANS_BUF_EVT_HI) { - rxs->buf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_LO); - if (!rxs->buf) { - return -1; - } - } - - if (rxs->buf) { - memcpy(rxs->buf, rxs->hdr, rxs->len); - } - - rxs->expected_len = rxs->hdr[1] + 2; - break; -#endif - default: - assert(0); - break; - } - - return 0; -} - -static int -ble_hci_trans_h4_rx_state_w4_payload(struct ble_hci_trans_h4_rx_state *rxs, - struct input_buffer *ib) -{ - uint16_t mbuf_len; - uint16_t len; - int rc; - - len = min(ib->len, rxs->expected_len - rxs->len); - - switch (rxs->pkt_type) { -#if MYNEWT_VAL(BLE_CONTROLLER) - case BLE_HCI_TRANS_H4_PKT_TYPE_CMD: -#endif -#if MYNEWT_VAL(BLE_HOST) - case BLE_HCI_TRANS_H4_PKT_TYPE_EVT: -#endif - if (rxs->buf) { - memcpy(&rxs->buf[rxs->len], ib->buf, len); - } - break; - case BLE_HCI_TRANS_H4_PKT_TYPE_ACL: - assert(rxs->om); - - mbuf_len = OS_MBUF_PKTLEN(rxs->om); - rc = os_mbuf_append(rxs->om, ib->buf, len); - if (rc) { - /* - * Some data may already be appended so need to adjust rxs only by - * the size of appended data. - */ - len = OS_MBUF_PKTLEN(rxs->om) - mbuf_len; - rxs->len += len; - ble_hci_trans_h4_ib_adjust(ib, len); - - return -1; - } - break; - default: - assert(0); - break; - } - - rxs->len += len; - ble_hci_trans_h4_ib_adjust(ib, len); - - /* return 1 if need more data */ - return rxs->len != rxs->expected_len; -} - -static void -ble_hci_trans_h4_rx_state_completed(struct ble_hci_trans_h4_rx_state *rxs, - ble_hci_trans_h4_frame_cb *frame_cb) -{ - int rc; - - switch (rxs->pkt_type) { -#if MYNEWT_VAL(BLE_CONTROLLER) - case BLE_HCI_TRANS_H4_PKT_TYPE_CMD: -#endif -#if MYNEWT_VAL(BLE_HOST) - case BLE_HCI_TRANS_H4_PKT_TYPE_EVT: -#endif - if (rxs->buf) { - rc = frame_cb(rxs->pkt_type, rxs->buf); - if (rc != 0) { - ble_hci_trans_buf_free(rxs->buf); - } - rxs->buf = NULL; - } - break; - case BLE_HCI_TRANS_H4_PKT_TYPE_ACL: - if (rxs->om) { - rc = frame_cb(rxs->pkt_type, rxs->om); - if (rc != 0) { - os_mbuf_free_chain(rxs->om); - } - rxs->om = NULL; - } - break; - default: - assert(0); - break; - } -} - -int -ble_hci_trans_h4_rx(struct ble_hci_trans_h4_rx_state *rxs, const uint8_t *buf, - uint16_t len, ble_hci_trans_h4_frame_cb *frame_cb) -{ - struct input_buffer ib = { - .buf = buf, - .len = len, - }; - int rc = 0; - - while (ib.len && (rc >= 0)) { - rc = 0; - switch (rxs->state) { - case RXS_STATE_W4_PKT_TYPE: - ble_hci_trans_h4_rxs_start(rxs, ib.buf[0]); - ble_hci_trans_h4_ib_adjust(&ib, 1); - rxs->state = RXS_STATE_W4_HEADER; - /* no break */ - - case RXS_STATE_W4_HEADER: - rc = ble_hci_trans_h4_rx_state_w4_header(rxs, &ib); - if (rc) { - break; - } - rxs->state = RXS_STATE_W4_PAYLOAD; - /* no break */ - - case RXS_STATE_W4_PAYLOAD: - rc = ble_hci_trans_h4_rx_state_w4_payload(rxs, &ib); - if (rc) { - break; - } - rxs->state = RXS_STATE_COMPLETED; - /* no break */ - - case RXS_STATE_COMPLETED: - ble_hci_trans_h4_rx_state_completed(rxs, frame_cb); - rxs->state = RXS_STATE_W4_PKT_TYPE; - break; - - default: - assert(0); - /* consume all remaining data */ - ble_hci_trans_h4_ib_adjust(&ib, ib.len); - break; - } - } - - /* - * Calculate consumed bytes - * - * Note: we should always consume some bytes unless there is an oom error. - * It's also possible that we have an oom error but already consumed some - * data, in such case just return success and error will be returned on next - * pass. - */ - len = len - ib.len; - if (len == 0) { - assert(rc < 0); - return -1; - } - - return len; -} diff --git a/nimble/transport/dialog_cmac/src/ble_hci_trans_h4.h b/nimble/transport/dialog_cmac/src/ble_hci_trans_h4.h deleted file mode 100644 index 5b83f6b001..0000000000 --- a/nimble/transport/dialog_cmac/src/ble_hci_trans_h4.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef _BLE_HCI_TRANS_H4_H_ -#define _BLE_HCI_TRANS_H4_H_ - -#include - -#define BLE_HCI_TRANS_H4_PKT_TYPE_NONE 0x00 -#define BLE_HCI_TRANS_H4_PKT_TYPE_CMD 0x01 -#define BLE_HCI_TRANS_H4_PKT_TYPE_ACL 0x02 -#define BLE_HCI_TRANS_H4_PKT_TYPE_EVT 0x04 - -struct ble_hci_trans_h4_rx_state { - uint8_t state; - uint8_t pkt_type; - uint8_t min_len; - uint16_t len; - uint16_t expected_len; - uint8_t hdr[4]; - union { - uint8_t *buf; - struct os_mbuf *om; - }; -}; - -typedef int (ble_hci_trans_h4_frame_cb)(uint8_t pkt_type, void *data); - -int ble_hci_trans_h4_rx(struct ble_hci_trans_h4_rx_state *rxs, - const uint8_t *buf, uint16_t len, - ble_hci_trans_h4_frame_cb *frame_cb); - -#endif /* _BLE_HCI_TRANS_H4_H_ */ diff --git a/nimble/transport/dialog_cmac/src/hci_cmac.c b/nimble/transport/dialog_cmac/src/hci_cmac.c new file mode 100644 index 0000000000..164be6680c --- /dev/null +++ b/nimble/transport/dialog_cmac/src/hci_cmac.c @@ -0,0 +1,214 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#if MYNEWT_VAL(BLE_CONTROLLER) +/* to enable dser diag */ +#include +#endif /* BLE_CONTROLLER */ +#include +#include +#if !MYNEWT_VAL(BLE_CONTROLLER) +#include +#endif /* !BLE_CONTROLLER */ +#include +#include +#include +#include + +static struct hci_h4_sm hci_cmac_h4sm; + +static int +hci_cmac_acl_tx(struct os_mbuf *om) +{ + uint8_t pkt_type = HCI_H4_ACL; + struct os_mbuf *om_next; + + cmac_mbox_write(&pkt_type, sizeof(pkt_type)); + + while (om) { + om_next = SLIST_NEXT(om, om_next); + + cmac_mbox_write(om->om_data, om->om_len); + + os_mbuf_free(om); + om = om_next; + } + + return 0; +} + +#if !MYNEWT_VAL(BLE_CONTROLLER) +static int +hci_cmac_hs_frame_cb(uint8_t pkt_type, void *data) +{ + int rc; + + switch (pkt_type) { + case HCI_H4_ACL: + rc = ble_transport_to_hs_acl(data); + break; + case HCI_H4_EVT: + rc = ble_transport_to_hs_evt(data); + break; + default: + assert(0); + break; + } + + return rc; +} + +static int +hci_cmac_hs_mbox_read_cb(const void *data, uint16_t len) +{ + int rlen; + + rlen = hci_h4_sm_rx(&hci_cmac_h4sm, data, len); + assert(rlen >= 0); + + return rlen; +} + +static void +hci_cmac_hs_mbox_write_notif_cb(void) +{ + cmac_host_signal2cmac(); +} + +void +ble_transport_ll_init(void) +{ + hci_h4_sm_init(&hci_cmac_h4sm, &hci_h4_allocs_from_ll, hci_cmac_hs_frame_cb); + + /* We can now handle data from CMAC, initialize it */ + cmac_mbox_cb_set(hci_cmac_hs_mbox_read_cb, + hci_cmac_hs_mbox_write_notif_cb); + cmac_host_init(); +} +#endif /* !BLE_CONTROLLER */ + +#if MYNEWT_VAL(BLE_CONTROLLER) +#if !MYNEWT_VAL(MCU_DEBUG_DSER_BLE_HCI_CMAC_LL) +#define MCU_DIAG_SER_DISABLE +#endif + +static int +hci_cmac_ll_frame_cb(uint8_t pkt_type, void *data) +{ + int rc; + + switch (pkt_type) { + case HCI_H4_CMD: + rc = ble_transport_to_ll_cmd(data); + break; + case HCI_H4_ACL: + rc = ble_transport_to_ll_acl(data); + break; + default: + assert(0); + break; + } + + return rc; +} + +static int +hci_cmac_ll_mbox_read_cb(const void *data, uint16_t len) +{ + int rlen; + + MCU_DIAG_SER('R'); + rlen = hci_h4_sm_rx(&hci_cmac_h4sm, data, len); + assert(rlen >= 0); + + return rlen; +} + +static void +hci_cmac_ll_mbox_write_notif_cb(void) +{ + MCU_DIAG_SER('W'); + CMAC->CM_EV_SET_REG = CMAC_CM_EV_SET_REG_EV1C_CMAC2SYS_IRQ_SET_Msk; +} + +void +ble_transport_hs_init(void) +{ + hci_h4_sm_init(&hci_cmac_h4sm, &hci_h4_allocs_from_hs, hci_cmac_ll_frame_cb); + + /* Setup callbacks for mailboxes */ + cmac_mbox_cb_set(hci_cmac_ll_mbox_read_cb, + hci_cmac_ll_mbox_write_notif_cb); + + /* Synchronize with SYS */ + cmac_shm_ll_ready(); +} +#endif + +#if !MYNEWT_VAL(BLE_CONTROLLER) +int +ble_transport_to_ll_cmd_impl(void *buf) +{ + uint8_t pkt_type = HCI_H4_CMD; + uint8_t *cmd = buf; + + cmac_mbox_write(&pkt_type, sizeof(pkt_type)); + cmac_mbox_write(cmd, cmd[2] + 3); + + ble_transport_free(buf); + + return 0; +} + +int +ble_transport_to_ll_acl_impl(struct os_mbuf *om) +{ + return hci_cmac_acl_tx(om); +} +#endif + +#if MYNEWT_VAL(BLE_CONTROLLER) +int +ble_transport_to_hs_acl_impl(struct os_mbuf *om) +{ + return hci_cmac_acl_tx(om); +} + +int +ble_transport_to_hs_evt_impl(void *buf) +{ + uint8_t pkt_type = HCI_H4_EVT; + uint8_t *evt = buf; + os_sr_t sr; + + OS_ENTER_CRITICAL(sr); + + cmac_mbox_write(&pkt_type, sizeof(pkt_type)); + cmac_mbox_write(evt, evt[1] + 2); + + ble_transport_free(buf); + + OS_EXIT_CRITICAL(sr); + + return 0; +} +#endif /* BLE_CONTROLLER */ diff --git a/nimble/transport/emspi/src/ble_hci_emspi.c b/nimble/transport/emspi/src/ble_hci_emspi.c index 61fe96b2b3..d07820f7bb 100644 --- a/nimble/transport/emspi/src/ble_hci_emspi.c +++ b/nimble/transport/emspi/src/ble_hci_emspi.c @@ -35,23 +35,12 @@ #include "nimble/ble.h" #include "nimble/nimble_opt.h" #include "nimble/hci_common.h" -#include "nimble/ble_hci_trans.h" +#include "nimble/transport.h" #include "transport/emspi/ble_hci_emspi.h" #include "am_mcu_apollo.h" -/*** - * NOTES: - * The emspi HCI transport doesn't use event buffer priorities. All incoming - * and outgoing events use buffers from the same pool. - * - */ - -#define BLE_HCI_EMSPI_PKT_EVT_COUNT \ - (MYNEWT_VAL(BLE_HCI_EVT_HI_BUF_COUNT) + \ - MYNEWT_VAL(BLE_HCI_EVT_LO_BUF_COUNT)) - #define BLE_HCI_EMSPI_PKT_NONE 0x00 #define BLE_HCI_EMSPI_PKT_CMD 0x01 #define BLE_HCI_EMSPI_PKT_ACL 0x02 @@ -71,46 +60,6 @@ static struct os_eventq ble_hci_emspi_evq; static struct os_task ble_hci_emspi_task; static os_stack_t ble_hci_emspi_stack[MYNEWT_VAL(BLE_HCI_EMSPI_STACK_SIZE)]; -static ble_hci_trans_rx_cmd_fn *ble_hci_emspi_rx_cmd_cb; -static void *ble_hci_emspi_rx_cmd_arg; - -static ble_hci_trans_rx_acl_fn *ble_hci_emspi_rx_acl_cb; -static void *ble_hci_emspi_rx_acl_arg; - -static struct os_mempool ble_hci_emspi_evt_hi_pool; -static os_membuf_t ble_hci_emspi_evt_hi_buf[ - OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_HCI_EVT_HI_BUF_COUNT), - MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE)) -]; - -static struct os_mempool ble_hci_emspi_evt_lo_pool; -static os_membuf_t ble_hci_emspi_evt_lo_buf[ - OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_HCI_EVT_LO_BUF_COUNT), - MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE)) -]; - -static struct os_mempool ble_hci_emspi_cmd_pool; -static os_membuf_t ble_hci_emspi_cmd_buf[ - OS_MEMPOOL_SIZE(1, BLE_HCI_TRANS_CMD_SZ) -]; - -static struct os_mbuf_pool ble_hci_emspi_acl_mbuf_pool; -static struct os_mempool_ext ble_hci_emspi_acl_pool; - -/* - * The MBUF payload size must accommodate the HCI data header size plus the - * maximum ACL data packet length. The ACL block size is the size of the - * mbufs we will allocate. - */ -#define ACL_BLOCK_SIZE OS_ALIGN(MYNEWT_VAL(BLE_ACL_BUF_SIZE) \ - + BLE_MBUF_MEMBLOCK_OVERHEAD \ - + BLE_HCI_DATA_HDR_SZ, OS_ALIGNMENT) - -static os_membuf_t ble_hci_emspi_acl_buf[ - OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_ACL_BUF_COUNT), - ACL_BLOCK_SIZE) -]; - /** * A packet to be sent over the EMSPI. This can be a command, an event, or ACL * data. @@ -124,8 +73,7 @@ STAILQ_HEAD(, ble_hci_emspi_pkt) ble_hci_emspi_tx_q; static struct os_mempool ble_hci_emspi_pkt_pool; static os_membuf_t ble_hci_emspi_pkt_buf[ - OS_MEMPOOL_SIZE(BLE_HCI_EMSPI_PKT_EVT_COUNT + 1 + - MYNEWT_VAL(BLE_HCI_ACL_OUT_COUNT), + OS_MEMPOOL_SIZE(1 + MYNEWT_VAL(BLE_TRANSPORT_ACL_FROM_HS_COUNT), sizeof (struct ble_hci_emspi_pkt)) ]; @@ -286,18 +234,6 @@ ble_hci_emspi_rx(uint8_t *data, int max_len) return rc; } -/** - * Allocates a buffer (mbuf) for ACL operation. - * - * @return The allocated buffer on success; - * NULL on buffer exhaustion. - */ -static struct os_mbuf * -ble_hci_trans_acl_buf_alloc(void) -{ - return os_mbuf_get_pkthdr(&ble_hci_emspi_acl_mbuf_pool, 0); -} - /** * Transmits an ACL data packet to the controller. The caller relinquishes the * specified mbuf, regardless of return status. @@ -344,7 +280,7 @@ ble_hci_emspi_cmdevt_tx(uint8_t *cmd_buf, uint8_t pkt_type) pkt = os_memblock_get(&ble_hci_emspi_pkt_pool); if (pkt == NULL) { - ble_hci_trans_buf_free(cmd_buf); + ble_transport_free(cmd_buf); return BLE_ERR_MEM_CAPACITY; } @@ -449,7 +385,7 @@ ble_hci_emspi_tx_pkt(void) switch (pkt->type) { case BLE_HCI_EMSPI_PKT_CMD: rc = ble_hci_emspi_tx_cmd(pkt->data); - ble_hci_trans_buf_free(pkt->data); + ble_transport_free(pkt->data); break; case BLE_HCI_EMSPI_PKT_ACL: @@ -477,7 +413,7 @@ ble_hci_emspi_rx_evt(void) /* XXX: we should not assert if host cannot allocate an event. Need * to determine what to do here. */ - data = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); + data = ble_transport_alloc_evt(0); assert(data != NULL); rc = ble_hci_emspi_rx(data, sizeof(struct ble_hci_ev)); @@ -493,8 +429,7 @@ ble_hci_emspi_rx_evt(void) } } - assert(ble_hci_emspi_rx_cmd_cb != NULL); - ble_hci_emspi_rx_cmd_cb(data, ble_hci_emspi_rx_cmd_arg); + rc = ble_transport_to_hs_evt(data); if (rc != 0) { goto err; } @@ -502,7 +437,7 @@ ble_hci_emspi_rx_evt(void) return 0; err: - ble_hci_trans_buf_free(data); + ble_transport_free(data); return rc; } @@ -516,7 +451,7 @@ ble_hci_emspi_rx_acl(void) /* XXX: we should not assert if host cannot allocate an mbuf. Need to * determine what to do here. */ - om = ble_hci_trans_acl_buf_alloc(); + om = ble_transport_alloc_acl_from_ll(); assert(om != NULL); rc = ble_hci_emspi_rx(om->om_data, BLE_HCI_DATA_HDR_SZ); @@ -525,7 +460,7 @@ ble_hci_emspi_rx_acl(void) } len = get_le16(om->om_data + 2); - if (len > MYNEWT_VAL(BLE_ACL_BUF_SIZE)) { + if (len > MYNEWT_VAL(BLE_TRANSPORT_ACL_SIZE)) { /* * Data portion cannot exceed data length of acl buffer. If it does * this is considered to be a loss of sync. @@ -544,8 +479,7 @@ ble_hci_emspi_rx_acl(void) OS_MBUF_PKTLEN(om) = BLE_HCI_DATA_HDR_SZ + len; om->om_len = BLE_HCI_DATA_HDR_SZ + len; - assert(ble_hci_emspi_rx_cmd_cb != NULL); - rc = ble_hci_emspi_rx_acl_cb(om, ble_hci_emspi_rx_acl_arg); + rc = ble_transport_to_hs_acl(om); if (rc != 0) { goto err; } @@ -586,18 +520,6 @@ ble_hci_emspi_rx_pkt(void) } } -static void -ble_hci_emspi_set_rx_cbs(ble_hci_trans_rx_cmd_fn *cmd_cb, - void *cmd_arg, - ble_hci_trans_rx_acl_fn *acl_cb, - void *acl_arg) -{ - ble_hci_emspi_rx_cmd_cb = cmd_cb; - ble_hci_emspi_rx_cmd_arg = cmd_arg; - ble_hci_emspi_rx_acl_cb = acl_cb; - ble_hci_emspi_rx_acl_arg = acl_arg; -} - static void ble_hci_emspi_free_pkt(uint8_t type, uint8_t *cmdevt, struct os_mbuf *acl) { @@ -607,7 +529,7 @@ ble_hci_emspi_free_pkt(uint8_t type, uint8_t *cmdevt, struct os_mbuf *acl) case BLE_HCI_EMSPI_PKT_CMD: case BLE_HCI_EMSPI_PKT_EVT: - ble_hci_trans_buf_free(cmdevt); + ble_transport_free(cmdevt); break; case BLE_HCI_EMSPI_PKT_ACL: @@ -620,24 +542,6 @@ ble_hci_emspi_free_pkt(uint8_t type, uint8_t *cmdevt, struct os_mbuf *acl) } } -/** - * Unsupported. This is a host-only transport. - */ -int -ble_hci_trans_ll_evt_tx(uint8_t *cmd) -{ - return BLE_ERR_UNSUPPORTED; -} - -/** - * Unsupported. This is a host-only transport. - */ -int -ble_hci_trans_ll_acl_tx(struct os_mbuf *om) -{ - return BLE_ERR_UNSUPPORTED; -} - /** * Sends an HCI command from the host to the controller. * @@ -673,134 +577,6 @@ ble_hci_trans_hs_acl_tx(struct os_mbuf *om) return rc; } -/** - * Configures the HCI transport to call the specified callback upon receiving - * HCI packets from the controller. This function should only be called by by - * host. - * - * @param cmd_cb The callback to execute upon receiving an HCI - * event. - * @param cmd_arg Optional argument to pass to the command - * callback. - * @param acl_cb The callback to execute upon receiving ACL - * data. - * @param acl_arg Optional argument to pass to the ACL - * callback. - */ -void -ble_hci_trans_cfg_hs(ble_hci_trans_rx_cmd_fn *cmd_cb, - void *cmd_arg, - ble_hci_trans_rx_acl_fn *acl_cb, - void *acl_arg) -{ - ble_hci_emspi_set_rx_cbs(cmd_cb, cmd_arg, acl_cb, acl_arg); -} - -/** - * Configures the HCI transport to operate with a host. The transport will - * execute specified callbacks upon receiving HCI packets from the controller. - * - * @param cmd_cb The callback to execute upon receiving an HCI - * event. - * @param cmd_arg Optional argument to pass to the command - * callback. - * @param acl_cb The callback to execute upon receiving ACL - * data. - * @param acl_arg Optional argument to pass to the ACL - * callback. - */ -void -ble_hci_trans_cfg_ll(ble_hci_trans_rx_cmd_fn *cmd_cb, - void *cmd_arg, - ble_hci_trans_rx_acl_fn *acl_cb, - void *acl_arg) -{ - /* Unsupported. */ - assert(0); -} - -/** - * Allocates a flat buffer of the specified type. - * - * @param type The type of buffer to allocate; one of the - * BLE_HCI_TRANS_BUF_[...] constants. - * - * @return The allocated buffer on success; - * NULL on buffer exhaustion. - */ -uint8_t * -ble_hci_trans_buf_alloc(int type) -{ - uint8_t *buf; - - switch (type) { - case BLE_HCI_TRANS_BUF_CMD: - buf = os_memblock_get(&ble_hci_emspi_cmd_pool); - break; - case BLE_HCI_TRANS_BUF_EVT_HI: - buf = os_memblock_get(&ble_hci_emspi_evt_hi_pool); - if (buf == NULL) { - /* If no high-priority event buffers remain, try to grab a - * low-priority one. - */ - buf = os_memblock_get(&ble_hci_emspi_evt_lo_pool); - } - break; - - case BLE_HCI_TRANS_BUF_EVT_LO: - buf = os_memblock_get(&ble_hci_emspi_evt_lo_pool); - break; - - default: - assert(0); - buf = NULL; - } - - return buf; -} - -/** - * Frees the specified flat buffer. The buffer must have been allocated via - * ble_hci_trans_buf_alloc(). - * - * @param buf The buffer to free. - */ -void -ble_hci_trans_buf_free(uint8_t *buf) -{ - int rc; - - if (buf != NULL) { - if (os_memblock_from(&ble_hci_emspi_evt_hi_pool, buf)) { - rc = os_memblock_put(&ble_hci_emspi_evt_hi_pool, buf); - assert(rc == 0); - } else if (os_memblock_from(&ble_hci_emspi_evt_lo_pool, buf)) { - rc = os_memblock_put(&ble_hci_emspi_evt_lo_pool, buf); - assert(rc == 0); - } else { - assert(os_memblock_from(&ble_hci_emspi_cmd_pool, buf)); - rc = os_memblock_put(&ble_hci_emspi_cmd_pool, buf); - assert(rc == 0); - } - } -} - -/** - * Configures a callback to get executed whenever an ACL data packet is freed. - * The function is called in lieu of actually freeing the packet. - * - * @param cb The callback to configure. - * - * @return 0 on success. - */ -int -ble_hci_trans_set_acl_free_cb(os_mempool_put_fn *cb, void *arg) -{ - ble_hci_emspi_acl_pool.mpe_put_cb = cb; - ble_hci_emspi_acl_pool.mpe_put_arg = arg; - return 0; -} - /** * Resets the HCI UART transport to a clean state. Frees all buffers and * reconfigures the UART. @@ -875,69 +651,22 @@ ble_hci_emspi_init_hw(void) hal_gpio_write(MYNEWT_VAL(BLE_HCI_EMSPI_RESET_PIN), 1); } -/** - * Initializes the UART HCI transport module. - * - * @return 0 on success; - * A BLE_ERR_[...] error code on failure. - */ void -ble_hci_emspi_init(void) +ble_transport_ll_init(void) { int rc; /* Ensure this function only gets called by sysinit. */ SYSINIT_ASSERT_ACTIVE(); - rc = os_mempool_ext_init(&ble_hci_emspi_acl_pool, - MYNEWT_VAL(BLE_ACL_BUF_COUNT), - ACL_BLOCK_SIZE, - ble_hci_emspi_acl_buf, - "ble_hci_emspi_acl_pool"); - SYSINIT_PANIC_ASSERT(rc == 0); - - rc = os_mbuf_pool_init(&ble_hci_emspi_acl_mbuf_pool, - &ble_hci_emspi_acl_pool.mpe_mp, - ACL_BLOCK_SIZE, - MYNEWT_VAL(BLE_ACL_BUF_COUNT)); - SYSINIT_PANIC_ASSERT(rc == 0); - - /* - * Create memory pool of HCI command buffers. NOTE: we currently dont - * allow this to be configured. The controller will only allow one - * outstanding command. We decided to keep this a pool in case we allow - * allow the controller to handle more than one outstanding command. - */ - rc = os_mempool_init(&ble_hci_emspi_cmd_pool, - 1, - BLE_HCI_TRANS_CMD_SZ, - ble_hci_emspi_cmd_buf, - "ble_hci_emspi_cmd_pool"); - SYSINIT_PANIC_ASSERT(rc == 0); - - rc = os_mempool_init(&ble_hci_emspi_evt_hi_pool, - MYNEWT_VAL(BLE_HCI_EVT_HI_BUF_COUNT), - MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE), - ble_hci_emspi_evt_hi_buf, - "ble_hci_emspi_evt_hi_pool"); - SYSINIT_PANIC_ASSERT(rc == 0); - - rc = os_mempool_init(&ble_hci_emspi_evt_lo_pool, - MYNEWT_VAL(BLE_HCI_EVT_LO_BUF_COUNT), - MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE), - ble_hci_emspi_evt_lo_buf, - "ble_hci_emspi_evt_lo_pool"); - SYSINIT_PANIC_ASSERT(rc == 0); - /* * Create memory pool of packet list nodes. NOTE: the number of these - * buffers should be, at least, the total number of event buffers (hi - * and lo), the number of command buffers (currently 1) and the total - * number of buffers that the controller could possibly hand to the host. + * buffers should be, at least, the number of command buffers (currently 1) + * and the total number of buffers that the controller could possibly hand + * to the host. */ - rc = os_mempool_init(&ble_hci_emspi_pkt_pool, - BLE_HCI_EMSPI_PKT_EVT_COUNT + 1 + - MYNEWT_VAL(BLE_HCI_ACL_OUT_COUNT), + rc = os_mempool_init(&ble_hci_emspi_pkt_pool, 1 + + MYNEWT_VAL(BLE_TRANSPORT_ACL_FROM_HS_COUNT), sizeof (struct ble_hci_emspi_pkt), ble_hci_emspi_pkt_buf, "ble_hci_emspi_pkt_pool"); @@ -955,3 +684,15 @@ ble_hci_emspi_init(void) MYNEWT_VAL(BLE_HCI_EMSPI_STACK_SIZE)); SYSINIT_PANIC_ASSERT(rc == 0); } + +int +ble_transport_to_ll_cmd_impl(void *buf) +{ + return ble_hci_emspi_cmdevt_tx(buf, BLE_HCI_EMSPI_PKT_CMD); +} + +int +ble_transport_to_ll_acl_impl(struct os_mbuf *om) +{ + return ble_hci_emspi_acl_tx(om); +} \ No newline at end of file diff --git a/nimble/transport/emspi/syscfg.yml b/nimble/transport/emspi/syscfg.yml index 4751271b0d..12a853e749 100644 --- a/nimble/transport/emspi/syscfg.yml +++ b/nimble/transport/emspi/syscfg.yml @@ -28,38 +28,6 @@ syscfg.defs: # This is a host-only transport. - BLE_HOST - BLE_HCI_EVT_HI_BUF_COUNT: - description: 'Number of high-priority event buffers.' - value: 2 - - BLE_HCI_EVT_LO_BUF_COUNT: - description: 'Number of low-priority event buffers.' - value: 8 - - BLE_HCI_EVT_BUF_SIZE: - description: 'Size of each event buffer, in bytes.' - value: 70 - - BLE_ACL_BUF_COUNT: - description: 'The number of ACL data buffers' - value: 4 - - BLE_ACL_BUF_SIZE: - description: > - This is the maximum size of the data portion of HCI ACL data - packets. It does not include the HCI data header (of 4 bytes). - value: 255 - - BLE_HCI_ACL_OUT_COUNT: - description: > - This count is used in creating a pool of elements used by the - code to enqueue various elements. In the case of the controller - only HCI, this number should be equal to the number of mbufs in - the msys pool. For host only, it is really dependent on the - number of ACL buffers that the controller tells the host it - has. - value: 12 - BLE_HCI_EMSPI_SPI_NUM: description: The index of the SPI device to use for HCI. value: 5 @@ -94,6 +62,3 @@ syscfg.defs: description: > Sysinit stage for the EMSPI BLE transport. value: 100 - -syscfg.vals.BLE_EXT_ADV: - BLE_HCI_EVT_BUF_SIZE: 257 diff --git a/nimble/transport/include/nimble/transport.h b/nimble/transport/include/nimble/transport.h new file mode 100644 index 0000000000..f5a30780b6 --- /dev/null +++ b/nimble/transport/include/nimble/transport.h @@ -0,0 +1,69 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_NIMBLE_TRANSPORT_ +#define H_NIMBLE_TRANSPORT_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#if MYNEWT_PKG_apache_mynewt_nimble__nimble_transport_common_hci_ipc +#include +#endif + +struct os_mbuf; + +/* Initialization */ +void ble_transport_init(void); + +/* Common HCI RX task functions */ +typedef void ble_transport_rx_func_t(void *arg); +void ble_transport_rx_register(ble_transport_rx_func_t *func, void *arg); +void ble_transport_rx(void); + +/* Allocators for supported data types */ +void *ble_transport_alloc_cmd(void); +void *ble_transport_alloc_evt(int discardable); +struct os_mbuf *ble_transport_alloc_acl_from_hs(void); +struct os_mbuf *ble_transport_alloc_iso_from_hs(void); +struct os_mbuf *ble_transport_alloc_acl_from_ll(void); +struct os_mbuf *ble_transport_alloc_iso_from_ll(void); + +/* Generic deallocator for cmd/evt buffers */ +void ble_transport_free(void *buf); + +/* Register put callback on acl_from_ll mbufs (for ll-hs flow control) */ +int ble_transport_register_put_acl_from_ll_cb(os_mempool_put_fn *cb); + +/* Send data to hs/ll side */ +int ble_transport_to_ll_cmd(void *buf); +int ble_transport_to_ll_acl(struct os_mbuf *om); +int ble_transport_to_ll_iso(struct os_mbuf *om); +int ble_transport_to_hs_evt(void *buf); +int ble_transport_to_hs_acl(struct os_mbuf *om); +int ble_transport_to_hs_iso(struct os_mbuf *om); + +#ifdef __cplusplus +} +#endif + +#endif /* H_NIMBLE_TRANSPORT_ */ diff --git a/nimble/transport/include/nimble/transport/monitor.h b/nimble/transport/include/nimble/transport/monitor.h new file mode 100644 index 0000000000..dc12c69c4a --- /dev/null +++ b/nimble/transport/include/nimble/transport/monitor.h @@ -0,0 +1,91 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_BLE_MONITOR_ +#define H_BLE_MONITOR_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define BLE_MONITOR (MYNEWT_VAL(BLE_MONITOR_RTT) || \ + MYNEWT_VAL(BLE_MONITOR_UART)) + +#if BLE_MONITOR +int ble_monitor_out(int c); +int ble_monitor_log(int level, const char *fmt, ...); +#else +static inline int +ble_monitor_out(int c) +{ + (void)c; + return 0; +} +static inline int +ble_monitor_log(int level, const char *fmt, ...) +{ + (void)level; + (void)fmt; + return 0; +} + +static inline int +ble_transport_to_ll_cmd(void *buf) +{ + return ble_transport_to_ll_cmd_impl(buf); +} + +static inline int +ble_transport_to_ll_acl(struct os_mbuf *om) +{ + return ble_transport_to_ll_acl_impl(om); +} + +static inline int +ble_transport_to_ll_iso(struct os_mbuf *om) +{ + return ble_transport_to_ll_iso_impl(om); +} + +static inline int +ble_transport_to_hs_evt(void *buf) +{ + return ble_transport_to_hs_evt_impl(buf); +} + +static inline int +ble_transport_to_hs_acl(struct os_mbuf *om) +{ + return ble_transport_to_hs_acl_impl(om); +} + +static inline int +ble_transport_to_hs_iso(struct os_mbuf *om) +{ + return ble_transport_to_hs_iso_impl(om); +} +#endif /* BLE_MONITOR */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/nimble/transport/include/nimble/transport/transport_ipc.h b/nimble/transport/include/nimble/transport/transport_ipc.h new file mode 100644 index 0000000000..8059c3aeb8 --- /dev/null +++ b/nimble/transport/include/nimble/transport/transport_ipc.h @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_NIMBLE_TRANSPORT_IPC_ +#define H_NIMBLE_TRANSPORT_IPC_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +/* NOTE: These APIs shall only be used by IPC transports */ + +#define BLE_TRANSPORT_IPC \ + MYNEWT_PKG_apache_mynewt_nimble__nimble_transport_common_hci_ipc +#define BLE_TRANSPORT_IPC_ON_HS \ + (BLE_TRANSPORT_IPC && !MYNEWT_VAL(BLE_CONTROLLER)) +#define BLE_TRANSPORT_IPC_ON_LL \ + (BLE_TRANSPORT_IPC && MYNEWT_VAL(BLE_CONTROLLER)) + +/* Free cmd/evt buffer sent over IPC */ +void ble_transport_ipc_free(void *buf); + +/* Get IPC type for cmd/evt buffer */ +uint8_t ble_transport_ipc_buf_evt_type_get(void *buf); + +#ifdef __cplusplus +} +#endif + +#endif /* H_NIMBLE_TRANSPORT_IPC_ */ diff --git a/nimble/transport/include/nimble/transport_impl.h b/nimble/transport/include/nimble/transport_impl.h new file mode 100644 index 0000000000..8d95c8920e --- /dev/null +++ b/nimble/transport/include/nimble/transport_impl.h @@ -0,0 +1,43 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_NIMBLE_TRANSPORT_IMPL_ +#define H_NIMBLE_TRANSPORT_IMPL_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Init functions to be implemented for transport acting as HS/LL side */ +extern void ble_transport_ll_init(void); +extern void ble_transport_hs_init(void); + +/* APIs to be implemented by HS/LL side of transports */ +extern int ble_transport_to_ll_cmd_impl(void *buf); +extern int ble_transport_to_ll_acl_impl(struct os_mbuf *om); +extern int ble_transport_to_ll_iso_impl(struct os_mbuf *om); +extern int ble_transport_to_hs_evt_impl(void *buf); +extern int ble_transport_to_hs_acl_impl(struct os_mbuf *om); +extern int ble_transport_to_hs_iso_impl(struct os_mbuf *om); + +#ifdef __cplusplus +} +#endif + +#endif /* H_NIMBLE_TRANSPORT_IMPL_ */ diff --git a/nimble/transport/nrf5340/pkg.yml b/nimble/transport/nrf5340/pkg.yml index 4db567c81f..be44d0f8d1 100644 --- a/nimble/transport/nrf5340/pkg.yml +++ b/nimble/transport/nrf5340/pkg.yml @@ -27,12 +27,10 @@ pkg.keywords: - nrf5340 pkg.deps: - - "@apache-mynewt-nimble/nimble" + - nimble + - nimble/transport/common/hci_ipc - "@apache-mynewt-core/kernel/os" - "@apache-mynewt-core/hw/drivers/ipc_nrf5340" pkg.apis: - ble_transport - -pkg.init: - nrf5340_ble_hci_init: 'MYNEWT_VAL(BLE_TRANS_NRF5340_SYSINIT_STAGE)' diff --git a/nimble/transport/nrf5340/src/nrf5340_ble_hci.c b/nimble/transport/nrf5340/src/nrf5340_ble_hci.c index 9bf956b56b..f73be05522 100644 --- a/nimble/transport/nrf5340/src/nrf5340_ble_hci.c +++ b/nimble/transport/nrf5340/src/nrf5340_ble_hci.c @@ -19,117 +19,53 @@ #include #include -#include +#include +#include #include -#include -#include #include - -#define HCI_PKT_NONE 0x00 -#define HCI_PKT_CMD 0x01 -#define HCI_PKT_ACL 0x02 -#define HCI_PKT_EVT 0x04 - -#define POOL_ACL_BLOCK_SIZE OS_ALIGN(MYNEWT_VAL(BLE_ACL_BUF_SIZE) + \ - BLE_MBUF_MEMBLOCK_OVERHEAD + \ - BLE_HCI_DATA_HDR_SZ, OS_ALIGNMENT) +#include +#include +#include #if MYNEWT_VAL(BLE_CONTROLLER) #define IPC_TX_CHANNEL 0 #define IPC_RX_CHANNEL 1 -#endif - -#if MYNEWT_VAL(BLE_HOST) +#else #define IPC_TX_CHANNEL 1 #define IPC_RX_CHANNEL 0 #endif -struct nrf5340_ble_hci_api { -#if MYNEWT_VAL(BLE_CONTROLLER) - ble_hci_trans_rx_cmd_fn *cmd_cb; - void *cmd_arg; -#endif -#if MYNEWT_VAL(BLE_HOST) - ble_hci_trans_rx_cmd_fn *evt_cb; - void *evt_arg; -#endif - ble_hci_trans_rx_acl_fn *acl_cb; - void *acl_arg; -}; - -struct nrf5340_ble_hci_rx_data { - uint8_t type; - uint8_t hdr[4]; - uint16_t len; - uint16_t expected_len; - union { - uint8_t *buf; - struct os_mbuf *om; - }; -}; - -struct nrf5340_ble_hci_pool_cmd { - uint8_t cmd[BLE_HCI_TRANS_CMD_SZ]; - bool allocated; -}; - -/* - * If controller-to-host flow control is enabled we need to hold an extra command - * buffer for HCI_Host_Number_Of_Completed_Packets which can be sent at any time. - */ -#if MYNEWT_VAL(BLE_HS_FLOW_CTRL) || MYNEWT_VAL(BLE_LL_CFG_FEAT_CTRL_TO_HOST_FLOW_CONTROL) -#define HCI_CMD_COUNT 2 -#else -#define HCI_CMD_COUNT 1 -#endif - -static uint8_t nrf5340_ble_hci_pool_cmd_mempool_buf[OS_MEMPOOL_BYTES( - HCI_CMD_COUNT, - BLE_HCI_TRANS_CMD_SZ)]; -static struct os_mempool nrf5340_ble_hci_pool_cmd_mempool; - -/* Pools for HCI events (high and low priority) */ -static uint8_t nrf5340_ble_hci_pool_evt_hi_buf[OS_MEMPOOL_BYTES( - MYNEWT_VAL(BLE_HCI_EVT_HI_BUF_COUNT), - MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE))]; -static struct os_mempool nrf5340_ble_hci_pool_evt_hi; -static uint8_t nrf5340_ble_hci_pool_evt_lo_buf[OS_MEMPOOL_BYTES( - MYNEWT_VAL(BLE_HCI_EVT_LO_BUF_COUNT), - MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE))]; -static struct os_mempool nrf5340_ble_hci_pool_evt_lo; - -/* Pool for ACL data */ -static uint8_t nrf5340_ble_hci_pool_acl_buf[OS_MEMPOOL_BYTES( - MYNEWT_VAL(BLE_ACL_BUF_COUNT), - POOL_ACL_BLOCK_SIZE)]; -static struct os_mempool_ext nrf5340_ble_hci_pool_acl; -static struct os_mbuf_pool nrf5340_ble_hci_pool_acl_mbuf; - -/* Interface to host/ll */ -static struct nrf5340_ble_hci_api nrf5340_ble_hci_api; - -/* State of RX currently in progress (needs to reassemble frame) */ -static struct nrf5340_ble_hci_rx_data nrf5340_ble_hci_rx_data; +static struct hci_ipc_sm g_hci_ipc_sm; -int -ble_hci_trans_reset(void) +static void +rx_func(void *arg) { - /* XXX Should we do something with RF and/or BLE core? */ - return 0; + uint8_t *buf; + int len; + + len = ipc_nrf5340_available_buf(IPC_RX_CHANNEL, (void **)&buf); + while (len > 0) { + len = hci_ipc_rx(&g_hci_ipc_sm, buf, len); + ipc_nrf5340_consume(IPC_RX_CHANNEL, len); + len = ipc_nrf5340_available_buf(IPC_RX_CHANNEL, (void **)&buf); + } } static int -ble_hci_trans_acl_tx(struct os_mbuf *om) +nrf5340_ble_hci_acl_tx(struct os_mbuf *om) { - uint8_t ind = HCI_PKT_ACL; + struct hci_ipc_hdr hdr; struct os_mbuf *x; int rc; - rc = ipc_nrf5340_send(IPC_TX_CHANNEL, &ind, 1); + hdr.type = HCI_IPC_TYPE_ACL; + hdr.length = 4 + get_le16(&om->om_data[2]); + + rc = ipc_nrf5340_write(IPC_TX_CHANNEL, &hdr, sizeof(hdr), false); if (rc == 0) { x = om; while (x) { - rc = ipc_nrf5340_send(IPC_TX_CHANNEL, x->om_data, x->om_len); + rc = ipc_nrf5340_write(IPC_TX_CHANNEL, x->om_data, x->om_len, true); if (rc < 0) { break; } @@ -142,343 +78,176 @@ ble_hci_trans_acl_tx(struct os_mbuf *om) return (rc < 0) ? BLE_ERR_MEM_CAPACITY : 0; } -#if MYNEWT_VAL(BLE_CONTROLLER) -void -ble_hci_trans_cfg_ll(ble_hci_trans_rx_cmd_fn *cmd_cb, void *cmd_arg, - ble_hci_trans_rx_acl_fn *acl_cb, void *acl_arg) -{ - nrf5340_ble_hci_api.cmd_cb = cmd_cb; - nrf5340_ble_hci_api.cmd_arg = cmd_arg; - nrf5340_ble_hci_api.acl_cb = acl_cb; - nrf5340_ble_hci_api.acl_arg = acl_arg; -} - -int -ble_hci_trans_ll_evt_tx(uint8_t *hci_ev) +#if !MYNEWT_VAL(BLE_CONTROLLER) +static int +nrf5340_ble_hci_iso_tx(struct os_mbuf *om) { - uint8_t ind = HCI_PKT_EVT; - int len = 2 + hci_ev[1]; + struct hci_ipc_hdr hdr; + struct os_mbuf *x; int rc; - rc = ipc_nrf5340_send(IPC_TX_CHANNEL, &ind, 1); + hdr.type = HCI_IPC_TYPE_ISO; + hdr.length = 4 + BLE_HCI_ISO_LENGTH(get_le16(&om->om_data[2])); + + rc = ipc_nrf5340_write(IPC_TX_CHANNEL, &hdr, sizeof(hdr), false); if (rc == 0) { - rc = ipc_nrf5340_send(IPC_TX_CHANNEL, hci_ev, len); + x = om; + while (x) { + rc = ipc_nrf5340_write(IPC_TX_CHANNEL, x->om_data, x->om_len, true); + if (rc < 0) { + break; + } + x = SLIST_NEXT(x, om_next); + } } - ble_hci_trans_buf_free(hci_ev); + os_mbuf_free_chain(om); return (rc < 0) ? BLE_ERR_MEM_CAPACITY : 0; } +#endif -int -ble_hci_trans_ll_acl_tx(struct os_mbuf *om) +static void +nrf5340_ble_hci_trans_rx(int channel, void *user_data) { - return ble_hci_trans_acl_tx(om); -} + assert(channel == IPC_RX_CHANNEL); + +#if MYNEWT_VAL(BLE_TRANSPORT_RX_TASK) + ble_transport_rx(); +#else + rx_func(NULL); #endif +} -#if MYNEWT_VAL(BLE_HOST) -void -ble_hci_trans_cfg_hs(ble_hci_trans_rx_cmd_fn *evt_cb, void *evt_arg, - ble_hci_trans_rx_acl_fn *acl_cb, void *acl_arg) +static void +nrf5340_ble_hci_init(void) { - nrf5340_ble_hci_api.evt_cb = evt_cb; - nrf5340_ble_hci_api.evt_arg = evt_arg; - nrf5340_ble_hci_api.acl_cb = acl_cb; - nrf5340_ble_hci_api.acl_arg = acl_arg; + os_sr_t sr; + + SYSINIT_ASSERT_ACTIVE(); + +#if MYNEWT_VAL(BLE_TRANSPORT_RX_TASK) + ble_transport_rx_register(rx_func, NULL); +#endif + ipc_nrf5340_recv(IPC_RX_CHANNEL, nrf5340_ble_hci_trans_rx, NULL); + + OS_ENTER_CRITICAL(sr); + nrf5340_ble_hci_trans_rx(IPC_RX_CHANNEL, NULL); + OS_EXIT_CRITICAL(sr); } +#if MYNEWT_VAL(BLE_CONTROLLER) int -ble_hci_trans_hs_cmd_tx(uint8_t *cmd) +ble_transport_to_hs_evt_impl(void *buf) { - uint8_t ind = HCI_PKT_CMD; - int len = 3 + cmd[2]; + struct hci_ipc_hdr hdr; + uint8_t *hci_ev = buf; int rc; - rc = ipc_nrf5340_send(IPC_TX_CHANNEL, &ind, 1); + hdr.type = ble_transport_ipc_buf_evt_type_get(buf); + hdr.length = 2 + hci_ev[1]; + + rc = ipc_nrf5340_write(IPC_TX_CHANNEL, &hdr, sizeof(hdr), false); if (rc == 0) { - rc = ipc_nrf5340_send(IPC_TX_CHANNEL, cmd, len); + rc = ipc_nrf5340_write(IPC_TX_CHANNEL, hci_ev, hdr.length, true); } - ble_hci_trans_buf_free(cmd); + ble_transport_ipc_free(buf); - return (rc < 0) ? BLE_ERR_MEM_CAPACITY : 0; + return (rc < 0) ? BLE_ERR_MEM_CAPACITY : 0; } int -ble_hci_trans_hs_acl_tx(struct os_mbuf *om) -{ - return ble_hci_trans_acl_tx(om); -} -#endif - -uint8_t * -ble_hci_trans_buf_alloc(int type) +ble_transport_to_hs_acl_impl(struct os_mbuf *om) { - uint8_t *buf; - - switch (type) { - case BLE_HCI_TRANS_BUF_CMD: - buf = os_memblock_get(&nrf5340_ble_hci_pool_cmd_mempool); - break; - case BLE_HCI_TRANS_BUF_EVT_HI: - buf = os_memblock_get(&nrf5340_ble_hci_pool_evt_hi); - if (buf) { - break; - } - /* no break */ - case BLE_HCI_TRANS_BUF_EVT_LO: - buf = os_memblock_get(&nrf5340_ble_hci_pool_evt_lo); - break; - default: - assert(0); - buf = NULL; - } - - return buf; + return nrf5340_ble_hci_acl_tx(om); } void -ble_hci_trans_buf_free(uint8_t *buf) +ble_transport_hs_init(void) { - int rc; + volatile struct hci_ipc_shm *shm = ipc_nrf5340_hci_shm_get(); - if (os_memblock_from(&nrf5340_ble_hci_pool_cmd_mempool, buf)) { - rc = os_memblock_put(&nrf5340_ble_hci_pool_cmd_mempool, buf); - assert(rc == 0); - } else if (os_memblock_from(&nrf5340_ble_hci_pool_evt_hi, buf)) { - rc = os_memblock_put(&nrf5340_ble_hci_pool_evt_hi, buf); - assert(rc == 0); - } else { - assert(os_memblock_from(&nrf5340_ble_hci_pool_evt_lo, buf)); - rc = os_memblock_put(&nrf5340_ble_hci_pool_evt_lo, buf); - assert(rc == 0); - } + hci_ipc_init(shm, &g_hci_ipc_sm); + nrf5340_ble_hci_init(); } +#endif /* BLE_CONTROLLER */ -static void -nrf5340_ble_hci_trans_rx_process(int channel) +#if !MYNEWT_VAL(BLE_CONTROLLER) +int +ble_transport_to_ll_cmd_impl(void *buf) { - struct nrf5340_ble_hci_rx_data *rxd = &nrf5340_ble_hci_rx_data; -#if MYNEWT_VAL(BLE_HOST) - int pool = BLE_HCI_TRANS_BUF_EVT_HI; -#endif + struct hci_ipc_hdr hdr; + uint8_t *cmd = buf; int rc; - switch (rxd->type) { - case HCI_PKT_NONE: - ipc_nrf5340_read(channel, &rxd->type, 1); - rxd->len = 0; - rxd->expected_len = 0; - -#if MYNEWT_VAL(BLE_CONTROLLER) - assert((rxd->type == HCI_PKT_ACL) || (rxd->type == HCI_PKT_CMD)); -#endif -#if MYNEWT_VAL(BLE_HOST) - assert((rxd->type == HCI_PKT_ACL) || (rxd->type == HCI_PKT_EVT)); -#endif - break; -#if MYNEWT_VAL(BLE_CONTROLLER) - case HCI_PKT_CMD: - /* header */ - if (rxd->len < 3) { - rxd->len += ipc_nrf5340_read(channel, &rxd->hdr[rxd->len], - 3 - rxd->len); - if (rxd->len < 3) { - break; - } - } - - if (rxd->expected_len == 0) { - rxd->buf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_CMD); - memcpy(rxd->buf, rxd->hdr, rxd->len); - - rxd->expected_len = 3 + rxd->hdr[2]; - } - - if (rxd->len < rxd->expected_len) { - rxd->len += ipc_nrf5340_read(channel, &rxd->buf[rxd->len], - rxd->expected_len - rxd->len); - if (rxd->len < rxd->expected_len) { - break; - } - } - - rc = nrf5340_ble_hci_api.cmd_cb(rxd->buf, nrf5340_ble_hci_api.cmd_arg); - if (rc != 0) { - ble_hci_trans_buf_free(rxd->buf); - } - - rxd->type = HCI_PKT_NONE; - break; -#endif -#if MYNEWT_VAL(BLE_HOST) - case HCI_PKT_EVT: - /* header */ - if (rxd->len < 2) { - rxd->len += ipc_nrf5340_read(channel, &rxd->hdr[rxd->len], - 2 - rxd->len); - if (rxd->len < 2) { - break; - } - } - - if (rxd->hdr[0] == BLE_HCI_EVCODE_LE_META) { - if (rxd->len < 3) { - /* For LE Meta event we need 3 bytes to parse header */ - rxd->len += ipc_nrf5340_read(channel, &rxd->hdr[rxd->len], 1); - if (rxd->len < 3) { - break; - } - } - - /* Advertising reports shall be allocated from low-prio pool */ - if ((rxd->hdr[2] == BLE_HCI_LE_SUBEV_ADV_RPT) || - (rxd->hdr[2] == BLE_HCI_LE_SUBEV_EXT_ADV_RPT)) { - pool = BLE_HCI_TRANS_BUF_EVT_LO; - } - } - - if (rxd->expected_len == 0) { - rxd->buf = ble_hci_trans_buf_alloc(pool); - if (!rxd->buf) { - /* - * Only care about valid buffer when shall be allocated from - * high-prio pool, otherwise NULL is fine and we'll just skip - * this event. - */ - if (pool != BLE_HCI_TRANS_BUF_EVT_LO) { - rxd->buf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_LO); - } - } - - rxd->expected_len = 2 + rxd->hdr[1]; - - /* copy header */ - if (rxd->buf) { - memcpy(rxd->buf, rxd->hdr, rxd->len); - } - } - - if (rxd->buf) { - rxd->len += ipc_nrf5340_read(channel, &rxd->buf[rxd->len], - rxd->expected_len - rxd->len); - if (rxd->len < rxd->expected_len) { - break; - } - - rc = nrf5340_ble_hci_api.evt_cb(rxd->buf, - nrf5340_ble_hci_api.evt_arg); - if (rc != 0) { - ble_hci_trans_buf_free(rxd->buf); - } - } else { - rxd->len += ipc_nrf5340_consume(channel, - rxd->expected_len - rxd->len); - if (rxd->len < rxd->expected_len) { - break; - } - } - - rxd->type = HCI_PKT_NONE; - break; -#endif - case HCI_PKT_ACL: - if (rxd->len < 4) { - rxd->len += ipc_nrf5340_read(channel, &rxd->hdr[rxd->len], - 4 - rxd->len); - if (rxd->len < 4) { - break; - } - } - - /* Parse header and allocate proper buffer if not done yet */ - if (rxd->expected_len == 0) { - rxd->om = os_mbuf_get_pkthdr(&nrf5340_ble_hci_pool_acl_mbuf, - sizeof(struct ble_mbuf_hdr)); - if (!rxd->om) { - /* TODO not much we can do here... */ - assert(0); - } + hdr.type = HCI_IPC_TYPE_CMD; + hdr.length = 3 + cmd[2]; - os_mbuf_append(rxd->om, rxd->hdr, rxd->len); - rxd->expected_len = get_le16(&rxd->hdr[2]) + 4; - } + rc = ipc_nrf5340_write(IPC_TX_CHANNEL, &hdr, sizeof(hdr), false); + if (rc == 0) { + rc = ipc_nrf5340_write(IPC_TX_CHANNEL, cmd, hdr.length, true); + } - if (rxd->len != rxd->expected_len) { - rxd->len += ipc_nrf5340_read_om(channel, rxd->om, - rxd->expected_len - rxd->len); - } + ble_transport_ipc_free(buf); - if (rxd->len == rxd->expected_len) { - rc = nrf5340_ble_hci_api.acl_cb(rxd->om, - nrf5340_ble_hci_api.acl_arg); - if (rc != 0) { - os_mbuf_free_chain(rxd->om); - } - rxd->type = HCI_PKT_NONE; - } - break; - default: - assert(0); - break; - } + return (rc < 0) ? BLE_ERR_MEM_CAPACITY : 0; } -static void -nrf5340_ble_hci_trans_rx(int channel, void *user_data) +int +ble_transport_to_ll_acl_impl(struct os_mbuf *om) { - while (ipc_nrf5340_available(channel) > 0) { - nrf5340_ble_hci_trans_rx_process(channel); - } + return nrf5340_ble_hci_acl_tx(om); } int -ble_hci_trans_set_acl_free_cb(os_mempool_put_fn *cb, void *arg) +ble_transport_to_ll_iso_impl(struct os_mbuf *om) { - nrf5340_ble_hci_pool_acl.mpe_put_cb = cb; - nrf5340_ble_hci_pool_acl.mpe_put_arg = arg; - - return 0; + return nrf5340_ble_hci_iso_tx(om); } void -nrf5340_ble_hci_init(void) +ble_transport_ll_init(void) { - int rc; + volatile struct hci_ipc_shm *shm = ipc_nrf5340_hci_shm_get(); - SYSINIT_ASSERT_ACTIVE(); + hci_ipc_init(shm, &g_hci_ipc_sm); + nrf5340_ble_hci_init(); +} +#endif /* !BLE_CONTROLLER */ - rc = os_mempool_ext_init(&nrf5340_ble_hci_pool_acl, - MYNEWT_VAL(BLE_ACL_BUF_COUNT), POOL_ACL_BLOCK_SIZE, - nrf5340_ble_hci_pool_acl_buf, - "nrf5340_ble_hci_pool_acl"); - SYSINIT_PANIC_ASSERT(rc == 0); - - rc = os_mbuf_pool_init(&nrf5340_ble_hci_pool_acl_mbuf, - &nrf5340_ble_hci_pool_acl.mpe_mp, POOL_ACL_BLOCK_SIZE, - MYNEWT_VAL(BLE_ACL_BUF_COUNT)); - SYSINIT_PANIC_ASSERT(rc == 0); - - rc = os_mempool_init(&nrf5340_ble_hci_pool_evt_hi, - MYNEWT_VAL(BLE_HCI_EVT_HI_BUF_COUNT), - MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE), - nrf5340_ble_hci_pool_evt_hi_buf, - "nrf5340_ble_hci_pool_evt_hi"); - SYSINIT_PANIC_ASSERT(rc == 0); - - rc = os_mempool_init(&nrf5340_ble_hci_pool_evt_lo, - MYNEWT_VAL(BLE_HCI_EVT_LO_BUF_COUNT), - MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE), - nrf5340_ble_hci_pool_evt_lo_buf, - "nrf5340_ble_hci_pool_evt_lo"); - SYSINIT_PANIC_ASSERT(rc == 0); - - rc = os_mempool_init(&nrf5340_ble_hci_pool_cmd_mempool, - HCI_CMD_COUNT, BLE_HCI_TRANS_CMD_SZ, - nrf5340_ble_hci_pool_cmd_mempool_buf, - "nrf5340_ble_hci_pool_cmd_mempool"); - SYSINIT_PANIC_ASSERT(rc == 0); +uint16_t +hci_ipc_atomic_get(volatile uint16_t *num) +{ + int ret; + + __asm__ volatile (".syntax unified \n" + "1: ldrexh r1, [%[addr]] \n" + " mov %[ret], r1 \n" + " cmp r1, #0 \n" + " itte ne \n" + " subne r2, r1, #1 \n" + " strexhne r1, r2, [%[addr]] \n" + " clrexeq \n" + " cmp r1, #0 \n" + " bne 1b \n" + : [ret] "=&r" (ret) + : [addr] "r" (num) + : "r1", "r2", "memory"); + + return ret; +} - ipc_nrf5340_recv(IPC_RX_CHANNEL, nrf5340_ble_hci_trans_rx, NULL); +void +hci_ipc_atomic_put(volatile uint16_t *num) +{ + __asm__ volatile (".syntax unified \n" + "1: ldrexh r1, [%[addr]] \n" + " add r1, r1, #1 \n" + " strexh r2, r1, [%[addr]] \n" + " cmp r2, #0 \n" + " bne 1b \n" + : + : [addr] "r" (num) + : "r1", "r2", "memory"); } diff --git a/nimble/transport/nrf5340/syscfg.yml b/nimble/transport/nrf5340/syscfg.yml index 1417bbc03d..a784a79299 100644 --- a/nimble/transport/nrf5340/syscfg.yml +++ b/nimble/transport/nrf5340/syscfg.yml @@ -14,38 +14,7 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -# - -syscfg.defs: - BLE_HCI_EVT_HI_BUF_COUNT: - description: 'Number of high-priority event buffers.' - value: 2 - - BLE_HCI_EVT_LO_BUF_COUNT: - description: 'Number of low-priority event buffers.' - value: 8 - - BLE_HCI_EVT_BUF_SIZE: - description: 'Size of each event buffer, in bytes.' - value: 70 - - BLE_ACL_BUF_COUNT: - description: 'The number of ACL data buffers' - value: 4 - - BLE_ACL_BUF_SIZE: - description: > - This is the maximum size of the data portion of HCI ACL data - packets. It does not include the HCI data header (of 4 bytes). - value: 255 - - BLE_TRANS_NRF5340_SYSINIT_STAGE: - description: > - Sysinit stage for the RAM BLE transport. - value: 100 -syscfg.vals.BLE_EXT_ADV: - BLE_HCI_EVT_BUF_SIZE: 257 - -syscfg.restrictions: - - '!(BLE_HOST && BLE_CONTROLLER)' +syscfg.vals.BLE_MONITOR: + BLE_TRANSPORT_RX_TASK_STACK_SIZE: 120 + BLE_TRANSPORT_RX_TASK_PRIO: 1 diff --git a/nimble/transport/pkg.yml b/nimble/transport/pkg.yml index 8174286d06..30237f75bd 100644 --- a/nimble/transport/pkg.yml +++ b/nimble/transport/pkg.yml @@ -25,30 +25,40 @@ pkg.keywords: - ble - bluetooth -pkg.deps.'BLE_HCI_TRANSPORT == "builtin"': - - nimble/transport/ram - - nimble/controller +pkg.apis: + - ble_transport -pkg.deps.'BLE_HCI_TRANSPORT == "emspi"': +pkg.deps.'BLE_TRANSPORT_HS == "native"': + - nimble/host +pkg.deps.'BLE_TRANSPORT_LL == "native"': + - nimble/controller +pkg.deps.'BLE_TRANSPORT_LL == "emspi"': - nimble/transport/emspi - -pkg.deps.'BLE_HCI_TRANSPORT == "ram"': - - nimble/transport/ram - -pkg.deps.'BLE_HCI_TRANSPORT == "socket"': +pkg.deps.'BLE_TRANSPORT_HS == "dialog_cmac" || BLE_TRANSPORT_LL == "dialog_cmac"': + - nimble/transport/dialog_cmac +pkg.deps.'BLE_TRANSPORT_HS == "nrf5340" || BLE_TRANSPORT_LL == "nrf5340"': + - nimble/transport/nrf5340 +pkg.deps.'BLE_TRANSPORT_LL == "socket"': - nimble/transport/socket - -pkg.deps.'BLE_HCI_TRANSPORT == "uart"': +pkg.deps.'BLE_TRANSPORT_HS == "uart"': - nimble/transport/uart +pkg.deps.'BLE_TRANSPORT_HS == "usb"': + - nimble/transport/usb +pkg.deps.'BLE_TRANSPORT_HS == "cdc"': + - nimble/transport/cdc +pkg.deps.'BLE_TRANSPORT_LL == "apollo3"': + - nimble/transport/apollo3 +pkg.deps.'BLE_TRANSPORT_LL == "uart_ll"': + - nimble/transport/uart_ll -pkg.deps.'BLE_HCI_TRANSPORT == "da1469x"': - - nimble/transport/da1469x - -pkg.deps.'BLE_HCI_TRANSPORT == "dialog_cmac"': - - nimble/transport/dialog_cmac +pkg.deps.BLE_MONITOR_RTT: + - "@apache-mynewt-core/hw/drivers/rtt" -pkg.deps.'BLE_HCI_TRANSPORT == "usb"': - - nimble/transport/usb +pkg.init: + ble_transport_init: 250 + ble_transport_hs_init: 251 + ble_transport_ll_init: + - $after:ble_transport_hs_init -pkg.deps.'BLE_HCI_TRANSPORT == "nrf5340"': - - nimble/transport/nrf5340 +pkg.init.'BLE_MONITOR_RTT || BLE_MONITOR_UART': + ble_monitor_init: $before:ble_transport_init diff --git a/nimble/transport/ram/src/ble_hci_ram.c b/nimble/transport/ram/src/ble_hci_ram.c deleted file mode 100644 index 3f10e9df73..0000000000 --- a/nimble/transport/ram/src/ble_hci_ram.c +++ /dev/null @@ -1,238 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#include -#include -#include -#include "syscfg/syscfg.h" -#include "sysinit/sysinit.h" -#include "os/os.h" -#include "mem/mem.h" -#include "nimble/ble.h" -#include "nimble/ble_hci_trans.h" -#include "transport/ram/ble_hci_ram.h" - -static ble_hci_trans_rx_cmd_fn *ble_hci_ram_rx_cmd_hs_cb; -static void *ble_hci_ram_rx_cmd_hs_arg; - -static ble_hci_trans_rx_cmd_fn *ble_hci_ram_rx_cmd_ll_cb; -static void *ble_hci_ram_rx_cmd_ll_arg; - -static ble_hci_trans_rx_acl_fn *ble_hci_ram_rx_acl_hs_cb; -static void *ble_hci_ram_rx_acl_hs_arg; - -static ble_hci_trans_rx_acl_fn *ble_hci_ram_rx_acl_ll_cb; -static void *ble_hci_ram_rx_acl_ll_arg; - -static struct os_mempool ble_hci_ram_cmd_pool; -static os_membuf_t ble_hci_ram_cmd_buf[ - OS_MEMPOOL_SIZE(1, BLE_HCI_TRANS_CMD_SZ) -]; - -static struct os_mempool ble_hci_ram_evt_hi_pool; -static os_membuf_t ble_hci_ram_evt_hi_buf[ - OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_HCI_EVT_HI_BUF_COUNT), - MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE)) -]; - -static struct os_mempool ble_hci_ram_evt_lo_pool; -static os_membuf_t ble_hci_ram_evt_lo_buf[ - OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_HCI_EVT_LO_BUF_COUNT), - MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE)) -]; - -void -ble_hci_trans_cfg_hs(ble_hci_trans_rx_cmd_fn *cmd_cb, - void *cmd_arg, - ble_hci_trans_rx_acl_fn *acl_cb, - void *acl_arg) -{ - ble_hci_ram_rx_cmd_hs_cb = cmd_cb; - ble_hci_ram_rx_cmd_hs_arg = cmd_arg; - ble_hci_ram_rx_acl_hs_cb = acl_cb; - ble_hci_ram_rx_acl_hs_arg = acl_arg; -} - -void -ble_hci_trans_cfg_ll(ble_hci_trans_rx_cmd_fn *cmd_cb, - void *cmd_arg, - ble_hci_trans_rx_acl_fn *acl_cb, - void *acl_arg) -{ - ble_hci_ram_rx_cmd_ll_cb = cmd_cb; - ble_hci_ram_rx_cmd_ll_arg = cmd_arg; - ble_hci_ram_rx_acl_ll_cb = acl_cb; - ble_hci_ram_rx_acl_ll_arg = acl_arg; -} - -int -ble_hci_trans_hs_cmd_tx(uint8_t *cmd) -{ - int rc; - - assert(ble_hci_ram_rx_cmd_ll_cb != NULL); - - rc = ble_hci_ram_rx_cmd_ll_cb(cmd, ble_hci_ram_rx_cmd_ll_arg); - return rc; -} - -int -ble_hci_trans_ll_evt_tx(uint8_t *hci_ev) -{ - int rc; - - assert(ble_hci_ram_rx_cmd_hs_cb != NULL); - - rc = ble_hci_ram_rx_cmd_hs_cb(hci_ev, ble_hci_ram_rx_cmd_hs_arg); - return rc; -} - -int -ble_hci_trans_hs_acl_tx(struct os_mbuf *om) -{ - int rc; - - assert(ble_hci_ram_rx_acl_ll_cb != NULL); - - rc = ble_hci_ram_rx_acl_ll_cb(om, ble_hci_ram_rx_acl_ll_arg); - return rc; -} - -int -ble_hci_trans_ll_acl_tx(struct os_mbuf *om) -{ - int rc; - - assert(ble_hci_ram_rx_acl_hs_cb != NULL); - - rc = ble_hci_ram_rx_acl_hs_cb(om, ble_hci_ram_rx_acl_hs_arg); - return rc; -} - -uint8_t * -ble_hci_trans_buf_alloc(int type) -{ - uint8_t *buf; - - switch (type) { - case BLE_HCI_TRANS_BUF_CMD: - buf = os_memblock_get(&ble_hci_ram_cmd_pool); - break; - - case BLE_HCI_TRANS_BUF_EVT_HI: - buf = os_memblock_get(&ble_hci_ram_evt_hi_pool); - if (buf == NULL) { - /* If no high-priority event buffers remain, try to grab a - * low-priority one. - */ - buf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_LO); - } - break; - - case BLE_HCI_TRANS_BUF_EVT_LO: - buf = os_memblock_get(&ble_hci_ram_evt_lo_pool); - break; - - default: - assert(0); - buf = NULL; - } - - return buf; -} - -void -ble_hci_trans_buf_free(uint8_t *buf) -{ - int rc; - - /* XXX: this may look a bit odd, but the controller uses the command - * buffer to send back the command complete/status as an immediate - * response to the command. This was done to insure that the controller - * could always send back one of these events when a command was received. - * Thus, we check to see which pool the buffer came from so we can free - * it to the appropriate pool - */ - if (os_memblock_from(&ble_hci_ram_evt_hi_pool, buf)) { - rc = os_memblock_put(&ble_hci_ram_evt_hi_pool, buf); - assert(rc == 0); - } else if (os_memblock_from(&ble_hci_ram_evt_lo_pool, buf)) { - rc = os_memblock_put(&ble_hci_ram_evt_lo_pool, buf); - assert(rc == 0); - } else { - assert(os_memblock_from(&ble_hci_ram_cmd_pool, buf)); - rc = os_memblock_put(&ble_hci_ram_cmd_pool, buf); - assert(rc == 0); - } -} - -/** - * Unsupported; the RAM transport does not have a dedicated ACL data packet - * pool. - */ -int -ble_hci_trans_set_acl_free_cb(os_mempool_put_fn *cb, void *arg) -{ - return BLE_ERR_UNSUPPORTED; -} - -int -ble_hci_trans_reset(void) -{ - /* No work to do. All allocated buffers are owned by the host or - * controller, and they will get freed by their owners. - */ - return 0; -} - -void -ble_hci_ram_init(void) -{ - int rc; - - /* Ensure this function only gets called by sysinit. */ - SYSINIT_ASSERT_ACTIVE(); - - /* - * Create memory pool of HCI command buffers. NOTE: we currently dont - * allow this to be configured. The controller will only allow one - * outstanding command. We decided to keep this a pool in case we allow - * allow the controller to handle more than one outstanding command. - */ - rc = os_mempool_init(&ble_hci_ram_cmd_pool, - 1, - BLE_HCI_TRANS_CMD_SZ, - ble_hci_ram_cmd_buf, - "ble_hci_ram_cmd_pool"); - SYSINIT_PANIC_ASSERT(rc == 0); - - rc = os_mempool_init(&ble_hci_ram_evt_hi_pool, - MYNEWT_VAL(BLE_HCI_EVT_HI_BUF_COUNT), - MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE), - ble_hci_ram_evt_hi_buf, - "ble_hci_ram_evt_hi_pool"); - SYSINIT_PANIC_ASSERT(rc == 0); - - rc = os_mempool_init(&ble_hci_ram_evt_lo_pool, - MYNEWT_VAL(BLE_HCI_EVT_LO_BUF_COUNT), - MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE), - ble_hci_ram_evt_lo_buf, - "ble_hci_ram_evt_lo_pool"); - SYSINIT_PANIC_ASSERT(rc == 0); -} diff --git a/nimble/transport/socket/pkg.yml b/nimble/transport/socket/pkg.yml index fb4144d3ae..b64075baeb 100644 --- a/nimble/transport/socket/pkg.yml +++ b/nimble/transport/socket/pkg.yml @@ -33,6 +33,3 @@ pkg.deps: pkg.apis: - ble_transport - -pkg.init: - ble_hci_sock_init: 'MYNEWT_VAL(BLE_SOCK_CLI_SYSINIT_STAGE)' diff --git a/nimble/transport/socket/src/ble_hci_socket.c b/nimble/transport/socket/src/ble_hci_socket.c index 44de8fed53..d76c4dfa5d 100644 --- a/nimble/transport/socket/src/ble_hci_socket.c +++ b/nimble/transport/socket/src/ble_hci_socket.c @@ -85,7 +85,7 @@ struct sockaddr_hci { #include "nimble/nimble_opt.h" #include "nimble/hci_common.h" #include "nimble/nimble_npl.h" -#include "nimble/ble_hci_trans.h" +#include "nimble/transport.h" #include "socket/ble_hci_socket.h" /*** @@ -103,11 +103,13 @@ STATS_SECT_START(hci_sock_stats) STATS_SECT_ENTRY(icmd) STATS_SECT_ENTRY(ievt) STATS_SECT_ENTRY(iacl) + STATS_SECT_ENTRY(iiso) STATS_SECT_ENTRY(ibytes) STATS_SECT_ENTRY(ierr) STATS_SECT_ENTRY(imem) STATS_SECT_ENTRY(omsg) STATS_SECT_ENTRY(oacl) + STATS_SECT_ENTRY(oiso) STATS_SECT_ENTRY(ocmd) STATS_SECT_ENTRY(oevt) STATS_SECT_ENTRY(obytes) @@ -120,11 +122,13 @@ STATS_NAME_START(hci_sock_stats) STATS_NAME(hci_sock_stats, icmd) STATS_NAME(hci_sock_stats, ievt) STATS_NAME(hci_sock_stats, iacl) + STATS_NAME(hci_sock_stats, iiso) STATS_NAME(hci_sock_stats, ibytes) STATS_NAME(hci_sock_stats, ierr) STATS_NAME(hci_sock_stats, imem) STATS_NAME(hci_sock_stats, omsg) STATS_NAME(hci_sock_stats, oacl) + STATS_NAME(hci_sock_stats, oiso) STATS_NAME(hci_sock_stats, ocmd) STATS_NAME(hci_sock_stats, oevt) STATS_NAME(hci_sock_stats, obytes) @@ -142,11 +146,12 @@ STATS_NAME_END(hci_sock_stats) #define BLE_HCI_UART_H4_ACL 0x02 #define BLE_HCI_UART_H4_SCO 0x03 #define BLE_HCI_UART_H4_EVT 0x04 +#define BLE_HCI_UART_H4_ISO 0x05 #define BLE_HCI_UART_H4_SYNC_LOSS 0x80 #define BLE_HCI_UART_H4_SKIP_CMD 0x81 #define BLE_HCI_UART_H4_SKIP_ACL 0x82 -#if MYNEWT +#ifdef MYNEWT #define BLE_SOCK_STACK_SIZE \ OS_STACK_ALIGN(MYNEWT_VAL(BLE_SOCK_STACK_SIZE)) @@ -155,45 +160,6 @@ struct os_task ble_sock_task; #endif -static struct os_mempool ble_hci_sock_evt_hi_pool; -static os_membuf_t ble_hci_sock_evt_hi_buf[ - OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_HCI_EVT_HI_BUF_COUNT), - MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE)) -]; - -static struct os_mempool ble_hci_sock_evt_lo_pool; -static os_membuf_t ble_hci_sock_evt_lo_buf[ - OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_HCI_EVT_LO_BUF_COUNT), - MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE)) -]; - -static struct os_mempool ble_hci_sock_cmd_pool; -static os_membuf_t ble_hci_sock_cmd_buf[ - OS_MEMPOOL_SIZE(1, BLE_HCI_TRANS_CMD_SZ) -]; - -static struct os_mempool ble_hci_sock_acl_pool; -static struct os_mbuf_pool ble_hci_sock_acl_mbuf_pool; - -#define ACL_BLOCK_SIZE OS_ALIGN(MYNEWT_VAL(BLE_ACL_BUF_SIZE) \ - + BLE_MBUF_MEMBLOCK_OVERHEAD \ - + BLE_HCI_DATA_HDR_SZ, OS_ALIGNMENT) -/* - * The MBUF payload size must accommodate the HCI data header size plus the - * maximum ACL data packet length. The ACL block size is the size of the - * mbufs we will allocate. - */ - -static os_membuf_t ble_hci_sock_acl_buf[ - OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_ACL_BUF_COUNT), - ACL_BLOCK_SIZE) -]; - -static ble_hci_trans_rx_cmd_fn *ble_hci_sock_rx_cmd_cb; -static void *ble_hci_sock_rx_cmd_arg; -static ble_hci_trans_rx_acl_fn *ble_hci_sock_rx_acl_cb; -static void *ble_hci_sock_rx_acl_arg; - static struct ble_hci_sock_state { int sock; struct ble_npl_eventq evq; @@ -212,27 +178,7 @@ static int s_ble_hci_device = MYNEWT_VAL(BLE_SOCK_LINUX_DEV); static int s_ble_hci_device = 0; #endif -/** - * Allocates a buffer (mbuf) for ACL operation. - * - * @return The allocated buffer on success; - * NULL on buffer exhaustion. - */ -static struct os_mbuf * -ble_hci_trans_acl_buf_alloc(void) -{ - struct os_mbuf *m; - - /* - * XXX: note that for host only there would be no need to allocate - * a user header. Address this later. - */ - m = os_mbuf_get_pkthdr(&ble_hci_sock_acl_mbuf_pool, - sizeof(struct ble_mbuf_hdr)); - return m; -} - -#if MYNEWT_VAL(BLE_SOCK_USE_LINUX_BLUE) +#if MYNEWT_VAL(BLE_SOCK_USE_LINUX_BLUE) || MYNEWT_VAL(BLE_SOCK_USE_TCP) static int ble_hci_sock_acl_tx(struct os_mbuf *om) { @@ -329,11 +275,54 @@ ble_hci_sock_acl_tx(struct os_mbuf *om) } #endif +#if MYNEWT_VAL(BLE_SOCK_USE_LINUX_BLUE) || MYNEWT_VAL(BLE_SOCK_USE_TCP) +static int +ble_hci_sock_iso_tx(struct os_mbuf *om) +{ + struct msghdr msg; + struct iovec iov[8]; + int i; + struct os_mbuf *m; + uint8_t ch; + + memset(&msg, 0, sizeof(msg)); + memset(iov, 0, sizeof(iov)); + + msg.msg_iov = iov; + + ch = BLE_HCI_UART_H4_ISO; + iov[0].iov_len = 1; + iov[0].iov_base = &ch; + i = 1; + for (m = om; m; m = SLIST_NEXT(m, om_next)) { + iov[i].iov_base = m->om_data; + iov[i].iov_len = m->om_len; + i++; + } + msg.msg_iovlen = i; + + STATS_INC(hci_sock_stats, omsg); + STATS_INC(hci_sock_stats, oiso); + STATS_INCN(hci_sock_stats, obytes, OS_MBUF_PKTLEN(om) + 1); + i = sendmsg(ble_hci_sock_state.sock, &msg, 0); + os_mbuf_free_chain(om); + if (i != OS_MBUF_PKTLEN(om) + 1) { + if (i < 0) { + dprintf(1, "sendmsg() failed : %d\n", errno); + } else { + dprintf(1, "sendmsg() partial write: %d\n", i); + } + STATS_INC(hci_sock_stats, oerr); + return BLE_ERR_MEM_CAPACITY; + } + return 0; +} +#endif /* BLE_SOCK_USE_LINUX_BLUE */ + #if MYNEWT_VAL(BLE_SOCK_USE_LINUX_BLUE) static int ble_hci_sock_cmdevt_tx(uint8_t *hci_ev, uint8_t h4_type) { - uint8_t btaddr[6]; struct msghdr msg; struct iovec iov[8]; int len; @@ -358,6 +347,7 @@ ble_hci_sock_cmdevt_tx(uint8_t *hci_ev, uint8_t h4_type) STATS_INC(hci_sock_stats, oevt); } else { assert(0); + return BLE_ERR_UNKNOWN_HCI_CMD; } iov[1].iov_len = len; @@ -365,7 +355,7 @@ ble_hci_sock_cmdevt_tx(uint8_t *hci_ev, uint8_t h4_type) STATS_INCN(hci_sock_stats, obytes, len + 1); i = sendmsg(ble_hci_sock_state.sock, &msg, 0); - ble_hci_trans_buf_free(hci_ev); + ble_transport_free(hci_ev); if (i != len + 1) { if (i < 0) { dprintf(1, "sendmsg() failed : %d\n", errno); @@ -393,6 +383,7 @@ ble_hci_sock_cmdevt_tx(uint8_t *hci_ev, uint8_t h4_type) memcpy(&addr, &addr, sizeof(struct sockaddr_hci)); + len = 0; if (h4_type == BLE_HCI_UART_H4_CMD) { len = sizeof(struct ble_hci_cmd) + hci_ev[2]; STATS_INC(hci_sock_stats, ocmd); @@ -415,7 +406,7 @@ ble_hci_sock_cmdevt_tx(uint8_t *hci_ev, uint8_t h4_type) (struct sockaddr *)&addr, sizeof(struct sockaddr_hci)); free(buf); - ble_hci_trans_buf_free(hci_ev); + ble_transport_free(hci_ev); if (i != len + 1) { if (i < 0) { dprintf(1, "sendto() failed : %d\n", errno); @@ -468,17 +459,17 @@ ble_hci_sock_rx_msg(void) } STATS_INC(hci_sock_stats, imsg); STATS_INC(hci_sock_stats, icmd); - data = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_CMD); + data = ble_transport_alloc_cmd(); if (!data) { STATS_INC(hci_sock_stats, ierr); break; } memcpy(data, &bhss->rx_data[1], len - 1); OS_ENTER_CRITICAL(sr); - rc = ble_hci_sock_rx_cmd_cb(data, ble_hci_sock_rx_cmd_arg); + rc = ble_transport_to_ll_cmd(data); OS_EXIT_CRITICAL(sr); if (rc) { - ble_hci_trans_buf_free(data); + ble_transport_free(data); STATS_INC(hci_sock_stats, ierr); break; } @@ -495,17 +486,17 @@ ble_hci_sock_rx_msg(void) } STATS_INC(hci_sock_stats, imsg); STATS_INC(hci_sock_stats, ievt); - data = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); + data = ble_transport_alloc_evt(0); if (!data) { STATS_INC(hci_sock_stats, ierr); break; } memcpy(data, &bhss->rx_data[1], len - 1); OS_ENTER_CRITICAL(sr); - rc = ble_hci_sock_rx_cmd_cb(data, ble_hci_sock_rx_cmd_arg); + rc = ble_transport_to_hs_evt(data); OS_EXIT_CRITICAL(sr); if (rc) { - ble_hci_trans_buf_free(data); + ble_transport_free(data); STATS_INC(hci_sock_stats, ierr); return 0; } @@ -522,7 +513,44 @@ ble_hci_sock_rx_msg(void) } STATS_INC(hci_sock_stats, imsg); STATS_INC(hci_sock_stats, iacl); - m = ble_hci_trans_acl_buf_alloc(); +#if MYNEWT_VAL(BLE_CONTROLLER) + m = ble_transport_alloc_acl_from_hs(); +#else + m = ble_transport_alloc_acl_from_ll(); +#endif + if (!m) { + STATS_INC(hci_sock_stats, imem); + break; + } + if (os_mbuf_append(m, &bhss->rx_data[1], len - 1)) { + STATS_INC(hci_sock_stats, imem); + os_mbuf_free_chain(m); + break; + } + OS_ENTER_CRITICAL(sr); +#if MYNEWT_VAL(BLE_CONTROLLER) + ble_transport_to_ll_acl(m); +#else + ble_transport_to_hs_acl(m); +#endif + OS_EXIT_CRITICAL(sr); + break; + case BLE_HCI_UART_H4_ISO: + if (bhss->rx_off < BLE_HCI_DATA_HDR_SZ) { + return -1; + } + len = 1 + BLE_HCI_DATA_HDR_SZ + (bhss->rx_data[4] << 8) + + bhss->rx_data[3]; + if (bhss->rx_off < len) { + return -1; + } + STATS_INC(hci_sock_stats, imsg); + STATS_INC(hci_sock_stats, iiso); +#if MYNEWT_VAL(BLE_CONTROLLER) + m = ble_transport_alloc_iso_from_hs(); +#else + m = ble_transport_alloc_iso_from_ll(); +#endif if (!m) { STATS_INC(hci_sock_stats, imem); break; @@ -533,7 +561,11 @@ ble_hci_sock_rx_msg(void) break; } OS_ENTER_CRITICAL(sr); - ble_hci_sock_rx_acl_cb(m, ble_hci_sock_rx_acl_arg); +#if MYNEWT_VAL(BLE_CONTROLLER) + ble_transport_to_ll_iso(m); +#else + ble_transport_to_hs_iso(m); +#endif OS_EXIT_CRITICAL(sr); break; default: @@ -785,129 +817,6 @@ ble_hci_trans_hs_acl_tx(struct os_mbuf *om) return ble_hci_sock_acl_tx(om); } -/** - * Configures the HCI transport to call the specified callback upon receiving - * HCI packets from the controller. This function should only be called by by - * host. - * - * @param cmd_cb The callback to execute upon receiving an HCI - * event. - * @param cmd_arg Optional argument to pass to the command - * callback. - * @param acl_cb The callback to execute upon receiving ACL - * data. - * @param acl_arg Optional argument to pass to the ACL - * callback. - */ -void -ble_hci_trans_cfg_hs(ble_hci_trans_rx_cmd_fn *cmd_cb, - void *cmd_arg, - ble_hci_trans_rx_acl_fn *acl_cb, - void *acl_arg) -{ - ble_hci_sock_rx_cmd_cb = cmd_cb; - ble_hci_sock_rx_cmd_arg = cmd_arg; - ble_hci_sock_rx_acl_cb = acl_cb; - ble_hci_sock_rx_acl_arg = acl_arg; -} - -/** - * Configures the HCI transport to operate with a host. The transport will - * execute specified callbacks upon receiving HCI packets from the controller. - * - * @param cmd_cb The callback to execute upon receiving an HCI - * event. - * @param cmd_arg Optional argument to pass to the command - * callback. - * @param acl_cb The callback to execute upon receiving ACL - * data. - * @param acl_arg Optional argument to pass to the ACL - * callback. - */ -void -ble_hci_trans_cfg_ll(ble_hci_trans_rx_cmd_fn *cmd_cb, - void *cmd_arg, - ble_hci_trans_rx_acl_fn *acl_cb, - void *acl_arg) -{ - ble_hci_sock_rx_cmd_cb = cmd_cb; - ble_hci_sock_rx_cmd_arg = cmd_arg; - ble_hci_sock_rx_acl_cb = acl_cb; - ble_hci_sock_rx_acl_arg = acl_arg; -} - -/** - * Allocates a flat buffer of the specified type. - * - * @param type The type of buffer to allocate; one of the - * BLE_HCI_TRANS_BUF_[...] constants. - * - * @return The allocated buffer on success; - * NULL on buffer exhaustion. - */ -uint8_t * -ble_hci_trans_buf_alloc(int type) -{ - uint8_t *buf; - - switch (type) { - case BLE_HCI_TRANS_BUF_CMD: - buf = os_memblock_get(&ble_hci_sock_cmd_pool); - break; - case BLE_HCI_TRANS_BUF_EVT_HI: - buf = os_memblock_get(&ble_hci_sock_evt_hi_pool); - if (buf == NULL) { - /* If no high-priority event buffers remain, try to grab a - * low-priority one. - */ - buf = os_memblock_get(&ble_hci_sock_evt_lo_pool); - } - break; - - case BLE_HCI_TRANS_BUF_EVT_LO: - buf = os_memblock_get(&ble_hci_sock_evt_lo_pool); - break; - - default: - assert(0); - buf = NULL; - } - - return buf; -} - -/** - * Frees the specified flat buffer. The buffer must have been allocated via - * ble_hci_trans_buf_alloc(). - * - * @param buf The buffer to free. - */ -void -ble_hci_trans_buf_free(uint8_t *buf) -{ - int rc; - - /* - * XXX: this may look a bit odd, but the controller uses the command - * buffer to send back the command complete/status as an immediate - * response to the command. This was done to insure that the controller - * could always send back one of these events when a command was received. - * Thus, we check to see which pool the buffer came from so we can free - * it to the appropriate pool - */ - if (os_memblock_from(&ble_hci_sock_evt_hi_pool, buf)) { - rc = os_memblock_put(&ble_hci_sock_evt_hi_pool, buf); - assert(rc == 0); - } else if (os_memblock_from(&ble_hci_sock_evt_lo_pool, buf)) { - rc = os_memblock_put(&ble_hci_sock_evt_lo_pool, buf); - assert(rc == 0); - } else { - assert(os_memblock_from(&ble_hci_sock_cmd_pool, buf)); - rc = os_memblock_put(&ble_hci_sock_cmd_pool, buf); - assert(rc == 0); - } -} - /** * Resets the HCI UART transport to a clean state. Frees all buffers and * reconfigures the UART. @@ -951,7 +860,7 @@ ble_hci_sock_init_task(void) ble_npl_callout_init(&ble_hci_sock_state.timer, &ble_hci_sock_state.evq, ble_hci_sock_rx_ev, NULL); -#if MYNEWT +#ifdef MYNEWT { os_stack_t *pstack; @@ -997,46 +906,6 @@ ble_hci_sock_init(void) ble_hci_sock_init_task(); ble_npl_event_init(&ble_hci_sock_state.ev, ble_hci_sock_rx_ev, NULL); - rc = os_mempool_init(&ble_hci_sock_acl_pool, - MYNEWT_VAL(BLE_ACL_BUF_COUNT), - ACL_BLOCK_SIZE, - ble_hci_sock_acl_buf, - "ble_hci_sock_acl_pool"); - SYSINIT_PANIC_ASSERT(rc == 0); - - rc = os_mbuf_pool_init(&ble_hci_sock_acl_mbuf_pool, - &ble_hci_sock_acl_pool, - ACL_BLOCK_SIZE, - MYNEWT_VAL(BLE_ACL_BUF_COUNT)); - SYSINIT_PANIC_ASSERT(rc == 0); - - /* - * Create memory pool of HCI command buffers. NOTE: we currently dont - * allow this to be configured. The controller will only allow one - * outstanding command. We decided to keep this a pool in case we allow - * allow the controller to handle more than one outstanding command. - */ - rc = os_mempool_init(&ble_hci_sock_cmd_pool, - 1, - BLE_HCI_TRANS_CMD_SZ, - &ble_hci_sock_cmd_buf, - "ble_hci_sock_cmd_pool"); - SYSINIT_PANIC_ASSERT(rc == 0); - - rc = os_mempool_init(&ble_hci_sock_evt_hi_pool, - MYNEWT_VAL(BLE_HCI_EVT_HI_BUF_COUNT), - MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE), - &ble_hci_sock_evt_hi_buf, - "ble_hci_sock_evt_hi_pool"); - SYSINIT_PANIC_ASSERT(rc == 0); - - rc = os_mempool_init(&ble_hci_sock_evt_lo_pool, - MYNEWT_VAL(BLE_HCI_EVT_LO_BUF_COUNT), - MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE), - ble_hci_sock_evt_lo_buf, - "ble_hci_sock_evt_lo_pool"); - SYSINIT_PANIC_ASSERT(rc == 0); - rc = ble_hci_sock_config(); SYSINIT_PANIC_ASSERT_MSG(rc == 0, "Failure configuring socket HCI"); @@ -1045,3 +914,31 @@ ble_hci_sock_init(void) STATS_NAME_INIT_PARMS(hci_sock_stats), "hci_socket"); SYSINIT_PANIC_ASSERT(rc == 0); } + +#if MYNEWT_VAL(BLE_SOCK_USE_LINUX_BLUE) || MYNEWT_VAL(BLE_SOCK_USE_TCP) +int +ble_transport_to_ll_iso_impl(struct os_mbuf *om) +{ + return ble_hci_sock_iso_tx(om); +} +#endif + +void +ble_transport_ll_init(void) +{ + ble_hci_sock_init(); +} + +int +ble_transport_to_ll_acl_impl(struct os_mbuf *om) +{ + return ble_hci_trans_hs_acl_tx(om); +} + +int +ble_transport_to_ll_cmd_impl(void *buf) +{ + return ble_hci_trans_hs_cmd_tx(buf); +} + +/* TODO: add ll-to-hs side if needed */ diff --git a/nimble/transport/socket/syscfg.yml b/nimble/transport/socket/syscfg.yml index 2050f64692..c74f056c5d 100644 --- a/nimble/transport/socket/syscfg.yml +++ b/nimble/transport/socket/syscfg.yml @@ -17,34 +17,6 @@ # syscfg.defs: - BLE_HCI_EVT_BUF_SIZE: - description: 'The size of the allocated event buffers' - value: 70 - BLE_HCI_EVT_HI_BUF_COUNT: - description: 'The number of high priority event buffers' - value: 8 - BLE_HCI_EVT_LO_BUF_COUNT: - description: 'The number of low priority event buffers' - value: 8 - BLE_ACL_BUF_COUNT: - description: 'The number of ACL data buffers' - value: 24 - BLE_ACL_BUF_SIZE: - description: > - This is the maximum size of the data portion of HCI ACL data - packets. It does not include the HCI data header (of 4 bytes). - value: 255 - - BLE_HCI_ACL_OUT_COUNT: - description: > - This count is used in creating a pool of elements used by the - code to enqueue various elements. In the case of the controller - only HCI, this number should be equal to the number of mbufs in - the msys pool. For host only, it is really dependent on the - number of ACL buffers that the controller tells the host it - has. - value: 12 - BLE_SOCK_USE_TCP: description: 'Use TCP socket, connects to BLE_SOCK_TCP_PORT' value: 1 @@ -61,6 +33,10 @@ syscfg.defs: description: 'linux kernel device' value: 0 + BLE_SOCK_USE_NUTTX: + description: 'Use NuttX socket' + value: 0 + BLE_SOCK_TASK_PRIO: description: 'Priority of the HCI socket task.' type: task_priority @@ -74,6 +50,3 @@ syscfg.defs: description: > Sysinit stage for the socket BLE transport. value: 500 - -syscfg.vals.BLE_EXT_ADV: - BLE_HCI_EVT_BUF_SIZE: 257 diff --git a/nimble/host/src/ble_monitor.c b/nimble/transport/src/monitor.c similarity index 81% rename from nimble/host/src/ble_monitor.c rename to nimble/transport/src/monitor.c index e6db48b825..66382c0736 100644 --- a/nimble/host/src/ble_monitor.c +++ b/nimble/transport/src/monitor.c @@ -17,12 +17,13 @@ * under the License. */ -#include "host/ble_monitor.h" +#include -#if BLE_MONITOR +#if MYNEWT_VAL(BLE_MONITOR_RTT) || MYNEWT_VAL(BLE_MONITOR_UART) -#if MYNEWT_VAL(BLE_MONITOR_UART) && MYNEWT_VAL(BLE_MONITOR_RTT) -#error "Cannot enable monitor over UART and RTT at the same time!" +#ifdef BABBLESIM +#define _GNU_SOURCE +#include #endif #include @@ -36,8 +37,10 @@ #if MYNEWT_VAL(BLE_MONITOR_RTT) #include "rtt/SEGGER_RTT.h" #endif -#include "ble_hs_priv.h" -#include "ble_monitor_priv.h" +#include +#include +#include +#include "monitor_priv.h" struct ble_npl_mutex lock; @@ -258,6 +261,7 @@ monitor_write_header(uint16_t opcode, uint16_t len) monitor_write(&ts_hdr, sizeof(ts_hdr)); } +#ifndef BABBLESIM static size_t btmon_write(FILE *instance, const char *bp, size_t n) { @@ -271,12 +275,13 @@ static FILE *btmon = (FILE *) &(struct File) { .write = btmon_write, }, }; +#endif #if MYNEWT_VAL(BLE_MONITOR_RTT) && MYNEWT_VAL(BLE_MONITOR_RTT_BUFFERED) static void drops_tmp_cb(struct ble_npl_event *ev) { - ble_npl_mutex_pend(&lock, OS_TIMEOUT_NEVER); + ble_npl_mutex_pend(&lock, BLE_NPL_TIME_FOREVER); /* * There's no "nop" in btsnoop protocol so we just send empty system note @@ -290,9 +295,12 @@ drops_tmp_cb(struct ble_npl_event *ev) } #endif -int +void ble_monitor_init(void) { + SYSINIT_ASSERT_ACTIVE(); + ble_npl_error_t rc; + #if MYNEWT_VAL(BLE_MONITOR_UART) struct uart_conf uc = { .uc_speed = MYNEWT_VAL(BLE_MONITOR_UART_BAUDRATE), @@ -307,14 +315,12 @@ ble_monitor_init(void) uart = (struct uart_dev *)os_dev_open(MYNEWT_VAL(BLE_MONITOR_UART_DEV), OS_TIMEOUT_NEVER, &uc); - if (!uart) { - return -1; - } + SYSINIT_PANIC_ASSERT(uart); #endif #if MYNEWT_VAL(BLE_MONITOR_RTT) #if MYNEWT_VAL(BLE_MONITOR_RTT_BUFFERED) - ble_npl_callout_init(&rtt_drops.tmo, ble_hs_evq_get(), drops_tmp_cb, NULL); + ble_npl_callout_init(&rtt_drops.tmo, ble_npl_eventq_dflt_get(), drops_tmp_cb, NULL); /* Initialize types in header (we won't touch them later) */ rtt_drops.drops_hdr.type_cmd = BLE_MONITOR_EXTHDR_COMMAND_DROPS; @@ -332,20 +338,21 @@ ble_monitor_init(void) SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL); #endif - if (rtt_index < 0) { - return -1; - } + SYSINIT_PANIC_ASSERT(rtt_index >= 0); #endif - ble_npl_mutex_init(&lock); + rc = ble_npl_mutex_init(&lock); + SYSINIT_PANIC_ASSERT(rc == 0); - return 0; +#if BLE_MONITOR + ble_monitor_new_index(0, (uint8_t[6]){ }, "nimble0"); +#endif } int ble_monitor_send(uint16_t opcode, const void *data, size_t len) { - ble_npl_mutex_pend(&lock, OS_TIMEOUT_NEVER); + ble_npl_mutex_pend(&lock, BLE_NPL_TIME_FOREVER); monitor_write_header(opcode, len); monitor_write(data, len); @@ -367,7 +374,7 @@ ble_monitor_send_om(uint16_t opcode, const struct os_mbuf *om) om_tmp = SLIST_NEXT(om_tmp, om_next); } - ble_npl_mutex_pend(&lock, OS_TIMEOUT_NEVER); + ble_npl_mutex_pend(&lock, BLE_NPL_TIME_FOREVER); monitor_write_header(opcode, length); @@ -429,16 +436,31 @@ ble_monitor_log(int level, const char *fmt, ...) ulog.ident_len = sizeof(id); - ble_npl_mutex_pend(&lock, OS_TIMEOUT_NEVER); + ble_npl_mutex_pend(&lock, BLE_NPL_TIME_FOREVER); monitor_write_header(BLE_MONITOR_OPCODE_USER_LOGGING, sizeof(ulog) + sizeof(id) + len + 1); monitor_write(&ulog, sizeof(ulog)); monitor_write(id, sizeof(id)); +#ifdef BABBLESIM + do { + char *tmp; + int len; + + va_start(va, fmt); + len = vasprintf(&tmp, fmt, va); + assert(len >= 0); + va_end(va); + + monitor_write(tmp, len); + free(tmp); + } while (0); +#else va_start(va, fmt); vfprintf(btmon, fmt, va); va_end(va); +#endif /* null-terminate string */ monitor_write("", 1); @@ -470,4 +492,58 @@ ble_monitor_out(int c) return c; } -#endif +int +ble_transport_to_ll_cmd(void *buf) +{ + struct ble_hci_cmd *cmd = buf; + + ble_monitor_send(BLE_MONITOR_OPCODE_COMMAND_PKT, buf, cmd->length + + sizeof(*cmd)); + + return ble_transport_to_ll_cmd_impl(buf); +} + +int +ble_transport_to_ll_acl(struct os_mbuf *om) +{ + ble_monitor_send_om(BLE_MONITOR_OPCODE_ACL_TX_PKT, om); + + return ble_transport_to_ll_acl_impl(om); +} + +int +ble_transport_to_ll_iso(struct os_mbuf *om) +{ + ble_monitor_send_om(BLE_MONITOR_OPCODE_ISO_TX_PKT, om); + + return ble_transport_to_ll_iso_impl(om); +} + +int +ble_transport_to_hs_acl(struct os_mbuf *om) +{ + ble_monitor_send_om(BLE_MONITOR_OPCODE_ACL_RX_PKT, om); + + return ble_transport_to_hs_acl_impl(om); +} + +int +ble_transport_to_hs_evt(void *buf) +{ + struct ble_hci_ev *ev = buf; + + ble_monitor_send(BLE_MONITOR_OPCODE_EVENT_PKT, buf, ev->length + + sizeof(*ev)); + + return ble_transport_to_hs_evt_impl(buf); +} + +int +ble_transport_to_hs_iso(struct os_mbuf *om) +{ + ble_monitor_send_om(BLE_MONITOR_OPCODE_ISO_RX_PKT, om); + + return ble_transport_to_hs_iso_impl(om); +} + +#endif /* MYNEWT_VAL(BLE_MONITOR_RTT) || MYNEWT_VAL(BLE_MONITOR_UART) */ diff --git a/nimble/host/src/ble_monitor_priv.h b/nimble/transport/src/monitor_priv.h similarity index 97% rename from nimble/host/src/ble_monitor_priv.h rename to nimble/transport/src/monitor_priv.h index 935787040f..938da8f5ba 100644 --- a/nimble/host/src/ble_monitor_priv.h +++ b/nimble/transport/src/monitor_priv.h @@ -38,6 +38,8 @@ extern "C" { #define BLE_MONITOR_OPCODE_VENDOR_DIAG 11 #define BLE_MONITOR_OPCODE_SYSTEM_NOTE 12 #define BLE_MONITOR_OPCODE_USER_LOGGING 13 +#define BLE_MONITOR_OPCODE_ISO_TX_PKT 18 +#define BLE_MONITOR_OPCODE_ISO_RX_PKT 19 #define BLE_MONITOR_EXTHDR_COMMAND_DROPS 1 #define BLE_MONITOR_EXTHDR_EVENT_DROPS 2 @@ -85,8 +87,6 @@ struct ble_monitor_user_logging { uint8_t ident_len; } __attribute__((packed)); -int ble_monitor_init(void); - int ble_monitor_send(uint16_t opcode, const void *data, size_t len); int ble_monitor_send_om(uint16_t opcode, const struct os_mbuf *om); diff --git a/nimble/transport/src/rx_task.c b/nimble/transport/src/rx_task.c new file mode 100644 index 0000000000..957ab79073 --- /dev/null +++ b/nimble/transport/src/rx_task.c @@ -0,0 +1,86 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#if MYNEWT +#include +#endif +#include +#include +#include + +#if !defined(MYNEWT) || MYNEWT_VAL(BLE_TRANSPORT_RX_TASK_STACK_SIZE) + +static ble_transport_rx_func_t *rx_func; +static void *rx_func_arg; + +#if MYNEWT +OS_TASK_STACK_DEFINE(rx_stack, MYNEWT_VAL(BLE_TRANSPORT_RX_TASK_STACK_SIZE)); +static struct os_task rx_task; +#endif + +static struct ble_npl_eventq rx_eventq; +static struct ble_npl_event rx_event; + +static void +rx_event_func(struct ble_npl_event *ev) +{ + rx_func(rx_func_arg); +} + +#ifdef MYNEWT +static void +rx_task_func(void *arg) +{ + struct ble_npl_event *ev; + + ble_npl_eventq_init(&rx_eventq); + + while (1) { + ev = ble_npl_eventq_get(&rx_eventq, BLE_NPL_TIME_FOREVER); + ble_npl_event_run(ev); + } +} +#endif + +void +ble_transport_rx_register(ble_transport_rx_func_t *func, void *arg) +{ + assert(func && !rx_func); + + rx_func = func; + rx_func_arg = arg; + + ble_npl_event_init(&rx_event, rx_event_func, NULL); + +#ifdef MYNEWT + os_task_init(&rx_task, "hci_rx_task", rx_task_func, NULL, + MYNEWT_VAL(BLE_TRANSPORT_RX_TASK_PRIO), OS_WAIT_FOREVER, + rx_stack, MYNEWT_VAL(BLE_TRANSPORT_RX_TASK_STACK_SIZE)); +#endif +} + +void +ble_transport_rx(void) +{ + ble_npl_eventq_put(&rx_eventq, &rx_event); +} + +#endif diff --git a/nimble/transport/src/transport.c b/nimble/transport/src/transport.c new file mode 100644 index 0000000000..99c11c266a --- /dev/null +++ b/nimble/transport/src/transport.c @@ -0,0 +1,375 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#if BLE_TRANSPORT_IPC +#include +#endif + +#define OMP_FLAG_FROM_HS (0x01) +#define OMP_FLAG_FROM_LL (0x02) +#define OMP_FLAG_FROM_MASK (0x03) + +#if MYNEWT_VAL(BLE_HS_FLOW_CTRL) || \ + MYNEWT_VAL(BLE_LL_CFG_FEAT_CTRL_TO_HOST_FLOW_CONTROL) || \ + (!MYNEWT_VAL(BLE_HOST) && BLE_TRANSPORT_IPC_ON_HS) +#define POOL_CMD_COUNT (2) +#else +#define POOL_CMD_COUNT (1) +#endif +#define POOL_CMD_SIZE (258) + +#define POOL_EVT_COUNT (MYNEWT_VAL(BLE_TRANSPORT_EVT_COUNT)) +#define POOL_EVT_LO_COUNT (MYNEWT_VAL(BLE_TRANSPORT_EVT_DISCARDABLE_COUNT)) +#define POOL_EVT_SIZE (MYNEWT_VAL(BLE_TRANSPORT_EVT_SIZE)) + +#if MYNEWT_VAL_CHOICE(BLE_TRANSPORT_LL, native) && \ + MYNEWT_VAL_CHOICE(BLE_TRANSPORT_HS, native) +#define POOL_ACL_COUNT (0) +#define POOL_ISO_COUNT (0) +#elif !MYNEWT_VAL_CHOICE(BLE_TRANSPORT_LL, native) && \ + !MYNEWT_VAL_CHOICE(BLE_TRANSPORT_HS, native) +#define POOL_ACL_COUNT ((MYNEWT_VAL(BLE_TRANSPORT_ACL_FROM_HS_COUNT)) + \ + (MYNEWT_VAL(BLE_TRANSPORT_ACL_FROM_LL_COUNT))) +#define POOL_ISO_COUNT ((MYNEWT_VAL(BLE_TRANSPORT_ISO_FROM_HS_COUNT)) + \ + (MYNEWT_VAL(BLE_TRANSPORT_ISO_FROM_LL_COUNT))) +#elif MYNEWT_VAL_CHOICE(BLE_TRANSPORT_LL, native) +#define POOL_ACL_COUNT (MYNEWT_VAL(BLE_TRANSPORT_ACL_FROM_HS_COUNT)) +#define POOL_ISO_COUNT (MYNEWT_VAL(BLE_TRANSPORT_ISO_FROM_HS_COUNT)) +#else +#define POOL_ACL_COUNT (MYNEWT_VAL(BLE_TRANSPORT_ACL_FROM_LL_COUNT)) +#define POOL_ISO_COUNT (MYNEWT_VAL(BLE_TRANSPORT_ISO_FROM_LL_COUNT)) +#endif +#define POOL_ACL_SIZE (OS_ALIGN( MYNEWT_VAL(BLE_TRANSPORT_ACL_SIZE) + \ + BLE_MBUF_MEMBLOCK_OVERHEAD + \ + BLE_HCI_DATA_HDR_SZ, OS_ALIGNMENT)) +#define POOL_ISO_SIZE (OS_ALIGN(MYNEWT_VAL(BLE_TRANSPORT_ISO_SIZE) + \ + BLE_MBUF_MEMBLOCK_OVERHEAD + \ + BLE_HCI_DATA_HDR_SZ, OS_ALIGNMENT)) + +static os_membuf_t pool_cmd_buf[ OS_MEMPOOL_SIZE(POOL_CMD_COUNT, POOL_CMD_SIZE) ]; +static struct os_mempool pool_cmd; + +static os_membuf_t pool_evt_buf[ OS_MEMPOOL_SIZE(POOL_EVT_COUNT, POOL_EVT_SIZE) ]; +static struct os_mempool pool_evt; + +static os_membuf_t pool_evt_lo_buf[ OS_MEMPOOL_SIZE(POOL_EVT_LO_COUNT, POOL_EVT_SIZE) ]; +static struct os_mempool pool_evt_lo; + +#if POOL_ACL_COUNT > 0 +static os_membuf_t pool_acl_buf[ OS_MEMPOOL_SIZE(POOL_ACL_COUNT, POOL_ACL_SIZE) ]; +static struct os_mempool_ext pool_acl; +static struct os_mbuf_pool mpool_acl; +#endif + +#if POOL_ISO_COUNT > 0 +static os_membuf_t pool_iso_buf[ OS_MEMPOOL_SIZE(POOL_ISO_COUNT, POOL_ISO_SIZE) ]; +static struct os_mempool_ext pool_iso; +static struct os_mbuf_pool mpool_iso; +#endif + +static os_mempool_put_fn *transport_put_acl_from_ll_cb; + +void * +ble_transport_alloc_cmd(void) +{ + return os_memblock_get(&pool_cmd); +} + +static void * +try_alloc_evt(struct os_mempool *mp) +{ +#if BLE_TRANSPORT_IPC_ON_LL + uint8_t type; +#endif + void *buf; + +#if BLE_TRANSPORT_IPC_ON_LL + if (mp == &pool_evt) { + type = HCI_IPC_TYPE_EVT; + } else { + type = HCI_IPC_TYPE_EVT_DISCARDABLE; + } + + if (!hci_ipc_get(type)) { + return NULL; + } +#endif + + buf = os_memblock_get(mp); + +#if BLE_TRANSPORT_IPC_ON_LL + if (!buf) { + hci_ipc_put(type); + } +#endif + + return buf; +} + +void * +ble_transport_alloc_evt(int discardable) +{ + void *buf; + + if (discardable) { + buf = try_alloc_evt(&pool_evt_lo); + } else { + buf = try_alloc_evt(&pool_evt); + if (!buf) { + buf = try_alloc_evt(&pool_evt_lo); + } + } + + return buf; +} + +struct os_mbuf * +ble_transport_alloc_acl_from_hs(void) +{ +#if POOL_ACL_COUNT > 0 + struct os_mbuf *om; + struct os_mbuf_pkthdr *pkthdr; + uint16_t usrhdr_len; + +#if MYNEWT_VAL_CHOICE(BLE_TRANSPORT_LL, native) + usrhdr_len = sizeof(struct ble_mbuf_hdr); +#else + usrhdr_len = 0; +#endif + + om = os_mbuf_get_pkthdr(&mpool_acl, usrhdr_len); + if (om) { + pkthdr = OS_MBUF_PKTHDR(om); + pkthdr->omp_flags = OMP_FLAG_FROM_HS; + } + + return om; +#else + return NULL; +#endif +} + +struct os_mbuf * +ble_transport_alloc_iso_from_hs(void) +{ +#if POOL_ISO_COUNT > 0 + struct os_mbuf *om; + struct os_mbuf_pkthdr *pkthdr; + uint16_t usrhdr_len; + +#if MYNEWT_VAL_CHOICE(BLE_TRANSPORT_LL, native) + usrhdr_len = sizeof(struct ble_mbuf_hdr); +#else + usrhdr_len = 0; +#endif + + om = os_mbuf_get_pkthdr(&mpool_iso, usrhdr_len); + if (om) { + pkthdr = OS_MBUF_PKTHDR(om); + pkthdr->omp_flags = OMP_FLAG_FROM_HS; + } + + return om; +#else + return NULL; +#endif +} + +struct os_mbuf * +ble_transport_alloc_acl_from_ll(void) +{ +#if POOL_ACL_COUNT > 0 + struct os_mbuf *om; + struct os_mbuf_pkthdr *pkthdr; + + om = os_mbuf_get_pkthdr(&mpool_acl, 0); + if (om) { + pkthdr = OS_MBUF_PKTHDR(om); + pkthdr->omp_flags = OMP_FLAG_FROM_LL; + } + + return om; +#else + return NULL; +#endif +} + +struct os_mbuf * +ble_transport_alloc_iso_from_ll(void) +{ +#if POOL_ISO_COUNT > 0 + struct os_mbuf *om; + struct os_mbuf_pkthdr *pkthdr; + + om = os_mbuf_get_pkthdr(&mpool_iso, 0); + if (om) { + pkthdr = OS_MBUF_PKTHDR(om); + pkthdr->omp_flags = OMP_FLAG_FROM_LL; + } + + return om; +#else + return NULL; +#endif +} + +void +ble_transport_free(void *buf) +{ + if (os_memblock_from(&pool_cmd, buf)) { + os_memblock_put(&pool_cmd, buf); + } else if (os_memblock_from(&pool_evt, buf)) { + os_memblock_put(&pool_evt, buf); +#if BLE_TRANSPORT_IPC + hci_ipc_put(HCI_IPC_TYPE_EVT); +#endif + } else if (os_memblock_from(&pool_evt_lo, buf)) { + os_memblock_put(&pool_evt_lo, buf); +#if BLE_TRANSPORT_IPC + hci_ipc_put(HCI_IPC_TYPE_EVT_DISCARDABLE); +#endif + } else { + assert(0); + } +} + +void +ble_transport_ipc_free(void *buf) +{ + if (os_memblock_from(&pool_cmd, buf)) { + os_memblock_put(&pool_cmd, buf); + } else if (os_memblock_from(&pool_evt, buf)) { + os_memblock_put(&pool_evt, buf); + } else if (os_memblock_from(&pool_evt_lo, buf)) { + os_memblock_put(&pool_evt_lo, buf); + } else { + assert(0); + } +} + +#if POOL_ACL_COUNT > 0 +static os_error_t +ble_transport_acl_put(struct os_mempool_ext *mpe, void *data, void *arg) +{ + struct os_mbuf *om; + struct os_mbuf_pkthdr *pkthdr; + bool do_put; + bool from_ll; + os_error_t err; + + om = data; + pkthdr = OS_MBUF_PKTHDR(om); + + do_put = true; + from_ll = (pkthdr->omp_flags & OMP_FLAG_FROM_MASK) == OMP_FLAG_FROM_LL; + err = 0; + + if (from_ll && transport_put_acl_from_ll_cb) { + err = transport_put_acl_from_ll_cb(mpe, data, arg); + do_put = false; + } + + if (do_put) { + err = os_memblock_put_from_cb(&mpe->mpe_mp, data); + } + +#if BLE_TRANSPORT_IPC_ON_HS + if (from_ll && !err) { + hci_ipc_put(HCI_IPC_TYPE_ACL); + } +#endif + + return err; +} +#endif + +void +ble_transport_init(void) +{ + int rc; + + SYSINIT_ASSERT_ACTIVE(); + + rc = os_mempool_init(&pool_cmd, POOL_CMD_COUNT, POOL_CMD_SIZE, + pool_cmd_buf, "transport_pool_cmd"); + SYSINIT_PANIC_ASSERT(rc == 0); + + rc = os_mempool_init(&pool_evt, POOL_EVT_COUNT, POOL_EVT_SIZE, + pool_evt_buf, "transport_pool_evt"); + SYSINIT_PANIC_ASSERT(rc == 0); + + rc = os_mempool_init(&pool_evt_lo, POOL_EVT_LO_COUNT, POOL_EVT_SIZE, + pool_evt_lo_buf, "transport_pool_evt_lo"); + SYSINIT_PANIC_ASSERT(rc == 0); + +#if POOL_ACL_COUNT > 0 + rc = os_mempool_ext_init(&pool_acl, POOL_ACL_COUNT, POOL_ACL_SIZE, + pool_acl_buf, "transport_pool_acl"); + SYSINIT_PANIC_ASSERT(rc == 0); + + rc = os_mbuf_pool_init(&mpool_acl, &pool_acl.mpe_mp, + POOL_ACL_SIZE, POOL_ACL_COUNT); + SYSINIT_PANIC_ASSERT(rc == 0); + + pool_acl.mpe_put_cb = ble_transport_acl_put; +#endif + +#if POOL_ISO_COUNT > 0 + rc = os_mempool_ext_init(&pool_iso, POOL_ISO_COUNT, POOL_ISO_SIZE, + pool_iso_buf, "transport_pool_iso"); + SYSINIT_PANIC_ASSERT(rc == 0); + + rc = os_mbuf_pool_init(&mpool_iso, &pool_iso.mpe_mp, + POOL_ISO_SIZE, POOL_ISO_COUNT); + SYSINIT_PANIC_ASSERT(rc == 0); +#endif +} + +int +ble_transport_register_put_acl_from_ll_cb(os_mempool_put_fn (*cb)) +{ + transport_put_acl_from_ll_cb = cb; + + return 0; +} + +#if BLE_TRANSPORT_IPC +uint8_t +ble_transport_ipc_buf_evt_type_get(void *buf) +{ + if (os_memblock_from(&pool_cmd, buf)) { + return HCI_IPC_TYPE_EVT_IN_CMD; + } else if (os_memblock_from(&pool_evt, buf)) { + return HCI_IPC_TYPE_EVT; + } else if (os_memblock_from(&pool_evt_lo, buf)) { + return HCI_IPC_TYPE_EVT_DISCARDABLE; + } else { + assert(0); + } + return 0; +} +#endif diff --git a/nimble/transport/da1469x/syscfg.yml b/nimble/transport/syscfg.defunct.yml similarity index 62% rename from nimble/transport/da1469x/syscfg.yml rename to nimble/transport/syscfg.defunct.yml index 4ea9da9b36..dc18ef4155 100644 --- a/nimble/transport/da1469x/syscfg.yml +++ b/nimble/transport/syscfg.defunct.yml @@ -17,27 +17,24 @@ # syscfg.defs: + BLE_HCI_TRANSPORT: + description: see doc/transport.md + defunct: 1 + BLE_HCI_BRIDGE: + description: see doc/transport.md + defunct: 1 BLE_HCI_EVT_HI_BUF_COUNT: - description: 'Number of high-priority event buffers.' - value: 2 - + description: use BLE_TRANSPORT_EVT_COUNT + defunct: 1 BLE_HCI_EVT_LO_BUF_COUNT: - description: 'Number of low-priority event buffers.' - value: 8 - + description: use BLE_TRANSPORT_EVT_DISCARDABLE_COUNT + defunct: 1 BLE_HCI_EVT_BUF_SIZE: - description: 'Size of each event buffer, in bytes.' - value: 70 - + description: use BLE_TRANSPORT_EVT_SIZE + defunct: 1 BLE_ACL_BUF_COUNT: - description: 'The number of ACL data buffers' - value: 4 - + description: use BLE_TRANSPORT_ACL_COUNT + defunct: 1 BLE_ACL_BUF_SIZE: - description: > - This is the maximum size of the data portion of HCI ACL data - packets. It does not include the HCI data header (of 4 bytes). - value: 255 - -syscfg.vals.BLE_EXT_ADV: - BLE_HCI_EVT_BUF_SIZE: 274 + description: use BLE_TRANSPORT_ACL_SIZE + defunct: 1 diff --git a/nimble/transport/syscfg.monitor.yml b/nimble/transport/syscfg.monitor.yml new file mode 100644 index 0000000000..4defd910bc --- /dev/null +++ b/nimble/transport/syscfg.monitor.yml @@ -0,0 +1,61 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +syscfg.defs: + BLE_MONITOR_UART: + description: Enables monitor interface over UART + value: 0 + BLE_MONITOR_UART_DEV: + description: Monitor interface UART device + value: '"uart0"' + BLE_MONITOR_UART_BAUDRATE: + description: Baudrate for monitor interface UART + value: 1000000 + BLE_MONITOR_UART_BUFFER_SIZE: + description: > + Monitor interface ringbuffer size for UART. + This value should be a power of 2. + value: 64 + BLE_MONITOR_RTT: + description: Enables monitor interface over RTT + value: 0 + BLE_MONITOR_RTT_BUFFER_NAME: + description: Monitor interface upstream buffer name + value: '"btmonitor"' + BLE_MONITOR_RTT_BUFFER_SIZE: + description: Monitor interface upstream buffer size + value: 256 + BLE_MONITOR_RTT_BUFFERED: + description: > + Enables buffering when using monitor interface over RTT. The data + are written to RTT once complete packet is created in intermediate + buffer. This allows to skip complete packet if there is not enough + space in RTT buffer (e.g. there is no reader connected). If disabled, + monitor will simply block waiting for RTT to free space in buffer. + value: 1 + BLE_MONITOR_CONSOLE_BUFFER_SIZE: + description: > + Size of internal buffer for console output. Any line exceeding this + length value will be split. + value: 128 + +syscfg.defs.'BLE_MONITOR_UART || BLE_MONITOR_RTT': + BLE_MONITOR: 1 + +syscfg.restrictions: + - '!(BLE_MONITOR_UART && BLE_MONITOR_RTT)' diff --git a/nimble/transport/syscfg.yml b/nimble/transport/syscfg.yml index 5bec6adf4d..c2b9ec1e91 100644 --- a/nimble/transport/syscfg.yml +++ b/nimble/transport/syscfg.yml @@ -17,55 +17,121 @@ # syscfg.defs: - BLE_HCI_TRANSPORT: + BLE_TRANSPORT: 1 + + BLE_TRANSPORT_HS: description: > - Selects HCI transport to be included in build. - This has virtually the same effect as including package dependency - manually, but it allows to easily override HCI transport package in - application or target settings. - value: builtin - restrictions: $notnull + Select HCI transport used towards host. + "native" means NimBLE host is running on the same core and no + transport is required. + value: native + choices: + - native + - dialog_cmac + - nrf5340 + - uart + - usb + - cdc + - custom + BLE_TRANSPORT_LL: + description: > + Select HCI transport used towards controller. + "native" means NimBLE controller is running on the same core and no + transport is required. + value: native choices: - - builtin # Built-in NimBLE controller and RAM transport - - custom # Custom transport, has to be included manually by user - - ram # RAM transport - - uart # UART HCI H4 transport - - socket # Socket transport (for native builds) - - emspi # SPI transport for EM Microelectionic controllers - - da1469x # Dialog DA1469x integrated controller - - dialog_cmac # Dialog CMAC via shared memory - - usb # USB - - nrf5340 # nRF5340 + - native + - emspi + - dialog_cmac + - nrf5340 + - socket + - apollo3 + - uart_ll + - custom + + BLE_TRANSPORT_ACL_COUNT: + description: > + Number of ACL buffers available in transport. This determines + number of buffers used by host/controller for flow control. + Buffers pool is allocated for each non-native transport side + selected, unless overriden by BLE_TRANSPORT_ACL_FROM_[HS|LL]_COUNT. + value: 10 + BLE_TRANSPORT_ACL_SIZE: + description: Size of each buffer in ACL pool. + value: 251 + BLE_TRANSPORT_ISO_COUNT: + description: > + Number of ISO buffers available in transport. This determines + number of buffers used by host/controller for flow control. + Buffers pool is allocated for each non-native transport side + selected, unless overriden by BLE_TRANSPORT_ISO_FROM_[HS|LL]_COUNT. + value: 10 + BLE_TRANSPORT_ISO_SIZE: + description: Size of each buffer in ISO pool. + value: 300 + BLE_TRANSPORT_EVT_COUNT: + description: > + Number of event buffers available in transport. + value: 4 + BLE_TRANSPORT_EVT_DISCARDABLE_COUNT: + description: > + Number of discardable event buffers available in transport. + Discardable event buffers are used for events that can be safely + dropped by controller if there's no free buffer available, e.g. + advertising reports. + value: 16 + BLE_TRANSPORT_EVT_SIZE: + description: > + Size of each buffer in events pool. This applies to both regular + and discardable buffers. Value is automatically adjusted if + extended advertising is enabled so in most cases it's better to + leave it at default settings. + value: 70 + + BLE_TRANSPORT_ACL_FROM_HS_COUNT: + description: > + Overrides BLE_TRANSPORT_ACL_COUNT on host side, i.e. number + of ACL buffers available for host. + value: MYNEWT_VAL(BLE_TRANSPORT_ACL_COUNT) + BLE_TRANSPORT_ACL_FROM_LL_COUNT: + description: > + Overrides BLE_TRANSPORT_ACL_COUNT on controller side, i.e. number + of ACL buffers available for controller. + value: MYNEWT_VAL(BLE_TRANSPORT_ACL_COUNT) + + BLE_TRANSPORT_ISO_FROM_HS_COUNT: + description: > + Overrides BLE_TRANSPORT_ISO_COUNT on host side, i.e. number + of ISO buffers available for host. + value: MYNEWT_VAL(BLE_TRANSPORT_ISO_COUNT) + BLE_TRANSPORT_ISO_FROM_LL_COUNT: + description: > + Overrides BLE_TRANSPORT_ISO_COUNT on controller side, i.e. number + of ISO buffers available for controller. + value: MYNEWT_VAL(BLE_TRANSPORT_ISO_COUNT) + + BLE_TRANSPORT_RX_TASK_STACK_SIZE: + description: > + Stack size of RX task. + RX task is started if stack size is set to a valid value. + value: + +syscfg.defs.BLE_TRANSPORT_RX_TASK_STACK_SIZE: + BLE_TRANSPORT_RX_TASK: 1 + BLE_TRANSPORT_RX_TASK_PRIO: + description: Priority of RX task + type: task_priority + restrictions: $notnull + value: + +# import monitor and defunct settings from separate file to reduce clutter in main file +$import: + - "@apache-mynewt-nimble/nimble/transport/syscfg.monitor.yml" + - "@apache-mynewt-nimble/nimble/transport/syscfg.defunct.yml" -# Deprecated settings - BLE_HCI_TRANSPORT_NIMBLE_BUILTIN: - description: Use BLE_HCI_TRANSPORT instead. - value: 0 - deprecated: 1 - BLE_HCI_TRANSPORT_EMSPI: - description: Use BLE_HCI_TRANSPORT instead. - value: 0 - deprecated: 1 - BLE_HCI_TRANSPORT_RAM: - description: Use BLE_HCI_TRANSPORT instead. - value: 0 - deprecated: 1 - BLE_HCI_TRANSPORT_SOCKET: - description: Use BLE_HCI_TRANSPORT instead. - value: 0 - deprecated: 1 - BLE_HCI_TRANSPORT_UART: - description: Use BLE_HCI_TRANSPORT instead. - value: 0 - deprecated: 1 +syscfg.vals.'BLE_EXT_ADV || BLE_LL_CFG_FEAT_LL_EXT_ADV': + BLE_TRANSPORT_EVT_SIZE: 257 -syscfg.vals.BLE_HCI_TRANSPORT_NIMBLE_BUILTIN: - BLE_HCI_TRANSPORT: builtin -syscfg.vals.BLE_HCI_TRANSPORT_RAM: - BLE_HCI_TRANSPORT: ram -syscfg.vals.BLE_HCI_TRANSPORT_UART: - BLE_HCI_TRANSPORT: uart -syscfg.vals.BLE_HCI_TRANSPORT_SOCKET: - BLE_HCI_TRANSPORT: socket -syscfg.vals.BLE_HCI_TRANSPORT_EMSPI: - BLE_HCI_TRANSPORT: emspi +syscfg.vals.'BLE_CHANNEL_SOUNDING && !(BLE_EXT_ADV || BLE_LL_CFG_FEAT_LL_EXT_ADV)': + # A larger buffer is needed to sent the FAE table. + BLE_TRANSPORT_EVT_SIZE: 78 diff --git a/nimble/transport/uart/pkg.yml b/nimble/transport/uart/pkg.yml index 9568137392..2802961d90 100644 --- a/nimble/transport/uart/pkg.yml +++ b/nimble/transport/uart/pkg.yml @@ -18,21 +18,15 @@ # pkg.name: nimble/transport/uart -pkg.description: XXX +pkg.description: HCI H4 transport over UART pkg.author: "Apache Mynewt " -pkg.homepage: "http://mynewt.apache.org/" -pkg.keywords: - - ble - - bluetooth +pkg.homepage: "https://mynewt.apache.org/" pkg.deps: - "@apache-mynewt-core/hw/hal" - "@apache-mynewt-core/kernel/os" - - "@apache-mynewt-core/util/mem" - nimble + - nimble/transport/common/hci_h4 pkg.apis: - ble_transport - -pkg.init: - ble_hci_uart_init: 'MYNEWT_VAL(BLE_TRANS_UART_SYSINIT_STAGE)' diff --git a/nimble/transport/uart/src/ble_hci_uart.c b/nimble/transport/uart/src/ble_hci_uart.c deleted file mode 100644 index cbb6dd4259..0000000000 --- a/nimble/transport/uart/src/ble_hci_uart.c +++ /dev/null @@ -1,1185 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#include -#include -#include -#include -#include -#include "sysinit/sysinit.h" -#include "syscfg/syscfg.h" -#include "os/os_cputime.h" -#include "bsp/bsp.h" -#include "os/os.h" -#include "mem/mem.h" -#include "hal/hal_gpio.h" -#include "hal/hal_uart.h" - -/* BLE */ -#include "nimble/ble.h" -#include "nimble/nimble_opt.h" -#include "nimble/hci_common.h" -#include "nimble/ble_hci_trans.h" - -#include "transport/uart/ble_hci_uart.h" - -#define BLE_HCI_UART_EVT_COUNT \ - (MYNEWT_VAL(BLE_HCI_EVT_HI_BUF_COUNT) + MYNEWT_VAL(BLE_HCI_EVT_LO_BUF_COUNT)) - -/*** - * NOTES: - * The UART HCI transport doesn't use event buffer priorities. All incoming - * and outgoing events use buffers from the same pool. - * - * The "skip" definitions are here so that when buffers cannot be allocated, - * the command or acl packets are simply skipped so that the HCI interface - * does not lose synchronization and resets dont (necessarily) occur. - */ - -/* XXX: for now, define this here */ -#if MYNEWT_VAL(BLE_CONTROLLER) -extern void ble_ll_data_buffer_overflow(void); -extern void ble_ll_hw_error(uint8_t err); - -static const uint8_t ble_hci_uart_reset_cmd[4] = { 0x01, 0x03, 0x0C, 0x00 }; -#endif - -/*** - * NOTES: - * The "skip" definitions are here so that when buffers cannot be allocated, - * the command or acl packets are simply skipped so that the HCI interface - * does not lose synchronization and resets dont (necessarily) occur. - */ -#define BLE_HCI_UART_H4_NONE 0x00 -#define BLE_HCI_UART_H4_CMD 0x01 -#define BLE_HCI_UART_H4_ACL 0x02 -#define BLE_HCI_UART_H4_SCO 0x03 -#define BLE_HCI_UART_H4_EVT 0x04 -#define BLE_HCI_UART_H4_SYNC_LOSS 0x80 -#define BLE_HCI_UART_H4_SKIP_CMD 0x81 -#define BLE_HCI_UART_H4_SKIP_ACL 0x82 -#define BLE_HCI_UART_H4_LE_EVT 0x83 -#define BLE_HCI_UART_H4_SKIP_EVT 0x84 - -static ble_hci_trans_rx_cmd_fn *ble_hci_uart_rx_cmd_cb; -static void *ble_hci_uart_rx_cmd_arg; - -static ble_hci_trans_rx_acl_fn *ble_hci_uart_rx_acl_cb; -static void *ble_hci_uart_rx_acl_arg; - -static struct os_mempool ble_hci_uart_evt_hi_pool; -static os_membuf_t ble_hci_uart_evt_hi_buf[ - OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_HCI_EVT_HI_BUF_COUNT), - MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE)) -]; - -static struct os_mempool ble_hci_uart_evt_lo_pool; -static os_membuf_t ble_hci_uart_evt_lo_buf[ - OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_HCI_EVT_LO_BUF_COUNT), - MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE)) -]; - -static struct os_mempool ble_hci_uart_cmd_pool; -static os_membuf_t ble_hci_uart_cmd_buf[ - OS_MEMPOOL_SIZE(1, BLE_HCI_TRANS_CMD_SZ) -]; - -static struct os_mbuf_pool ble_hci_uart_acl_mbuf_pool; -static struct os_mempool_ext ble_hci_uart_acl_pool; - -/* - * The MBUF payload size must accommodate the HCI data header size plus the - * maximum ACL data packet length. The ACL block size is the size of the - * mbufs we will allocate. - */ -#define ACL_BLOCK_SIZE OS_ALIGN(MYNEWT_VAL(BLE_ACL_BUF_SIZE) \ - + BLE_MBUF_MEMBLOCK_OVERHEAD \ - + BLE_HCI_DATA_HDR_SZ, OS_ALIGNMENT) - -static os_membuf_t ble_hci_uart_acl_buf[ - OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_ACL_BUF_COUNT), - ACL_BLOCK_SIZE) -]; - -/** - * A packet to be sent over the UART. This can be a command, an event, or ACL - * data. - */ -struct ble_hci_uart_pkt { - STAILQ_ENTRY(ble_hci_uart_pkt) next; - void *data; - uint8_t type; -}; - -static struct os_mempool ble_hci_uart_pkt_pool; -static os_membuf_t ble_hci_uart_pkt_buf[ - OS_MEMPOOL_SIZE(BLE_HCI_UART_EVT_COUNT + 1 + - MYNEWT_VAL(BLE_HCI_ACL_OUT_COUNT), - sizeof (struct ble_hci_uart_pkt)) -]; - -/** - * An incoming or outgoing command or event. - */ -struct ble_hci_uart_cmd { - uint8_t *data; /* Pointer to ble_hci_uart_cmd data */ - uint16_t cur; /* Number of bytes read/written */ - uint16_t len; /* Total number of bytes to read/write */ -}; - -/** - * An incoming ACL data packet. - */ -struct ble_hci_uart_acl { - struct os_mbuf *buf; /* Buffer containing the data */ - uint8_t *dptr; /* Pointer to where bytes should be placed */ - uint16_t len; /* Target size when buf is considered complete */ - uint16_t rxd_bytes; /* current count of bytes received for packet */ -}; - -/** - * Structure for transmitting ACL packets over UART - * - */ -struct ble_hci_uart_h4_acl_tx -{ - uint8_t *dptr; - struct os_mbuf *tx_acl; -}; - -static struct { - /*** State of data received over UART. */ - uint8_t rx_type; /* Pending packet type. 0 means nothing pending */ - union { - struct ble_hci_uart_cmd rx_cmd; - struct ble_hci_uart_acl rx_acl; - }; - - /*** State of data transmitted over UART. */ - uint8_t tx_type; /* Pending packet type. 0 means nothing pending */ - uint16_t rem_tx_len; /* Used for acl tx only currently */ - union { - struct ble_hci_uart_cmd tx_cmd; - struct ble_hci_uart_h4_acl_tx tx_pkt; - }; - STAILQ_HEAD(, ble_hci_uart_pkt) tx_pkts; /* Packet queue to send to UART */ -} ble_hci_uart_state; - -/** - * Allocates a buffer (mbuf) for ACL operation. - * - * @return The allocated buffer on success; - * NULL on buffer exhaustion. - */ -static struct os_mbuf * -ble_hci_trans_acl_buf_alloc(void) -{ - struct os_mbuf *m; - uint8_t usrhdr_len; - -#if MYNEWT_VAL(BLE_CONTROLLER) - usrhdr_len = sizeof(struct ble_mbuf_hdr); -#else - usrhdr_len = 0; -#endif - - m = os_mbuf_get_pkthdr(&ble_hci_uart_acl_mbuf_pool, usrhdr_len); - return m; -} - -static int -ble_hci_uart_acl_tx(struct os_mbuf *om) -{ - struct ble_hci_uart_pkt *pkt; - os_sr_t sr; - - /* If this packet is zero length, just free it */ - if (OS_MBUF_PKTLEN(om) == 0) { - os_mbuf_free_chain(om); - return 0; - } - - pkt = os_memblock_get(&ble_hci_uart_pkt_pool); - if (pkt == NULL) { - os_mbuf_free_chain(om); - return BLE_ERR_MEM_CAPACITY; - } - - pkt->type = BLE_HCI_UART_H4_ACL; - pkt->data = om; - - OS_ENTER_CRITICAL(sr); - STAILQ_INSERT_TAIL(&ble_hci_uart_state.tx_pkts, pkt, next); - OS_EXIT_CRITICAL(sr); - - hal_uart_start_tx(MYNEWT_VAL(BLE_HCI_UART_PORT)); - - return 0; -} - -static int -ble_hci_uart_cmdevt_tx(uint8_t *hci_ev, uint8_t h4_type) -{ - struct ble_hci_uart_pkt *pkt; - os_sr_t sr; - - pkt = os_memblock_get(&ble_hci_uart_pkt_pool); - if (pkt == NULL) { - ble_hci_trans_buf_free(hci_ev); - return BLE_ERR_MEM_CAPACITY; - } - - pkt->type = h4_type; - pkt->data = hci_ev; - - OS_ENTER_CRITICAL(sr); - STAILQ_INSERT_TAIL(&ble_hci_uart_state.tx_pkts, pkt, next); - OS_EXIT_CRITICAL(sr); - - hal_uart_start_tx(MYNEWT_VAL(BLE_HCI_UART_PORT)); - - return 0; -} - -/** - * @return The packet type to transmit on success; - * -1 if there is nothing to send. - */ -static int -ble_hci_uart_tx_pkt_type(void) -{ - struct ble_hci_uart_pkt *pkt; - struct os_mbuf *om; - os_sr_t sr; - int rc; - - OS_ENTER_CRITICAL(sr); - - pkt = STAILQ_FIRST(&ble_hci_uart_state.tx_pkts); - if (!pkt) { - OS_EXIT_CRITICAL(sr); - return -1; - } - - STAILQ_REMOVE(&ble_hci_uart_state.tx_pkts, pkt, ble_hci_uart_pkt, next); - - OS_EXIT_CRITICAL(sr); - - rc = pkt->type; - switch (pkt->type) { - case BLE_HCI_UART_H4_CMD: - ble_hci_uart_state.tx_type = BLE_HCI_UART_H4_CMD; - ble_hci_uart_state.tx_cmd.data = pkt->data; - ble_hci_uart_state.tx_cmd.cur = 0; - ble_hci_uart_state.tx_cmd.len = ble_hci_uart_state.tx_cmd.data[2] + - sizeof(struct ble_hci_cmd); - break; - - case BLE_HCI_UART_H4_EVT: - ble_hci_uart_state.tx_type = BLE_HCI_UART_H4_EVT; - ble_hci_uart_state.tx_cmd.data = pkt->data; - ble_hci_uart_state.tx_cmd.cur = 0; - ble_hci_uart_state.tx_cmd.len = ble_hci_uart_state.tx_cmd.data[1] + - sizeof(struct ble_hci_ev); - break; - - case BLE_HCI_UART_H4_ACL: - ble_hci_uart_state.tx_type = BLE_HCI_UART_H4_ACL; - om = (struct os_mbuf *)pkt->data; - /* NOTE: first mbuf must have non-zero length */ - os_mbuf_trim_front(om); - ble_hci_uart_state.tx_pkt.tx_acl = om; - ble_hci_uart_state.tx_pkt.dptr = om->om_data; - ble_hci_uart_state.rem_tx_len = OS_MBUF_PKTLEN(om); - break; - - default: - rc = -1; - break; - } - - os_memblock_put(&ble_hci_uart_pkt_pool, pkt); - - return rc; -} - -/** - * @return The byte to transmit on success; - * -1 if there is nothing to send. - */ -static int -ble_hci_uart_tx_char(void *arg) -{ - uint8_t u8; - int rc; - struct os_mbuf *om; - - switch (ble_hci_uart_state.tx_type) { - case BLE_HCI_UART_H4_NONE: /* No pending packet, pick one from the queue */ - rc = ble_hci_uart_tx_pkt_type(); - break; - - case BLE_HCI_UART_H4_CMD: - case BLE_HCI_UART_H4_EVT: - rc = ble_hci_uart_state.tx_cmd.data[ble_hci_uart_state.tx_cmd.cur++]; - - if (ble_hci_uart_state.tx_cmd.cur == ble_hci_uart_state.tx_cmd.len) { - ble_hci_trans_buf_free(ble_hci_uart_state.tx_cmd.data); - ble_hci_uart_state.tx_type = BLE_HCI_UART_H4_NONE; - } - break; - - case BLE_HCI_UART_H4_ACL: - /* Copy the first unsent byte from the tx buffer and remove it from the - * source. - */ - u8 = ble_hci_uart_state.tx_pkt.dptr[0]; - --ble_hci_uart_state.rem_tx_len; - if (ble_hci_uart_state.rem_tx_len == 0) { - os_mbuf_free_chain(ble_hci_uart_state.tx_pkt.tx_acl); - ble_hci_uart_state.tx_type = BLE_HCI_UART_H4_NONE; - } else { - om = ble_hci_uart_state.tx_pkt.tx_acl; - --om->om_len; - if (om->om_len == 0) { - /* Remove and free any zero mbufs */ - while ((om != NULL) && (om->om_len == 0)) { - ble_hci_uart_state.tx_pkt.tx_acl = SLIST_NEXT(om, om_next); - os_mbuf_free(om); - om = ble_hci_uart_state.tx_pkt.tx_acl; - } - /* NOTE: om should never be NULL! What to do? */ - if (om == NULL) { - assert(0); - ble_hci_uart_state.tx_type = BLE_HCI_UART_H4_NONE; - } else { - ble_hci_uart_state.tx_pkt.dptr = om->om_data; - } - } else { - ble_hci_uart_state.tx_pkt.dptr++; - } - } - rc = u8; - break; - default: - rc = -1; - break; - } - - return rc; -} - -#if MYNEWT_VAL(BLE_CONTROLLER) -/** - * HCI uart sync lost. - * - * This occurs when the controller receives an invalid packet type or a length - * field that is out of range. The controller needs to send a HW error to the - * host and wait to find a LL reset command. - */ -static void -ble_hci_uart_sync_lost(void) -{ - ble_hci_uart_state.rx_cmd.len = 0; - ble_hci_uart_state.rx_cmd.cur = 0; - ble_hci_uart_state.rx_cmd.data = - ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_CMD); - ble_ll_hw_error(BLE_HW_ERR_HCI_SYNC_LOSS); - ble_hci_uart_state.rx_type = BLE_HCI_UART_H4_SYNC_LOSS; -} -#endif - -/** - * @return The type of packet to follow success; - * -1 if there is no valid packet to receive. - */ -static int -ble_hci_uart_rx_pkt_type(uint8_t data) -{ - struct os_mbuf *m; - - ble_hci_uart_state.rx_type = data; - - switch (ble_hci_uart_state.rx_type) { - /* Host should never receive a command! */ -#if MYNEWT_VAL(BLE_CONTROLLER) - case BLE_HCI_UART_H4_CMD: - ble_hci_uart_state.rx_cmd.len = 0; - ble_hci_uart_state.rx_cmd.cur = 0; - ble_hci_uart_state.rx_cmd.data = - ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_CMD); - if (ble_hci_uart_state.rx_cmd.data == NULL) { - ble_hci_uart_state.rx_type = BLE_HCI_UART_H4_SKIP_CMD; - } - break; -#endif - - /* Controller should never receive an event */ -#if MYNEWT_VAL(BLE_HOST) - case BLE_HCI_UART_H4_EVT: - /* - * The event code is unknown at the moment. Depending on event priority, - * buffer *shall* be allocated from ble_hci_uart_evt_hi_pool - * or "may* be allocated from ble_hci_uart_evt_lo_pool. - * Thus do not allocate the buffer yet. - */ - ble_hci_uart_state.rx_cmd.data = NULL; - ble_hci_uart_state.rx_cmd.len = 0; - ble_hci_uart_state.rx_cmd.cur = 0; - break; -#endif - - case BLE_HCI_UART_H4_ACL: - ble_hci_uart_state.rx_acl.len = 0; - ble_hci_uart_state.rx_acl.rxd_bytes = 0; - m = ble_hci_trans_acl_buf_alloc(); - if (m) { - ble_hci_uart_state.rx_acl.dptr = m->om_data; - } else { - ble_hci_uart_state.rx_type = BLE_HCI_UART_H4_SKIP_ACL; - } - ble_hci_uart_state.rx_acl.buf = m; - break; - - default: -#if MYNEWT_VAL(BLE_CONTROLLER) - /* - * If we receive an unknown HCI packet type this is considered a loss - * of sync. - */ - ble_hci_uart_sync_lost(); -#else - /* - * XXX: not sure what to do about host in this case. Just go back to - * none for now. - */ - ble_hci_uart_state.rx_type = BLE_HCI_UART_H4_NONE; -#endif - break; - } - - return 0; -} - -#if MYNEWT_VAL(BLE_CONTROLLER) -/** - * HCI uart sync loss. - * - * Find a LL reset command in the byte stream. The LL reset command is a - * sequence of 4 bytes: - * 0x01 HCI Packet Type = HCI CMD - * 0x03 OCF for reset command - * 0x0C OGF for reset command (0x03 shifted left by two bits as the OGF - * occupies the uopper 6 bits of this byte. - * 0x00 Parameter length of reset command (no parameters). - * - * @param data Byte received over serial port - */ -void -ble_hci_uart_rx_sync_loss(uint8_t data) -{ - int rc; - int index; - - /* - * If we couldnt allocate a command buffer (should not occur but - * possible) try to allocate one on each received character. If we get - * a reset and buffer is not available we have to ignore reset. - */ - if (ble_hci_uart_state.rx_cmd.data == NULL) { - ble_hci_uart_state.rx_cmd.data = - ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_CMD); - } - - index = ble_hci_uart_state.rx_cmd.cur; - if (data == ble_hci_uart_reset_cmd[index]) { - if (index == 3) { - if (ble_hci_uart_state.rx_cmd.data == NULL) { - index = 0; - } else { - assert(ble_hci_uart_rx_cmd_cb != NULL); - ble_hci_uart_state.rx_cmd.data[0] = 0x03; - ble_hci_uart_state.rx_cmd.data[1] = 0x0C; - ble_hci_uart_state.rx_cmd.data[2] = 0x00; - rc = ble_hci_uart_rx_cmd_cb(ble_hci_uart_state.rx_cmd.data, - ble_hci_uart_rx_cmd_arg); - if (rc != 0) { - ble_hci_trans_buf_free(ble_hci_uart_state.rx_cmd.data); - } - ble_hci_uart_state.rx_type = BLE_HCI_UART_H4_NONE; - } - } else { - ++index; - } - } else { - index = 0; - } - - ble_hci_uart_state.rx_cmd.cur = index; -} - -static void -ble_hci_uart_rx_cmd(uint8_t data) -{ - int rc; - - ble_hci_uart_state.rx_cmd.data[ble_hci_uart_state.rx_cmd.cur++] = data; - - if (ble_hci_uart_state.rx_cmd.cur < sizeof(struct ble_hci_cmd)) { - return; - } - - if (ble_hci_uart_state.rx_cmd.cur == sizeof(struct ble_hci_cmd)) { - ble_hci_uart_state.rx_cmd.len = ble_hci_uart_state.rx_cmd.data[2] + - sizeof(struct ble_hci_cmd); - } - - if (ble_hci_uart_state.rx_cmd.cur == ble_hci_uart_state.rx_cmd.len) { - assert(ble_hci_uart_rx_cmd_cb != NULL); - rc = ble_hci_uart_rx_cmd_cb(ble_hci_uart_state.rx_cmd.data, - ble_hci_uart_rx_cmd_arg); - if (rc != 0) { - ble_hci_trans_buf_free(ble_hci_uart_state.rx_cmd.data); - } - ble_hci_uart_state.rx_type = BLE_HCI_UART_H4_NONE; - } -} - -static void -ble_hci_uart_rx_skip_cmd(uint8_t data) -{ - ble_hci_uart_state.rx_cmd.cur++; - - if (ble_hci_uart_state.rx_cmd.cur < sizeof(struct ble_hci_cmd)) { - return; - } - - if (ble_hci_uart_state.rx_cmd.cur == sizeof(struct ble_hci_cmd)) { - ble_hci_uart_state.rx_cmd.len = data + sizeof(struct ble_hci_cmd); - } - - if (ble_hci_uart_state.rx_cmd.cur == ble_hci_uart_state.rx_cmd.len) { - /* - * XXX: for now we simply skip the command and do nothing. This - * should not happen but at least we retain HCI synch. The host - * can decide what to do in this case. It may be appropriate for - * the controller to attempt to send back a command complete or - * command status in this case. - */ - ble_hci_uart_state.rx_type = BLE_HCI_UART_H4_NONE; - } -} -#endif - -#if MYNEWT_VAL(BLE_HOST) -static inline void -ble_hci_uart_rx_evt_cb(void) -{ - int rc; - - if (ble_hci_uart_state.rx_cmd.cur == ble_hci_uart_state.rx_cmd.len) { - assert(ble_hci_uart_rx_cmd_cb != NULL); - rc = ble_hci_uart_rx_cmd_cb(ble_hci_uart_state.rx_cmd.data, - ble_hci_uart_rx_cmd_arg); - if (rc != 0) { - ble_hci_trans_buf_free(ble_hci_uart_state.rx_cmd.data); - } - ble_hci_uart_state.rx_type = BLE_HCI_UART_H4_NONE; - } -} - -static void -ble_hci_uart_rx_evt(uint8_t data) -{ - /* Determine event priority to allocate buffer */ - if (!ble_hci_uart_state.rx_cmd.data) { - /* In case of LE Meta Event priority might be still unknown */ - if (data == BLE_HCI_EVCODE_LE_META) { - ble_hci_uart_state.rx_type = BLE_HCI_UART_H4_LE_EVT; - ble_hci_uart_state.rx_cmd.cur++; - return; - } - - ble_hci_uart_state.rx_cmd.data = - ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); - assert(ble_hci_uart_state.rx_cmd.data != NULL); - } - - ble_hci_uart_state.rx_cmd.data[ble_hci_uart_state.rx_cmd.cur++] = data; - - if (ble_hci_uart_state.rx_cmd.cur < sizeof(struct ble_hci_ev)) { - return; - } - - if (ble_hci_uart_state.rx_cmd.cur == sizeof(struct ble_hci_ev)) { - ble_hci_uart_state.rx_cmd.len = ble_hci_uart_state.rx_cmd.data[1] + - sizeof(struct ble_hci_ev); - } - - ble_hci_uart_rx_evt_cb(); -} - -static void -ble_hci_uart_rx_le_evt(uint8_t data) -{ - ble_hci_uart_state.rx_cmd.cur++; - - if (ble_hci_uart_state.rx_cmd.cur == sizeof(struct ble_hci_ev)) { - /* LE Meta Event parameter length is never 0 */ - assert(data != 0); - ble_hci_uart_state.rx_cmd.len = data + sizeof(struct ble_hci_ev); - return; - } - - /* Determine event priority to allocate buffer */ - if (!ble_hci_uart_state.rx_cmd.data) { - /* Determine event priority to allocate buffer */ - if (data == BLE_HCI_LE_SUBEV_ADV_RPT || - data == BLE_HCI_LE_SUBEV_EXT_ADV_RPT) { - ble_hci_uart_state.rx_cmd.data = - ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_LO); - if (ble_hci_uart_state.rx_cmd.data == NULL) { - ble_hci_uart_state.rx_type = BLE_HCI_UART_H4_SKIP_EVT; - return; - } - } else { - ble_hci_uart_state.rx_cmd.data = - ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); - assert(ble_hci_uart_state.rx_cmd.data != NULL); - } - - ble_hci_uart_state.rx_cmd.data[0] = BLE_HCI_EVCODE_LE_META; - ble_hci_uart_state.rx_cmd.data[1] = - ble_hci_uart_state.rx_cmd.len - sizeof(struct ble_hci_ev); - } - - ble_hci_uart_state.rx_cmd.data[ble_hci_uart_state.rx_cmd.cur - 1] = data; - ble_hci_uart_rx_evt_cb(); -} - -static void -ble_hci_uart_rx_skip_evt(uint8_t data) -{ - if (++ble_hci_uart_state.rx_cmd.cur == ble_hci_uart_state.rx_cmd.len) { - ble_hci_uart_state.rx_type = BLE_HCI_UART_H4_NONE; - } -} -#endif - -static void -ble_hci_uart_rx_acl(uint8_t data) -{ - uint16_t rxd_bytes; - uint16_t pktlen; - - rxd_bytes = ble_hci_uart_state.rx_acl.rxd_bytes; - ble_hci_uart_state.rx_acl.dptr[rxd_bytes] = data; - ++rxd_bytes; - ble_hci_uart_state.rx_acl.rxd_bytes = rxd_bytes; - - if (rxd_bytes < BLE_HCI_DATA_HDR_SZ) { - return; - } - - if (rxd_bytes == BLE_HCI_DATA_HDR_SZ) { - pktlen = ble_hci_uart_state.rx_acl.dptr[3]; - pktlen = (pktlen << 8) + ble_hci_uart_state.rx_acl.dptr[2]; - ble_hci_uart_state.rx_acl.len = pktlen + BLE_HCI_DATA_HDR_SZ; - - /* - * Data portion cannot exceed data length of acl buffer. If it does - * this is considered to be a loss of sync. - */ - if (pktlen > MYNEWT_VAL(BLE_ACL_BUF_SIZE)) { - os_mbuf_free_chain(ble_hci_uart_state.rx_acl.buf); -#if MYNEWT_VAL(BLE_CONTROLLER) - ble_hci_uart_sync_lost(); -#else - /* - * XXX: not sure what to do about host in this case. Just go back to - * none for now. - */ - ble_hci_uart_state.rx_type = BLE_HCI_UART_H4_NONE; -#endif - } - } - - if (rxd_bytes == ble_hci_uart_state.rx_acl.len) { - assert(ble_hci_uart_rx_acl_cb != NULL); - /* XXX: can this callback fail? What if it does? */ - OS_MBUF_PKTLEN(ble_hci_uart_state.rx_acl.buf) = rxd_bytes; - ble_hci_uart_state.rx_acl.buf->om_len = rxd_bytes; - ble_hci_uart_rx_acl_cb(ble_hci_uart_state.rx_acl.buf, - ble_hci_uart_rx_acl_arg); - ble_hci_uart_state.rx_type = BLE_HCI_UART_H4_NONE; - } -} - -static void -ble_hci_uart_rx_skip_acl(uint8_t data) -{ - uint16_t rxd_bytes; - uint16_t pktlen; - - rxd_bytes = ble_hci_uart_state.rx_acl.rxd_bytes; - ++rxd_bytes; - ble_hci_uart_state.rx_acl.rxd_bytes = rxd_bytes; - - if (rxd_bytes == (BLE_HCI_DATA_HDR_SZ - 1)) { - ble_hci_uart_state.rx_acl.len = data; - return; - } - - if (rxd_bytes == BLE_HCI_DATA_HDR_SZ) { - pktlen = data; - pktlen = (pktlen << 8) + ble_hci_uart_state.rx_acl.len; - ble_hci_uart_state.rx_acl.len = pktlen + BLE_HCI_DATA_HDR_SZ; - } - - if (rxd_bytes == ble_hci_uart_state.rx_acl.len) { -/* XXX: I dont like this but for now this denotes controller only */ -#if MYNEWT_VAL(BLE_CONTROLLER) - ble_ll_data_buffer_overflow(); -#endif - ble_hci_uart_state.rx_type = BLE_HCI_UART_H4_NONE; - } -} - -static int -ble_hci_uart_rx_char(void *arg, uint8_t data) -{ - switch (ble_hci_uart_state.rx_type) { - case BLE_HCI_UART_H4_NONE: - return ble_hci_uart_rx_pkt_type(data); -#if MYNEWT_VAL(BLE_CONTROLLER) - case BLE_HCI_UART_H4_CMD: - ble_hci_uart_rx_cmd(data); - return 0; - case BLE_HCI_UART_H4_SKIP_CMD: - ble_hci_uart_rx_skip_cmd(data); - return 0; - case BLE_HCI_UART_H4_SYNC_LOSS: - ble_hci_uart_rx_sync_loss(data); - return 0; -#endif -#if MYNEWT_VAL(BLE_HOST) - case BLE_HCI_UART_H4_EVT: - ble_hci_uart_rx_evt(data); - return 0; - case BLE_HCI_UART_H4_LE_EVT: - ble_hci_uart_rx_le_evt(data); - return 0; - case BLE_HCI_UART_H4_SKIP_EVT: - ble_hci_uart_rx_skip_evt(data); - return 0; -#endif - case BLE_HCI_UART_H4_ACL: - ble_hci_uart_rx_acl(data); - return 0; - case BLE_HCI_UART_H4_SKIP_ACL: - ble_hci_uart_rx_skip_acl(data); - return 0; - default: - /* This should never happen! */ - assert(0); - return 0; - } -} - -static void -ble_hci_uart_set_rx_cbs(ble_hci_trans_rx_cmd_fn *cmd_cb, - void *cmd_arg, - ble_hci_trans_rx_acl_fn *acl_cb, - void *acl_arg) -{ - ble_hci_uart_rx_cmd_cb = cmd_cb; - ble_hci_uart_rx_cmd_arg = cmd_arg; - ble_hci_uart_rx_acl_cb = acl_cb; - ble_hci_uart_rx_acl_arg = acl_arg; -} - -static void -ble_hci_uart_free_pkt(uint8_t type, uint8_t *cmdevt, struct os_mbuf *acl) -{ - switch (type) { - case BLE_HCI_UART_H4_NONE: - break; - - case BLE_HCI_UART_H4_CMD: - case BLE_HCI_UART_H4_EVT: - ble_hci_trans_buf_free(cmdevt); - break; - - case BLE_HCI_UART_H4_ACL: - os_mbuf_free_chain(acl); - break; - - default: - assert(0); - break; - } -} - -static int -ble_hci_uart_config(void) -{ - int rc; - - rc = hal_uart_init_cbs(MYNEWT_VAL(BLE_HCI_UART_PORT), - ble_hci_uart_tx_char, NULL, - ble_hci_uart_rx_char, NULL); - if (rc != 0) { - return BLE_ERR_UNSPECIFIED; - } - - rc = hal_uart_config(MYNEWT_VAL(BLE_HCI_UART_PORT), - MYNEWT_VAL(BLE_HCI_UART_BAUD), - MYNEWT_VAL(BLE_HCI_UART_DATA_BITS), - MYNEWT_VAL(BLE_HCI_UART_STOP_BITS), - MYNEWT_VAL(BLE_HCI_UART_PARITY), - MYNEWT_VAL(BLE_HCI_UART_FLOW_CTRL)); - if (rc != 0) { - return BLE_ERR_HW_FAIL; - } - - return 0; -} - -/** - * Sends an HCI event from the controller to the host. - * - * @param cmd The HCI event to send. This buffer must be - * allocated via ble_hci_trans_buf_alloc(). - * - * @return 0 on success; - * A BLE_ERR_[...] error code on failure. - */ -int -ble_hci_trans_ll_evt_tx(uint8_t *cmd) -{ - int rc; - - rc = ble_hci_uart_cmdevt_tx(cmd, BLE_HCI_UART_H4_EVT); - return rc; -} - -/** - * Sends ACL data from controller to host. - * - * @param om The ACL data packet to send. - * - * @return 0 on success; - * A BLE_ERR_[...] error code on failure. - */ -int -ble_hci_trans_ll_acl_tx(struct os_mbuf *om) -{ - int rc; - - rc = ble_hci_uart_acl_tx(om); - return rc; -} - -/** - * Sends an HCI command from the host to the controller. - * - * @param cmd The HCI command to send. This buffer must be - * allocated via ble_hci_trans_buf_alloc(). - * - * @return 0 on success; - * A BLE_ERR_[...] error code on failure. - */ -int -ble_hci_trans_hs_cmd_tx(uint8_t *cmd) -{ - int rc; - - rc = ble_hci_uart_cmdevt_tx(cmd, BLE_HCI_UART_H4_CMD); - return rc; -} - -/** - * Sends ACL data from host to controller. - * - * @param om The ACL data packet to send. - * - * @return 0 on success; - * A BLE_ERR_[...] error code on failure. - */ -int -ble_hci_trans_hs_acl_tx(struct os_mbuf *om) -{ - int rc; - - rc = ble_hci_uart_acl_tx(om); - return rc; -} - -/** - * Configures the HCI transport to call the specified callback upon receiving - * HCI packets from the controller. This function should only be called by by - * host. - * - * @param cmd_cb The callback to execute upon receiving an HCI - * event. - * @param cmd_arg Optional argument to pass to the command - * callback. - * @param acl_cb The callback to execute upon receiving ACL - * data. - * @param acl_arg Optional argument to pass to the ACL - * callback. - */ -void -ble_hci_trans_cfg_hs(ble_hci_trans_rx_cmd_fn *cmd_cb, - void *cmd_arg, - ble_hci_trans_rx_acl_fn *acl_cb, - void *acl_arg) -{ - ble_hci_uart_set_rx_cbs(cmd_cb, cmd_arg, acl_cb, acl_arg); -} - -/** - * Configures the HCI transport to operate with a host. The transport will - * execute specified callbacks upon receiving HCI packets from the controller. - * - * @param cmd_cb The callback to execute upon receiving an HCI - * event. - * @param cmd_arg Optional argument to pass to the command - * callback. - * @param acl_cb The callback to execute upon receiving ACL - * data. - * @param acl_arg Optional argument to pass to the ACL - * callback. - */ -void -ble_hci_trans_cfg_ll(ble_hci_trans_rx_cmd_fn *cmd_cb, - void *cmd_arg, - ble_hci_trans_rx_acl_fn *acl_cb, - void *acl_arg) -{ - ble_hci_uart_set_rx_cbs(cmd_cb, cmd_arg, acl_cb, acl_arg); -} - -/** - * Allocates a flat buffer of the specified type. - * - * @param type The type of buffer to allocate; one of the - * BLE_HCI_TRANS_BUF_[...] constants. - * - * @return The allocated buffer on success; - * NULL on buffer exhaustion. - */ -uint8_t * -ble_hci_trans_buf_alloc(int type) -{ - uint8_t *buf; - - switch (type) { - case BLE_HCI_TRANS_BUF_CMD: - buf = os_memblock_get(&ble_hci_uart_cmd_pool); - break; - case BLE_HCI_TRANS_BUF_EVT_HI: - buf = os_memblock_get(&ble_hci_uart_evt_hi_pool); - if (buf == NULL) { - /* If no high-priority event buffers remain, try to grab a - * low-priority one. - */ - buf = os_memblock_get(&ble_hci_uart_evt_lo_pool); - } - break; - - case BLE_HCI_TRANS_BUF_EVT_LO: - buf = os_memblock_get(&ble_hci_uart_evt_lo_pool); - break; - - default: - assert(0); - buf = NULL; - } - - return buf; -} - -/** - * Frees the specified flat buffer. The buffer must have been allocated via - * ble_hci_trans_buf_alloc(). - * - * @param buf The buffer to free. - */ -void -ble_hci_trans_buf_free(uint8_t *buf) -{ - int rc; - - /* - * XXX: this may look a bit odd, but the controller uses the command - * buffer to send back the command complete/status as an immediate - * response to the command. This was done to insure that the controller - * could always send back one of these events when a command was received. - * Thus, we check to see which pool the buffer came from so we can free - * it to the appropriate pool - */ - if (os_memblock_from(&ble_hci_uart_evt_hi_pool, buf)) { - rc = os_memblock_put(&ble_hci_uart_evt_hi_pool, buf); - assert(rc == 0); - } else if (os_memblock_from(&ble_hci_uart_evt_lo_pool, buf)) { - rc = os_memblock_put(&ble_hci_uart_evt_lo_pool, buf); - assert(rc == 0); - } else { - assert(os_memblock_from(&ble_hci_uart_cmd_pool, buf)); - rc = os_memblock_put(&ble_hci_uart_cmd_pool, buf); - assert(rc == 0); - } -} - -/** - * Configures a callback to get executed whenever an ACL data packet is freed. - * The function is called in lieu of actually freeing the packet. - * - * @param cb The callback to configure. - * - * @return 0 on success. - */ -int -ble_hci_trans_set_acl_free_cb(os_mempool_put_fn *cb, void *arg) -{ - ble_hci_uart_acl_pool.mpe_put_cb = cb; - ble_hci_uart_acl_pool.mpe_put_arg = arg; - return 0; -} - -/** - * Resets the HCI UART transport to a clean state. Frees all buffers and - * reconfigures the UART. - * - * @return 0 on success; - * A BLE_ERR_[...] error code on failure. - */ -int -ble_hci_trans_reset(void) -{ - struct ble_hci_uart_pkt *pkt; - int rc; - - /* Close the UART to prevent race conditions as the buffers are freed. */ - rc = hal_uart_close(MYNEWT_VAL(BLE_HCI_UART_PORT)); - if (rc != 0) { - return BLE_ERR_HW_FAIL; - } - - ble_hci_uart_free_pkt(ble_hci_uart_state.rx_type, - ble_hci_uart_state.rx_cmd.data, - ble_hci_uart_state.rx_acl.buf); - ble_hci_uart_state.rx_type = BLE_HCI_UART_H4_NONE; - - ble_hci_uart_free_pkt(ble_hci_uart_state.tx_type, - ble_hci_uart_state.tx_cmd.data, - ble_hci_uart_state.tx_pkt.tx_acl); - ble_hci_uart_state.tx_type = BLE_HCI_UART_H4_NONE; - - while ((pkt = STAILQ_FIRST(&ble_hci_uart_state.tx_pkts)) != NULL) { - STAILQ_REMOVE(&ble_hci_uart_state.tx_pkts, pkt, ble_hci_uart_pkt, - next); - ble_hci_uart_free_pkt(pkt->type, pkt->data, pkt->data); - os_memblock_put(&ble_hci_uart_pkt_pool, pkt); - } - - /* Reopen the UART. */ - rc = ble_hci_uart_config(); - if (rc != 0) { - return rc; - } - - return 0; -} - -/** - * Initializes the UART HCI transport module. - * - * @return 0 on success; - * A BLE_ERR_[...] error code on failure. - */ -void -ble_hci_uart_init(void) -{ - int rc; - - /* Ensure this function only gets called by sysinit. */ - SYSINIT_ASSERT_ACTIVE(); - - rc = os_mempool_ext_init(&ble_hci_uart_acl_pool, - MYNEWT_VAL(BLE_ACL_BUF_COUNT), - ACL_BLOCK_SIZE, - ble_hci_uart_acl_buf, - "ble_hci_uart_acl_pool"); - SYSINIT_PANIC_ASSERT(rc == 0); - - rc = os_mbuf_pool_init(&ble_hci_uart_acl_mbuf_pool, - &ble_hci_uart_acl_pool.mpe_mp, - ACL_BLOCK_SIZE, - MYNEWT_VAL(BLE_ACL_BUF_COUNT)); - SYSINIT_PANIC_ASSERT(rc == 0); - - /* - * Create memory pool of HCI command buffers. NOTE: we currently dont - * allow this to be configured. The controller will only allow one - * outstanding command. We decided to keep this a pool in case we allow - * allow the controller to handle more than one outstanding command. - */ - rc = os_mempool_init(&ble_hci_uart_cmd_pool, - 1, - BLE_HCI_TRANS_CMD_SZ, - ble_hci_uart_cmd_buf, - "ble_hci_uart_cmd_pool"); - SYSINIT_PANIC_ASSERT(rc == 0); - - rc = os_mempool_init(&ble_hci_uart_evt_hi_pool, - MYNEWT_VAL(BLE_HCI_EVT_HI_BUF_COUNT), - MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE), - ble_hci_uart_evt_hi_buf, - "ble_hci_uart_evt_hi_pool"); - SYSINIT_PANIC_ASSERT(rc == 0); - - rc = os_mempool_init(&ble_hci_uart_evt_lo_pool, - MYNEWT_VAL(BLE_HCI_EVT_LO_BUF_COUNT), - MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE), - ble_hci_uart_evt_lo_buf, - "ble_hci_uart_evt_lo_pool"); - SYSINIT_PANIC_ASSERT(rc == 0); - - /* - * Create memory pool of packet list nodes. NOTE: the number of these - * buffers should be, at least, the total number of event buffers (hi - * and lo), the number of command buffers (currently 1) and the total - * number of buffers that the controller could possibly hand to the host. - */ - rc = os_mempool_init(&ble_hci_uart_pkt_pool, - BLE_HCI_UART_EVT_COUNT + 1 + - MYNEWT_VAL(BLE_HCI_ACL_OUT_COUNT), - sizeof (struct ble_hci_uart_pkt), - ble_hci_uart_pkt_buf, - "ble_hci_uart_pkt_pool"); - SYSINIT_PANIC_ASSERT(rc == 0); - - rc = ble_hci_uart_config(); - SYSINIT_PANIC_ASSERT_MSG(rc == 0, "Failure configuring UART HCI"); - - memset(&ble_hci_uart_state, 0, sizeof ble_hci_uart_state); - STAILQ_INIT(&ble_hci_uart_state.tx_pkts); -} diff --git a/nimble/transport/uart/src/hci_uart.c b/nimble/transport/uart/src/hci_uart.c new file mode 100644 index 0000000000..af1f45ae92 --- /dev/null +++ b/nimble/transport/uart/src/hci_uart.c @@ -0,0 +1,277 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#include +#include +#include +#include "os/os_mbuf.h" +#include "os/os_mempool.h" +#include "hal/hal_uart.h" +#include "nimble/transport.h" +#include "nimble/transport/hci_h4.h" + +#define TX_Q_SIZE (MYNEWT_VAL(BLE_TRANSPORT_ACL_FROM_LL_COUNT) + \ + MYNEWT_VAL(BLE_TRANSPORT_EVT_COUNT) + \ + MYNEWT_VAL(BLE_TRANSPORT_EVT_DISCARDABLE_COUNT)) + +struct hci_uart_tx { + uint8_t type; + uint8_t sent_type; + uint16_t len; + uint16_t idx; + + struct os_mbuf *om; + uint8_t *buf; + + STAILQ_ENTRY(hci_uart_tx) tx_q_next; +}; + +static STAILQ_HEAD(, hci_uart_tx) tx_q; + +static struct os_mempool pool_tx_q; +static uint8_t pool_tx_q_buf[ OS_MEMPOOL_BYTES(TX_Q_SIZE, + sizeof(struct hci_uart_tx)) ]; + +struct hci_h4_sm hci_uart_h4sm; + +static int +hci_uart_frame_cb(uint8_t pkt_type, void *data) +{ + switch (pkt_type) { + case HCI_H4_CMD: + return ble_transport_to_ll_cmd(data); + case HCI_H4_ACL: + return ble_transport_to_ll_acl(data); + case HCI_H4_ISO: + return ble_transport_to_ll_iso(data); + default: + assert(0); + break; + } + + return -1; +} + +static int +hci_uart_rx_char(void *arg, uint8_t data) +{ + hci_h4_sm_rx(&hci_uart_h4sm, &data, 1); + + return 0; +} + +static int +hci_uart_tx_char(void *arg) +{ + struct hci_uart_tx *tx; + uint8_t ch; + os_sr_t sr; + + OS_ENTER_CRITICAL(sr); + tx = STAILQ_FIRST(&tx_q); + OS_EXIT_CRITICAL(sr); + if (!tx) { + return -1; + } + + if (!tx->sent_type) { + tx->sent_type = 1; + return tx->type; + } + + switch (tx->type) { + case HCI_H4_EVT: + ch = tx->buf[tx->idx]; + tx->idx++; + if (tx->idx == tx->len) { + ble_transport_free(tx->buf); + OS_ENTER_CRITICAL(sr); + STAILQ_REMOVE_HEAD(&tx_q, tx_q_next); + OS_EXIT_CRITICAL(sr); + os_memblock_put(&pool_tx_q, tx); + } + break; + case HCI_H4_ACL: + os_mbuf_copydata(tx->om, 0, 1, &ch); + os_mbuf_adj(tx->om, 1); + tx->len--; + if (tx->len == 0) { + os_mbuf_free_chain(tx->om); + OS_ENTER_CRITICAL(sr); + STAILQ_REMOVE_HEAD(&tx_q, tx_q_next); + OS_EXIT_CRITICAL(sr); + os_memblock_put(&pool_tx_q, tx); + } + break; + default: + assert(0); + OS_ENTER_CRITICAL(sr); + STAILQ_REMOVE_HEAD(&tx_q, tx_q_next); + OS_EXIT_CRITICAL(sr); + os_memblock_put(&pool_tx_q, tx); + } + + return ch; +} + +static int +hci_uart_configure(void) +{ + enum hal_uart_parity parity; + enum hal_uart_flow_ctl flowctl; + int rc; + + rc = hal_uart_init_cbs(MYNEWT_VAL(BLE_TRANSPORT_UART_PORT), + hci_uart_tx_char, NULL, + hci_uart_rx_char, NULL); + if (rc != 0) { + return -1; + } + + if (MYNEWT_VAL_CHOICE(BLE_TRANSPORT_UART_PARITY, odd)) { + parity = HAL_UART_PARITY_ODD; + } else if (MYNEWT_VAL_CHOICE(BLE_TRANSPORT_UART_PARITY, even)) { + parity = HAL_UART_PARITY_EVEN; + } else { + parity = HAL_UART_PARITY_NONE; + } + + if (MYNEWT_VAL_CHOICE(BLE_TRANSPORT_UART_FLOW_CONTROL, rtscts)) { + flowctl = HAL_UART_FLOW_CTL_RTS_CTS; + } else { + flowctl = HAL_UART_FLOW_CTL_NONE; + } + + rc = hal_uart_config(MYNEWT_VAL(BLE_TRANSPORT_UART_PORT), + MYNEWT_VAL(BLE_TRANSPORT_UART_BAUDRATE), + MYNEWT_VAL(BLE_TRANSPORT_UART_DATA_BITS), + MYNEWT_VAL(BLE_TRANSPORT_UART_STOP_BITS), + parity, flowctl); + if (rc != 0) { + return -1; + } + + return 0; +} + +int +ble_transport_to_hs_evt_impl(void *buf) +{ + struct hci_uart_tx *txe; + os_sr_t sr; + + txe = os_memblock_get(&pool_tx_q); + if (!txe) { + assert(0); + return -ENOMEM; + } + + txe->type = HCI_H4_EVT; + txe->sent_type = 0; + txe->len = 2 + ((uint8_t *)buf)[1]; + txe->buf = buf; + txe->idx = 0; + txe->om = NULL; + + OS_ENTER_CRITICAL(sr); + STAILQ_INSERT_TAIL(&tx_q, txe, tx_q_next); + OS_EXIT_CRITICAL(sr); + + hal_uart_start_tx(MYNEWT_VAL(BLE_TRANSPORT_UART_PORT)); + + return 0; +} + +int +ble_transport_to_hs_acl_impl(struct os_mbuf *om) +{ + struct hci_uart_tx *txe; + os_sr_t sr; + + txe = os_memblock_get(&pool_tx_q); + if (!txe) { + assert(0); + return -ENOMEM; + } + + txe->type = HCI_H4_ACL; + txe->sent_type = 0; + txe->len = OS_MBUF_PKTLEN(om); + txe->idx = 0; + txe->buf = NULL; + txe->om = om; + + OS_ENTER_CRITICAL(sr); + STAILQ_INSERT_TAIL(&tx_q, txe, tx_q_next); + OS_EXIT_CRITICAL(sr); + + hal_uart_start_tx(MYNEWT_VAL(BLE_TRANSPORT_UART_PORT)); + + return 0; +} + +int +ble_transport_to_hs_iso_impl(struct os_mbuf *om) +{ + struct hci_uart_tx *txe; + os_sr_t sr; + + txe = os_memblock_get(&pool_tx_q); + if (!txe) { + assert(0); + return -ENOMEM; + } + + txe->type = HCI_H4_ISO; + txe->sent_type = 0; + txe->len = OS_MBUF_PKTLEN(om); + txe->idx = 0; + txe->buf = NULL; + txe->om = om; + + OS_ENTER_CRITICAL(sr); + STAILQ_INSERT_TAIL(&tx_q, txe, tx_q_next); + OS_EXIT_CRITICAL(sr); + + hal_uart_start_tx(MYNEWT_VAL(BLE_TRANSPORT_UART_PORT)); + + return 0; +} + +void +ble_transport_hs_init(void) +{ + int rc; + + SYSINIT_ASSERT_ACTIVE(); + + rc = hci_uart_configure(); + SYSINIT_PANIC_ASSERT(rc == 0); + + rc = os_mempool_init(&pool_tx_q, TX_Q_SIZE, sizeof(struct hci_uart_tx), + pool_tx_q_buf, "hci_uart_tx_q"); + SYSINIT_PANIC_ASSERT(rc == 0); + + hci_h4_sm_init(&hci_uart_h4sm, &hci_h4_allocs_from_hs, hci_uart_frame_cb); + + STAILQ_INIT(&tx_q); +} diff --git a/nimble/transport/uart/syscfg.yml b/nimble/transport/uart/syscfg.yml index 43486a8bfe..21d21777e9 100644 --- a/nimble/transport/uart/syscfg.yml +++ b/nimble/transport/uart/syscfg.yml @@ -17,56 +17,23 @@ # syscfg.defs: - BLE_HCI_EVT_BUF_SIZE: - description: 'The size of the allocated event buffers' - value: 70 - BLE_HCI_EVT_HI_BUF_COUNT: - description: 'The number of high priority event buffers' + BLE_TRANSPORT_UART_PORT: + description: UART index to use for HCI interface + value: 0 + BLE_TRANSPORT_UART_BAUDRATE: + description: Baudrate on UART + value: 1000000 + BLE_TRANSPORT_UART_DATA_BITS: + description: Number of data bits on UART value: 8 - BLE_HCI_EVT_LO_BUF_COUNT: - description: 'The number of low priority event buffers' - value: 8 - BLE_ACL_BUF_COUNT: - description: 'The number of ACL data buffers' - value: 12 - BLE_ACL_BUF_SIZE: - description: > - This is the maximum size of the data portion of HCI ACL data - packets. It does not include the HCI data header (of 4 bytes). - value: 255 - - BLE_HCI_ACL_OUT_COUNT: - description: > - This count is used in creating a pool of elements used by the - code to enqueue various elements. In the case of the controller - only HCI, this number should be equal to the number of mbufs in - the msys pool. For host only, it is really dependent on the - number of ACL buffers that the controller tells the host it - has. - value: 12 - - BLE_HCI_UART_PORT: - description: 'The uart to use for the HCI uart interface' - value: 0 - BLE_HCI_UART_BAUD: - description: 'The baud rate of the HCI uart interface' - value: 1000000 - BLE_HCI_UART_DATA_BITS: - description: 'Number of data bits used for HCI uart interface' - value: 8 - BLE_HCI_UART_STOP_BITS: - description: 'Number of stop bits used for HCI uart interface' - value: 1 - BLE_HCI_UART_PARITY: - description: 'Parity used for HCI uart interface' - value: HAL_UART_PARITY_NONE - BLE_HCI_UART_FLOW_CTRL: - description: 'Flow control used for HCI uart interface' - value: HAL_UART_FLOW_CTL_RTS_CTS - BLE_TRANS_UART_SYSINIT_STAGE: - description: > - Sysinit stage for the UART BLE transport. - value: 500 - -syscfg.vals.BLE_EXT_ADV: - BLE_HCI_EVT_BUF_SIZE: 257 + BLE_TRANSPORT_UART_STOP_BITS: + description: Number of stop bits on UART + value: 1 + BLE_TRANSPORT_UART_PARITY: + description: Parity on UART + value: none + choices: none,even,odd + BLE_TRANSPORT_UART_FLOW_CONTROL: + description: Flow control on UART + choices: off,rtscts + value: rtscts diff --git a/nimble/transport/ram/pkg.yml b/nimble/transport/uart_ll/pkg.yml similarity index 81% rename from nimble/transport/ram/pkg.yml rename to nimble/transport/uart_ll/pkg.yml index bb8397bf36..efc97d5456 100644 --- a/nimble/transport/ram/pkg.yml +++ b/nimble/transport/uart_ll/pkg.yml @@ -17,20 +17,16 @@ # under the License. # -pkg.name: nimble/transport/ram -pkg.description: XXX +pkg.name: nimble/transport/uart_ll +pkg.description: HCI H4 transport over UART to external controller pkg.author: "Apache Mynewt " -pkg.homepage: "http://mynewt.apache.org/" -pkg.keywords: - - ble - - bluetooth +pkg.homepage: "https://mynewt.apache.org/" pkg.deps: + - "@apache-mynewt-core/hw/hal" - "@apache-mynewt-core/kernel/os" - nimble + - nimble/transport/common/hci_h4 pkg.apis: - ble_transport - -pkg.init: - ble_hci_ram_init: 'MYNEWT_VAL(BLE_TRANS_RAM_SYSINIT_STAGE)' diff --git a/nimble/transport/uart_ll/src/hci_uart.c b/nimble/transport/uart_ll/src/hci_uart.c new file mode 100644 index 0000000000..692b415c6d --- /dev/null +++ b/nimble/transport/uart_ll/src/hci_uart.c @@ -0,0 +1,245 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include +#include +#include +#include +#include "os/os_mbuf.h" +#include "os/os_mempool.h" +#include "hal/hal_uart.h" +#include "nimble/transport.h" +#include "nimble/transport/hci_h4.h" + +#define TX_Q_SIZE (MYNEWT_VAL(BLE_TRANSPORT_ACL_FROM_HS_COUNT) + 1) + +struct hci_uart_tx { + uint8_t type; + uint8_t sent_type; + uint16_t len; + uint16_t idx; + + struct os_mbuf *om; + uint8_t *buf; + + STAILQ_ENTRY(hci_uart_tx) tx_q_next; +}; + +static STAILQ_HEAD(, hci_uart_tx) tx_q; + +static struct os_mempool pool_tx_q; +static uint8_t pool_tx_q_buf[ OS_MEMPOOL_BYTES(TX_Q_SIZE, + sizeof(struct hci_uart_tx)) ]; + +struct hci_h4_sm hci_uart_h4sm; + +static int +hci_uart_frame_cb(uint8_t pkt_type, void *data) +{ + switch (pkt_type) { + case HCI_H4_EVT: + return ble_transport_to_hs_evt(data); + case HCI_H4_ACL: + return ble_transport_to_hs_acl(data); + default: + assert(0); + break; + } + + return -1; +} + +static int +hci_uart_rx_char(void *arg, uint8_t data) +{ + hci_h4_sm_rx(&hci_uart_h4sm, &data, 1); + + return 0; +} + +static int +hci_uart_tx_char(void *arg) +{ + struct hci_uart_tx *tx; + uint8_t ch; + os_sr_t sr; + + OS_ENTER_CRITICAL(sr); + tx = STAILQ_FIRST(&tx_q); + OS_EXIT_CRITICAL(sr); + if (!tx) { + return -1; + } + + if (!tx->sent_type) { + tx->sent_type = 1; + return tx->type; + } + + switch (tx->type) { + case HCI_H4_CMD: + ch = tx->buf[tx->idx]; + tx->idx++; + if (tx->idx == tx->len) { + ble_transport_free(tx->buf); + OS_ENTER_CRITICAL(sr); + STAILQ_REMOVE_HEAD(&tx_q, tx_q_next); + OS_EXIT_CRITICAL(sr); + os_memblock_put(&pool_tx_q, tx); + } + break; + case HCI_H4_ACL: + os_mbuf_copydata(tx->om, 0, 1, &ch); + os_mbuf_adj(tx->om, 1); + tx->len--; + if (tx->len == 0) { + os_mbuf_free_chain(tx->om); + OS_ENTER_CRITICAL(sr); + STAILQ_REMOVE_HEAD(&tx_q, tx_q_next); + OS_EXIT_CRITICAL(sr); + os_memblock_put(&pool_tx_q, tx); + } + break; + default: + assert(0); + OS_ENTER_CRITICAL(sr); + STAILQ_REMOVE_HEAD(&tx_q, tx_q_next); + OS_EXIT_CRITICAL(sr); + os_memblock_put(&pool_tx_q, tx); + } + + return ch; +} + +static int +hci_uart_configure(void) +{ + enum hal_uart_parity parity; + enum hal_uart_flow_ctl flowctl; + int rc; + + rc = hal_uart_init_cbs(MYNEWT_VAL(BLE_TRANSPORT_UART_LL_PORT), + hci_uart_tx_char, NULL, + hci_uart_rx_char, NULL); + if (rc != 0) { + return -1; + } + + if (MYNEWT_VAL_CHOICE(BLE_TRANSPORT_UART_LL_PARITY, odd)) { + parity = HAL_UART_PARITY_ODD; + } else if (MYNEWT_VAL_CHOICE(BLE_TRANSPORT_UART_LL_PARITY, even)) { + parity = HAL_UART_PARITY_EVEN; + } else { + parity = HAL_UART_PARITY_NONE; + } + + if (MYNEWT_VAL_CHOICE(BLE_TRANSPORT_UART_LL_FLOW_CONTROL, rtscts)) { + flowctl = HAL_UART_FLOW_CTL_RTS_CTS; + } else { + flowctl = HAL_UART_FLOW_CTL_NONE; + } + + rc = hal_uart_config(MYNEWT_VAL(BLE_TRANSPORT_UART_LL_PORT), + MYNEWT_VAL(BLE_TRANSPORT_UART_LL_BAUDRATE), + MYNEWT_VAL(BLE_TRANSPORT_UART_LL_DATA_BITS), + MYNEWT_VAL(BLE_TRANSPORT_UART_LL_STOP_BITS), + parity, flowctl); + if (rc != 0) { + return -1; + } + + return 0; +} + +int +ble_transport_to_ll_cmd_impl(void *buf) +{ + struct hci_uart_tx *txe; + os_sr_t sr; + + txe = os_memblock_get(&pool_tx_q); + if (!txe) { + assert(0); + return -ENOMEM; + } + + txe->type = HCI_H4_CMD; + txe->sent_type = 0; + txe->len = 3 + ((uint8_t *)buf)[2]; + txe->buf = buf; + txe->idx = 0; + txe->om = NULL; + + OS_ENTER_CRITICAL(sr); + STAILQ_INSERT_TAIL(&tx_q, txe, tx_q_next); + OS_EXIT_CRITICAL(sr); + + hal_uart_start_tx(MYNEWT_VAL(BLE_TRANSPORT_UART_LL_PORT)); + + return 0; +} + +int +ble_transport_to_ll_acl_impl(struct os_mbuf *om) +{ + struct hci_uart_tx *txe; + os_sr_t sr; + + txe = os_memblock_get(&pool_tx_q); + if (!txe) { + assert(0); + return -ENOMEM; + } + + txe->type = HCI_H4_ACL; + txe->sent_type = 0; + txe->len = OS_MBUF_PKTLEN(om); + txe->idx = 0; + txe->buf = NULL; + txe->om = om; + + OS_ENTER_CRITICAL(sr); + STAILQ_INSERT_TAIL(&tx_q, txe, tx_q_next); + OS_EXIT_CRITICAL(sr); + + hal_uart_start_tx(MYNEWT_VAL(BLE_TRANSPORT_UART_LL_PORT)); + + return 0; +} + +void +ble_transport_ll_init(void) +{ + int rc; + + SYSINIT_ASSERT_ACTIVE(); + + rc = hci_uart_configure(); + SYSINIT_PANIC_ASSERT(rc == 0); + + rc = os_mempool_init(&pool_tx_q, TX_Q_SIZE, sizeof(struct hci_uart_tx), + pool_tx_q_buf, "hci_uart_tx_q"); + SYSINIT_PANIC_ASSERT(rc == 0); + + hci_h4_sm_init(&hci_uart_h4sm, &hci_h4_allocs_from_ll, hci_uart_frame_cb); + + STAILQ_INIT(&tx_q); +} diff --git a/nimble/transport/uart_ll/syscfg.yml b/nimble/transport/uart_ll/syscfg.yml new file mode 100644 index 0000000000..ccf38b61a5 --- /dev/null +++ b/nimble/transport/uart_ll/syscfg.yml @@ -0,0 +1,39 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +syscfg.defs: + BLE_TRANSPORT_UART_LL_PORT: + description: UART index to use for HCI interface + value: 0 + BLE_TRANSPORT_UART_LL_BAUDRATE: + description: Baudrate on UART + value: 1000000 + BLE_TRANSPORT_UART_LL_DATA_BITS: + description: Number of data bits on UART + value: 8 + BLE_TRANSPORT_UART_LL_STOP_BITS: + description: Number of stop bits on UART + value: 1 + BLE_TRANSPORT_UART_LL_PARITY: + description: Parity on UART + value: none + choices: none,even,odd + BLE_TRANSPORT_UART_LL_FLOW_CONTROL: + description: Flow control on UART + choices: off,rtscts + value: rtscts diff --git a/nimble/transport/usb/pkg.yml b/nimble/transport/usb/pkg.yml index 49317c97d5..199afe6126 100644 --- a/nimble/transport/usb/pkg.yml +++ b/nimble/transport/usb/pkg.yml @@ -31,9 +31,7 @@ pkg.deps: - "@apache-mynewt-core/kernel/os" - "@apache-mynewt-core/util/mem" - nimble + - "@apache-mynewt-core/hw/usb/tinyusb" pkg.apis: - ble_transport - -pkg.init: - ble_hci_usb_init: 'MYNEWT_VAL(BLE_TRANS_USB_SYSINIT_STAGE)' diff --git a/nimble/transport/usb/src/ble_hci_usb.c b/nimble/transport/usb/src/ble_hci_usb.c index 3f87856f11..01c60b88d9 100644 --- a/nimble/transport/usb/src/ble_hci_usb.c +++ b/nimble/transport/usb/src/ble_hci_usb.c @@ -25,78 +25,20 @@ #include "mem/mem.h" #include "nimble/ble.h" -#include "nimble/ble_hci_trans.h" #include "nimble/hci_common.h" +#include "nimble/transport.h" #include -/* - * The MBUF payload size must accommodate the HCI data header size plus the - * maximum ACL data packet length. The ACL block size is the size of the - * mbufs we will allocate. - */ -#define ACL_BLOCK_SIZE OS_ALIGN(MYNEWT_VAL(BLE_ACL_BUF_SIZE) \ - + BLE_MBUF_MEMBLOCK_OVERHEAD \ - + BLE_HCI_DATA_HDR_SZ, OS_ALIGNMENT) - -struct usb_ble_hci_pool_cmd { - uint8_t cmd[BLE_HCI_TRANS_CMD_SZ]; - bool allocated; -}; - -/* (Pseudo)pool for HCI commands */ -static struct usb_ble_hci_pool_cmd usb_ble_hci_pool_cmd; - -static ble_hci_trans_rx_cmd_fn *ble_hci_usb_rx_cmd_ll_cb; -static void *ble_hci_usb_rx_cmd_ll_arg; - -static ble_hci_trans_rx_acl_fn *ble_hci_usb_rx_acl_ll_cb; -static void *ble_hci_usb_rx_acl_ll_arg; - -static struct os_mempool ble_hci_usb_evt_hi_pool; -static os_membuf_t ble_hci_usb_evt_hi_buf[ - OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_HCI_EVT_HI_BUF_COUNT), - MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE)) -]; - -static struct os_mempool ble_hci_usb_evt_lo_pool; -static os_membuf_t ble_hci_usb_evt_lo_buf[ - OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_HCI_EVT_LO_BUF_COUNT), - MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE)) -]; - -static uint8_t ble_hci_pool_acl_mempool_buf[ - OS_MEMPOOL_BYTES(MYNEWT_VAL(BLE_ACL_BUF_COUNT), - ACL_BLOCK_SIZE)]; -static struct os_mempool ble_hci_pool_acl_mempool; -static struct os_mbuf_pool ble_hci_pool_acl_mbuf_pool; - static struct os_mbuf *incoming_acl_data; -static struct os_mbuf * -ble_hci_trans_acl_buf_alloc(void) -{ - struct os_mbuf *m; - - m = os_mbuf_get_pkthdr(&ble_hci_pool_acl_mbuf_pool, - sizeof(struct ble_mbuf_hdr)); - return m; -} +#define TX_Q_SIZE (MYNEWT_VAL(BLE_TRANSPORT_ACL_FROM_LL_COUNT) + \ + MYNEWT_VAL(BLE_TRANSPORT_EVT_COUNT) + \ + MYNEWT_VAL(BLE_TRANSPORT_EVT_DISCARDABLE_COUNT)) -void -ble_hci_trans_cfg_ll(ble_hci_trans_rx_cmd_fn *cmd_cb, - void *cmd_arg, - ble_hci_trans_rx_acl_fn *acl_cb, - void *acl_arg) -{ - ble_hci_usb_rx_cmd_ll_cb = cmd_cb; - ble_hci_usb_rx_cmd_ll_arg = cmd_arg; - ble_hci_usb_rx_acl_ll_cb = acl_cb; - ble_hci_usb_rx_acl_ll_arg = acl_arg; -} #define BLE_HCI_USB_EVT_COUNT \ - (MYNEWT_VAL(BLE_HCI_EVT_HI_BUF_COUNT) + MYNEWT_VAL(BLE_HCI_EVT_LO_BUF_COUNT)) + (MYNEWT_VAL(BLE_TRANSPORT_EVT_COUNT)) /** * A packet to be sent over the USB. This can be a command, an event, or ACL @@ -107,11 +49,9 @@ struct ble_hci_pkt { void *data; }; -static struct os_mempool ble_hci_pkt_pool; -static os_membuf_t ble_hci_pkt_buf[ - OS_MEMPOOL_SIZE(BLE_HCI_USB_EVT_COUNT + 1 + - MYNEWT_VAL(BLE_HCI_ACL_OUT_COUNT), - sizeof(struct ble_hci_pkt))]; +static struct os_mempool pool_tx_q; +static os_membuf_t pool_tx_q_buf[ OS_MEMPOOL_SIZE(TX_Q_SIZE, + sizeof(struct ble_hci_pkt)) ]; struct tx_queue { STAILQ_HEAD(, ble_hci_pkt) queue; @@ -151,7 +91,7 @@ tud_bt_acl_data_sent_cb(uint16_t sent_bytes) STAILQ_REMOVE_HEAD(&ble_hci_tx_acl_queue.queue, next); next_acl = STAILQ_FIRST(&ble_hci_tx_acl_queue.queue); OS_EXIT_CRITICAL(sr); - os_memblock_put(&ble_hci_pkt_pool, curr_acl); + os_memblock_put(&pool_tx_q, curr_acl); if (next_acl != NULL) { om = next_acl->data; } @@ -178,13 +118,13 @@ tud_bt_event_sent_cb(uint16_t sent_bytes) assert(hci_ev != NULL && hci_ev[1] + sizeof(struct ble_hci_ev) == sent_bytes); - ble_hci_trans_buf_free(hci_ev); + ble_transport_free(hci_ev); OS_ENTER_CRITICAL(sr); STAILQ_REMOVE_HEAD(&ble_hci_tx_evt_queue.queue, next); next_evt = STAILQ_FIRST(&ble_hci_tx_evt_queue.queue); OS_EXIT_CRITICAL(sr); - os_memblock_put(&ble_hci_pkt_pool, curr_evt); + os_memblock_put(&pool_tx_q, curr_evt); if (next_evt != NULL) { hci_ev = next_evt->data; @@ -201,10 +141,11 @@ tud_bt_acl_data_received_cb(void *acl_data, uint16_t data_len) int rc; if (om == NULL) { - om = ble_hci_trans_acl_buf_alloc(); + om = ble_transport_alloc_acl_from_hs(); assert(om != NULL); } - assert(om->om_len + data_len <= MYNEWT_VAL(BLE_ACL_BUF_SIZE) + BLE_HCI_DATA_HDR_SZ); + assert(om->om_len + data_len <= MYNEWT_VAL(BLE_TRANSPORT_ACL_SIZE) + + BLE_HCI_DATA_HDR_SZ); os_mbuf_append(om, acl_data, data_len); incoming_acl_data = om; @@ -213,7 +154,7 @@ tud_bt_acl_data_received_cb(void *acl_data, uint16_t data_len) len = data[2] + (data[3] << 8) + BLE_HCI_DATA_HDR_SZ; if (incoming_acl_data->om_len >= len) { incoming_acl_data = NULL; - rc = ble_hci_usb_rx_acl_ll_cb(om, ble_hci_usb_rx_acl_ll_arg); + rc = ble_transport_to_ll_acl(om); (void)rc; } } @@ -225,17 +166,14 @@ tud_bt_hci_cmd_cb(void *hci_cmd, size_t cmd_len) uint8_t *buf; int rc = -1; - assert(ble_hci_usb_rx_cmd_ll_cb); - if (ble_hci_usb_rx_cmd_ll_cb) { - buf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_CMD); - assert(buf != NULL); - memcpy(buf, hci_cmd, min(cmd_len, BLE_HCI_TRANS_CMD_SZ)); + buf = ble_transport_alloc_cmd(); + assert(buf != NULL); + memcpy(buf, hci_cmd, min(cmd_len, 258)); - rc = ble_hci_usb_rx_cmd_ll_cb(buf, ble_hci_usb_rx_cmd_ll_arg); - } + rc = ble_transport_to_ll_cmd(buf); if (rc != 0) { - ble_hci_trans_buf_free(buf); + ble_transport_free(buf); } } @@ -252,7 +190,7 @@ ble_hci_trans_ll_tx(struct tx_queue *queue, struct os_mbuf *om) return 0; } - pkt = os_memblock_get(&ble_hci_pkt_pool); + pkt = os_memblock_get(&pool_tx_q); if (pkt == NULL) { os_mbuf_free_chain(om); return BLE_ERR_MEM_CAPACITY; @@ -270,24 +208,24 @@ ble_hci_trans_ll_tx(struct tx_queue *queue, struct os_mbuf *om) return 0; } -int -ble_hci_trans_ll_acl_tx(struct os_mbuf *om) -{ - return ble_hci_trans_ll_tx(&ble_hci_tx_acl_queue, om); -} - -int -ble_hci_trans_ll_evt_tx(uint8_t *hci_ev) +static int +ble_hci_trans_ll_evt_tx(void *buf) { struct ble_hci_pkt *pkt; + uint8_t *hci_ev = buf; os_sr_t sr; bool first; assert(hci_ev != NULL); - pkt = os_memblock_get(&ble_hci_pkt_pool); + if (!tud_ready()) { + ble_transport_free(hci_ev); + return 0; + } + + pkt = os_memblock_get(&pool_tx_q); if (pkt == NULL) { - ble_hci_trans_buf_free(hci_ev); + ble_transport_free(hci_ev); return BLE_ERR_MEM_CAPACITY; } @@ -303,108 +241,27 @@ ble_hci_trans_ll_evt_tx(uint8_t *hci_ev) return 0; } -uint8_t * -ble_hci_trans_buf_alloc(int type) -{ - uint8_t *buf; - - switch (type) { - case BLE_HCI_TRANS_BUF_CMD: - assert(!usb_ble_hci_pool_cmd.allocated); - usb_ble_hci_pool_cmd.allocated = 1; - buf = usb_ble_hci_pool_cmd.cmd; - break; - - case BLE_HCI_TRANS_BUF_EVT_HI: - buf = os_memblock_get(&ble_hci_usb_evt_hi_pool); - if (buf == NULL) { - /* If no high-priority event buffers remain, try to grab a - * low-priority one. - */ - buf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_LO); - } - break; - - case BLE_HCI_TRANS_BUF_EVT_LO: - buf = os_memblock_get(&ble_hci_usb_evt_lo_pool); - break; - - default: - assert(0); - buf = NULL; - } - - return buf; -} - -void -ble_hci_trans_buf_free(uint8_t *buf) +int +ble_transport_to_hs_acl_impl(struct os_mbuf *om) { - int rc; - - /* XXX: this may look a bit odd, but the controller uses the command - * buffer to send back the command complete/status as an immediate - * response to the command. This was done to insure that the controller - * could always send back one of these events when a command was received. - * Thus, we check to see which pool the buffer came from so we can free - * it to the appropriate pool - */ - if (os_memblock_from(&ble_hci_usb_evt_hi_pool, buf)) { - rc = os_memblock_put(&ble_hci_usb_evt_hi_pool, buf); - assert(rc == 0); - } else if (os_memblock_from(&ble_hci_usb_evt_lo_pool, buf)) { - rc = os_memblock_put(&ble_hci_usb_evt_lo_pool, buf); - assert(rc == 0); - } else { - assert(usb_ble_hci_pool_cmd.allocated); - usb_ble_hci_pool_cmd.allocated = 0; - } - (void)rc; + return ble_hci_trans_ll_tx(&ble_hci_tx_acl_queue, om); } int -ble_hci_trans_reset(void) +ble_transport_to_hs_evt_impl(void *buf) { - return 0; + return ble_hci_trans_ll_evt_tx(buf); } void -ble_hci_usb_init(void) +ble_transport_hs_init(void) { int rc; /* Ensure this function only gets called by sysinit. */ SYSINIT_ASSERT_ACTIVE(); - rc = mem_init_mbuf_pool(ble_hci_pool_acl_mempool_buf, &ble_hci_pool_acl_mempool, &ble_hci_pool_acl_mbuf_pool, - MYNEWT_VAL(BLE_ACL_BUF_COUNT), ACL_BLOCK_SIZE, "ble_hci_acl"); - SYSINIT_PANIC_ASSERT(rc == 0); - - rc = os_mempool_init(&ble_hci_usb_evt_hi_pool, - MYNEWT_VAL(BLE_HCI_EVT_HI_BUF_COUNT), - MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE), - ble_hci_usb_evt_hi_buf, - "ble_hci_usb_evt_hi_pool"); - SYSINIT_PANIC_ASSERT(rc == 0); - - rc = os_mempool_init(&ble_hci_usb_evt_lo_pool, - MYNEWT_VAL(BLE_HCI_EVT_LO_BUF_COUNT), - MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE), - ble_hci_usb_evt_lo_buf, - "ble_hci_usb_evt_lo_pool"); - SYSINIT_PANIC_ASSERT(rc == 0); - - /* - * Create memory pool of packet list nodes. NOTE: the number of these - * buffers should be, at least, the total number of event buffers (hi - * and lo), the number of command buffers (currently 1) and the total - * number of buffers that the controller could possibly hand to the host. - */ - rc = os_mempool_init(&ble_hci_pkt_pool, - BLE_HCI_USB_EVT_COUNT + 1 + - MYNEWT_VAL(BLE_HCI_ACL_OUT_COUNT), - sizeof (struct ble_hci_pkt), - ble_hci_pkt_buf, - "ble_hci_usb_pkt_pool"); + rc = os_mempool_init(&pool_tx_q, TX_Q_SIZE, sizeof(struct ble_hci_pkt), + pool_tx_q_buf, "ble_hci_usb_tx_q"); SYSINIT_PANIC_ASSERT(rc == 0); } diff --git a/nimble/transport/usb/syscfg.yml b/nimble/transport/usb/syscfg.yml index ebc261a23d..614f6437f6 100644 --- a/nimble/transport/usb/syscfg.yml +++ b/nimble/transport/usb/syscfg.yml @@ -17,41 +17,6 @@ # syscfg.defs: - BLE_HCI_EVT_BUF_SIZE: - description: 'The size of the allocated event buffers' - value: 70 - BLE_HCI_EVT_HI_BUF_COUNT: - description: 'The number of high priority event buffers' - value: 8 - BLE_HCI_EVT_LO_BUF_COUNT: - description: 'The number of low priority event buffers' - value: 8 - BLE_ACL_BUF_COUNT: - description: 'The number of ACL data buffers' - value: 12 - BLE_ACL_BUF_SIZE: - description: > - This is the maximum size of the data portion of HCI ACL data - packets. It does not include the HCI data header (of 4 bytes). - value: 255 - BLE_HCI_ACL_OUT_COUNT: - description: > - This count is used in creating a pool of elements used by the - code to enqueue various elements. In the case of the controller - only HCI, this number should be equal to the number of mbufs in - the msys pool. For host only, it is really dependent on the - number of ACL buffers that the controller tells the host it - has. - value: 12 - - BLE_TRANS_USB_SYSINIT_STAGE: - description: > - Sysinit stage for the USB BLE transport. - value: 500 - -syscfg.vals.BLE_EXT_ADV: - BLE_HCI_EVT_BUF_SIZE: 257 - -syscfg.restrictions: - - '!BLE_HOST' +syscfg.vals: + USBD_BTH: 1 diff --git a/porting/examples/dummy/Makefile b/porting/examples/dummy/Makefile index 861934f7f0..6e2f061d27 100644 --- a/porting/examples/dummy/Makefile +++ b/porting/examples/dummy/Makefile @@ -46,6 +46,7 @@ include $(NIMBLE_ROOT)/porting/nimble/Makefile.defs SRC = \ $(wildcard $(NIMBLE_ROOT)/porting/npl/dummy/src/*.c) \ $(NIMBLE_SRC) \ + $(wildcard $(NIMBLE_ROOT)/nimble/transport/socket/src/*.c) \ $(TINYCRYPT_SRC) \ main.c \ @@ -53,6 +54,7 @@ SRC = \ INC = \ $(NIMBLE_ROOT)/porting/npl/dummy/include \ $(NIMBLE_INCLUDE) \ + $(NIMBLE_ROOT)/nimble/transport/socket/include \ $(TINYCRYPT_INCLUDE) \ $(INCLUDE) \ @@ -60,6 +62,7 @@ OBJ := $(SRC:.c=.o) TINYCRYPT_OBJ := $(TINYCRYPT_SRC:.c=.o) CFLAGS := $(NIMBLE_CFLAGS) +LDFLAGS := $(NIMBLE_LDFLAGS) .PHONY: all clean .DEFAULT: all @@ -76,4 +79,4 @@ $(TINYCRYPT_OBJ): CFLAGS+=$(TINYCRYPT_CFLAGS) $(CC) -c $(addprefix -I, $(INC)) $(CFLAGS) -o $@ $< dummy: $(OBJ) $(TINYCRYPT_OBJ) - $(CC) -o $@ $^ + $(CC) -o $@ $^ $(LDFLAGS) diff --git a/porting/examples/linux/Makefile b/porting/examples/linux/Makefile index 11f4ebc308..c3eee16cb5 100644 --- a/porting/examples/linux/Makefile +++ b/porting/examples/linux/Makefile @@ -81,7 +81,7 @@ CFLAGS = \ -D_GNU_SOURCE \ $(NULL) -LIBS := -lrt -lpthread -lstdc++ +LIBS := $(NIMBLE_LDFLAGS) -lrt -lpthread -lstdc++ .PHONY: all clean .DEFAULT: all diff --git a/porting/examples/linux/README.md b/porting/examples/linux/README.md index bbf68bb5e3..c7e256557a 100644 --- a/porting/examples/linux/README.md +++ b/porting/examples/linux/README.md @@ -23,7 +23,7 @@ ## Overview -See (https://mynewt.apache.org/network/ble/ble_intro/). +See https://mynewt.apache.org/latest/network ## Building @@ -59,7 +59,7 @@ in sysconfig.h to use hci0. ```no-highlight cd porting/examples/linux - sudo ./_build/nimble_linux.out + sudo ./nimble-linux ``` 3. Build and run the unit tests @@ -68,6 +68,6 @@ The Operating System Abstraction Layer (OSAL) used to port Nimble to Linux has a suite of unit tests. ```no-highlight - cd tests/unit/porting/npl + cd porting/npl/linux/test make test ``` diff --git a/porting/examples/linux/ble.c b/porting/examples/linux/ble.c index ea6655f21f..f196f514ab 100644 --- a/porting/examples/linux/ble.c +++ b/porting/examples/linux/ble.c @@ -52,7 +52,7 @@ update_ad(void) uint8_t ad_flags = BLE_HS_ADV_F_DISC_GEN | BLE_HS_ADV_F_BREDR_UNSUP; put_ad(BLE_HS_ADV_TYPE_FLAGS, 1, &ad_flags, ad, &ad_len); - put_ad(BLE_HS_ADV_TYPE_COMP_NAME, sizeof(gap_name), gap_name, ad, &ad_len); + put_ad(BLE_HS_ADV_TYPE_COMP_NAME, strlen(gap_name), gap_name, ad, &ad_len); ble_gap_adv_set_data(ad, ad_len); } diff --git a/porting/examples/linux/include/logcfg/logcfg.h b/porting/examples/linux/include/logcfg/logcfg.h deleted file mode 100644 index 837cdeac1f..0000000000 --- a/porting/examples/linux/include/logcfg/logcfg.h +++ /dev/null @@ -1,32 +0,0 @@ -/** - * This file was generated by Apache newt version: 1.9.0-dev - */ - -#ifndef H_MYNEWT_LOGCFG_ -#define H_MYNEWT_LOGCFG_ - -#include "modlog/modlog.h" -#include "log_common/log_common.h" - -#define BLE_HS_LOG_DEBUG(...) IGNORE(__VA_ARGS__) -#define BLE_HS_LOG_INFO(...) MODLOG_INFO(4, __VA_ARGS__) -#define BLE_HS_LOG_WARN(...) MODLOG_WARN(4, __VA_ARGS__) -#define BLE_HS_LOG_ERROR(...) MODLOG_ERROR(4, __VA_ARGS__) -#define BLE_HS_LOG_CRITICAL(...) MODLOG_CRITICAL(4, __VA_ARGS__) -#define BLE_HS_LOG_DISABLED(...) MODLOG_DISABLED(4, __VA_ARGS__) - -#define DFLT_LOG_DEBUG(...) IGNORE(__VA_ARGS__) -#define DFLT_LOG_INFO(...) MODLOG_INFO(0, __VA_ARGS__) -#define DFLT_LOG_WARN(...) MODLOG_WARN(0, __VA_ARGS__) -#define DFLT_LOG_ERROR(...) MODLOG_ERROR(0, __VA_ARGS__) -#define DFLT_LOG_CRITICAL(...) MODLOG_CRITICAL(0, __VA_ARGS__) -#define DFLT_LOG_DISABLED(...) MODLOG_DISABLED(0, __VA_ARGS__) - -#define MFG_LOG_DEBUG(...) IGNORE(__VA_ARGS__) -#define MFG_LOG_INFO(...) IGNORE(__VA_ARGS__) -#define MFG_LOG_WARN(...) IGNORE(__VA_ARGS__) -#define MFG_LOG_ERROR(...) IGNORE(__VA_ARGS__) -#define MFG_LOG_CRITICAL(...) IGNORE(__VA_ARGS__) -#define MFG_LOG_DISABLED(...) MODLOG_DISABLED(128, __VA_ARGS__) - -#endif diff --git a/porting/examples/linux/include/syscfg/syscfg.h b/porting/examples/linux/include/syscfg/syscfg.h index 8363336eed..25dcac4786 100644 --- a/porting/examples/linux/include/syscfg/syscfg.h +++ b/porting/examples/linux/include/syscfg/syscfg.h @@ -1,38 +1,52 @@ -/** - * This file was generated by Apache newt version: 1.9.0-dev +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. */ #ifndef H_MYNEWT_SYSCFG_ #define H_MYNEWT_SYSCFG_ -/** - * This macro exists to ensure code includes this header when needed. If code - * checks the existence of a setting directly via ifdef without including this - * header, the setting macro will silently evaluate to 0. In contrast, an - * attempt to use these macros without including this header will result in a - * compiler error. - */ #define MYNEWT_VAL(_name) MYNEWT_VAL_ ## _name #define MYNEWT_VAL_CHOICE(_name, _val) MYNEWT_VAL_ ## _name ## __ ## _val -/*** @apache-mynewt-core/crypto/tinycrypt */ #ifndef MYNEWT_VAL_TINYCRYPT_SYSINIT_STAGE #define MYNEWT_VAL_TINYCRYPT_SYSINIT_STAGE (200) #endif #ifndef MYNEWT_VAL_TINYCRYPT_UECC_RNG_TRNG_DEV_NAME -#define MYNEWT_VAL_TINYCRYPT_UECC_RNG_TRNG_DEV_NAME ("trng") +#define MYNEWT_VAL_TINYCRYPT_UECC_RNG_TRNG_DEV_NAME "trng" #endif #ifndef MYNEWT_VAL_TINYCRYPT_UECC_RNG_USE_TRNG #define MYNEWT_VAL_TINYCRYPT_UECC_RNG_USE_TRNG (0) #endif -/*** @apache-mynewt-core/hw/hal */ +#ifndef MYNEWT_VAL_BSP_SIMULATED +#define MYNEWT_VAL_BSP_SIMULATED (1) +#endif + #ifndef MYNEWT_VAL_HAL_ENABLE_SOFTWARE_BREAKPOINTS #define MYNEWT_VAL_HAL_ENABLE_SOFTWARE_BREAKPOINTS (1) #endif +#ifndef MYNEWT_VAL_HAL_FLASH_MAX_DEVICE_COUNT +#define MYNEWT_VAL_HAL_FLASH_MAX_DEVICE_COUNT (0) +#endif + #ifndef MYNEWT_VAL_HAL_FLASH_VERIFY_BUF_SZ #define MYNEWT_VAL_HAL_FLASH_VERIFY_BUF_SZ (16) #endif @@ -45,11 +59,46 @@ #define MYNEWT_VAL_HAL_FLASH_VERIFY_WRITES (0) #endif +#ifndef MYNEWT_VAL_HAL_SBRK +#define MYNEWT_VAL_HAL_SBRK (1) +#endif + #ifndef MYNEWT_VAL_HAL_SYSTEM_RESET_CB #define MYNEWT_VAL_HAL_SYSTEM_RESET_CB (0) #endif -/*** @apache-mynewt-core/kernel/os */ +#ifndef MYNEWT_VAL_I2C_0 +#define MYNEWT_VAL_I2C_0 (0) +#endif + +#ifndef MYNEWT_VAL_MCU_FLASH_MIN_WRITE_SIZE +#define MYNEWT_VAL_MCU_FLASH_MIN_WRITE_SIZE (1) +#endif + +#ifndef MYNEWT_VAL_MCU_FLASH_STYLE_NORDIC +#define MYNEWT_VAL_MCU_FLASH_STYLE_NORDIC (0) +#endif + +#ifndef MYNEWT_VAL_MCU_FLASH_STYLE_ST +#define MYNEWT_VAL_MCU_FLASH_STYLE_ST (1) +#endif + +#ifndef MYNEWT_VAL_MCU_NATIVE +#define MYNEWT_VAL_MCU_NATIVE (1) +#endif + +#ifndef MYNEWT_VAL_MCU_NATIVE_USE_SIGNALS +#define MYNEWT_VAL_MCU_NATIVE_USE_SIGNALS (1) +#endif + +#ifndef MYNEWT_VAL_MCU_TIMER_POLLER_PRIO +#define MYNEWT_VAL_MCU_TIMER_POLLER_PRIO (0) +#endif + +#ifndef MYNEWT_VAL_MCU_UART_POLLER_PRIO +#define MYNEWT_VAL_MCU_UART_POLLER_PRIO (1) +#endif + #ifndef MYNEWT_VAL_FLOAT_USER #define MYNEWT_VAL_FLOAT_USER (0) #endif @@ -94,6 +143,10 @@ #define MYNEWT_VAL_OS_COREDUMP (0) #endif +#ifndef MYNEWT_VAL_OS_COREDUMP_CB +#define MYNEWT_VAL_OS_COREDUMP_CB (0) +#endif + #ifndef MYNEWT_VAL_OS_CPUTIME_FREQ #define MYNEWT_VAL_OS_CPUTIME_FREQ (1000000) #endif @@ -103,7 +156,7 @@ #endif #ifndef MYNEWT_VAL_OS_CRASH_FILE_LINE -#define MYNEWT_VAL_OS_CRASH_FILE_LINE (0) +#define MYNEWT_VAL_OS_CRASH_FILE_LINE (1) #endif #ifndef MYNEWT_VAL_OS_CRASH_LOG @@ -130,6 +183,10 @@ #define MYNEWT_VAL_OS_DEBUG_MODE (0) #endif +#ifndef MYNEWT_VAL_OS_DEFAULT_IRQ_CB +#define MYNEWT_VAL_OS_DEFAULT_IRQ_CB (0) +#endif + #ifndef MYNEWT_VAL_OS_EVENTQ_DEBUG #define MYNEWT_VAL_OS_EVENTQ_DEBUG (0) #endif @@ -143,7 +200,7 @@ #endif #ifndef MYNEWT_VAL_OS_IDLE_TICKLESS_MS_MIN -#define MYNEWT_VAL_OS_IDLE_TICKLESS_MS_MIN (100) +#define MYNEWT_VAL_OS_IDLE_TICKLESS_MS_MIN (1) #endif #ifndef MYNEWT_VAL_OS_MAIN_STACK_SIZE @@ -210,6 +267,10 @@ #define MYNEWT_VAL_OS_TASK_RUN_TIME_CPUTIME (0) #endif +#ifndef MYNEWT_VAL_OS_TICKS_PER_SEC +#define MYNEWT_VAL_OS_TICKS_PER_SEC (100) +#endif + #ifndef MYNEWT_VAL_OS_TIME_DEBUG #define MYNEWT_VAL_OS_TIME_DEBUG (0) #endif @@ -226,29 +287,56 @@ #define MYNEWT_VAL_WATCHDOG_INTERVAL (30000) #endif -/*** @apache-mynewt-core/sys/console/stub */ +#ifndef MYNEWT_VAL_NATIVE_SOCKETS_MAX +#define MYNEWT_VAL_NATIVE_SOCKETS_MAX (8) +#endif + +#ifndef MYNEWT_VAL_NATIVE_SOCKETS_MAX_UDP +#define MYNEWT_VAL_NATIVE_SOCKETS_MAX_UDP (2048) +#endif + +#ifndef MYNEWT_VAL_NATIVE_SOCKETS_POLL_INTERVAL_MS +#define MYNEWT_VAL_NATIVE_SOCKETS_POLL_INTERVAL_MS (200) +#endif + +#undef MYNEWT_VAL_NATIVE_SOCKETS_POLL_ITVL + +#ifndef MYNEWT_VAL_NATIVE_SOCKETS_PRIO +#define MYNEWT_VAL_NATIVE_SOCKETS_PRIO (2) +#endif + +#ifndef MYNEWT_VAL_NATIVE_SOCKETS_STACK_SZ +#define MYNEWT_VAL_NATIVE_SOCKETS_STACK_SZ (4096) +#endif + +#ifndef MYNEWT_VAL_NATIVE_SOCKETS_SYSINIT_STAGE +#define MYNEWT_VAL_NATIVE_SOCKETS_SYSINIT_STAGE (200) +#endif + #ifndef MYNEWT_VAL_CONSOLE_UART_BAUD #define MYNEWT_VAL_CONSOLE_UART_BAUD (115200) #endif #ifndef MYNEWT_VAL_CONSOLE_UART_DEV -#define MYNEWT_VAL_CONSOLE_UART_DEV ("uart0") +#define MYNEWT_VAL_CONSOLE_UART_DEV "uart0" #endif #ifndef MYNEWT_VAL_CONSOLE_UART_FLOW_CONTROL #define MYNEWT_VAL_CONSOLE_UART_FLOW_CONTROL (UART_FLOW_CTL_NONE) #endif -/*** @apache-mynewt-core/sys/flash_map */ #ifndef MYNEWT_VAL_FLASH_MAP_MAX_AREAS #define MYNEWT_VAL_FLASH_MAP_MAX_AREAS (10) #endif +#ifndef MYNEWT_VAL_FLASH_MAP_SUPPORT_MFG +#define MYNEWT_VAL_FLASH_MAP_SUPPORT_MFG (0) +#endif + #ifndef MYNEWT_VAL_FLASH_MAP_SYSINIT_STAGE -#define MYNEWT_VAL_FLASH_MAP_SYSINIT_STAGE (2) +#define MYNEWT_VAL_FLASH_MAP_SYSINIT_STAGE (9) #endif -/*** @apache-mynewt-core/sys/log/common */ #ifndef MYNEWT_VAL_DFLT_LOG_LVL #define MYNEWT_VAL_DFLT_LOG_LVL (1) #endif @@ -261,7 +349,6 @@ #define MYNEWT_VAL_LOG_GLOBAL_IDX (1) #endif -/*** @apache-mynewt-core/sys/log/modlog */ #ifndef MYNEWT_VAL_MODLOG_CONSOLE_DFLT #define MYNEWT_VAL_MODLOG_CONSOLE_DFLT (1) #endif @@ -282,7 +369,6 @@ #define MYNEWT_VAL_MODLOG_SYSINIT_STAGE (100) #endif -/*** @apache-mynewt-core/sys/log/stub */ #ifndef MYNEWT_VAL_LOG_CONSOLE #define MYNEWT_VAL_LOG_CONSOLE (1) #endif @@ -295,34 +381,14 @@ #define MYNEWT_VAL_LOG_FCB_SLOT1 (0) #endif -/* Overridden by @apache-mynewt-nimble/porting/targets/linux (defined by @apache-mynewt-core/sys/log/stub) */ #ifndef MYNEWT_VAL_LOG_LEVEL #define MYNEWT_VAL_LOG_LEVEL (0) #endif -/*** @apache-mynewt-core/sys/mfg */ -#ifndef MYNEWT_VAL_MFG_LOG_LVL -#define MYNEWT_VAL_MFG_LOG_LVL (15) -#endif - -#ifndef MYNEWT_VAL_MFG_LOG_MODULE -#define MYNEWT_VAL_MFG_LOG_MODULE (128) -#endif - -#ifndef MYNEWT_VAL_MFG_MAX_MMRS -#define MYNEWT_VAL_MFG_MAX_MMRS (2) -#endif - -#ifndef MYNEWT_VAL_MFG_SYSINIT_STAGE -#define MYNEWT_VAL_MFG_SYSINIT_STAGE (100) -#endif - -/*** @apache-mynewt-core/sys/sys */ #ifndef MYNEWT_VAL_DEBUG_PANIC_ENABLED #define MYNEWT_VAL_DEBUG_PANIC_ENABLED (1) #endif -/*** @apache-mynewt-core/sys/sysdown */ #ifndef MYNEWT_VAL_SYSDOWN_CONSTRAIN_DOWN #define MYNEWT_VAL_SYSDOWN_CONSTRAIN_DOWN (1) #endif @@ -339,25 +405,30 @@ #define MYNEWT_VAL_SYSDOWN_TIMEOUT_MS (10000) #endif -/*** @apache-mynewt-core/sys/sysinit */ #ifndef MYNEWT_VAL_SYSINIT_CONSTRAIN_INIT #define MYNEWT_VAL_SYSINIT_CONSTRAIN_INIT (1) #endif #ifndef MYNEWT_VAL_SYSINIT_PANIC_FILE_LINE -#define MYNEWT_VAL_SYSINIT_PANIC_FILE_LINE (0) +#define MYNEWT_VAL_SYSINIT_PANIC_FILE_LINE (1) #endif #ifndef MYNEWT_VAL_SYSINIT_PANIC_MESSAGE -#define MYNEWT_VAL_SYSINIT_PANIC_MESSAGE (0) +#define MYNEWT_VAL_SYSINIT_PANIC_MESSAGE (1) #endif -/*** @apache-mynewt-core/util/rwlock */ #ifndef MYNEWT_VAL_RWLOCK_DEBUG #define MYNEWT_VAL_RWLOCK_DEBUG (0) #endif -/*** @apache-mynewt-nimble/nimble */ +#ifndef MYNEWT_VAL_BLE_CHANNEL_SOUNDING +#define MYNEWT_VAL_BLE_CHANNEL_SOUNDING (0) +#endif + +#ifndef MYNEWT_VAL_BLE_CONN_SUBRATING +#define MYNEWT_VAL_BLE_CONN_SUBRATING (0) +#endif + #ifndef MYNEWT_VAL_BLE_EXT_ADV #define MYNEWT_VAL_BLE_EXT_ADV (0) #endif @@ -366,10 +437,26 @@ #define MYNEWT_VAL_BLE_EXT_ADV_MAX_SIZE (31) #endif +#ifndef MYNEWT_VAL_BLE_HCI_VS +#define MYNEWT_VAL_BLE_HCI_VS (0) +#endif + +#ifndef MYNEWT_VAL_BLE_HCI_VS_OCF_OFFSET +#define MYNEWT_VAL_BLE_HCI_VS_OCF_OFFSET (0) +#endif + #ifndef MYNEWT_VAL_BLE_ISO #define MYNEWT_VAL_BLE_ISO (0) #endif +#ifndef MYNEWT_VAL_BLE_ISO_BROADCAST_SINK +#define MYNEWT_VAL_BLE_ISO_BROADCAST_SINK (0) +#endif + +#ifndef MYNEWT_VAL_BLE_ISO_BROADCAST_SOURCE +#define MYNEWT_VAL_BLE_ISO_BROADCAST_SOURCE (0) +#endif + #ifndef MYNEWT_VAL_BLE_ISO_TEST #define MYNEWT_VAL_BLE_ISO_TEST (0) #endif @@ -390,10 +477,26 @@ #define MYNEWT_VAL_BLE_PERIODIC_ADV (0) #endif +#ifndef MYNEWT_VAL_BLE_PERIODIC_ADV_SYNC_BIGINFO_REPORTS +#define MYNEWT_VAL_BLE_PERIODIC_ADV_SYNC_BIGINFO_REPORTS (0) +#endif + #ifndef MYNEWT_VAL_BLE_PERIODIC_ADV_SYNC_TRANSFER #define MYNEWT_VAL_BLE_PERIODIC_ADV_SYNC_TRANSFER (0) #endif +#ifndef MYNEWT_VAL_BLE_PHY_2M +#define MYNEWT_VAL_BLE_PHY_2M (0) +#endif + +#ifndef MYNEWT_VAL_BLE_PHY_CODED +#define MYNEWT_VAL_BLE_PHY_CODED (0) +#endif + +#ifndef MYNEWT_VAL_BLE_POWER_CONTROL +#define MYNEWT_VAL_BLE_POWER_CONTROL (0) +#endif + #ifndef MYNEWT_VAL_BLE_ROLE_BROADCASTER #define MYNEWT_VAL_BLE_ROLE_BROADCASTER (1) #endif @@ -418,7 +521,6 @@ #define MYNEWT_VAL_BLE_WHITELIST (1) #endif -/*** @apache-mynewt-nimble/nimble/host */ #ifndef MYNEWT_VAL_BLE_ATT_PREFERRED_MTU #define MYNEWT_VAL_BLE_ATT_PREFERRED_MTU (256) #endif @@ -443,6 +545,10 @@ #define MYNEWT_VAL_BLE_ATT_SVR_NOTIFY (1) #endif +#ifndef MYNEWT_VAL_BLE_ATT_SVR_NOTIFY_MULTI +#define MYNEWT_VAL_BLE_ATT_SVR_NOTIFY_MULTI (MYNEWT_VAL_BLE_ATT_SVR_NOTIFY && (MYNEWT_VAL_BLE_VERSION >= 52)) +#endif + #ifndef MYNEWT_VAL_BLE_ATT_SVR_QUEUED_WRITE #define MYNEWT_VAL_BLE_ATT_SVR_QUEUED_WRITE (1) #endif @@ -483,6 +589,26 @@ #define MYNEWT_VAL_BLE_ATT_SVR_WRITE_NO_RSP (1) #endif +#ifndef MYNEWT_VAL_BLE_AUDIO +#define MYNEWT_VAL_BLE_AUDIO (0) +#endif + +#ifndef MYNEWT_VAL_BLE_EATT_CHAN_NUM +#define MYNEWT_VAL_BLE_EATT_CHAN_NUM (0) +#endif + +#ifndef MYNEWT_VAL_BLE_EATT_LOG_LVL +#define MYNEWT_VAL_BLE_EATT_LOG_LVL (1) +#endif + +#ifndef MYNEWT_VAL_BLE_EATT_LOG_MOD +#define MYNEWT_VAL_BLE_EATT_LOG_MOD (27) +#endif + +#ifndef MYNEWT_VAL_BLE_EATT_MTU +#define MYNEWT_VAL_BLE_EATT_MTU (128) +#endif + #ifndef MYNEWT_VAL_BLE_GAP_MAX_PENDING_CONN_PARAM_UPDATE #define MYNEWT_VAL_BLE_GAP_MAX_PENDING_CONN_PARAM_UPDATE (1) #endif @@ -523,6 +649,10 @@ #define MYNEWT_VAL_BLE_GATT_NOTIFY (1) #endif +#ifndef MYNEWT_VAL_BLE_GATT_NOTIFY_MULTIPLE +#define MYNEWT_VAL_BLE_GATT_NOTIFY_MULTIPLE ((MYNEWT_VAL_BLE_VERSION >= 52)) +#endif + #ifndef MYNEWT_VAL_BLE_GATT_READ #define MYNEWT_VAL_BLE_GATT_READ (MYNEWT_VAL_BLE_ROLE_CENTRAL) #endif @@ -539,6 +669,10 @@ #define MYNEWT_VAL_BLE_GATT_READ_MULT (MYNEWT_VAL_BLE_ROLE_CENTRAL) #endif +#ifndef MYNEWT_VAL_BLE_GATT_READ_MULT_VAR +#define MYNEWT_VAL_BLE_GATT_READ_MULT_VAR (MYNEWT_VAL_BLE_ROLE_CENTRAL && (MYNEWT_VAL_BLE_VERSION >= 52)) +#endif + #ifndef MYNEWT_VAL_BLE_GATT_READ_UUID #define MYNEWT_VAL_BLE_GATT_READ_UUID (MYNEWT_VAL_BLE_ROLE_CENTRAL) #endif @@ -583,6 +717,10 @@ #define MYNEWT_VAL_BLE_HS_DEBUG (0) #endif +#ifndef MYNEWT_VAL_BLE_HS_EXT_ADV_LEGACY_INSTANCE +#define MYNEWT_VAL_BLE_HS_EXT_ADV_LEGACY_INSTANCE (0) +#endif + #ifndef MYNEWT_VAL_BLE_HS_FLOW_CTRL #define MYNEWT_VAL_BLE_HS_FLOW_CTRL (0) #endif @@ -599,6 +737,10 @@ #define MYNEWT_VAL_BLE_HS_FLOW_CTRL_TX_ON_DISCONNECT (0) #endif +#ifndef MYNEWT_VAL_BLE_HS_GAP_UNHANDLED_HCI_EVENT +#define MYNEWT_VAL_BLE_HS_GAP_UNHANDLED_HCI_EVENT (0) +#endif + #ifndef MYNEWT_VAL_BLE_HS_LOG_LVL #define MYNEWT_VAL_BLE_HS_LOG_LVL (1) #endif @@ -627,6 +769,14 @@ #define MYNEWT_VAL_BLE_HS_SYSINIT_STAGE (200) #endif +#ifndef MYNEWT_VAL_BLE_ISO_MAX_BIGS +#define MYNEWT_VAL_BLE_ISO_MAX_BIGS (MYNEWT_VAL_BLE_MULTI_ADV_INSTANCES) +#endif + +#ifndef MYNEWT_VAL_BLE_ISO_MAX_BISES +#define MYNEWT_VAL_BLE_ISO_MAX_BISES (4) +#endif + #ifndef MYNEWT_VAL_BLE_L2CAP_COC_MAX_NUM #define MYNEWT_VAL_BLE_L2CAP_COC_MAX_NUM (0) #endif @@ -635,6 +785,10 @@ #define MYNEWT_VAL_BLE_L2CAP_COC_MPS (MYNEWT_VAL_MSYS_1_BLOCK_SIZE-8) #endif +#ifndef MYNEWT_VAL_BLE_L2CAP_COC_SDU_BUFF_COUNT +#define MYNEWT_VAL_BLE_L2CAP_COC_SDU_BUFF_COUNT (1) +#endif + #ifndef MYNEWT_VAL_BLE_L2CAP_ENHANCED_COC #define MYNEWT_VAL_BLE_L2CAP_ENHANCED_COC (0) #endif @@ -659,42 +813,6 @@ #define MYNEWT_VAL_BLE_MESH (0) #endif -#ifndef MYNEWT_VAL_BLE_MONITOR_CONSOLE_BUFFER_SIZE -#define MYNEWT_VAL_BLE_MONITOR_CONSOLE_BUFFER_SIZE (128) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_RTT -#define MYNEWT_VAL_BLE_MONITOR_RTT (0) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFERED -#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFERED (1) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_NAME -#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_NAME ("btmonitor") -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_SIZE -#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_SIZE (256) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_UART -#define MYNEWT_VAL_BLE_MONITOR_UART (0) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_UART_BAUDRATE -#define MYNEWT_VAL_BLE_MONITOR_UART_BAUDRATE (1000000) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_UART_BUFFER_SIZE -#define MYNEWT_VAL_BLE_MONITOR_UART_BUFFER_SIZE (64) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_UART_DEV -#define MYNEWT_VAL_BLE_MONITOR_UART_DEV ("uart0") -#endif - #ifndef MYNEWT_VAL_BLE_RPA_TIMEOUT #define MYNEWT_VAL_BLE_RPA_TIMEOUT (300) #endif @@ -703,6 +821,10 @@ #define MYNEWT_VAL_BLE_SM_BONDING (0) #endif +#ifndef MYNEWT_VAL_BLE_SM_CSIS_SIRK +#define MYNEWT_VAL_BLE_SM_CSIS_SIRK (0) +#endif + #ifndef MYNEWT_VAL_BLE_SM_IO_CAP #define MYNEWT_VAL_BLE_SM_IO_CAP (BLE_HS_IO_NO_INPUT_OUTPUT) #endif @@ -715,6 +837,10 @@ #define MYNEWT_VAL_BLE_SM_LEGACY (1) #endif +#ifndef MYNEWT_VAL_BLE_SM_LVL +#define MYNEWT_VAL_BLE_SM_LVL (0) +#endif + #ifndef MYNEWT_VAL_BLE_SM_MAX_PROCS #define MYNEWT_VAL_BLE_SM_MAX_PROCS (1) #endif @@ -735,18 +861,14 @@ #define MYNEWT_VAL_BLE_SM_SC (0) #endif -#ifndef MYNEWT_VAL_BLE_SM_SC_ONLY -#define MYNEWT_VAL_BLE_SM_SC_ONLY (0) -#endif - -#ifndef MYNEWT_VAL_BLE_SM_SC_LVL -#define MYNEWT_VAL_BLE_SM_SC_LVL (0) -#endif - #ifndef MYNEWT_VAL_BLE_SM_SC_DEBUG_KEYS #define MYNEWT_VAL_BLE_SM_SC_DEBUG_KEYS (0) #endif +#ifndef MYNEWT_VAL_BLE_SM_SC_ONLY +#define MYNEWT_VAL_BLE_SM_SC_ONLY (0) +#endif + #ifndef MYNEWT_VAL_BLE_SM_THEIR_KEY_DIST #define MYNEWT_VAL_BLE_SM_THEIR_KEY_DIST (0) #endif @@ -759,7 +881,6 @@ #define MYNEWT_VAL_BLE_STORE_MAX_CCCDS (8) #endif -/*** @apache-mynewt-nimble/nimble/host/services/ans */ #ifndef MYNEWT_VAL_BLE_SVC_ANS_NEW_ALERT_CAT #define MYNEWT_VAL_BLE_SVC_ANS_NEW_ALERT_CAT (0) #endif @@ -772,7 +893,6 @@ #define MYNEWT_VAL_BLE_SVC_ANS_UNR_ALERT_CAT (0) #endif -/*** @apache-mynewt-nimble/nimble/host/services/bas */ #ifndef MYNEWT_VAL_BLE_SVC_BAS_BATTERY_LEVEL_NOTIFY_ENABLE #define MYNEWT_VAL_BLE_SVC_BAS_BATTERY_LEVEL_NOTIFY_ENABLE (1) #endif @@ -785,7 +905,6 @@ #define MYNEWT_VAL_BLE_SVC_BAS_SYSINIT_STAGE (303) #endif -/*** @apache-mynewt-nimble/nimble/host/services/dis */ #ifndef MYNEWT_VAL_BLE_SVC_DIS_DEFAULT_READ_PERM #define MYNEWT_VAL_BLE_SVC_DIS_DEFAULT_READ_PERM (-1) #endif @@ -794,7 +913,6 @@ #define MYNEWT_VAL_BLE_SVC_DIS_FIRMWARE_REVISION_DEFAULT (NULL) #endif -/* Value copied from BLE_SVC_DIS_DEFAULT_READ_PERM */ #ifndef MYNEWT_VAL_BLE_SVC_DIS_FIRMWARE_REVISION_READ_PERM #define MYNEWT_VAL_BLE_SVC_DIS_FIRMWARE_REVISION_READ_PERM (-1) #endif @@ -803,7 +921,6 @@ #define MYNEWT_VAL_BLE_SVC_DIS_HARDWARE_REVISION_DEFAULT (NULL) #endif -/* Value copied from BLE_SVC_DIS_DEFAULT_READ_PERM */ #ifndef MYNEWT_VAL_BLE_SVC_DIS_HARDWARE_REVISION_READ_PERM #define MYNEWT_VAL_BLE_SVC_DIS_HARDWARE_REVISION_READ_PERM (-1) #endif @@ -812,13 +929,12 @@ #define MYNEWT_VAL_BLE_SVC_DIS_MANUFACTURER_NAME_DEFAULT (NULL) #endif -/* Value copied from BLE_SVC_DIS_DEFAULT_READ_PERM */ #ifndef MYNEWT_VAL_BLE_SVC_DIS_MANUFACTURER_NAME_READ_PERM #define MYNEWT_VAL_BLE_SVC_DIS_MANUFACTURER_NAME_READ_PERM (-1) #endif #ifndef MYNEWT_VAL_BLE_SVC_DIS_MODEL_NUMBER_DEFAULT -#define MYNEWT_VAL_BLE_SVC_DIS_MODEL_NUMBER_DEFAULT ("Apache Mynewt NimBLE") +#define MYNEWT_VAL_BLE_SVC_DIS_MODEL_NUMBER_DEFAULT "Apache Mynewt NimBLE" #endif #ifndef MYNEWT_VAL_BLE_SVC_DIS_MODEL_NUMBER_READ_PERM @@ -829,7 +945,6 @@ #define MYNEWT_VAL_BLE_SVC_DIS_SERIAL_NUMBER_DEFAULT (NULL) #endif -/* Value copied from BLE_SVC_DIS_DEFAULT_READ_PERM */ #ifndef MYNEWT_VAL_BLE_SVC_DIS_SERIAL_NUMBER_READ_PERM #define MYNEWT_VAL_BLE_SVC_DIS_SERIAL_NUMBER_READ_PERM (-1) #endif @@ -838,7 +953,6 @@ #define MYNEWT_VAL_BLE_SVC_DIS_SOFTWARE_REVISION_DEFAULT (NULL) #endif -/* Value copied from BLE_SVC_DIS_DEFAULT_READ_PERM */ #ifndef MYNEWT_VAL_BLE_SVC_DIS_SOFTWARE_REVISION_READ_PERM #define MYNEWT_VAL_BLE_SVC_DIS_SOFTWARE_REVISION_READ_PERM (-1) #endif @@ -851,12 +965,10 @@ #define MYNEWT_VAL_BLE_SVC_DIS_SYSTEM_ID_DEFAULT (NULL) #endif -/* Value copied from BLE_SVC_DIS_DEFAULT_READ_PERM */ #ifndef MYNEWT_VAL_BLE_SVC_DIS_SYSTEM_ID_READ_PERM #define MYNEWT_VAL_BLE_SVC_DIS_SYSTEM_ID_READ_PERM (-1) #endif -/*** @apache-mynewt-nimble/nimble/host/services/gap */ #ifndef MYNEWT_VAL_BLE_SVC_GAP_APPEARANCE #define MYNEWT_VAL_BLE_SVC_GAP_APPEARANCE (0) #endif @@ -870,7 +982,7 @@ #endif #ifndef MYNEWT_VAL_BLE_SVC_GAP_DEVICE_NAME -#define MYNEWT_VAL_BLE_SVC_GAP_DEVICE_NAME ("nimble") +#define MYNEWT_VAL_BLE_SVC_GAP_DEVICE_NAME "nimble" #endif #ifndef MYNEWT_VAL_BLE_SVC_GAP_DEVICE_NAME_MAX_LENGTH @@ -901,56 +1013,179 @@ #define MYNEWT_VAL_BLE_SVC_GAP_SYSINIT_STAGE (301) #endif -/*** @apache-mynewt-nimble/nimble/host/services/gatt */ #ifndef MYNEWT_VAL_BLE_SVC_GATT_SYSINIT_STAGE #define MYNEWT_VAL_BLE_SVC_GATT_SYSINIT_STAGE (302) #endif -/*** @apache-mynewt-nimble/nimble/host/services/ias */ #ifndef MYNEWT_VAL_BLE_SVC_IAS_SYSINIT_STAGE #define MYNEWT_VAL_BLE_SVC_IAS_SYSINIT_STAGE (303) #endif -/*** @apache-mynewt-nimble/nimble/host/services/ipss */ #ifndef MYNEWT_VAL_BLE_SVC_IPSS_SYSINIT_STAGE #define MYNEWT_VAL_BLE_SVC_IPSS_SYSINIT_STAGE (303) #endif -/*** @apache-mynewt-nimble/nimble/host/services/lls */ #ifndef MYNEWT_VAL_BLE_SVC_LLS_SYSINIT_STAGE #define MYNEWT_VAL_BLE_SVC_LLS_SYSINIT_STAGE (303) #endif -/*** @apache-mynewt-nimble/nimble/host/services/tps */ #ifndef MYNEWT_VAL_BLE_SVC_TPS_SYSINIT_STAGE #define MYNEWT_VAL_BLE_SVC_TPS_SYSINIT_STAGE (303) #endif -/*** @apache-mynewt-nimble/nimble/transport/socket */ -#ifndef MYNEWT_VAL_BLE_ACL_BUF_COUNT -#define MYNEWT_VAL_BLE_ACL_BUF_COUNT (24) +#undef MYNEWT_VAL_BLE_ACL_BUF_COUNT + +#undef MYNEWT_VAL_BLE_ACL_BUF_SIZE + +#undef MYNEWT_VAL_BLE_HCI_BRIDGE + +#undef MYNEWT_VAL_BLE_HCI_EVT_BUF_SIZE + +#undef MYNEWT_VAL_BLE_HCI_EVT_HI_BUF_COUNT + +#undef MYNEWT_VAL_BLE_HCI_EVT_LO_BUF_COUNT + +#undef MYNEWT_VAL_BLE_HCI_TRANSPORT + +#ifndef MYNEWT_VAL_BLE_MONITOR_CONSOLE_BUFFER_SIZE +#define MYNEWT_VAL_BLE_MONITOR_CONSOLE_BUFFER_SIZE (128) #endif -#ifndef MYNEWT_VAL_BLE_ACL_BUF_SIZE -#define MYNEWT_VAL_BLE_ACL_BUF_SIZE (255) +#ifndef MYNEWT_VAL_BLE_MONITOR_RTT +#define MYNEWT_VAL_BLE_MONITOR_RTT (0) #endif -#ifndef MYNEWT_VAL_BLE_HCI_ACL_OUT_COUNT -#define MYNEWT_VAL_BLE_HCI_ACL_OUT_COUNT (12) +#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFERED +#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFERED (1) #endif -#ifndef MYNEWT_VAL_BLE_HCI_EVT_BUF_SIZE -#define MYNEWT_VAL_BLE_HCI_EVT_BUF_SIZE (70) +#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_NAME +#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_NAME "btmonitor" #endif -#ifndef MYNEWT_VAL_BLE_HCI_EVT_HI_BUF_COUNT -#define MYNEWT_VAL_BLE_HCI_EVT_HI_BUF_COUNT (8) +#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_SIZE +#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_SIZE (256) #endif -#ifndef MYNEWT_VAL_BLE_HCI_EVT_LO_BUF_COUNT -#define MYNEWT_VAL_BLE_HCI_EVT_LO_BUF_COUNT (8) +#ifndef MYNEWT_VAL_BLE_MONITOR_UART +#define MYNEWT_VAL_BLE_MONITOR_UART (0) #endif +#ifndef MYNEWT_VAL_BLE_MONITOR_UART_BAUDRATE +#define MYNEWT_VAL_BLE_MONITOR_UART_BAUDRATE (1000000) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_UART_BUFFER_SIZE +#define MYNEWT_VAL_BLE_MONITOR_UART_BUFFER_SIZE (64) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_UART_DEV +#define MYNEWT_VAL_BLE_MONITOR_UART_DEV "uart0" +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT +#define MYNEWT_VAL_BLE_TRANSPORT (1) +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT_ACL_COUNT +#define MYNEWT_VAL_BLE_TRANSPORT_ACL_COUNT (10) +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT_ACL_FROM_HS_COUNT +#define MYNEWT_VAL_BLE_TRANSPORT_ACL_FROM_HS_COUNT (10) +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT_ACL_FROM_LL_COUNT +#define MYNEWT_VAL_BLE_TRANSPORT_ACL_FROM_LL_COUNT (10) +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT_ACL_SIZE +#define MYNEWT_VAL_BLE_TRANSPORT_ACL_SIZE (251) +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT_EVT_COUNT +#define MYNEWT_VAL_BLE_TRANSPORT_EVT_COUNT (4) +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT_EVT_DISCARDABLE_COUNT +#define MYNEWT_VAL_BLE_TRANSPORT_EVT_DISCARDABLE_COUNT (16) +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT_EVT_SIZE +#define MYNEWT_VAL_BLE_TRANSPORT_EVT_SIZE (70) +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT_HS__cdc +#define MYNEWT_VAL_BLE_TRANSPORT_HS__cdc (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_HS__custom +#define MYNEWT_VAL_BLE_TRANSPORT_HS__custom (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_HS__dialog_cmac +#define MYNEWT_VAL_BLE_TRANSPORT_HS__dialog_cmac (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_HS__native +#define MYNEWT_VAL_BLE_TRANSPORT_HS__native (1) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_HS__nrf5340 +#define MYNEWT_VAL_BLE_TRANSPORT_HS__nrf5340 (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_HS__uart +#define MYNEWT_VAL_BLE_TRANSPORT_HS__uart (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_HS__usb +#define MYNEWT_VAL_BLE_TRANSPORT_HS__usb (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_HS +#define MYNEWT_VAL_BLE_TRANSPORT_HS (1) +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT_ISO_COUNT +#define MYNEWT_VAL_BLE_TRANSPORT_ISO_COUNT (10) +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT_ISO_FROM_HS_COUNT +#define MYNEWT_VAL_BLE_TRANSPORT_ISO_FROM_HS_COUNT (10) +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT_ISO_FROM_LL_COUNT +#define MYNEWT_VAL_BLE_TRANSPORT_ISO_FROM_LL_COUNT (10) +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT_ISO_SIZE +#define MYNEWT_VAL_BLE_TRANSPORT_ISO_SIZE (300) +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__apollo3 +#define MYNEWT_VAL_BLE_TRANSPORT_LL__apollo3 (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__custom +#define MYNEWT_VAL_BLE_TRANSPORT_LL__custom (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__dialog_cmac +#define MYNEWT_VAL_BLE_TRANSPORT_LL__dialog_cmac (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__emspi +#define MYNEWT_VAL_BLE_TRANSPORT_LL__emspi (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__native +#define MYNEWT_VAL_BLE_TRANSPORT_LL__native (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__nrf5340 +#define MYNEWT_VAL_BLE_TRANSPORT_LL__nrf5340 (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__socket +#define MYNEWT_VAL_BLE_TRANSPORT_LL__socket (1) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__uart_ll +#define MYNEWT_VAL_BLE_TRANSPORT_LL__uart_ll (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_LL +#define MYNEWT_VAL_BLE_TRANSPORT_LL (1) +#endif + +#undef MYNEWT_VAL_BLE_TRANSPORT_RX_TASK_STACK_SIZE + #ifndef MYNEWT_VAL_BLE_SOCK_CLI_SYSINIT_STAGE #define MYNEWT_VAL_BLE_SOCK_CLI_SYSINIT_STAGE (500) #endif @@ -959,12 +1194,10 @@ #define MYNEWT_VAL_BLE_SOCK_LINUX_DEV (0) #endif -/* Overridden by @apache-mynewt-nimble/porting/targets/linux (defined by @apache-mynewt-nimble/nimble/transport/socket) */ #ifndef MYNEWT_VAL_BLE_SOCK_STACK_SIZE #define MYNEWT_VAL_BLE_SOCK_STACK_SIZE (1028) #endif -/* Overridden by @apache-mynewt-nimble/porting/targets/linux (defined by @apache-mynewt-nimble/nimble/transport/socket) */ #ifndef MYNEWT_VAL_BLE_SOCK_TASK_PRIO #define MYNEWT_VAL_BLE_SOCK_TASK_PRIO (3) #endif @@ -973,19 +1206,20 @@ #define MYNEWT_VAL_BLE_SOCK_TCP_PORT (14433) #endif -/* Overridden by @apache-mynewt-nimble/porting/targets/linux (defined by @apache-mynewt-nimble/nimble/transport/socket) */ #ifndef MYNEWT_VAL_BLE_SOCK_USE_LINUX_BLUE #define MYNEWT_VAL_BLE_SOCK_USE_LINUX_BLUE (1) #endif -/* Overridden by @apache-mynewt-nimble/porting/targets/linux (defined by @apache-mynewt-nimble/nimble/transport/socket) */ +#ifndef MYNEWT_VAL_BLE_SOCK_USE_NUTTX +#define MYNEWT_VAL_BLE_SOCK_USE_NUTTX (0) +#endif + #ifndef MYNEWT_VAL_BLE_SOCK_USE_TCP #define MYNEWT_VAL_BLE_SOCK_USE_TCP (0) #endif -/*** newt */ #ifndef MYNEWT_VAL_APP_NAME -#define MYNEWT_VAL_APP_NAME ("dummy_app") +#define MYNEWT_VAL_APP_NAME "dummy_app" #endif #ifndef MYNEWT_VAL_APP_dummy_app @@ -993,19 +1227,19 @@ #endif #ifndef MYNEWT_VAL_ARCH_NAME -#define MYNEWT_VAL_ARCH_NAME ("dummy") +#define MYNEWT_VAL_ARCH_NAME "sim" #endif -#ifndef MYNEWT_VAL_ARCH_dummy -#define MYNEWT_VAL_ARCH_dummy (1) +#ifndef MYNEWT_VAL_ARCH_sim +#define MYNEWT_VAL_ARCH_sim (1) #endif #ifndef MYNEWT_VAL_BSP_NAME -#define MYNEWT_VAL_BSP_NAME ("dummy_bsp") +#define MYNEWT_VAL_BSP_NAME "native" #endif -#ifndef MYNEWT_VAL_BSP_dummy_bsp -#define MYNEWT_VAL_BSP_dummy_bsp (1) +#ifndef MYNEWT_VAL_BSP_native +#define MYNEWT_VAL_BSP_native (1) #endif #ifndef MYNEWT_VAL_NEWT_FEATURE_LOGCFG @@ -1017,11 +1251,61 @@ #endif #ifndef MYNEWT_VAL_TARGET_NAME -#define MYNEWT_VAL_TARGET_NAME ("linux") +#define MYNEWT_VAL_TARGET_NAME "linux" #endif #ifndef MYNEWT_VAL_TARGET_linux #define MYNEWT_VAL_TARGET_linux (1) #endif +#define MYNEWT_PKG_apache_mynewt_core__compiler_sim 1 +#define MYNEWT_PKG_apache_mynewt_core__crypto_tinycrypt 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_bsp_native 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_drivers_flash_enc_flash 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_drivers_flash_enc_flash_ef_tinycrypt 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_drivers_trng 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_drivers_trng_trng_sw 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_drivers_uart 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_drivers_uart_uart_hal 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_hal 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_mcu_native 1 +#define MYNEWT_PKG_apache_mynewt_core__kernel_os 1 +#define MYNEWT_PKG_apache_mynewt_core__kernel_sim 1 +#define MYNEWT_PKG_apache_mynewt_core__net_ip_mn_socket 1 +#define MYNEWT_PKG_apache_mynewt_core__net_ip_native_sockets 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_console_stub 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_defs 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_flash_map 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_log_common 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_log_modlog 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_log_stub 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_stats_stub 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_sys 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_sysdown 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_sysinit 1 +#define MYNEWT_PKG_apache_mynewt_core__util_mem 1 +#define MYNEWT_PKG_apache_mynewt_core__util_rwlock 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_ans 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_bas 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_dis 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_gap 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_gatt 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_ias 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_ipss 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_lls 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_tps 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_transport 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_transport_socket 1 +#define MYNEWT_PKG_apache_mynewt_nimble__porting_npl_mynewt 1 +#define MYNEWT_PKG_apache_mynewt_nimble__porting_targets_dummy_app 1 +#define MYNEWT_PKG_apache_mynewt_nimble__porting_targets_linux 1 + +#define MYNEWT_API_TRNG_HW_IMPL 1 +#define MYNEWT_API_ble_transport 1 +#define MYNEWT_API_console 1 +#define MYNEWT_API_log 1 +#define MYNEWT_API_stats 1 + #endif diff --git a/porting/examples/linux/include/sysflash/sysflash.h b/porting/examples/linux/include/sysflash/sysflash.h deleted file mode 100644 index ab1341b25d..0000000000 --- a/porting/examples/linux/include/sysflash/sysflash.h +++ /dev/null @@ -1,24 +0,0 @@ -/** - * This file was generated by Apache newt version: 1.9.0-dev - */ - -#ifndef H_MYNEWT_SYSFLASH_ -#define H_MYNEWT_SYSFLASH_ - -#include "flash_map/flash_map.h" - -/** - * This flash map definition is used for two purposes: - * 1. To locate the meta area, which contains the true flash map definition. - * 2. As a fallback in case the meta area cannot be read from flash. - */ -extern const struct flash_area sysflash_map_dflt[6]; - -#define FLASH_AREA_BOOTLOADER 0 -#define FLASH_AREA_IMAGE_0 1 -#define FLASH_AREA_IMAGE_1 2 -#define FLASH_AREA_IMAGE_SCRATCH 3 -#define FLASH_AREA_REBOOT_LOG 16 -#define FLASH_AREA_NFFS 17 - -#endif diff --git a/porting/examples/linux/main.c b/porting/examples/linux/main.c index a2e255d083..e81e60872b 100644 --- a/porting/examples/linux/main.c +++ b/porting/examples/linux/main.c @@ -37,8 +37,8 @@ static struct ble_npl_task s_task_hci; void nimble_host_task(void *param); void ble_hci_sock_ack_handler(void *param); -void ble_hci_sock_init(void); void ble_hci_sock_set_device(int dev); +void ble_store_ram_init(void); #define TASK_DEFAULT_PRIORITY 1 #define TASK_DEFAULT_STACK NULL @@ -66,7 +66,6 @@ int main(int argc, char *argv[]) } nimble_port_init(); - ble_hci_sock_init(); /* This example provides GATT Alert service */ ble_svc_gap_init(); diff --git a/porting/examples/linux_blemesh/Makefile b/porting/examples/linux_blemesh/Makefile index 556fc8ca6c..67783f2766 100644 --- a/porting/examples/linux_blemesh/Makefile +++ b/porting/examples/linux_blemesh/Makefile @@ -17,7 +17,7 @@ # Toolchain commands CROSS_COMPILE ?= -CC := ccache $(CROSS_COMPILIE)gcc +CC := ccache $(CROSS_COMPILE)gcc CXX := ccache $(CROSS_COMPILE)g++ LD := $(CROSS_COMPILE)gcc AR := $(CROSS_COMPILE)ar @@ -83,7 +83,7 @@ CFLAGS = \ -D_GNU_SOURCE \ $(NULL) -LIBS := -lrt -lpthread -lstdc++ +LIBS := $(NIMBLE_LDFLAGS) -lrt -lpthread -lstdc++ .PHONY: all clean .DEFAULT: all diff --git a/porting/examples/linux_blemesh/ble.c b/porting/examples/linux_blemesh/ble.c index deaef5a462..381c6299a8 100644 --- a/porting/examples/linux_blemesh/ble.c +++ b/porting/examples/linux_blemesh/ble.c @@ -54,7 +54,7 @@ fault_get_cur(struct bt_mesh_model *model, *test_id = recent_test_id; *company_id = CID_VENDOR; - *fault_count = min(*fault_count, sizeof(reg_faults)); + *fault_count = MIN(*fault_count, sizeof(reg_faults)); memcpy(faults, reg_faults, *fault_count); return 0; @@ -78,7 +78,7 @@ fault_get_reg(struct bt_mesh_model *model, if (has_reg_fault) { uint8_t reg_faults[FAULT_ARR_SIZE] = { [0 ... FAULT_ARR_SIZE-1] = 0xff }; - *fault_count = min(*fault_count, sizeof(reg_faults)); + *fault_count = MIN(*fault_count, sizeof(reg_faults)); memcpy(faults, reg_faults, *fault_count); } else { *fault_count = 0; @@ -142,11 +142,12 @@ static struct bt_mesh_model_pub gen_onoff_pub; static uint8_t gen_on_off_state; static int16_t gen_level_state; -static void gen_onoff_status(struct bt_mesh_model *model, +static int gen_onoff_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx) { struct os_mbuf *msg = NET_BUF_SIMPLE(3); uint8_t *status; + int rc; console_printf("#mesh-onoff STATUS\n"); @@ -154,23 +155,25 @@ static void gen_onoff_status(struct bt_mesh_model *model, status = net_buf_simple_add(msg, 1); *status = gen_on_off_state; - if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { + rc = bt_mesh_model_send(model, ctx, msg, NULL, NULL); + if (rc) { console_printf("#mesh-onoff STATUS: send status failed\n"); } os_mbuf_free_chain(msg); + return rc; } -static void gen_onoff_get(struct bt_mesh_model *model, +static int gen_onoff_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { console_printf("#mesh-onoff GET\n"); - gen_onoff_status(model, ctx); + return gen_onoff_status(model, ctx); } -static void gen_onoff_set(struct bt_mesh_model *model, +static int gen_onoff_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -178,16 +181,17 @@ static void gen_onoff_set(struct bt_mesh_model *model, gen_on_off_state = buf->om_data[0]; - gen_onoff_status(model, ctx); + return gen_onoff_status(model, ctx); } -static void gen_onoff_set_unack(struct bt_mesh_model *model, +static int gen_onoff_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { console_printf("#mesh-onoff SET-UNACK\n"); gen_on_off_state = buf->om_data[0]; + return 0; } static const struct bt_mesh_model_op gen_onoff_op[] = { @@ -214,16 +218,17 @@ static void gen_level_status(struct bt_mesh_model *model, os_mbuf_free_chain(msg); } -static void gen_level_get(struct bt_mesh_model *model, +static int gen_level_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { console_printf("#mesh-level GET\n"); gen_level_status(model, ctx); + return 0; } -static void gen_level_set(struct bt_mesh_model *model, +static int gen_level_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -236,9 +241,10 @@ static void gen_level_set(struct bt_mesh_model *model, gen_level_state = level; console_printf("#mesh-level: level=%d\n", gen_level_state); + return 0; } -static void gen_level_set_unack(struct bt_mesh_model *model, +static int gen_level_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -249,9 +255,10 @@ static void gen_level_set_unack(struct bt_mesh_model *model, gen_level_state = level; console_printf("#mesh-level: level=%d\n", gen_level_state); + return 0; } -static void gen_delta_set(struct bt_mesh_model *model, +static int gen_delta_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -264,9 +271,10 @@ static void gen_delta_set(struct bt_mesh_model *model, gen_level_state += delta_level; console_printf("#mesh-level: level=%d\n", gen_level_state); + return 0; } -static void gen_delta_set_unack(struct bt_mesh_model *model, +static int gen_delta_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { @@ -277,18 +285,21 @@ static void gen_delta_set_unack(struct bt_mesh_model *model, gen_level_state += delta_level; console_printf("#mesh-level: level=%d\n", gen_level_state); + return 0; } -static void gen_move_set(struct bt_mesh_model *model, +static int gen_move_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { + return 0; } -static void gen_move_set_unack(struct bt_mesh_model *model, +static int gen_move_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { + return 0; } static const struct bt_mesh_model_op gen_level_op[] = { @@ -313,11 +324,12 @@ static struct bt_mesh_model root_models[] = { static struct bt_mesh_model_pub vnd_model_pub; -static void vnd_model_recv(struct bt_mesh_model *model, +static int vnd_model_recv(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { struct os_mbuf *msg = NET_BUF_SIMPLE(3); + int rc; console_printf("#vendor-model-recv\n"); @@ -327,11 +339,13 @@ static void vnd_model_recv(struct bt_mesh_model *model, bt_mesh_model_msg_init(msg, BT_MESH_MODEL_OP_3(0x01, CID_VENDOR)); os_mbuf_append(msg, buf->om_data, buf->om_len); - if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { + rc = bt_mesh_model_send(model, ctx, msg, NULL, NULL); + if (rc) { console_printf("#vendor-model-recv: send rsp failed\n"); } os_mbuf_free_chain(msg); + return rc; } static const struct bt_mesh_model_op vnd_model_op[] = { @@ -412,6 +426,8 @@ blemesh_on_sync(void) if (bt_mesh_is_provisioned()) { printk("Mesh network restored from flash\n"); } + + bt_mesh_prov_enable(BT_MESH_PROV_GATT | BT_MESH_PROV_ADV); } void diff --git a/porting/examples/linux_blemesh/include/logcfg/logcfg.h b/porting/examples/linux_blemesh/include/logcfg/logcfg.h deleted file mode 100644 index 798418dabb..0000000000 --- a/porting/examples/linux_blemesh/include/logcfg/logcfg.h +++ /dev/null @@ -1,151 +0,0 @@ -/** - * This file was generated by Apache newt version: 1.9.0-dev - */ - -#ifndef H_MYNEWT_LOGCFG_ -#define H_MYNEWT_LOGCFG_ - -#include "modlog/modlog.h" -#include "log_common/log_common.h" - -#define BLE_HS_LOG_DEBUG(...) IGNORE(__VA_ARGS__) -#define BLE_HS_LOG_INFO(...) MODLOG_INFO(4, __VA_ARGS__) -#define BLE_HS_LOG_WARN(...) MODLOG_WARN(4, __VA_ARGS__) -#define BLE_HS_LOG_ERROR(...) MODLOG_ERROR(4, __VA_ARGS__) -#define BLE_HS_LOG_CRITICAL(...) MODLOG_CRITICAL(4, __VA_ARGS__) -#define BLE_HS_LOG_DISABLED(...) MODLOG_DISABLED(4, __VA_ARGS__) - -#define BLE_MESH_ACCESS_LOG_DEBUG(...) IGNORE(__VA_ARGS__) -#define BLE_MESH_ACCESS_LOG_INFO(...) MODLOG_INFO(10, __VA_ARGS__) -#define BLE_MESH_ACCESS_LOG_WARN(...) MODLOG_WARN(10, __VA_ARGS__) -#define BLE_MESH_ACCESS_LOG_ERROR(...) MODLOG_ERROR(10, __VA_ARGS__) -#define BLE_MESH_ACCESS_LOG_CRITICAL(...) MODLOG_CRITICAL(10, __VA_ARGS__) -#define BLE_MESH_ACCESS_LOG_DISABLED(...) MODLOG_DISABLED(10, __VA_ARGS__) - -#define BLE_MESH_ADV_LOG_DEBUG(...) IGNORE(__VA_ARGS__) -#define BLE_MESH_ADV_LOG_INFO(...) MODLOG_INFO(11, __VA_ARGS__) -#define BLE_MESH_ADV_LOG_WARN(...) MODLOG_WARN(11, __VA_ARGS__) -#define BLE_MESH_ADV_LOG_ERROR(...) MODLOG_ERROR(11, __VA_ARGS__) -#define BLE_MESH_ADV_LOG_CRITICAL(...) MODLOG_CRITICAL(11, __VA_ARGS__) -#define BLE_MESH_ADV_LOG_DISABLED(...) MODLOG_DISABLED(11, __VA_ARGS__) - -#define BLE_MESH_BEACON_LOG_DEBUG(...) IGNORE(__VA_ARGS__) -#define BLE_MESH_BEACON_LOG_INFO(...) MODLOG_INFO(12, __VA_ARGS__) -#define BLE_MESH_BEACON_LOG_WARN(...) MODLOG_WARN(12, __VA_ARGS__) -#define BLE_MESH_BEACON_LOG_ERROR(...) MODLOG_ERROR(12, __VA_ARGS__) -#define BLE_MESH_BEACON_LOG_CRITICAL(...) MODLOG_CRITICAL(12, __VA_ARGS__) -#define BLE_MESH_BEACON_LOG_DISABLED(...) MODLOG_DISABLED(12, __VA_ARGS__) - -#define BLE_MESH_CRYPTO_LOG_DEBUG(...) IGNORE(__VA_ARGS__) -#define BLE_MESH_CRYPTO_LOG_INFO(...) MODLOG_INFO(13, __VA_ARGS__) -#define BLE_MESH_CRYPTO_LOG_WARN(...) MODLOG_WARN(13, __VA_ARGS__) -#define BLE_MESH_CRYPTO_LOG_ERROR(...) MODLOG_ERROR(13, __VA_ARGS__) -#define BLE_MESH_CRYPTO_LOG_CRITICAL(...) MODLOG_CRITICAL(13, __VA_ARGS__) -#define BLE_MESH_CRYPTO_LOG_DISABLED(...) MODLOG_DISABLED(13, __VA_ARGS__) - -#define BLE_MESH_FRIEND_LOG_DEBUG(...) IGNORE(__VA_ARGS__) -#define BLE_MESH_FRIEND_LOG_INFO(...) MODLOG_INFO(14, __VA_ARGS__) -#define BLE_MESH_FRIEND_LOG_WARN(...) MODLOG_WARN(14, __VA_ARGS__) -#define BLE_MESH_FRIEND_LOG_ERROR(...) MODLOG_ERROR(14, __VA_ARGS__) -#define BLE_MESH_FRIEND_LOG_CRITICAL(...) MODLOG_CRITICAL(14, __VA_ARGS__) -#define BLE_MESH_FRIEND_LOG_DISABLED(...) MODLOG_DISABLED(14, __VA_ARGS__) - -#define BLE_MESH_LOG_DEBUG(...) IGNORE(__VA_ARGS__) -#define BLE_MESH_LOG_INFO(...) MODLOG_INFO(9, __VA_ARGS__) -#define BLE_MESH_LOG_WARN(...) MODLOG_WARN(9, __VA_ARGS__) -#define BLE_MESH_LOG_ERROR(...) MODLOG_ERROR(9, __VA_ARGS__) -#define BLE_MESH_LOG_CRITICAL(...) MODLOG_CRITICAL(9, __VA_ARGS__) -#define BLE_MESH_LOG_DISABLED(...) MODLOG_DISABLED(9, __VA_ARGS__) - -#define BLE_MESH_LOW_POWER_LOG_DEBUG(...) IGNORE(__VA_ARGS__) -#define BLE_MESH_LOW_POWER_LOG_INFO(...) MODLOG_INFO(15, __VA_ARGS__) -#define BLE_MESH_LOW_POWER_LOG_WARN(...) MODLOG_WARN(15, __VA_ARGS__) -#define BLE_MESH_LOW_POWER_LOG_ERROR(...) MODLOG_ERROR(15, __VA_ARGS__) -#define BLE_MESH_LOW_POWER_LOG_CRITICAL(...) MODLOG_CRITICAL(15, __VA_ARGS__) -#define BLE_MESH_LOW_POWER_LOG_DISABLED(...) MODLOG_DISABLED(15, __VA_ARGS__) - -#define BLE_MESH_MODEL_LOG_DEBUG(...) IGNORE(__VA_ARGS__) -#define BLE_MESH_MODEL_LOG_INFO(...) MODLOG_INFO(16, __VA_ARGS__) -#define BLE_MESH_MODEL_LOG_WARN(...) MODLOG_WARN(16, __VA_ARGS__) -#define BLE_MESH_MODEL_LOG_ERROR(...) MODLOG_ERROR(16, __VA_ARGS__) -#define BLE_MESH_MODEL_LOG_CRITICAL(...) MODLOG_CRITICAL(16, __VA_ARGS__) -#define BLE_MESH_MODEL_LOG_DISABLED(...) MODLOG_DISABLED(16, __VA_ARGS__) - -#define BLE_MESH_NET_LOG_DEBUG(...) IGNORE(__VA_ARGS__) -#define BLE_MESH_NET_LOG_INFO(...) MODLOG_INFO(17, __VA_ARGS__) -#define BLE_MESH_NET_LOG_WARN(...) MODLOG_WARN(17, __VA_ARGS__) -#define BLE_MESH_NET_LOG_ERROR(...) MODLOG_ERROR(17, __VA_ARGS__) -#define BLE_MESH_NET_LOG_CRITICAL(...) MODLOG_CRITICAL(17, __VA_ARGS__) -#define BLE_MESH_NET_LOG_DISABLED(...) MODLOG_DISABLED(17, __VA_ARGS__) - -#define BLE_MESH_PROV_LOG_DEBUG(...) IGNORE(__VA_ARGS__) -#define BLE_MESH_PROV_LOG_INFO(...) MODLOG_INFO(18, __VA_ARGS__) -#define BLE_MESH_PROV_LOG_WARN(...) MODLOG_WARN(18, __VA_ARGS__) -#define BLE_MESH_PROV_LOG_ERROR(...) MODLOG_ERROR(18, __VA_ARGS__) -#define BLE_MESH_PROV_LOG_CRITICAL(...) MODLOG_CRITICAL(18, __VA_ARGS__) -#define BLE_MESH_PROV_LOG_DISABLED(...) MODLOG_DISABLED(18, __VA_ARGS__) - -#define BLE_MESH_PROXY_LOG_DEBUG(...) IGNORE(__VA_ARGS__) -#define BLE_MESH_PROXY_LOG_INFO(...) MODLOG_INFO(19, __VA_ARGS__) -#define BLE_MESH_PROXY_LOG_WARN(...) MODLOG_WARN(19, __VA_ARGS__) -#define BLE_MESH_PROXY_LOG_ERROR(...) MODLOG_ERROR(19, __VA_ARGS__) -#define BLE_MESH_PROXY_LOG_CRITICAL(...) MODLOG_CRITICAL(19, __VA_ARGS__) -#define BLE_MESH_PROXY_LOG_DISABLED(...) MODLOG_DISABLED(19, __VA_ARGS__) - -#define BLE_MESH_SETTINGS_LOG_DEBUG(...) IGNORE(__VA_ARGS__) -#define BLE_MESH_SETTINGS_LOG_INFO(...) MODLOG_INFO(20, __VA_ARGS__) -#define BLE_MESH_SETTINGS_LOG_WARN(...) MODLOG_WARN(20, __VA_ARGS__) -#define BLE_MESH_SETTINGS_LOG_ERROR(...) MODLOG_ERROR(20, __VA_ARGS__) -#define BLE_MESH_SETTINGS_LOG_CRITICAL(...) MODLOG_CRITICAL(20, __VA_ARGS__) -#define BLE_MESH_SETTINGS_LOG_DISABLED(...) MODLOG_DISABLED(20, __VA_ARGS__) - -#define BLE_MESH_TRANS_LOG_DEBUG(...) IGNORE(__VA_ARGS__) -#define BLE_MESH_TRANS_LOG_INFO(...) MODLOG_INFO(21, __VA_ARGS__) -#define BLE_MESH_TRANS_LOG_WARN(...) MODLOG_WARN(21, __VA_ARGS__) -#define BLE_MESH_TRANS_LOG_ERROR(...) MODLOG_ERROR(21, __VA_ARGS__) -#define BLE_MESH_TRANS_LOG_CRITICAL(...) MODLOG_CRITICAL(21, __VA_ARGS__) -#define BLE_MESH_TRANS_LOG_DISABLED(...) MODLOG_DISABLED(21, __VA_ARGS__) - -#define BLE_MESH_RPL_LOG_DEBUG(...) IGNORE(__VA_ARGS__) -#define BLE_MESH_RPL_LOG_INFO(...) MODLOG_INFO(22, __VA_ARGS__) -#define BLE_MESH_RPL_LOG_WARN(...) MODLOG_WARN(22, __VA_ARGS__) -#define BLE_MESH_RPL_LOG_ERROR(...) MODLOG_ERROR(22, __VA_ARGS__) -#define BLE_MESH_RPL_LOG_CRITICAL(...) MODLOG_CRITICAL(22, __VA_ARGS__) -#define BLE_MESH_RPL_LOG_DISABLED(...) MODLOG_DISABLED(22, __VA_ARGS__) - -#define BLE_MESH_NET_KEYS_LOG_DEBUG(...) IGNORE(__VA_ARGS__) -#define BLE_MESH_NET_KEYS_LOG_INFO(...) MODLOG_INFO(23, __VA_ARGS__) -#define BLE_MESH_NET_KEYS_LOG_WARN(...) MODLOG_WARN(23, __VA_ARGS__) -#define BLE_MESH_NET_KEYS_LOG_ERROR(...) MODLOG_ERROR(23, __VA_ARGS__) -#define BLE_MESH_NET_KEYS_LOG_CRITICAL(...) MODLOG_CRITICAL(23, __VA_ARGS__) -#define BLE_MESH_NET_KEYS_LOG_DISABLED(...) MODLOG_DISABLED(23, __VA_ARGS__) - -#define BLE_MESH_PROV_DEVICE_LOG_DEBUG(...) IGNORE(__VA_ARGS__) -#define BLE_MESH_PROV_DEVICE_LOG_INFO(...) MODLOG_INFO(24, __VA_ARGS__) -#define BLE_MESH_PROV_DEVICE_LOG_WARN(...) MODLOG_WARN(24, __VA_ARGS__) -#define BLE_MESH_PROV_DEVICE_LOG_ERROR(...) MODLOG_ERROR(24, __VA_ARGS__) -#define BLE_MESH_PROV_DEVICE_LOG_CRITICAL(...) MODLOG_CRITICAL(24, __VA_ARGS__) -#define BLE_MESH_PROV_DEVICE_LOG_DISABLED(...) MODLOG_DISABLED(24, __VA_ARGS__) - -#define BLE_MESH_HEARTBEAT_LOG_DEBUG(...) IGNORE(__VA_ARGS__) -#define BLE_MESH_HEARTBEAT_LOG_INFO(...) MODLOG_INFO(25, __VA_ARGS__) -#define BLE_MESH_HEARTBEAT_LOG_WARN(...) MODLOG_WARN(25, __VA_ARGS__) -#define BLE_MESH_HEARTBEAT_LOG_ERROR(...) MODLOG_ERROR(25, __VA_ARGS__) -#define BLE_MESH_HEARTBEAT_LOG_CRITICAL(...) MODLOG_CRITICAL(25, __VA_ARGS__) -#define BLE_MESH_HEARTBEAT_LOG_DISABLED(...) MODLOG_DISABLED(25, __VA_ARGS__) - -#define DFLT_LOG_DEBUG(...) IGNORE(__VA_ARGS__) -#define DFLT_LOG_INFO(...) MODLOG_INFO(0, __VA_ARGS__) -#define DFLT_LOG_WARN(...) MODLOG_WARN(0, __VA_ARGS__) -#define DFLT_LOG_ERROR(...) MODLOG_ERROR(0, __VA_ARGS__) -#define DFLT_LOG_CRITICAL(...) MODLOG_CRITICAL(0, __VA_ARGS__) -#define DFLT_LOG_DISABLED(...) MODLOG_DISABLED(0, __VA_ARGS__) - -#define MFG_LOG_DEBUG(...) IGNORE(__VA_ARGS__) -#define MFG_LOG_INFO(...) IGNORE(__VA_ARGS__) -#define MFG_LOG_WARN(...) IGNORE(__VA_ARGS__) -#define MFG_LOG_ERROR(...) IGNORE(__VA_ARGS__) -#define MFG_LOG_CRITICAL(...) IGNORE(__VA_ARGS__) -#define MFG_LOG_DISABLED(...) MODLOG_DISABLED(128, __VA_ARGS__) - -#endif diff --git a/porting/examples/linux_blemesh/include/syscfg/syscfg.h b/porting/examples/linux_blemesh/include/syscfg/syscfg.h index a3df8b6ea0..ac89b3ba53 100644 --- a/porting/examples/linux_blemesh/include/syscfg/syscfg.h +++ b/porting/examples/linux_blemesh/include/syscfg/syscfg.h @@ -1,38 +1,52 @@ -/** - * This file was generated by Apache newt version: 1.9.0-dev +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. */ #ifndef H_MYNEWT_SYSCFG_ #define H_MYNEWT_SYSCFG_ -/** - * This macro exists to ensure code includes this header when needed. If code - * checks the existence of a setting directly via ifdef without including this - * header, the setting macro will silently evaluate to 0. In contrast, an - * attempt to use these macros without including this header will result in a - * compiler error. - */ #define MYNEWT_VAL(_name) MYNEWT_VAL_ ## _name #define MYNEWT_VAL_CHOICE(_name, _val) MYNEWT_VAL_ ## _name ## __ ## _val -/*** @apache-mynewt-core/crypto/tinycrypt */ #ifndef MYNEWT_VAL_TINYCRYPT_SYSINIT_STAGE #define MYNEWT_VAL_TINYCRYPT_SYSINIT_STAGE (200) #endif #ifndef MYNEWT_VAL_TINYCRYPT_UECC_RNG_TRNG_DEV_NAME -#define MYNEWT_VAL_TINYCRYPT_UECC_RNG_TRNG_DEV_NAME ("trng") +#define MYNEWT_VAL_TINYCRYPT_UECC_RNG_TRNG_DEV_NAME "trng" #endif #ifndef MYNEWT_VAL_TINYCRYPT_UECC_RNG_USE_TRNG #define MYNEWT_VAL_TINYCRYPT_UECC_RNG_USE_TRNG (0) #endif -/*** @apache-mynewt-core/hw/hal */ +#ifndef MYNEWT_VAL_BSP_SIMULATED +#define MYNEWT_VAL_BSP_SIMULATED (1) +#endif + #ifndef MYNEWT_VAL_HAL_ENABLE_SOFTWARE_BREAKPOINTS #define MYNEWT_VAL_HAL_ENABLE_SOFTWARE_BREAKPOINTS (1) #endif +#ifndef MYNEWT_VAL_HAL_FLASH_MAX_DEVICE_COUNT +#define MYNEWT_VAL_HAL_FLASH_MAX_DEVICE_COUNT (0) +#endif + #ifndef MYNEWT_VAL_HAL_FLASH_VERIFY_BUF_SZ #define MYNEWT_VAL_HAL_FLASH_VERIFY_BUF_SZ (16) #endif @@ -45,16 +59,50 @@ #define MYNEWT_VAL_HAL_FLASH_VERIFY_WRITES (0) #endif +#ifndef MYNEWT_VAL_HAL_SBRK +#define MYNEWT_VAL_HAL_SBRK (1) +#endif + #ifndef MYNEWT_VAL_HAL_SYSTEM_RESET_CB #define MYNEWT_VAL_HAL_SYSTEM_RESET_CB (0) #endif -/*** @apache-mynewt-core/kernel/os */ +#ifndef MYNEWT_VAL_I2C_0 +#define MYNEWT_VAL_I2C_0 (0) +#endif + +#ifndef MYNEWT_VAL_MCU_FLASH_MIN_WRITE_SIZE +#define MYNEWT_VAL_MCU_FLASH_MIN_WRITE_SIZE (1) +#endif + +#ifndef MYNEWT_VAL_MCU_FLASH_STYLE_NORDIC +#define MYNEWT_VAL_MCU_FLASH_STYLE_NORDIC (0) +#endif + +#ifndef MYNEWT_VAL_MCU_FLASH_STYLE_ST +#define MYNEWT_VAL_MCU_FLASH_STYLE_ST (1) +#endif + +#ifndef MYNEWT_VAL_MCU_NATIVE +#define MYNEWT_VAL_MCU_NATIVE (1) +#endif + +#ifndef MYNEWT_VAL_MCU_NATIVE_USE_SIGNALS +#define MYNEWT_VAL_MCU_NATIVE_USE_SIGNALS (1) +#endif + +#ifndef MYNEWT_VAL_MCU_TIMER_POLLER_PRIO +#define MYNEWT_VAL_MCU_TIMER_POLLER_PRIO (0) +#endif + +#ifndef MYNEWT_VAL_MCU_UART_POLLER_PRIO +#define MYNEWT_VAL_MCU_UART_POLLER_PRIO (1) +#endif + #ifndef MYNEWT_VAL_FLOAT_USER #define MYNEWT_VAL_FLOAT_USER (0) #endif -/* Overridden by @apache-mynewt-nimble/porting/targets/linux_blemesh (defined by @apache-mynewt-core/kernel/os) */ #ifndef MYNEWT_VAL_MSYS_1_BLOCK_COUNT #define MYNEWT_VAL_MSYS_1_BLOCK_COUNT (80) #endif @@ -95,6 +143,10 @@ #define MYNEWT_VAL_OS_COREDUMP (0) #endif +#ifndef MYNEWT_VAL_OS_COREDUMP_CB +#define MYNEWT_VAL_OS_COREDUMP_CB (0) +#endif + #ifndef MYNEWT_VAL_OS_CPUTIME_FREQ #define MYNEWT_VAL_OS_CPUTIME_FREQ (1000000) #endif @@ -104,7 +156,7 @@ #endif #ifndef MYNEWT_VAL_OS_CRASH_FILE_LINE -#define MYNEWT_VAL_OS_CRASH_FILE_LINE (0) +#define MYNEWT_VAL_OS_CRASH_FILE_LINE (1) #endif #ifndef MYNEWT_VAL_OS_CRASH_LOG @@ -131,6 +183,10 @@ #define MYNEWT_VAL_OS_DEBUG_MODE (0) #endif +#ifndef MYNEWT_VAL_OS_DEFAULT_IRQ_CB +#define MYNEWT_VAL_OS_DEFAULT_IRQ_CB (0) +#endif + #ifndef MYNEWT_VAL_OS_EVENTQ_DEBUG #define MYNEWT_VAL_OS_EVENTQ_DEBUG (0) #endif @@ -144,7 +200,7 @@ #endif #ifndef MYNEWT_VAL_OS_IDLE_TICKLESS_MS_MIN -#define MYNEWT_VAL_OS_IDLE_TICKLESS_MS_MIN (100) +#define MYNEWT_VAL_OS_IDLE_TICKLESS_MS_MIN (1) #endif #ifndef MYNEWT_VAL_OS_MAIN_STACK_SIZE @@ -211,6 +267,10 @@ #define MYNEWT_VAL_OS_TASK_RUN_TIME_CPUTIME (0) #endif +#ifndef MYNEWT_VAL_OS_TICKS_PER_SEC +#define MYNEWT_VAL_OS_TICKS_PER_SEC (100) +#endif + #ifndef MYNEWT_VAL_OS_TIME_DEBUG #define MYNEWT_VAL_OS_TIME_DEBUG (0) #endif @@ -227,29 +287,56 @@ #define MYNEWT_VAL_WATCHDOG_INTERVAL (30000) #endif -/*** @apache-mynewt-core/sys/console/stub */ +#ifndef MYNEWT_VAL_NATIVE_SOCKETS_MAX +#define MYNEWT_VAL_NATIVE_SOCKETS_MAX (8) +#endif + +#ifndef MYNEWT_VAL_NATIVE_SOCKETS_MAX_UDP +#define MYNEWT_VAL_NATIVE_SOCKETS_MAX_UDP (2048) +#endif + +#ifndef MYNEWT_VAL_NATIVE_SOCKETS_POLL_INTERVAL_MS +#define MYNEWT_VAL_NATIVE_SOCKETS_POLL_INTERVAL_MS (200) +#endif + +#undef MYNEWT_VAL_NATIVE_SOCKETS_POLL_ITVL + +#ifndef MYNEWT_VAL_NATIVE_SOCKETS_PRIO +#define MYNEWT_VAL_NATIVE_SOCKETS_PRIO (2) +#endif + +#ifndef MYNEWT_VAL_NATIVE_SOCKETS_STACK_SZ +#define MYNEWT_VAL_NATIVE_SOCKETS_STACK_SZ (4096) +#endif + +#ifndef MYNEWT_VAL_NATIVE_SOCKETS_SYSINIT_STAGE +#define MYNEWT_VAL_NATIVE_SOCKETS_SYSINIT_STAGE (200) +#endif + #ifndef MYNEWT_VAL_CONSOLE_UART_BAUD #define MYNEWT_VAL_CONSOLE_UART_BAUD (115200) #endif #ifndef MYNEWT_VAL_CONSOLE_UART_DEV -#define MYNEWT_VAL_CONSOLE_UART_DEV ("uart0") +#define MYNEWT_VAL_CONSOLE_UART_DEV "uart0" #endif #ifndef MYNEWT_VAL_CONSOLE_UART_FLOW_CONTROL #define MYNEWT_VAL_CONSOLE_UART_FLOW_CONTROL (UART_FLOW_CTL_NONE) #endif -/*** @apache-mynewt-core/sys/flash_map */ #ifndef MYNEWT_VAL_FLASH_MAP_MAX_AREAS #define MYNEWT_VAL_FLASH_MAP_MAX_AREAS (10) #endif +#ifndef MYNEWT_VAL_FLASH_MAP_SUPPORT_MFG +#define MYNEWT_VAL_FLASH_MAP_SUPPORT_MFG (0) +#endif + #ifndef MYNEWT_VAL_FLASH_MAP_SYSINIT_STAGE -#define MYNEWT_VAL_FLASH_MAP_SYSINIT_STAGE (2) +#define MYNEWT_VAL_FLASH_MAP_SYSINIT_STAGE (9) #endif -/*** @apache-mynewt-core/sys/log/common */ #ifndef MYNEWT_VAL_DFLT_LOG_LVL #define MYNEWT_VAL_DFLT_LOG_LVL (1) #endif @@ -262,7 +349,6 @@ #define MYNEWT_VAL_LOG_GLOBAL_IDX (1) #endif -/*** @apache-mynewt-core/sys/log/modlog */ #ifndef MYNEWT_VAL_MODLOG_CONSOLE_DFLT #define MYNEWT_VAL_MODLOG_CONSOLE_DFLT (1) #endif @@ -283,7 +369,6 @@ #define MYNEWT_VAL_MODLOG_SYSINIT_STAGE (100) #endif -/*** @apache-mynewt-core/sys/log/stub */ #ifndef MYNEWT_VAL_LOG_CONSOLE #define MYNEWT_VAL_LOG_CONSOLE (1) #endif @@ -296,34 +381,14 @@ #define MYNEWT_VAL_LOG_FCB_SLOT1 (0) #endif -/* Overridden by @apache-mynewt-nimble/porting/targets/linux_blemesh (defined by @apache-mynewt-core/sys/log/stub) */ #ifndef MYNEWT_VAL_LOG_LEVEL #define MYNEWT_VAL_LOG_LEVEL (0) #endif -/*** @apache-mynewt-core/sys/mfg */ -#ifndef MYNEWT_VAL_MFG_LOG_LVL -#define MYNEWT_VAL_MFG_LOG_LVL (15) -#endif - -#ifndef MYNEWT_VAL_MFG_LOG_MODULE -#define MYNEWT_VAL_MFG_LOG_MODULE (128) -#endif - -#ifndef MYNEWT_VAL_MFG_MAX_MMRS -#define MYNEWT_VAL_MFG_MAX_MMRS (2) -#endif - -#ifndef MYNEWT_VAL_MFG_SYSINIT_STAGE -#define MYNEWT_VAL_MFG_SYSINIT_STAGE (100) -#endif - -/*** @apache-mynewt-core/sys/sys */ #ifndef MYNEWT_VAL_DEBUG_PANIC_ENABLED #define MYNEWT_VAL_DEBUG_PANIC_ENABLED (1) #endif -/*** @apache-mynewt-core/sys/sysdown */ #ifndef MYNEWT_VAL_SYSDOWN_CONSTRAIN_DOWN #define MYNEWT_VAL_SYSDOWN_CONSTRAIN_DOWN (1) #endif @@ -340,25 +405,30 @@ #define MYNEWT_VAL_SYSDOWN_TIMEOUT_MS (10000) #endif -/*** @apache-mynewt-core/sys/sysinit */ #ifndef MYNEWT_VAL_SYSINIT_CONSTRAIN_INIT #define MYNEWT_VAL_SYSINIT_CONSTRAIN_INIT (1) #endif #ifndef MYNEWT_VAL_SYSINIT_PANIC_FILE_LINE -#define MYNEWT_VAL_SYSINIT_PANIC_FILE_LINE (0) +#define MYNEWT_VAL_SYSINIT_PANIC_FILE_LINE (1) #endif #ifndef MYNEWT_VAL_SYSINIT_PANIC_MESSAGE -#define MYNEWT_VAL_SYSINIT_PANIC_MESSAGE (0) +#define MYNEWT_VAL_SYSINIT_PANIC_MESSAGE (1) #endif -/*** @apache-mynewt-core/util/rwlock */ #ifndef MYNEWT_VAL_RWLOCK_DEBUG #define MYNEWT_VAL_RWLOCK_DEBUG (0) #endif -/*** @apache-mynewt-nimble/nimble */ +#ifndef MYNEWT_VAL_BLE_CHANNEL_SOUNDING +#define MYNEWT_VAL_BLE_CHANNEL_SOUNDING (0) +#endif + +#ifndef MYNEWT_VAL_BLE_CONN_SUBRATING +#define MYNEWT_VAL_BLE_CONN_SUBRATING (0) +#endif + #ifndef MYNEWT_VAL_BLE_EXT_ADV #define MYNEWT_VAL_BLE_EXT_ADV (0) #endif @@ -367,10 +437,26 @@ #define MYNEWT_VAL_BLE_EXT_ADV_MAX_SIZE (31) #endif +#ifndef MYNEWT_VAL_BLE_HCI_VS +#define MYNEWT_VAL_BLE_HCI_VS (0) +#endif + +#ifndef MYNEWT_VAL_BLE_HCI_VS_OCF_OFFSET +#define MYNEWT_VAL_BLE_HCI_VS_OCF_OFFSET (0) +#endif + #ifndef MYNEWT_VAL_BLE_ISO #define MYNEWT_VAL_BLE_ISO (0) #endif +#ifndef MYNEWT_VAL_BLE_ISO_BROADCAST_SINK +#define MYNEWT_VAL_BLE_ISO_BROADCAST_SINK (0) +#endif + +#ifndef MYNEWT_VAL_BLE_ISO_BROADCAST_SOURCE +#define MYNEWT_VAL_BLE_ISO_BROADCAST_SOURCE (0) +#endif + #ifndef MYNEWT_VAL_BLE_ISO_TEST #define MYNEWT_VAL_BLE_ISO_TEST (0) #endif @@ -391,10 +477,26 @@ #define MYNEWT_VAL_BLE_PERIODIC_ADV (0) #endif +#ifndef MYNEWT_VAL_BLE_PERIODIC_ADV_SYNC_BIGINFO_REPORTS +#define MYNEWT_VAL_BLE_PERIODIC_ADV_SYNC_BIGINFO_REPORTS (0) +#endif + #ifndef MYNEWT_VAL_BLE_PERIODIC_ADV_SYNC_TRANSFER #define MYNEWT_VAL_BLE_PERIODIC_ADV_SYNC_TRANSFER (0) #endif +#ifndef MYNEWT_VAL_BLE_PHY_2M +#define MYNEWT_VAL_BLE_PHY_2M (0) +#endif + +#ifndef MYNEWT_VAL_BLE_PHY_CODED +#define MYNEWT_VAL_BLE_PHY_CODED (0) +#endif + +#ifndef MYNEWT_VAL_BLE_POWER_CONTROL +#define MYNEWT_VAL_BLE_POWER_CONTROL (0) +#endif + #ifndef MYNEWT_VAL_BLE_ROLE_BROADCASTER #define MYNEWT_VAL_BLE_ROLE_BROADCASTER (1) #endif @@ -419,7 +521,6 @@ #define MYNEWT_VAL_BLE_WHITELIST (1) #endif -/*** @apache-mynewt-nimble/nimble/host */ #ifndef MYNEWT_VAL_BLE_ATT_PREFERRED_MTU #define MYNEWT_VAL_BLE_ATT_PREFERRED_MTU (256) #endif @@ -444,6 +545,10 @@ #define MYNEWT_VAL_BLE_ATT_SVR_NOTIFY (1) #endif +#ifndef MYNEWT_VAL_BLE_ATT_SVR_NOTIFY_MULTI +#define MYNEWT_VAL_BLE_ATT_SVR_NOTIFY_MULTI (MYNEWT_VAL_BLE_ATT_SVR_NOTIFY && (MYNEWT_VAL_BLE_VERSION >= 52)) +#endif + #ifndef MYNEWT_VAL_BLE_ATT_SVR_QUEUED_WRITE #define MYNEWT_VAL_BLE_ATT_SVR_QUEUED_WRITE (1) #endif @@ -484,6 +589,26 @@ #define MYNEWT_VAL_BLE_ATT_SVR_WRITE_NO_RSP (1) #endif +#ifndef MYNEWT_VAL_BLE_AUDIO +#define MYNEWT_VAL_BLE_AUDIO (0) +#endif + +#ifndef MYNEWT_VAL_BLE_EATT_CHAN_NUM +#define MYNEWT_VAL_BLE_EATT_CHAN_NUM (0) +#endif + +#ifndef MYNEWT_VAL_BLE_EATT_LOG_LVL +#define MYNEWT_VAL_BLE_EATT_LOG_LVL (1) +#endif + +#ifndef MYNEWT_VAL_BLE_EATT_LOG_MOD +#define MYNEWT_VAL_BLE_EATT_LOG_MOD (27) +#endif + +#ifndef MYNEWT_VAL_BLE_EATT_MTU +#define MYNEWT_VAL_BLE_EATT_MTU (128) +#endif + #ifndef MYNEWT_VAL_BLE_GAP_MAX_PENDING_CONN_PARAM_UPDATE #define MYNEWT_VAL_BLE_GAP_MAX_PENDING_CONN_PARAM_UPDATE (1) #endif @@ -524,6 +649,10 @@ #define MYNEWT_VAL_BLE_GATT_NOTIFY (1) #endif +#ifndef MYNEWT_VAL_BLE_GATT_NOTIFY_MULTIPLE +#define MYNEWT_VAL_BLE_GATT_NOTIFY_MULTIPLE ((MYNEWT_VAL_BLE_VERSION >= 52)) +#endif + #ifndef MYNEWT_VAL_BLE_GATT_READ #define MYNEWT_VAL_BLE_GATT_READ (MYNEWT_VAL_BLE_ROLE_CENTRAL) #endif @@ -540,6 +669,10 @@ #define MYNEWT_VAL_BLE_GATT_READ_MULT (MYNEWT_VAL_BLE_ROLE_CENTRAL) #endif +#ifndef MYNEWT_VAL_BLE_GATT_READ_MULT_VAR +#define MYNEWT_VAL_BLE_GATT_READ_MULT_VAR (MYNEWT_VAL_BLE_ROLE_CENTRAL && (MYNEWT_VAL_BLE_VERSION >= 52)) +#endif + #ifndef MYNEWT_VAL_BLE_GATT_READ_UUID #define MYNEWT_VAL_BLE_GATT_READ_UUID (MYNEWT_VAL_BLE_ROLE_CENTRAL) #endif @@ -584,6 +717,10 @@ #define MYNEWT_VAL_BLE_HS_DEBUG (0) #endif +#ifndef MYNEWT_VAL_BLE_HS_EXT_ADV_LEGACY_INSTANCE +#define MYNEWT_VAL_BLE_HS_EXT_ADV_LEGACY_INSTANCE (0) +#endif + #ifndef MYNEWT_VAL_BLE_HS_FLOW_CTRL #define MYNEWT_VAL_BLE_HS_FLOW_CTRL (0) #endif @@ -600,6 +737,10 @@ #define MYNEWT_VAL_BLE_HS_FLOW_CTRL_TX_ON_DISCONNECT (0) #endif +#ifndef MYNEWT_VAL_BLE_HS_GAP_UNHANDLED_HCI_EVENT +#define MYNEWT_VAL_BLE_HS_GAP_UNHANDLED_HCI_EVENT (0) +#endif + #ifndef MYNEWT_VAL_BLE_HS_LOG_LVL #define MYNEWT_VAL_BLE_HS_LOG_LVL (1) #endif @@ -628,6 +769,14 @@ #define MYNEWT_VAL_BLE_HS_SYSINIT_STAGE (200) #endif +#ifndef MYNEWT_VAL_BLE_ISO_MAX_BIGS +#define MYNEWT_VAL_BLE_ISO_MAX_BIGS (MYNEWT_VAL_BLE_MULTI_ADV_INSTANCES) +#endif + +#ifndef MYNEWT_VAL_BLE_ISO_MAX_BISES +#define MYNEWT_VAL_BLE_ISO_MAX_BISES (4) +#endif + #ifndef MYNEWT_VAL_BLE_L2CAP_COC_MAX_NUM #define MYNEWT_VAL_BLE_L2CAP_COC_MAX_NUM (0) #endif @@ -636,6 +785,10 @@ #define MYNEWT_VAL_BLE_L2CAP_COC_MPS (MYNEWT_VAL_MSYS_1_BLOCK_SIZE-8) #endif +#ifndef MYNEWT_VAL_BLE_L2CAP_COC_SDU_BUFF_COUNT +#define MYNEWT_VAL_BLE_L2CAP_COC_SDU_BUFF_COUNT (1) +#endif + #ifndef MYNEWT_VAL_BLE_L2CAP_ENHANCED_COC #define MYNEWT_VAL_BLE_L2CAP_ENHANCED_COC (0) #endif @@ -656,47 +809,10 @@ #define MYNEWT_VAL_BLE_L2CAP_SIG_MAX_PROCS (1) #endif -/* Overridden by @apache-mynewt-nimble/porting/targets/linux_blemesh (defined by @apache-mynewt-nimble/nimble/host) */ #ifndef MYNEWT_VAL_BLE_MESH #define MYNEWT_VAL_BLE_MESH (1) #endif -#ifndef MYNEWT_VAL_BLE_MONITOR_CONSOLE_BUFFER_SIZE -#define MYNEWT_VAL_BLE_MONITOR_CONSOLE_BUFFER_SIZE (128) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_RTT -#define MYNEWT_VAL_BLE_MONITOR_RTT (0) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFERED -#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFERED (1) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_NAME -#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_NAME ("btmonitor") -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_SIZE -#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_SIZE (256) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_UART -#define MYNEWT_VAL_BLE_MONITOR_UART (0) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_UART_BAUDRATE -#define MYNEWT_VAL_BLE_MONITOR_UART_BAUDRATE (1000000) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_UART_BUFFER_SIZE -#define MYNEWT_VAL_BLE_MONITOR_UART_BUFFER_SIZE (64) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_UART_DEV -#define MYNEWT_VAL_BLE_MONITOR_UART_DEV ("uart0") -#endif - #ifndef MYNEWT_VAL_BLE_RPA_TIMEOUT #define MYNEWT_VAL_BLE_RPA_TIMEOUT (300) #endif @@ -705,6 +821,10 @@ #define MYNEWT_VAL_BLE_SM_BONDING (0) #endif +#ifndef MYNEWT_VAL_BLE_SM_CSIS_SIRK +#define MYNEWT_VAL_BLE_SM_CSIS_SIRK (0) +#endif + #ifndef MYNEWT_VAL_BLE_SM_IO_CAP #define MYNEWT_VAL_BLE_SM_IO_CAP (BLE_HS_IO_NO_INPUT_OUTPUT) #endif @@ -717,6 +837,10 @@ #define MYNEWT_VAL_BLE_SM_LEGACY (1) #endif +#ifndef MYNEWT_VAL_BLE_SM_LVL +#define MYNEWT_VAL_BLE_SM_LVL (0) +#endif + #ifndef MYNEWT_VAL_BLE_SM_MAX_PROCS #define MYNEWT_VAL_BLE_SM_MAX_PROCS (1) #endif @@ -733,23 +857,18 @@ #define MYNEWT_VAL_BLE_SM_OUR_KEY_DIST (0) #endif -/* Overridden by @apache-mynewt-nimble/nimble/host (defined by @apache-mynewt-nimble/nimble/host) */ #ifndef MYNEWT_VAL_BLE_SM_SC #define MYNEWT_VAL_BLE_SM_SC (1) #endif -#ifndef MYNEWT_VAL_BLE_SM_SC_ONLY -#define MYNEWT_VAL_BLE_SM_SC_ONLY (0) -#endif - -#ifndef MYNEWT_VAL_BLE_SM_SC_LVL -#define MYNEWT_VAL_BLE_SM_SC_LVL (0) -#endif - #ifndef MYNEWT_VAL_BLE_SM_SC_DEBUG_KEYS #define MYNEWT_VAL_BLE_SM_SC_DEBUG_KEYS (0) #endif +#ifndef MYNEWT_VAL_BLE_SM_SC_ONLY +#define MYNEWT_VAL_BLE_SM_SC_ONLY (0) +#endif + #ifndef MYNEWT_VAL_BLE_SM_THEIR_KEY_DIST #define MYNEWT_VAL_BLE_SM_THEIR_KEY_DIST (0) #endif @@ -762,7 +881,10 @@ #define MYNEWT_VAL_BLE_STORE_MAX_CCCDS (8) #endif -/*** @apache-mynewt-nimble/nimble/host/mesh */ +#ifndef MYNEWT_VAL_BLE_MESH_ACCESS_LAYER_MSG +#define MYNEWT_VAL_BLE_MESH_ACCESS_LAYER_MSG (1) +#endif + #ifndef MYNEWT_VAL_BLE_MESH_ACCESS_LOG_LVL #define MYNEWT_VAL_BLE_MESH_ACCESS_LOG_LVL (1) #endif @@ -771,11 +893,22 @@ #define MYNEWT_VAL_BLE_MESH_ACCESS_LOG_MOD (10) #endif -/* Overridden by @apache-mynewt-nimble/porting/targets/linux_blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ +#ifndef MYNEWT_VAL_BLE_MESH_ADV +#define MYNEWT_VAL_BLE_MESH_ADV (1) +#endif + #ifndef MYNEWT_VAL_BLE_MESH_ADV_BUF_COUNT #define MYNEWT_VAL_BLE_MESH_ADV_BUF_COUNT (20) #endif +#ifndef MYNEWT_VAL_BLE_MESH_ADV_EXT +#define MYNEWT_VAL_BLE_MESH_ADV_EXT (0) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_ADV_LEGACY +#define MYNEWT_VAL_BLE_MESH_ADV_LEGACY (1) +#endif + #ifndef MYNEWT_VAL_BLE_MESH_ADV_LOG_LVL #define MYNEWT_VAL_BLE_MESH_ADV_LOG_LVL (1) #endif @@ -784,15 +917,22 @@ #define MYNEWT_VAL_BLE_MESH_ADV_LOG_MOD (11) #endif +#ifndef MYNEWT_VAL_BLE_MESH_ADV_STACK_SIZE +#define MYNEWT_VAL_BLE_MESH_ADV_STACK_SIZE (768) +#endif + #ifndef MYNEWT_VAL_BLE_MESH_ADV_TASK_PRIO #define MYNEWT_VAL_BLE_MESH_ADV_TASK_PRIO (9) #endif -/* Overridden by @apache-mynewt-nimble/porting/targets/linux_blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ #ifndef MYNEWT_VAL_BLE_MESH_APP_KEY_COUNT #define MYNEWT_VAL_BLE_MESH_APP_KEY_COUNT (4) #endif +#ifndef MYNEWT_VAL_BLE_MESH_BEACON_ENABLED +#define MYNEWT_VAL_BLE_MESH_BEACON_ENABLED (1) +#endif + #ifndef MYNEWT_VAL_BLE_MESH_BEACON_LOG_LVL #define MYNEWT_VAL_BLE_MESH_BEACON_LOG_LVL (1) #endif @@ -801,7 +941,22 @@ #define MYNEWT_VAL_BLE_MESH_BEACON_LOG_MOD (12) #endif -/* Overridden by @apache-mynewt-nimble/porting/targets/linux_blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ +#ifndef MYNEWT_VAL_BLE_MESH_CDB +#define MYNEWT_VAL_BLE_MESH_CDB (0) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_CDB_APP_KEY_COUNT +#define MYNEWT_VAL_BLE_MESH_CDB_APP_KEY_COUNT (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_CDB_NODE_COUNT +#define MYNEWT_VAL_BLE_MESH_CDB_NODE_COUNT (8) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_CDB_SUBNET_COUNT +#define MYNEWT_VAL_BLE_MESH_CDB_SUBNET_COUNT (1) +#endif + #ifndef MYNEWT_VAL_BLE_MESH_CFG_CLI #define MYNEWT_VAL_BLE_MESH_CFG_CLI (1) #endif @@ -818,19 +973,38 @@ #define MYNEWT_VAL_BLE_MESH_CRYPTO_LOG_MOD (13) #endif +#ifndef MYNEWT_VAL_BLE_MESH_DEBUG_CDB +#define MYNEWT_VAL_BLE_MESH_DEBUG_CDB (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_DEBUG_CFG +#define MYNEWT_VAL_BLE_MESH_DEBUG_CFG (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_DEBUG_USE_ID_ADDR +#define MYNEWT_VAL_BLE_MESH_DEBUG_USE_ID_ADDR (0) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_DEFAULT_TTL +#define MYNEWT_VAL_BLE_MESH_DEFAULT_TTL (7) +#endif + #ifndef MYNEWT_VAL_BLE_MESH_DEVICE_NAME -#define MYNEWT_VAL_BLE_MESH_DEVICE_NAME ("nimble-mesh-node") +#define MYNEWT_VAL_BLE_MESH_DEVICE_NAME "nimble-mesh-node" #endif #ifndef MYNEWT_VAL_BLE_MESH_DEV_UUID #define MYNEWT_VAL_BLE_MESH_DEV_UUID (((uint8_t[16]){0x11, 0x22, 0})) #endif -/* Overridden by @apache-mynewt-nimble/porting/targets/linux_blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ #ifndef MYNEWT_VAL_BLE_MESH_FRIEND #define MYNEWT_VAL_BLE_MESH_FRIEND (1) #endif +#ifndef MYNEWT_VAL_BLE_MESH_FRIEND_ENABLED +#define MYNEWT_VAL_BLE_MESH_FRIEND_ENABLED (1) +#endif + #ifndef MYNEWT_VAL_BLE_MESH_FRIEND_LOG_LVL #define MYNEWT_VAL_BLE_MESH_FRIEND_LOG_LVL (1) #endif @@ -859,25 +1033,46 @@ #define MYNEWT_VAL_BLE_MESH_FRIEND_SUB_LIST_SIZE (3) #endif -/* Overridden by @apache-mynewt-nimble/porting/targets/linux_blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ +#ifndef MYNEWT_VAL_BLE_MESH_GATT +#define MYNEWT_VAL_BLE_MESH_GATT (1) +#endif + #ifndef MYNEWT_VAL_BLE_MESH_GATT_PROXY #define MYNEWT_VAL_BLE_MESH_GATT_PROXY (1) #endif +#ifndef MYNEWT_VAL_BLE_MESH_GATT_PROXY_ENABLED +#define MYNEWT_VAL_BLE_MESH_GATT_PROXY_ENABLED (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_GATT_SERVER +#define MYNEWT_VAL_BLE_MESH_GATT_SERVER (1) +#endif + #ifndef MYNEWT_VAL_BLE_MESH_HEALTH_CLI #define MYNEWT_VAL_BLE_MESH_HEALTH_CLI (0) #endif +#ifndef MYNEWT_VAL_BLE_MESH_HEARTBEAT_LOG_LVL +#define MYNEWT_VAL_BLE_MESH_HEARTBEAT_LOG_LVL (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_HEARTBEAT_LOG_MOD +#define MYNEWT_VAL_BLE_MESH_HEARTBEAT_LOG_MOD (26) +#endif + #ifndef MYNEWT_VAL_BLE_MESH_IVU_DIVIDER #define MYNEWT_VAL_BLE_MESH_IVU_DIVIDER (4) #endif -/* Overridden by @apache-mynewt-nimble/porting/targets/linux_blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ +#ifndef MYNEWT_VAL_BLE_MESH_IV_UPDATE_SEQ_LIMIT +#define MYNEWT_VAL_BLE_MESH_IV_UPDATE_SEQ_LIMIT (0x800000) +#endif + #ifndef MYNEWT_VAL_BLE_MESH_IV_UPDATE_TEST #define MYNEWT_VAL_BLE_MESH_IV_UPDATE_TEST (1) #endif -/* Overridden by @apache-mynewt-nimble/porting/targets/linux_blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ #ifndef MYNEWT_VAL_BLE_MESH_LABEL_COUNT #define MYNEWT_VAL_BLE_MESH_LABEL_COUNT (2) #endif @@ -890,7 +1085,10 @@ #define MYNEWT_VAL_BLE_MESH_LOG_MOD (9) #endif -/* Overridden by @apache-mynewt-nimble/porting/targets/linux_blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ +#ifndef MYNEWT_VAL_BLE_MESH_LOOPBACK_BUFS +#define MYNEWT_VAL_BLE_MESH_LOOPBACK_BUFS (3) +#endif + #ifndef MYNEWT_VAL_BLE_MESH_LOW_POWER #define MYNEWT_VAL_BLE_MESH_LOW_POWER (1) #endif @@ -903,7 +1101,6 @@ #define MYNEWT_VAL_BLE_MESH_LOW_POWER_LOG_MOD (15) #endif -/* Overridden by @apache-mynewt-nimble/porting/targets/linux_blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ #ifndef MYNEWT_VAL_BLE_MESH_LPN_AUTO #define MYNEWT_VAL_BLE_MESH_LPN_AUTO (0) #endif @@ -920,10 +1117,6 @@ #define MYNEWT_VAL_BLE_MESH_LPN_GROUPS (10) #endif -#ifndef MYNEWT_VAL_BLE_MESH_LPN_SUB_ALL_NODES_ADDR -#define MYNEWT_VAL_BLE_MESH_LPN_SUB_ALL_NODES_ADDR (1) -#endif - #ifndef MYNEWT_VAL_BLE_MESH_LPN_INIT_POLL_TIMEOUT #define MYNEWT_VAL_BLE_MESH_LPN_INIT_POLL_TIMEOUT (MYNEWT_VAL_BLE_MESH_LPN_POLL_TIMEOUT) #endif @@ -956,11 +1149,14 @@ #define MYNEWT_VAL_BLE_MESH_LPN_SCAN_LATENCY (10) #endif +#ifndef MYNEWT_VAL_BLE_MESH_LPN_SUB_ALL_NODES_ADDR +#define MYNEWT_VAL_BLE_MESH_LPN_SUB_ALL_NODES_ADDR (0) +#endif + #ifndef MYNEWT_VAL_BLE_MESH_MODEL_EXTENSIONS #define MYNEWT_VAL_BLE_MESH_MODEL_EXTENSIONS (0) #endif -/* Overridden by @apache-mynewt-nimble/porting/targets/linux_blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ #ifndef MYNEWT_VAL_BLE_MESH_MODEL_GROUP_COUNT #define MYNEWT_VAL_BLE_MESH_MODEL_GROUP_COUNT (2) #endif @@ -977,10 +1173,34 @@ #define MYNEWT_VAL_BLE_MESH_MODEL_LOG_MOD (16) #endif +#ifndef MYNEWT_VAL_BLE_MESH_MODEL_VND_MSG_CID_FORCE +#define MYNEWT_VAL_BLE_MESH_MODEL_VND_MSG_CID_FORCE (1) +#endif + #ifndef MYNEWT_VAL_BLE_MESH_MSG_CACHE_SIZE #define MYNEWT_VAL_BLE_MESH_MSG_CACHE_SIZE (10) #endif +#ifndef MYNEWT_VAL_BLE_MESH_NETWORK_TRANSMIT_COUNT +#define MYNEWT_VAL_BLE_MESH_NETWORK_TRANSMIT_COUNT (2) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_NETWORK_TRANSMIT_INTERVAL +#define MYNEWT_VAL_BLE_MESH_NETWORK_TRANSMIT_INTERVAL (20) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_NET_BUF_USER_DATA_SIZE +#define MYNEWT_VAL_BLE_MESH_NET_BUF_USER_DATA_SIZE (4) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_NET_KEYS_LOG_LVL +#define MYNEWT_VAL_BLE_MESH_NET_KEYS_LOG_LVL (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_NET_KEYS_LOG_MOD +#define MYNEWT_VAL_BLE_MESH_NET_KEYS_LOG_MOD (23) +#endif + #ifndef MYNEWT_VAL_BLE_MESH_NET_LOG_LVL #define MYNEWT_VAL_BLE_MESH_NET_LOG_LVL (1) #endif @@ -989,10 +1209,6 @@ #define MYNEWT_VAL_BLE_MESH_NET_LOG_MOD (17) #endif -#ifndef MYNEWT_VAL_BLE_MESH_NODE_COUNT -#define MYNEWT_VAL_BLE_MESH_NODE_COUNT (1) -#endif - #ifndef MYNEWT_VAL_BLE_MESH_NODE_ID_TIMEOUT #define MYNEWT_VAL_BLE_MESH_NODE_ID_TIMEOUT (60) #endif @@ -1013,39 +1229,48 @@ #define MYNEWT_VAL_BLE_MESH_OOB_OUTPUT_SIZE (4) #endif -/* Overridden by @apache-mynewt-nimble/porting/targets/linux_blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ #ifndef MYNEWT_VAL_BLE_MESH_PB_ADV #define MYNEWT_VAL_BLE_MESH_PB_ADV (1) #endif -/* Overridden by @apache-mynewt-nimble/porting/targets/linux_blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ +#ifndef MYNEWT_VAL_BLE_MESH_PB_ADV_RETRANS_TIMEOUT +#define MYNEWT_VAL_BLE_MESH_PB_ADV_RETRANS_TIMEOUT (500) +#endif + #ifndef MYNEWT_VAL_BLE_MESH_PB_GATT #define MYNEWT_VAL_BLE_MESH_PB_GATT (1) #endif -/* Overridden by @apache-mynewt-nimble/porting/targets/linux_blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ +#ifndef MYNEWT_VAL_BLE_MESH_PB_GATT_USE_DEVICE_NAME +#define MYNEWT_VAL_BLE_MESH_PB_GATT_USE_DEVICE_NAME (1) +#endif + #ifndef MYNEWT_VAL_BLE_MESH_PROV #define MYNEWT_VAL_BLE_MESH_PROV (1) #endif #ifndef MYNEWT_VAL_BLE_MESH_PROVISIONER -#define MYNEWT_VAL_BLE_MESH_PROVISIONER (0) +#define MYNEWT_VAL_BLE_MESH_PROVISIONER (1) #endif -#ifndef MYNEWT_VAL_BLE_MESH_CDB -#define MYNEWT_VAL_BLE_MESH_CDB (0) +#ifndef MYNEWT_VAL_BLE_MESH_PROVISIONER_LOG_LVL +#define MYNEWT_VAL_BLE_MESH_PROVISIONER_LOG_LVL (1) #endif -#ifndef MYNEWT_VAL_BLE_MESH_CDB_SUBNET_COUNT -#define MYNEWT_VAL_BLE_MESH_CDB_SUBNET_COUNT (1) +#ifndef MYNEWT_VAL_BLE_MESH_PROVISIONER_LOG_MOD +#define MYNEWT_VAL_BLE_MESH_PROVISIONER_LOG_MOD (25) #endif -#ifndef MYNEWT_VAL_BLE_MESH_CDB_NODE_COUNT -#define MYNEWT_VAL_BLE_MESH_CDB_NODE_COUNT (1) +#ifndef MYNEWT_VAL_BLE_MESH_PROV_DEVICE +#define MYNEWT_VAL_BLE_MESH_PROV_DEVICE (1) #endif -#ifndef MYNEWT_VAL_BLE_MESH_CDB_APP_KEY_COUNT -#define MYNEWT_VAL_BLE_MESH_CDB_APP_KEY_COUNT (1) +#ifndef MYNEWT_VAL_BLE_MESH_PROV_DEVICE_LOG_LVL +#define MYNEWT_VAL_BLE_MESH_PROV_DEVICE_LOG_LVL (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_PROV_DEVICE_LOG_MOD +#define MYNEWT_VAL_BLE_MESH_PROV_DEVICE_LOG_MOD (24) #endif #ifndef MYNEWT_VAL_BLE_MESH_PROV_LOG_LVL @@ -1056,13 +1281,16 @@ #define MYNEWT_VAL_BLE_MESH_PROV_LOG_MOD (18) #endif -/* Overridden by @apache-mynewt-nimble/nimble/host/mesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ +#ifndef MYNEWT_VAL_BLE_MESH_PROV_OOB_PUBLIC_KEY +#define MYNEWT_VAL_BLE_MESH_PROV_OOB_PUBLIC_KEY (0) +#endif + #ifndef MYNEWT_VAL_BLE_MESH_PROXY #define MYNEWT_VAL_BLE_MESH_PROXY (1) #endif #ifndef MYNEWT_VAL_BLE_MESH_PROXY_FILTER_SIZE -#define MYNEWT_VAL_BLE_MESH_PROXY_FILTER_SIZE (1) +#define MYNEWT_VAL_BLE_MESH_PROXY_FILTER_SIZE (3) #endif #ifndef MYNEWT_VAL_BLE_MESH_PROXY_LOG_LVL @@ -1073,17 +1301,40 @@ #define MYNEWT_VAL_BLE_MESH_PROXY_LOG_MOD (19) #endif -/* Overridden by @apache-mynewt-nimble/porting/targets/linux_blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ +#ifndef MYNEWT_VAL_BLE_MESH_PROXY_MSG_LEN +#define MYNEWT_VAL_BLE_MESH_PROXY_MSG_LEN (66) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_PROXY_USE_DEVICE_NAME +#define MYNEWT_VAL_BLE_MESH_PROXY_USE_DEVICE_NAME (0) +#endif + #ifndef MYNEWT_VAL_BLE_MESH_RELAY #define MYNEWT_VAL_BLE_MESH_RELAY (1) #endif -#ifndef MYNEWT_VAL_BLE_MESH_RPL_STORE_TIMEOUT -#define MYNEWT_VAL_BLE_MESH_RPL_STORE_TIMEOUT (5) +#ifndef MYNEWT_VAL_BLE_MESH_RELAY_ENABLED +#define MYNEWT_VAL_BLE_MESH_RELAY_ENABLED (1) #endif -#ifndef MYNEWT_VAL_BLE_MESH_SEG_BUFS -#define MYNEWT_VAL_BLE_MESH_SEG_BUFS (72) +#ifndef MYNEWT_VAL_BLE_MESH_RELAY_RETRANSMIT_COUNT +#define MYNEWT_VAL_BLE_MESH_RELAY_RETRANSMIT_COUNT (2) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_RELAY_RETRANSMIT_INTERVAL +#define MYNEWT_VAL_BLE_MESH_RELAY_RETRANSMIT_INTERVAL (20) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_RPL_LOG_LVL +#define MYNEWT_VAL_BLE_MESH_RPL_LOG_LVL (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_RPL_LOG_MOD +#define MYNEWT_VAL_BLE_MESH_RPL_LOG_MOD (22) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_RPL_STORE_TIMEOUT +#define MYNEWT_VAL_BLE_MESH_RPL_STORE_TIMEOUT (5) #endif #ifndef MYNEWT_VAL_BLE_MESH_RX_SEG_MAX @@ -1094,6 +1345,10 @@ #define MYNEWT_VAL_BLE_MESH_RX_SEG_MSG_COUNT (2) #endif +#ifndef MYNEWT_VAL_BLE_MESH_SEG_BUFS +#define MYNEWT_VAL_BLE_MESH_SEG_BUFS (64) +#endif + #ifndef MYNEWT_VAL_BLE_MESH_SEG_RETRANSMIT_ATTEMPTS #define MYNEWT_VAL_BLE_MESH_SEG_RETRANSMIT_ATTEMPTS (4) #endif @@ -1102,7 +1357,6 @@ #define MYNEWT_VAL_BLE_MESH_SEQ_STORE_RATE (128) #endif -/* Overridden by @apache-mynewt-nimble/porting/targets/linux_blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ #ifndef MYNEWT_VAL_BLE_MESH_SETTINGS #define MYNEWT_VAL_BLE_MESH_SETTINGS (0) #endif @@ -1115,7 +1369,6 @@ #define MYNEWT_VAL_BLE_MESH_SETTINGS_LOG_MOD (20) #endif -/* Overridden by @apache-mynewt-nimble/porting/targets/linux_blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ #ifndef MYNEWT_VAL_BLE_MESH_SHELL #define MYNEWT_VAL_BLE_MESH_SHELL (0) #endif @@ -1128,7 +1381,6 @@ #define MYNEWT_VAL_BLE_MESH_STORE_TIMEOUT (2) #endif -/* Overridden by @apache-mynewt-nimble/porting/targets/linux_blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ #ifndef MYNEWT_VAL_BLE_MESH_SUBNET_COUNT #define MYNEWT_VAL_BLE_MESH_SUBNET_COUNT (2) #endif @@ -1141,7 +1393,6 @@ #define MYNEWT_VAL_BLE_MESH_SYSINIT_STAGE_SHELL (1000) #endif -/* Overridden by @apache-mynewt-nimble/porting/targets/linux_blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ #ifndef MYNEWT_VAL_BLE_MESH_TESTING #define MYNEWT_VAL_BLE_MESH_TESTING (1) #endif @@ -1154,89 +1405,30 @@ #define MYNEWT_VAL_BLE_MESH_TRANS_LOG_MOD (21) #endif -/* Overridden by @apache-mynewt-nimble/porting/targets/linux_blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ -#ifndef MYNEWT_VAL_BLE_MESH_RPL_LOG_LVL -#define MYNEWT_VAL_BLE_MESH_RPL_LOG_LVL (1) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_RPL_LOG_MOD -#define MYNEWT_VAL_BLE_MESH_RPL_LOG_MOD (22) -#endif - -/* Overridden by @apache-mynewt-nimble/porting/targets/linux_blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ #ifndef MYNEWT_VAL_BLE_MESH_TX_SEG_MAX #define MYNEWT_VAL_BLE_MESH_TX_SEG_MAX (6) #endif -#ifndef MYNEWT_VAL_BLE_MESH_RX_SEG_MSG_COUNT -#define MYNEWT_VAL_BLE_MESH_RX_SEG_MSG_COUNT (3) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_UNPROV_BEACON_INT -#define MYNEWT_VAL_BLE_MESH_UNPROV_BEACON_INT (5) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_PB_ADV_RETRANS_TIMEOUT -#define MYNEWT_VAL_BLE_MESH_PB_ADV_RETRANS_TIMEOUT (500) -#endif - #ifndef MYNEWT_VAL_BLE_MESH_TX_SEG_MSG_COUNT -#define MYNEWT_VAL_BLE_MESH_TX_SEG_MSG_COUNT (4) +#define MYNEWT_VAL_BLE_MESH_TX_SEG_MSG_COUNT (1) #endif #ifndef MYNEWT_VAL_BLE_MESH_TX_SEG_RETRANS_COUNT #define MYNEWT_VAL_BLE_MESH_TX_SEG_RETRANS_COUNT (4) #endif -#ifndef MYNEWT_VAL_BLE_MESH_TX_SEG_RETRANS_TIMEOUT_UNICAST -#define MYNEWT_VAL_BLE_MESH_TX_SEG_RETRANS_TIMEOUT_UNICAST (400) -#endif - #ifndef MYNEWT_VAL_BLE_MESH_TX_SEG_RETRANS_TIMEOUT_GROUP #define MYNEWT_VAL_BLE_MESH_TX_SEG_RETRANS_TIMEOUT_GROUP (50) #endif -#ifndef MYNEWT_VAL_BLE_MESH_LOOPBACK_BUFS -#define MYNEWT_VAL_BLE_MESH_LOOPBACK_BUFS (3) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_DEFAULT_TTL -#define MYNEWT_VAL_BLE_MESH_DEFAULT_TTL (7) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_NETWORK_TRANSMIT_COUNT -#define MYNEWT_VAL_BLE_MESH_NETWORK_TRANSMIT_COUNT (2) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_NETWORK_TRANSMIT_INTERVAL -#define MYNEWT_VAL_BLE_MESH_NETWORK_TRANSMIT_INTERVAL (20) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_RELAY_RETRANSMIT_COUNT -#define MYNEWT_VAL_BLE_MESH_RELAY_RETRANSMIT_COUNT (2) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_BEACON_ENABLED -#define MYNEWT_VAL_BLE_MESH_BEACON_ENABLED (1) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_GATT_PROXY_ENABLED -#define MYNEWT_VAL_BLE_MESH_GATT_PROXY_ENABLED (1) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_FRIEND_ENABLED -#define MYNEWT_VAL_BLE_MESH_FRIEND_ENABLED (1) -#endif - -#ifndef MYNEWT_VAL_BLE_MESH_RELAY_ENABLED -#define MYNEWT_VAL_BLE_MESH_RELAY_ENABLED (1) +#ifndef MYNEWT_VAL_BLE_MESH_TX_SEG_RETRANS_TIMEOUT_UNICAST +#define MYNEWT_VAL_BLE_MESH_TX_SEG_RETRANS_TIMEOUT_UNICAST (400) #endif -#ifndef MYNEWT_VAL_BLE_MESH_RELAY_RETRANSMIT_INTERVAL -#define MYNEWT_VAL_BLE_MESH_RELAY_RETRANSMIT_INTERVAL (20) +#ifndef MYNEWT_VAL_BLE_MESH_UNPROV_BEACON_INT +#define MYNEWT_VAL_BLE_MESH_UNPROV_BEACON_INT (5) #endif -/*** @apache-mynewt-nimble/nimble/host/services/ans */ #ifndef MYNEWT_VAL_BLE_SVC_ANS_NEW_ALERT_CAT #define MYNEWT_VAL_BLE_SVC_ANS_NEW_ALERT_CAT (0) #endif @@ -1249,7 +1441,6 @@ #define MYNEWT_VAL_BLE_SVC_ANS_UNR_ALERT_CAT (0) #endif -/*** @apache-mynewt-nimble/nimble/host/services/bas */ #ifndef MYNEWT_VAL_BLE_SVC_BAS_BATTERY_LEVEL_NOTIFY_ENABLE #define MYNEWT_VAL_BLE_SVC_BAS_BATTERY_LEVEL_NOTIFY_ENABLE (1) #endif @@ -1262,7 +1453,6 @@ #define MYNEWT_VAL_BLE_SVC_BAS_SYSINIT_STAGE (303) #endif -/*** @apache-mynewt-nimble/nimble/host/services/dis */ #ifndef MYNEWT_VAL_BLE_SVC_DIS_DEFAULT_READ_PERM #define MYNEWT_VAL_BLE_SVC_DIS_DEFAULT_READ_PERM (-1) #endif @@ -1271,7 +1461,6 @@ #define MYNEWT_VAL_BLE_SVC_DIS_FIRMWARE_REVISION_DEFAULT (NULL) #endif -/* Value copied from BLE_SVC_DIS_DEFAULT_READ_PERM */ #ifndef MYNEWT_VAL_BLE_SVC_DIS_FIRMWARE_REVISION_READ_PERM #define MYNEWT_VAL_BLE_SVC_DIS_FIRMWARE_REVISION_READ_PERM (-1) #endif @@ -1280,7 +1469,6 @@ #define MYNEWT_VAL_BLE_SVC_DIS_HARDWARE_REVISION_DEFAULT (NULL) #endif -/* Value copied from BLE_SVC_DIS_DEFAULT_READ_PERM */ #ifndef MYNEWT_VAL_BLE_SVC_DIS_HARDWARE_REVISION_READ_PERM #define MYNEWT_VAL_BLE_SVC_DIS_HARDWARE_REVISION_READ_PERM (-1) #endif @@ -1289,13 +1477,12 @@ #define MYNEWT_VAL_BLE_SVC_DIS_MANUFACTURER_NAME_DEFAULT (NULL) #endif -/* Value copied from BLE_SVC_DIS_DEFAULT_READ_PERM */ #ifndef MYNEWT_VAL_BLE_SVC_DIS_MANUFACTURER_NAME_READ_PERM #define MYNEWT_VAL_BLE_SVC_DIS_MANUFACTURER_NAME_READ_PERM (-1) #endif #ifndef MYNEWT_VAL_BLE_SVC_DIS_MODEL_NUMBER_DEFAULT -#define MYNEWT_VAL_BLE_SVC_DIS_MODEL_NUMBER_DEFAULT ("Apache Mynewt NimBLE") +#define MYNEWT_VAL_BLE_SVC_DIS_MODEL_NUMBER_DEFAULT "Apache Mynewt NimBLE" #endif #ifndef MYNEWT_VAL_BLE_SVC_DIS_MODEL_NUMBER_READ_PERM @@ -1306,7 +1493,6 @@ #define MYNEWT_VAL_BLE_SVC_DIS_SERIAL_NUMBER_DEFAULT (NULL) #endif -/* Value copied from BLE_SVC_DIS_DEFAULT_READ_PERM */ #ifndef MYNEWT_VAL_BLE_SVC_DIS_SERIAL_NUMBER_READ_PERM #define MYNEWT_VAL_BLE_SVC_DIS_SERIAL_NUMBER_READ_PERM (-1) #endif @@ -1315,7 +1501,6 @@ #define MYNEWT_VAL_BLE_SVC_DIS_SOFTWARE_REVISION_DEFAULT (NULL) #endif -/* Value copied from BLE_SVC_DIS_DEFAULT_READ_PERM */ #ifndef MYNEWT_VAL_BLE_SVC_DIS_SOFTWARE_REVISION_READ_PERM #define MYNEWT_VAL_BLE_SVC_DIS_SOFTWARE_REVISION_READ_PERM (-1) #endif @@ -1328,12 +1513,10 @@ #define MYNEWT_VAL_BLE_SVC_DIS_SYSTEM_ID_DEFAULT (NULL) #endif -/* Value copied from BLE_SVC_DIS_DEFAULT_READ_PERM */ #ifndef MYNEWT_VAL_BLE_SVC_DIS_SYSTEM_ID_READ_PERM #define MYNEWT_VAL_BLE_SVC_DIS_SYSTEM_ID_READ_PERM (-1) #endif -/*** @apache-mynewt-nimble/nimble/host/services/gap */ #ifndef MYNEWT_VAL_BLE_SVC_GAP_APPEARANCE #define MYNEWT_VAL_BLE_SVC_GAP_APPEARANCE (0) #endif @@ -1347,7 +1530,7 @@ #endif #ifndef MYNEWT_VAL_BLE_SVC_GAP_DEVICE_NAME -#define MYNEWT_VAL_BLE_SVC_GAP_DEVICE_NAME ("nimble") +#define MYNEWT_VAL_BLE_SVC_GAP_DEVICE_NAME "nimble" #endif #ifndef MYNEWT_VAL_BLE_SVC_GAP_DEVICE_NAME_MAX_LENGTH @@ -1378,55 +1561,178 @@ #define MYNEWT_VAL_BLE_SVC_GAP_SYSINIT_STAGE (301) #endif -/*** @apache-mynewt-nimble/nimble/host/services/gatt */ #ifndef MYNEWT_VAL_BLE_SVC_GATT_SYSINIT_STAGE #define MYNEWT_VAL_BLE_SVC_GATT_SYSINIT_STAGE (302) #endif -/*** @apache-mynewt-nimble/nimble/host/services/ias */ #ifndef MYNEWT_VAL_BLE_SVC_IAS_SYSINIT_STAGE #define MYNEWT_VAL_BLE_SVC_IAS_SYSINIT_STAGE (303) #endif -/*** @apache-mynewt-nimble/nimble/host/services/ipss */ #ifndef MYNEWT_VAL_BLE_SVC_IPSS_SYSINIT_STAGE #define MYNEWT_VAL_BLE_SVC_IPSS_SYSINIT_STAGE (303) #endif -/*** @apache-mynewt-nimble/nimble/host/services/lls */ #ifndef MYNEWT_VAL_BLE_SVC_LLS_SYSINIT_STAGE #define MYNEWT_VAL_BLE_SVC_LLS_SYSINIT_STAGE (303) #endif -/*** @apache-mynewt-nimble/nimble/host/services/tps */ #ifndef MYNEWT_VAL_BLE_SVC_TPS_SYSINIT_STAGE #define MYNEWT_VAL_BLE_SVC_TPS_SYSINIT_STAGE (303) #endif -/*** @apache-mynewt-nimble/nimble/transport/socket */ -#ifndef MYNEWT_VAL_BLE_ACL_BUF_COUNT -#define MYNEWT_VAL_BLE_ACL_BUF_COUNT (24) +#undef MYNEWT_VAL_BLE_ACL_BUF_COUNT + +#undef MYNEWT_VAL_BLE_ACL_BUF_SIZE + +#undef MYNEWT_VAL_BLE_HCI_BRIDGE + +#undef MYNEWT_VAL_BLE_HCI_EVT_BUF_SIZE + +#undef MYNEWT_VAL_BLE_HCI_EVT_HI_BUF_COUNT + +#undef MYNEWT_VAL_BLE_HCI_EVT_LO_BUF_COUNT + +#undef MYNEWT_VAL_BLE_HCI_TRANSPORT + +#ifndef MYNEWT_VAL_BLE_MONITOR_CONSOLE_BUFFER_SIZE +#define MYNEWT_VAL_BLE_MONITOR_CONSOLE_BUFFER_SIZE (128) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_RTT +#define MYNEWT_VAL_BLE_MONITOR_RTT (0) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFERED +#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFERED (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_NAME +#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_NAME "btmonitor" +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_SIZE +#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_SIZE (256) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_UART +#define MYNEWT_VAL_BLE_MONITOR_UART (0) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_UART_BAUDRATE +#define MYNEWT_VAL_BLE_MONITOR_UART_BAUDRATE (1000000) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_UART_BUFFER_SIZE +#define MYNEWT_VAL_BLE_MONITOR_UART_BUFFER_SIZE (64) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_UART_DEV +#define MYNEWT_VAL_BLE_MONITOR_UART_DEV "uart0" +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT +#define MYNEWT_VAL_BLE_TRANSPORT (1) +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT_ACL_COUNT +#define MYNEWT_VAL_BLE_TRANSPORT_ACL_COUNT (10) +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT_ACL_FROM_HS_COUNT +#define MYNEWT_VAL_BLE_TRANSPORT_ACL_FROM_HS_COUNT (10) +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT_ACL_FROM_LL_COUNT +#define MYNEWT_VAL_BLE_TRANSPORT_ACL_FROM_LL_COUNT (10) +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT_ACL_SIZE +#define MYNEWT_VAL_BLE_TRANSPORT_ACL_SIZE (251) +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT_EVT_COUNT +#define MYNEWT_VAL_BLE_TRANSPORT_EVT_COUNT (4) +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT_EVT_DISCARDABLE_COUNT +#define MYNEWT_VAL_BLE_TRANSPORT_EVT_DISCARDABLE_COUNT (16) +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT_EVT_SIZE +#define MYNEWT_VAL_BLE_TRANSPORT_EVT_SIZE (70) +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT_HS__cdc +#define MYNEWT_VAL_BLE_TRANSPORT_HS__cdc (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_HS__custom +#define MYNEWT_VAL_BLE_TRANSPORT_HS__custom (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_HS__dialog_cmac +#define MYNEWT_VAL_BLE_TRANSPORT_HS__dialog_cmac (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_HS__native +#define MYNEWT_VAL_BLE_TRANSPORT_HS__native (1) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_HS__nrf5340 +#define MYNEWT_VAL_BLE_TRANSPORT_HS__nrf5340 (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_HS__uart +#define MYNEWT_VAL_BLE_TRANSPORT_HS__uart (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_HS__usb +#define MYNEWT_VAL_BLE_TRANSPORT_HS__usb (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_HS +#define MYNEWT_VAL_BLE_TRANSPORT_HS (1) #endif -#ifndef MYNEWT_VAL_BLE_ACL_BUF_SIZE -#define MYNEWT_VAL_BLE_ACL_BUF_SIZE (255) +#ifndef MYNEWT_VAL_BLE_TRANSPORT_ISO_COUNT +#define MYNEWT_VAL_BLE_TRANSPORT_ISO_COUNT (10) #endif -#ifndef MYNEWT_VAL_BLE_HCI_ACL_OUT_COUNT -#define MYNEWT_VAL_BLE_HCI_ACL_OUT_COUNT (12) +#ifndef MYNEWT_VAL_BLE_TRANSPORT_ISO_FROM_HS_COUNT +#define MYNEWT_VAL_BLE_TRANSPORT_ISO_FROM_HS_COUNT (10) #endif -#ifndef MYNEWT_VAL_BLE_HCI_EVT_BUF_SIZE -#define MYNEWT_VAL_BLE_HCI_EVT_BUF_SIZE (70) +#ifndef MYNEWT_VAL_BLE_TRANSPORT_ISO_FROM_LL_COUNT +#define MYNEWT_VAL_BLE_TRANSPORT_ISO_FROM_LL_COUNT (10) #endif -#ifndef MYNEWT_VAL_BLE_HCI_EVT_HI_BUF_COUNT -#define MYNEWT_VAL_BLE_HCI_EVT_HI_BUF_COUNT (8) +#ifndef MYNEWT_VAL_BLE_TRANSPORT_ISO_SIZE +#define MYNEWT_VAL_BLE_TRANSPORT_ISO_SIZE (300) #endif -#ifndef MYNEWT_VAL_BLE_HCI_EVT_LO_BUF_COUNT -#define MYNEWT_VAL_BLE_HCI_EVT_LO_BUF_COUNT (8) +#ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__apollo3 +#define MYNEWT_VAL_BLE_TRANSPORT_LL__apollo3 (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__custom +#define MYNEWT_VAL_BLE_TRANSPORT_LL__custom (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__dialog_cmac +#define MYNEWT_VAL_BLE_TRANSPORT_LL__dialog_cmac (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__emspi +#define MYNEWT_VAL_BLE_TRANSPORT_LL__emspi (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__native +#define MYNEWT_VAL_BLE_TRANSPORT_LL__native (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__nrf5340 +#define MYNEWT_VAL_BLE_TRANSPORT_LL__nrf5340 (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__socket +#define MYNEWT_VAL_BLE_TRANSPORT_LL__socket (1) #endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__uart_ll +#define MYNEWT_VAL_BLE_TRANSPORT_LL__uart_ll (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_LL +#define MYNEWT_VAL_BLE_TRANSPORT_LL (1) +#endif + +#undef MYNEWT_VAL_BLE_TRANSPORT_RX_TASK_STACK_SIZE #ifndef MYNEWT_VAL_BLE_SOCK_CLI_SYSINIT_STAGE #define MYNEWT_VAL_BLE_SOCK_CLI_SYSINIT_STAGE (500) @@ -1436,12 +1742,10 @@ #define MYNEWT_VAL_BLE_SOCK_LINUX_DEV (0) #endif -/* Overridden by @apache-mynewt-nimble/porting/targets/linux_blemesh (defined by @apache-mynewt-nimble/nimble/transport/socket) */ #ifndef MYNEWT_VAL_BLE_SOCK_STACK_SIZE #define MYNEWT_VAL_BLE_SOCK_STACK_SIZE (1028) #endif -/* Overridden by @apache-mynewt-nimble/porting/targets/linux_blemesh (defined by @apache-mynewt-nimble/nimble/transport/socket) */ #ifndef MYNEWT_VAL_BLE_SOCK_TASK_PRIO #define MYNEWT_VAL_BLE_SOCK_TASK_PRIO (3) #endif @@ -1450,19 +1754,20 @@ #define MYNEWT_VAL_BLE_SOCK_TCP_PORT (14433) #endif -/* Overridden by @apache-mynewt-nimble/porting/targets/linux_blemesh (defined by @apache-mynewt-nimble/nimble/transport/socket) */ #ifndef MYNEWT_VAL_BLE_SOCK_USE_LINUX_BLUE #define MYNEWT_VAL_BLE_SOCK_USE_LINUX_BLUE (1) #endif -/* Overridden by @apache-mynewt-nimble/porting/targets/linux_blemesh (defined by @apache-mynewt-nimble/nimble/transport/socket) */ +#ifndef MYNEWT_VAL_BLE_SOCK_USE_NUTTX +#define MYNEWT_VAL_BLE_SOCK_USE_NUTTX (0) +#endif + #ifndef MYNEWT_VAL_BLE_SOCK_USE_TCP #define MYNEWT_VAL_BLE_SOCK_USE_TCP (0) #endif -/*** newt */ #ifndef MYNEWT_VAL_APP_NAME -#define MYNEWT_VAL_APP_NAME ("dummy_app") +#define MYNEWT_VAL_APP_NAME "dummy_app" #endif #ifndef MYNEWT_VAL_APP_dummy_app @@ -1470,19 +1775,19 @@ #endif #ifndef MYNEWT_VAL_ARCH_NAME -#define MYNEWT_VAL_ARCH_NAME ("dummy") +#define MYNEWT_VAL_ARCH_NAME "sim" #endif -#ifndef MYNEWT_VAL_ARCH_dummy -#define MYNEWT_VAL_ARCH_dummy (1) +#ifndef MYNEWT_VAL_ARCH_sim +#define MYNEWT_VAL_ARCH_sim (1) #endif #ifndef MYNEWT_VAL_BSP_NAME -#define MYNEWT_VAL_BSP_NAME ("dummy_bsp") +#define MYNEWT_VAL_BSP_NAME "native" #endif -#ifndef MYNEWT_VAL_BSP_dummy_bsp -#define MYNEWT_VAL_BSP_dummy_bsp (1) +#ifndef MYNEWT_VAL_BSP_native +#define MYNEWT_VAL_BSP_native (1) #endif #ifndef MYNEWT_VAL_NEWT_FEATURE_LOGCFG @@ -1494,11 +1799,62 @@ #endif #ifndef MYNEWT_VAL_TARGET_NAME -#define MYNEWT_VAL_TARGET_NAME ("linux_blemesh") +#define MYNEWT_VAL_TARGET_NAME "linux_blemesh" #endif #ifndef MYNEWT_VAL_TARGET_linux_blemesh #define MYNEWT_VAL_TARGET_linux_blemesh (1) #endif +#define MYNEWT_PKG_apache_mynewt_core__compiler_sim 1 +#define MYNEWT_PKG_apache_mynewt_core__crypto_tinycrypt 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_bsp_native 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_drivers_flash_enc_flash 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_drivers_flash_enc_flash_ef_tinycrypt 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_drivers_trng 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_drivers_trng_trng_sw 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_drivers_uart 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_drivers_uart_uart_hal 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_hal 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_mcu_native 1 +#define MYNEWT_PKG_apache_mynewt_core__kernel_os 1 +#define MYNEWT_PKG_apache_mynewt_core__kernel_sim 1 +#define MYNEWT_PKG_apache_mynewt_core__net_ip_mn_socket 1 +#define MYNEWT_PKG_apache_mynewt_core__net_ip_native_sockets 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_console_stub 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_defs 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_flash_map 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_log_common 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_log_modlog 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_log_stub 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_stats_stub 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_sys 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_sysdown 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_sysinit 1 +#define MYNEWT_PKG_apache_mynewt_core__util_mem 1 +#define MYNEWT_PKG_apache_mynewt_core__util_rwlock 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_mesh 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_ans 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_bas 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_dis 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_gap 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_gatt 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_ias 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_ipss 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_lls 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_tps 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_transport 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_transport_socket 1 +#define MYNEWT_PKG_apache_mynewt_nimble__porting_npl_mynewt 1 +#define MYNEWT_PKG_apache_mynewt_nimble__porting_targets_dummy_app 1 +#define MYNEWT_PKG_apache_mynewt_nimble__porting_targets_linux_blemesh 1 + +#define MYNEWT_API_TRNG_HW_IMPL 1 +#define MYNEWT_API_ble_transport 1 +#define MYNEWT_API_console 1 +#define MYNEWT_API_log 1 +#define MYNEWT_API_stats 1 + #endif diff --git a/porting/examples/linux_blemesh/include/sysflash/sysflash.h b/porting/examples/linux_blemesh/include/sysflash/sysflash.h deleted file mode 100644 index ab1341b25d..0000000000 --- a/porting/examples/linux_blemesh/include/sysflash/sysflash.h +++ /dev/null @@ -1,24 +0,0 @@ -/** - * This file was generated by Apache newt version: 1.9.0-dev - */ - -#ifndef H_MYNEWT_SYSFLASH_ -#define H_MYNEWT_SYSFLASH_ - -#include "flash_map/flash_map.h" - -/** - * This flash map definition is used for two purposes: - * 1. To locate the meta area, which contains the true flash map definition. - * 2. As a fallback in case the meta area cannot be read from flash. - */ -extern const struct flash_area sysflash_map_dflt[6]; - -#define FLASH_AREA_BOOTLOADER 0 -#define FLASH_AREA_IMAGE_0 1 -#define FLASH_AREA_IMAGE_1 2 -#define FLASH_AREA_IMAGE_SCRATCH 3 -#define FLASH_AREA_REBOOT_LOG 16 -#define FLASH_AREA_NFFS 17 - -#endif diff --git a/porting/examples/linux_blemesh/main.c b/porting/examples/linux_blemesh/main.c index f5c5e4f04f..678062f207 100644 --- a/porting/examples/linux_blemesh/main.c +++ b/porting/examples/linux_blemesh/main.c @@ -38,6 +38,8 @@ static struct ble_npl_task s_task_mesh_adv; void nimble_host_task(void *param); void ble_hci_sock_ack_handler(void *param); void ble_hci_sock_init(void); +void ble_hci_sock_set_device(int dev); +void ble_store_ram_init(void); #define TASK_DEFAULT_PRIORITY 1 #define TASK_DEFAULT_STACK NULL @@ -78,7 +80,6 @@ int main(int argc, char *argv[]) } nimble_port_init(); - ble_hci_sock_init(); ble_svc_gap_init(); ble_svc_gatt_init(); diff --git a/porting/examples/linux_blemesh_shell/Makefile b/porting/examples/linux_blemesh_shell/Makefile new file mode 100644 index 0000000000..c90f87781f --- /dev/null +++ b/porting/examples/linux_blemesh_shell/Makefile @@ -0,0 +1,110 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# * http://www.apache.org/licenses/LICENSE-2.0 +# * Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +# Toolchain commands +CROSS_COMPILE ?= +CC := ccache $(CROSS_COMPILE)gcc +CXX := ccache $(CROSS_COMPILE)g++ +LD := $(CROSS_COMPILE)gcc +AR := $(CROSS_COMPILE)ar +AS := $(CROSS_COMPILE)as +NM := $(CROSS_COMPILE)nm +OBJDUMP := $(CROSS_COMPILE)objdump +OBJCOPY := $(CROSS_COMPILE)objcopy +SIZE := $(CROSS_COMPILE)size + +# Configure NimBLE variables +NIMBLE_ROOT := ../../.. +NIMBLE_CFG_TINYCRYPT := 1 + +# Skip files that don't build for this port +NIMBLE_IGNORE := $(NIMBLE_ROOT)/porting/nimble/src/hal_timer.c \ + $(NIMBLE_ROOT)/porting/nimble/src/os_cputime.c \ + $(NIMBLE_ROOT)/porting/nimble/src/os_cputime_pwr2.c \ + $(NULL) + +include $(NIMBLE_ROOT)/porting/nimble/Makefile.defs +include $(NIMBLE_ROOT)/porting/nimble/Makefile.mesh + +SRC := $(NIMBLE_SRC) + +# Source files for NPL OSAL +SRC += \ + $(wildcard $(NIMBLE_ROOT)/porting/npl/linux/src/*.c) \ + $(wildcard $(NIMBLE_ROOT)/porting/npl/linux/src/*.cc) \ + $(wildcard $(NIMBLE_ROOT)/nimble/transport/socket/src/*.c) \ + $(TINYCRYPT_SRC) \ + $(wildcard $(NIMBLE_ROOT)/nimble/host/mesh/src/*.c) \ + $(NULL) + +# Source files for demo app +SRC += \ + ./src/main.c \ + ./src/ble.c \ + ./shell/shell_port.c \ + ./shell/console_port.c \ + $(NULL) + +# Add NPL and all NimBLE directories to include paths +INC = \ + ./include \ + $(NIMBLE_ROOT)/porting/npl/linux/include \ + $(NIMBLE_ROOT)/porting/npl/linux/src \ + $(NIMBLE_ROOT)/nimble/transport/socket/include \ + $(NIMBLE_INCLUDE) \ + $(TINYCRYPT_INCLUDE) \ + $(NULL) + +INCLUDES := $(addprefix -I, $(INC)) + +SRC_C = $(filter %.c, $(SRC)) +SRC_CC = $(filter %.cc, $(SRC)) + +OBJ := $(SRC_C:.c=.o) +OBJ += $(SRC_CC:.cc=.o) + +TINYCRYPT_OBJ := $(TINYCRYPT_SRC:.c=.o) + +CFLAGS = \ + $(NIMBLE_CFLAGS) \ + $(INCLUDES) \ + -g \ + -D_GNU_SOURCE \ + $(NULL) + +LIBS := $(NIMBLE_LDFLAGS) -lrt -lpthread -lstdc++ + +.PHONY: all clean +.DEFAULT: all + +all: nimble-linux-blemesh-shell + +clean: + rm $(OBJ) -f + rm nimble-linux-blemesh-shell -f + +$(TINYCRYPT_OBJ): CFLAGS+=$(TINYCRYPT_CFLAGS) + +%.o: %.c + $(CC) -c $(INCLUDES) $(CFLAGS) -o $@ $< + +%.o: %.cc + $(CXX) -c $(INCLUDES) $(CFLAGS) -o $@ $< + +nimble-linux-blemesh-shell: $(OBJ) $(TINYCRYPT_OBJ) + $(LD) -o $@ $^ $(LIBS) + $(SIZE) $@ diff --git a/porting/examples/linux_blemesh_shell/README.md b/porting/examples/linux_blemesh_shell/README.md new file mode 100644 index 0000000000..414fc7c2d6 --- /dev/null +++ b/porting/examples/linux_blemesh_shell/README.md @@ -0,0 +1,76 @@ + + +# Apache Mynewt NimBLE + +## Overview + +See https://mynewt.apache.org/latest/network + +## Building + +NimBLE is usually built as a part of Apache Mynewt OS, but ports for +other RTOS-es are also available. + +### Linux + +1. Build the sample application + +```no-highlight + cd porting/examples/linux_blemesh_shell + make +``` + +2. Run the sample application + +First insert a USB Bluetooth dongle. These are typically BLE 4.0 capable. + +Verify the dongle is connected with hciconfig: + +```no-highlight + $ hciconfig +hci0: Type: BR/EDR Bus: USB + BD Address: 00:1B:DC:06:62:5E ACL MTU: 310:10 SCO MTU: 64:8 + DOWN + RX bytes:5470 acl:0 sco:0 events:40 errors:0 + TX bytes:5537 acl:176 sco:0 commands:139 errors:1 +``` + +Then run the application built in step one. The application is configured +in sysconfig.h to use hci0. + +```no-highlight + cd porting/examples/linux_blemesh_shell + sudo ./nimble-linux-blemesh-shell +``` + +3. Run shell commands + +This example reads input form console, then execute all commands supported by nimble/host/mesh/src/shell.c + + +some example commands: + +```no-highlight + mesh>help + mesh>provision 0 1 0 + mesh>provision-adv c70512201872a85c9046a3e67ef1c55e 0 2 0 +``` diff --git a/nimble/host/include/host/ble_monitor.h b/porting/examples/linux_blemesh_shell/include/console/console_port.h similarity index 77% rename from nimble/host/include/host/ble_monitor.h rename to porting/examples/linux_blemesh_shell/include/console/console_port.h index 61722f7dbc..439ac9f3e6 100644 --- a/nimble/host/include/host/ble_monitor.h +++ b/porting/examples/linux_blemesh_shell/include/console/console_port.h @@ -17,21 +17,21 @@ * under the License. */ -#ifndef H_BLE_MONITOR_ -#define H_BLE_MONITOR_ - -#include - -#undef BLE_MONITOR -#define BLE_MONITOR (MYNEWT_VAL(BLE_MONITOR_UART) || MYNEWT_VAL(BLE_MONITOR_RTT)) +#ifndef __CONSOLE_PORT_H__ +#define __CONSOLE_PORT_H__ #ifdef __cplusplus extern "C" { #endif -int ble_monitor_log(int level, const char *fmt, ...); +#include "nimble/nimble_npl.h" +struct os_eventq; + +void console_set_queues(struct os_eventq *avail, struct os_eventq *lines); + +void console_set_event_cb(ble_npl_event_fn *cb); -int ble_monitor_out(int c); +int console_init(); #ifdef __cplusplus } diff --git a/porting/examples/linux_blemesh_shell/include/shell/shell.h b/porting/examples/linux_blemesh_shell/include/shell/shell.h new file mode 100644 index 0000000000..75130487d5 --- /dev/null +++ b/porting/examples/linux_blemesh_shell/include/shell/shell.h @@ -0,0 +1,220 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef __SHELL_H__ +#define __SHELL_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "syscfg/syscfg.h" + +/** + * porting for linux platform, modification of shell.c is not needed + */ +#include "nimble/nimble_npl.h" +#define TASK_DEFAULT_PRIORITY 1 +#define TASK_DEFAULT_STACK NULL +#define TASK_DEFAULT_STACK_SIZE 768 + +#define OS_TASK_STACK_DEFINE(g_blemesh_shell_stack, BLE_MESH_SHELL_STACK_SIZE) \ + unsigned g_blemesh_shell_stack = BLE_MESH_SHELL_STACK_SIZE; + +#define os_task ble_npl_task +#define os_eventq ble_npl_eventq +#define os_event ble_npl_event +#define OS_WAIT_FOREVER (-1) + +void ble_npl_eventq_run(struct ble_npl_eventq *evq); + +#define os_eventq_init(q) ble_npl_eventq_init(q) +#define os_eventq_run(q) ble_npl_eventq_run(q) +#define os_task_init(task, name, func, arg, prio, sanity_itvl, stack_bottom, stack_size) \ + ble_npl_task_init(task, name, (ble_npl_task_func_t)func, arg, TASK_DEFAULT_PRIORITY, sanity_itvl, NULL, stack_size) + +void handle_shell_evt(struct os_event *ev); + +int cmd_mesh_init(int argc, char *argv[]); + +void ble_mesh_shell_init(void); + +#ifndef MYNEWT_VAL_SHELL_CMD_ARGC_MAX +#define MYNEWT_VAL_SHELL_CMD_ARGC_MAX (16) +#endif + +/* + * The shell.h below is copied from mynewt core + */ +struct os_eventq; +struct shell_cmd; +struct streamer; + +/** Command IDs in the "shell" newtmgr group. */ +#define SHELL_NMGR_OP_EXEC 0 + +/** @brief Callback called when command is entered. + * + * @param argc Number of parameters passed. + * @param argv Array of option strings. First option is always command name. + * + * @return 0 in case of success or negative value in case of error. + */ +typedef int (*shell_cmd_func_t)(int argc, char *argv[]); + +/** + * @brief Callback for "extended" shell commands. + * + * @param cmd The shell command being executed. + * @param argc Number of arguments passed. + * @param argv Array of option strings. First option is always + * command name. + * @param streamer The streamer to write shell output to. + * + * @return 0 on success; SYS_E[...] on failure. + */ +typedef int (*shell_cmd_ext_func_t)(const struct shell_cmd *cmd, + int argc, char *argv[], + struct streamer *streamer); + +struct shell_param { + const char *param_name; + const char *help; +}; + +struct shell_cmd_help { + const char *summary; + const char *usage; + const struct shell_param *params; +}; + +struct shell_cmd { + uint8_t sc_ext : 1; /* 1 if this is an extended shell comand. */ + union { + shell_cmd_func_t sc_cmd_func; + shell_cmd_ext_func_t sc_cmd_ext_func; + }; + + const char *sc_cmd; + const struct shell_cmd_help *help; +}; + +struct shell_module { + const char *name; + const struct shell_cmd *commands; +}; + +#if MYNEWT_VAL(SHELL_CMD_HELP) +#define SHELL_HELP_(help_) (help_) +#else +#define SHELL_HELP_(help_) NULL +#endif + +/** + * @brief constructs a legacy shell command. + */ +#define SHELL_CMD(cmd_, func_, help_) { \ + .sc_ext = 0, \ + .sc_cmd_func = func_, \ + .sc_cmd = cmd_, \ + .help = SHELL_HELP_(help_), \ +} + +/** + * @brief constructs an extended shell command. + */ +#define SHELL_CMD_EXT(cmd_, func_, help_) { \ + .sc_ext = 1, \ + .sc_cmd_ext_func = func_, \ + .sc_cmd = cmd_, \ + .help = SHELL_HELP_(help_), \ +} + +/** @brief Register a shell_module object + * + * @param shell_name Module name to be entered in shell console. + * + * @param shell_commands Array of commands to register. + * The array should be terminated with an empty element. + */ +int shell_register(const char *shell_name, + const struct shell_cmd *shell_commands); + +/** @brief Optionally register an app default cmd handler. + * + * @param handler To be called if no cmd found in cmds registered with + * shell_init. + */ +void shell_register_app_cmd_handler(shell_cmd_func_t handler); + +/** @brief Callback to get the current prompt. + * + * @returns Current prompt string. + */ +typedef const char *(*shell_prompt_function_t)(void); + +/** @brief Optionally register a custom prompt callback. + * + * @param handler To be called to get the current prompt. + */ +void shell_register_prompt_handler(shell_prompt_function_t handler); + +/** @brief Optionally register a default module, to avoid typing it in + * shell console. + * + * @param name Module name. + */ +void shell_register_default_module(const char *name); + +/** @brief Optionally set event queue to process shell command events + * + * @param evq Event queue to be used in shell + */ +void shell_evq_set(struct os_eventq *evq); + +/** + * @brief Processes a set of arguments and executes their corresponding shell + * command. + * + * @param argc The argument count (including command name). + * @param argv The argument list ([0] is command name). + * @param streamer The streamer to send output to. + * + * @return 0 on success; SYS_E[...] on failure. + */ +int shell_exec(int argc, char **argv, struct streamer *streamer); + +#if MYNEWT_VAL(SHELL_MGMT) +struct os_mbuf; +typedef int (*shell_nlip_input_func_t)(struct os_mbuf *, void *arg); +int shell_nlip_input_register(shell_nlip_input_func_t nf, void *arg); +int shell_nlip_output(struct os_mbuf *m); +#endif + +#if MYNEWT_VAL(SHELL_COMPAT) +int shell_cmd_register(const struct shell_cmd *sc); +#endif + + +#ifdef __cplusplus +} +#endif + +#endif /* __SHELL_H__ */ diff --git a/porting/examples/linux_blemesh_shell/include/syscfg/syscfg.h b/porting/examples/linux_blemesh_shell/include/syscfg/syscfg.h new file mode 100644 index 0000000000..deaded7db0 --- /dev/null +++ b/porting/examples/linux_blemesh_shell/include/syscfg/syscfg.h @@ -0,0 +1,1934 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_MYNEWT_SYSCFG_ +#define H_MYNEWT_SYSCFG_ + +#define MYNEWT_VAL(_name) MYNEWT_VAL_ ## _name +#define MYNEWT_VAL_CHOICE(_name, _val) MYNEWT_VAL_ ## _name ## __ ## _val + +#ifndef MYNEWT_VAL_TINYCRYPT_SYSINIT_STAGE +#define MYNEWT_VAL_TINYCRYPT_SYSINIT_STAGE (200) +#endif + +#ifndef MYNEWT_VAL_TINYCRYPT_UECC_RNG_TRNG_DEV_NAME +#define MYNEWT_VAL_TINYCRYPT_UECC_RNG_TRNG_DEV_NAME "trng" +#endif + +#ifndef MYNEWT_VAL_TINYCRYPT_UECC_RNG_USE_TRNG +#define MYNEWT_VAL_TINYCRYPT_UECC_RNG_USE_TRNG (0) +#endif + +/*** @apache-mynewt-core/hw/bsp/native */ +#ifndef MYNEWT_VAL_BSP_SIMULATED +#define MYNEWT_VAL_BSP_SIMULATED (1) +#endif + +/*** @apache-mynewt-core/hw/hal */ +#ifndef MYNEWT_VAL_HAL_ENABLE_SOFTWARE_BREAKPOINTS +#define MYNEWT_VAL_HAL_ENABLE_SOFTWARE_BREAKPOINTS (1) +#endif + +#ifndef MYNEWT_VAL_HAL_FLASH_MAX_DEVICE_COUNT +#define MYNEWT_VAL_HAL_FLASH_MAX_DEVICE_COUNT (0) +#endif + +#ifndef MYNEWT_VAL_HAL_FLASH_VERIFY_BUF_SZ +#define MYNEWT_VAL_HAL_FLASH_VERIFY_BUF_SZ (16) +#endif + +#ifndef MYNEWT_VAL_HAL_FLASH_VERIFY_ERASES +#define MYNEWT_VAL_HAL_FLASH_VERIFY_ERASES (0) +#endif + +#ifndef MYNEWT_VAL_HAL_FLASH_VERIFY_WRITES +#define MYNEWT_VAL_HAL_FLASH_VERIFY_WRITES (0) +#endif + +#ifndef MYNEWT_VAL_HAL_SBRK +#define MYNEWT_VAL_HAL_SBRK (1) +#endif + +#ifndef MYNEWT_VAL_HAL_SYSTEM_RESET_CB +#define MYNEWT_VAL_HAL_SYSTEM_RESET_CB (0) +#endif + +/*** @apache-mynewt-core/hw/mcu/native */ +#ifndef MYNEWT_VAL_I2C_0 +#define MYNEWT_VAL_I2C_0 (0) +#endif + +#ifndef MYNEWT_VAL_MCU_FLASH_MIN_WRITE_SIZE +#define MYNEWT_VAL_MCU_FLASH_MIN_WRITE_SIZE (1) +#endif + +#ifndef MYNEWT_VAL_MCU_FLASH_STYLE_NORDIC +#define MYNEWT_VAL_MCU_FLASH_STYLE_NORDIC (0) +#endif + +#ifndef MYNEWT_VAL_MCU_FLASH_STYLE_ST +#define MYNEWT_VAL_MCU_FLASH_STYLE_ST (1) +#endif + +#ifndef MYNEWT_VAL_MCU_NATIVE +#define MYNEWT_VAL_MCU_NATIVE (1) +#endif + +#ifndef MYNEWT_VAL_MCU_NATIVE_USE_SIGNALS +#define MYNEWT_VAL_MCU_NATIVE_USE_SIGNALS (1) +#endif + +#ifndef MYNEWT_VAL_MCU_TIMER_POLLER_PRIO +#define MYNEWT_VAL_MCU_TIMER_POLLER_PRIO (0) +#endif + +#ifndef MYNEWT_VAL_MCU_UART_POLLER_PRIO +#define MYNEWT_VAL_MCU_UART_POLLER_PRIO (1) +#endif + +/*** @apache-mynewt-core/kernel/os */ +#ifndef MYNEWT_VAL_FLOAT_USER +#define MYNEWT_VAL_FLOAT_USER (0) +#endif + +/* Overridden by @apache-mynewt-nimble/porting/targets/linux_blemesh (defined by @apache-mynewt-core/kernel/os) */ +#ifndef MYNEWT_VAL_MSYS_1_BLOCK_COUNT +#define MYNEWT_VAL_MSYS_1_BLOCK_COUNT (80) +#endif + +#ifndef MYNEWT_VAL_MSYS_1_BLOCK_SIZE +#define MYNEWT_VAL_MSYS_1_BLOCK_SIZE (292) +#endif + +#ifndef MYNEWT_VAL_MSYS_1_SANITY_MIN_COUNT +#define MYNEWT_VAL_MSYS_1_SANITY_MIN_COUNT (0) +#endif + +#ifndef MYNEWT_VAL_MSYS_2_BLOCK_COUNT +#define MYNEWT_VAL_MSYS_2_BLOCK_COUNT (0) +#endif + +#ifndef MYNEWT_VAL_MSYS_2_BLOCK_SIZE +#define MYNEWT_VAL_MSYS_2_BLOCK_SIZE (0) +#endif + +#ifndef MYNEWT_VAL_MSYS_2_SANITY_MIN_COUNT +#define MYNEWT_VAL_MSYS_2_SANITY_MIN_COUNT (0) +#endif + +#ifndef MYNEWT_VAL_MSYS_SANITY_TIMEOUT +#define MYNEWT_VAL_MSYS_SANITY_TIMEOUT (60000) +#endif + +#ifndef MYNEWT_VAL_OS_ASSERT_CB +#define MYNEWT_VAL_OS_ASSERT_CB (0) +#endif + +#ifndef MYNEWT_VAL_OS_CLI +#define MYNEWT_VAL_OS_CLI (0) +#endif + +#ifndef MYNEWT_VAL_OS_COREDUMP +#define MYNEWT_VAL_OS_COREDUMP (0) +#endif + +#ifndef MYNEWT_VAL_OS_COREDUMP_CB +#define MYNEWT_VAL_OS_COREDUMP_CB (0) +#endif + +#ifndef MYNEWT_VAL_OS_CPUTIME_FREQ +#define MYNEWT_VAL_OS_CPUTIME_FREQ (1000000) +#endif + +#ifndef MYNEWT_VAL_OS_CPUTIME_TIMER_NUM +#define MYNEWT_VAL_OS_CPUTIME_TIMER_NUM (0) +#endif + +/* Overridden by @apache-mynewt-core/hw/bsp/native (defined by @apache-mynewt-core/kernel/os) */ +#ifndef MYNEWT_VAL_OS_CRASH_FILE_LINE +#define MYNEWT_VAL_OS_CRASH_FILE_LINE (1) +#endif + +#ifndef MYNEWT_VAL_OS_CRASH_LOG +#define MYNEWT_VAL_OS_CRASH_LOG (0) +#endif + +#ifndef MYNEWT_VAL_OS_CRASH_RESTORE_REGS +#define MYNEWT_VAL_OS_CRASH_RESTORE_REGS (0) +#endif + +#ifndef MYNEWT_VAL_OS_CRASH_STACKTRACE +#define MYNEWT_VAL_OS_CRASH_STACKTRACE (0) +#endif + +#ifndef MYNEWT_VAL_OS_CTX_SW_STACK_CHECK +#define MYNEWT_VAL_OS_CTX_SW_STACK_CHECK (0) +#endif + +#ifndef MYNEWT_VAL_OS_CTX_SW_STACK_GUARD +#define MYNEWT_VAL_OS_CTX_SW_STACK_GUARD (4) +#endif + +#ifndef MYNEWT_VAL_OS_DEBUG_MODE +#define MYNEWT_VAL_OS_DEBUG_MODE (0) +#endif + +#ifndef MYNEWT_VAL_OS_DEFAULT_IRQ_CB +#define MYNEWT_VAL_OS_DEFAULT_IRQ_CB (0) +#endif + +#ifndef MYNEWT_VAL_OS_EVENTQ_DEBUG +#define MYNEWT_VAL_OS_EVENTQ_DEBUG (0) +#endif + +#ifndef MYNEWT_VAL_OS_EVENTQ_MONITOR +#define MYNEWT_VAL_OS_EVENTQ_MONITOR (0) +#endif + +#ifndef MYNEWT_VAL_OS_IDLE_TICKLESS_MS_MAX +#define MYNEWT_VAL_OS_IDLE_TICKLESS_MS_MAX (600000) +#endif + +/* Overridden by @apache-mynewt-core/hw/bsp/native (defined by @apache-mynewt-core/kernel/os) */ +#ifndef MYNEWT_VAL_OS_IDLE_TICKLESS_MS_MIN +#define MYNEWT_VAL_OS_IDLE_TICKLESS_MS_MIN (1) +#endif + +#ifndef MYNEWT_VAL_OS_MAIN_STACK_SIZE +#define MYNEWT_VAL_OS_MAIN_STACK_SIZE (1024) +#endif + +#ifndef MYNEWT_VAL_OS_MAIN_TASK_PRIO +#define MYNEWT_VAL_OS_MAIN_TASK_PRIO (127) +#endif + +#ifndef MYNEWT_VAL_OS_MAIN_TASK_SANITY_ITVL_MS +#define MYNEWT_VAL_OS_MAIN_TASK_SANITY_ITVL_MS (0) +#endif + +#ifndef MYNEWT_VAL_OS_MEMPOOL_CHECK +#define MYNEWT_VAL_OS_MEMPOOL_CHECK (0) +#endif + +#ifndef MYNEWT_VAL_OS_MEMPOOL_GUARD +#define MYNEWT_VAL_OS_MEMPOOL_GUARD (0) +#endif + +#ifndef MYNEWT_VAL_OS_MEMPOOL_POISON +#define MYNEWT_VAL_OS_MEMPOOL_POISON (0) +#endif + +#ifndef MYNEWT_VAL_OS_SCHEDULING +#define MYNEWT_VAL_OS_SCHEDULING (1) +#endif + +#ifndef MYNEWT_VAL_OS_SYSINIT_STAGE +#define MYNEWT_VAL_OS_SYSINIT_STAGE (0) +#endif + +#ifndef MYNEWT_VAL_OS_SYSVIEW +#define MYNEWT_VAL_OS_SYSVIEW (0) +#endif + +#ifndef MYNEWT_VAL_OS_SYSVIEW_TRACE_CALLOUT +#define MYNEWT_VAL_OS_SYSVIEW_TRACE_CALLOUT (1) +#endif + +#ifndef MYNEWT_VAL_OS_SYSVIEW_TRACE_EVENTQ +#define MYNEWT_VAL_OS_SYSVIEW_TRACE_EVENTQ (1) +#endif + +#ifndef MYNEWT_VAL_OS_SYSVIEW_TRACE_MBUF +#define MYNEWT_VAL_OS_SYSVIEW_TRACE_MBUF (0) +#endif + +#ifndef MYNEWT_VAL_OS_SYSVIEW_TRACE_MEMPOOL +#define MYNEWT_VAL_OS_SYSVIEW_TRACE_MEMPOOL (0) +#endif + +#ifndef MYNEWT_VAL_OS_SYSVIEW_TRACE_MUTEX +#define MYNEWT_VAL_OS_SYSVIEW_TRACE_MUTEX (1) +#endif + +#ifndef MYNEWT_VAL_OS_SYSVIEW_TRACE_SEM +#define MYNEWT_VAL_OS_SYSVIEW_TRACE_SEM (1) +#endif + +#ifndef MYNEWT_VAL_OS_TASK_RUN_TIME_CPUTIME +#define MYNEWT_VAL_OS_TASK_RUN_TIME_CPUTIME (0) +#endif + +/* Overridden by @apache-mynewt-core/hw/mcu/native (defined by @apache-mynewt-core/kernel/os) */ +#ifndef MYNEWT_VAL_OS_TICKS_PER_SEC +#define MYNEWT_VAL_OS_TICKS_PER_SEC (100) +#endif + +#ifndef MYNEWT_VAL_OS_TIME_DEBUG +#define MYNEWT_VAL_OS_TIME_DEBUG (0) +#endif + +#ifndef MYNEWT_VAL_OS_WATCHDOG_MONITOR +#define MYNEWT_VAL_OS_WATCHDOG_MONITOR (0) +#endif + +#ifndef MYNEWT_VAL_SANITY_INTERVAL +#define MYNEWT_VAL_SANITY_INTERVAL (15000) +#endif + +#ifndef MYNEWT_VAL_WATCHDOG_INTERVAL +#define MYNEWT_VAL_WATCHDOG_INTERVAL (30000) +#endif + +/*** @apache-mynewt-core/net/ip/native_sockets */ +#ifndef MYNEWT_VAL_NATIVE_SOCKETS_MAX +#define MYNEWT_VAL_NATIVE_SOCKETS_MAX (8) +#endif + +#ifndef MYNEWT_VAL_NATIVE_SOCKETS_MAX_UDP +#define MYNEWT_VAL_NATIVE_SOCKETS_MAX_UDP (2048) +#endif + +#ifndef MYNEWT_VAL_NATIVE_SOCKETS_POLL_INTERVAL_MS +#define MYNEWT_VAL_NATIVE_SOCKETS_POLL_INTERVAL_MS (200) +#endif + +#undef MYNEWT_VAL_NATIVE_SOCKETS_POLL_ITVL + +#ifndef MYNEWT_VAL_NATIVE_SOCKETS_PRIO +#define MYNEWT_VAL_NATIVE_SOCKETS_PRIO (2) +#endif + +#ifndef MYNEWT_VAL_NATIVE_SOCKETS_STACK_SZ +#define MYNEWT_VAL_NATIVE_SOCKETS_STACK_SZ (4096) +#endif + +#ifndef MYNEWT_VAL_NATIVE_SOCKETS_SYSINIT_STAGE +#define MYNEWT_VAL_NATIVE_SOCKETS_SYSINIT_STAGE (200) +#endif + +/*** @apache-mynewt-core/sys/console/stub */ +/* + #ifndef MYNEWT_VAL_CONSOLE_UART_BAUD + #define MYNEWT_VAL_CONSOLE_UART_BAUD (115200) + #endif + + #ifndef MYNEWT_VAL_CONSOLE_UART_DEV + #define MYNEWT_VAL_CONSOLE_UART_DEV "uart0" + #endif + + #ifndef MYNEWT_VAL_CONSOLE_UART_FLOW_CONTROL + #define MYNEWT_VAL_CONSOLE_UART_FLOW_CONTROL (UART_FLOW_CTL_NONE) + #endif + */ + +/*** @apache-mynewt-core/sys/flash_map */ +#ifndef MYNEWT_VAL_FLASH_MAP_MAX_AREAS +#define MYNEWT_VAL_FLASH_MAP_MAX_AREAS (10) +#endif + +#ifndef MYNEWT_VAL_FLASH_MAP_SUPPORT_MFG +#define MYNEWT_VAL_FLASH_MAP_SUPPORT_MFG (0) +#endif + +#ifndef MYNEWT_VAL_FLASH_MAP_SYSINIT_STAGE +#define MYNEWT_VAL_FLASH_MAP_SYSINIT_STAGE (9) +#endif + +/*** @apache-mynewt-core/sys/log/common */ +#ifndef MYNEWT_VAL_DFLT_LOG_LVL +#define MYNEWT_VAL_DFLT_LOG_LVL (1) +#endif + +#ifndef MYNEWT_VAL_DFLT_LOG_MOD +#define MYNEWT_VAL_DFLT_LOG_MOD (0) +#endif + +#ifndef MYNEWT_VAL_LOG_GLOBAL_IDX +#define MYNEWT_VAL_LOG_GLOBAL_IDX (1) +#endif + +/*** @apache-mynewt-core/sys/log/modlog */ +#ifndef MYNEWT_VAL_MODLOG_CONSOLE_DFLT +#define MYNEWT_VAL_MODLOG_CONSOLE_DFLT (1) +#endif + +#ifndef MYNEWT_VAL_MODLOG_LOG_MACROS +#define MYNEWT_VAL_MODLOG_LOG_MACROS (0) +#endif + +#ifndef MYNEWT_VAL_MODLOG_MAX_MAPPINGS +#define MYNEWT_VAL_MODLOG_MAX_MAPPINGS (16) +#endif + +#ifndef MYNEWT_VAL_MODLOG_MAX_PRINTF_LEN +#define MYNEWT_VAL_MODLOG_MAX_PRINTF_LEN (128) +#endif + +#ifndef MYNEWT_VAL_MODLOG_SYSINIT_STAGE +#define MYNEWT_VAL_MODLOG_SYSINIT_STAGE (100) +#endif + +/*** @apache-mynewt-core/sys/log/stub */ +#ifndef MYNEWT_VAL_LOG_CONSOLE +#define MYNEWT_VAL_LOG_CONSOLE (1) +#endif + +#ifndef MYNEWT_VAL_LOG_FCB +#define MYNEWT_VAL_LOG_FCB (0) +#endif + +#ifndef MYNEWT_VAL_LOG_FCB_SLOT1 +#define MYNEWT_VAL_LOG_FCB_SLOT1 (0) +#endif + +/* Overridden by @apache-mynewt-nimble/porting/targets/linux_blemesh (defined by @apache-mynewt-core/sys/log/stub) */ +#ifndef MYNEWT_VAL_LOG_LEVEL +#define MYNEWT_VAL_LOG_LEVEL (0) +#endif + +/*** @apache-mynewt-core/sys/sys */ +#ifndef MYNEWT_VAL_DEBUG_PANIC_ENABLED +#define MYNEWT_VAL_DEBUG_PANIC_ENABLED (1) +#endif + +/*** @apache-mynewt-core/sys/sysdown */ +#ifndef MYNEWT_VAL_SYSDOWN_CONSTRAIN_DOWN +#define MYNEWT_VAL_SYSDOWN_CONSTRAIN_DOWN (1) +#endif + +#ifndef MYNEWT_VAL_SYSDOWN_PANIC_FILE_LINE +#define MYNEWT_VAL_SYSDOWN_PANIC_FILE_LINE (0) +#endif + +#ifndef MYNEWT_VAL_SYSDOWN_PANIC_MESSAGE +#define MYNEWT_VAL_SYSDOWN_PANIC_MESSAGE (0) +#endif + +#ifndef MYNEWT_VAL_SYSDOWN_TIMEOUT_MS +#define MYNEWT_VAL_SYSDOWN_TIMEOUT_MS (10000) +#endif + +/*** @apache-mynewt-core/sys/sysinit */ +#ifndef MYNEWT_VAL_SYSINIT_CONSTRAIN_INIT +#define MYNEWT_VAL_SYSINIT_CONSTRAIN_INIT (1) +#endif + +/* Overridden by @apache-mynewt-core/hw/bsp/native (defined by @apache-mynewt-core/sys/sysinit) */ +#ifndef MYNEWT_VAL_SYSINIT_PANIC_FILE_LINE +#define MYNEWT_VAL_SYSINIT_PANIC_FILE_LINE (1) +#endif + +/* Overridden by @apache-mynewt-core/hw/bsp/native (defined by @apache-mynewt-core/sys/sysinit) */ +#ifndef MYNEWT_VAL_SYSINIT_PANIC_MESSAGE +#define MYNEWT_VAL_SYSINIT_PANIC_MESSAGE (1) +#endif + +/*** @apache-mynewt-core/util/rwlock */ +#ifndef MYNEWT_VAL_RWLOCK_DEBUG +#define MYNEWT_VAL_RWLOCK_DEBUG (0) +#endif + +/*** @apache-mynewt-nimble/nimble */ +#ifndef MYNEWT_VAL_BLE_CONN_SUBRATING +#define MYNEWT_VAL_BLE_CONN_SUBRATING (0) +#endif + +#ifndef MYNEWT_VAL_BLE_EXT_ADV +#define MYNEWT_VAL_BLE_EXT_ADV (0) +#endif + +#ifndef MYNEWT_VAL_BLE_EXT_ADV_MAX_SIZE +#define MYNEWT_VAL_BLE_EXT_ADV_MAX_SIZE (31) +#endif + +#ifndef MYNEWT_VAL_BLE_HCI_VS +#define MYNEWT_VAL_BLE_HCI_VS (0) +#endif + +#ifndef MYNEWT_VAL_BLE_HCI_VS_OCF_OFFSET +#define MYNEWT_VAL_BLE_HCI_VS_OCF_OFFSET (0) +#endif + +#ifndef MYNEWT_VAL_BLE_ISO +#define MYNEWT_VAL_BLE_ISO (0) +#endif + +#ifndef MYNEWT_VAL_BLE_ISO_BROADCAST_SINK +#define MYNEWT_VAL_BLE_ISO_BROADCAST_SINK (0) +#endif + +#ifndef MYNEWT_VAL_BLE_ISO_BROADCAST_SOURCE +#define MYNEWT_VAL_BLE_ISO_BROADCAST_SOURCE (0) +#endif + +#ifndef MYNEWT_VAL_BLE_ISO_TEST +#define MYNEWT_VAL_BLE_ISO_TEST (0) +#endif + +#ifndef MYNEWT_VAL_BLE_MAX_CONNECTIONS +#define MYNEWT_VAL_BLE_MAX_CONNECTIONS (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MAX_PERIODIC_SYNCS +#define MYNEWT_VAL_BLE_MAX_PERIODIC_SYNCS (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MULTI_ADV_INSTANCES +#define MYNEWT_VAL_BLE_MULTI_ADV_INSTANCES (0) +#endif + +#ifndef MYNEWT_VAL_BLE_PERIODIC_ADV +#define MYNEWT_VAL_BLE_PERIODIC_ADV (0) +#endif + +#ifndef MYNEWT_VAL_BLE_PERIODIC_ADV_SYNC_BIGINFO_REPORTS +#define MYNEWT_VAL_BLE_PERIODIC_ADV_SYNC_BIGINFO_REPORTS (0) +#endif + +#ifndef MYNEWT_VAL_BLE_PERIODIC_ADV_SYNC_TRANSFER +#define MYNEWT_VAL_BLE_PERIODIC_ADV_SYNC_TRANSFER (0) +#endif + +#ifndef MYNEWT_VAL_BLE_PHY_2M +#define MYNEWT_VAL_BLE_PHY_2M (0) +#endif + +#ifndef MYNEWT_VAL_BLE_PHY_CODED +#define MYNEWT_VAL_BLE_PHY_CODED (0) +#endif + +#ifndef MYNEWT_VAL_BLE_POWER_CONTROL +#define MYNEWT_VAL_BLE_POWER_CONTROL (0) +#endif + +#ifndef MYNEWT_VAL_BLE_ROLE_BROADCASTER +#define MYNEWT_VAL_BLE_ROLE_BROADCASTER (1) +#endif + +#ifndef MYNEWT_VAL_BLE_ROLE_CENTRAL +#define MYNEWT_VAL_BLE_ROLE_CENTRAL (1) +#endif + +#ifndef MYNEWT_VAL_BLE_ROLE_OBSERVER +#define MYNEWT_VAL_BLE_ROLE_OBSERVER (1) +#endif + +#ifndef MYNEWT_VAL_BLE_ROLE_PERIPHERAL +#define MYNEWT_VAL_BLE_ROLE_PERIPHERAL (1) +#endif + +#ifndef MYNEWT_VAL_BLE_VERSION +#define MYNEWT_VAL_BLE_VERSION (50) +#endif + +#ifndef MYNEWT_VAL_BLE_WHITELIST +#define MYNEWT_VAL_BLE_WHITELIST (1) +#endif + +/*** @apache-mynewt-nimble/nimble/host */ +#ifndef MYNEWT_VAL_BLE_ATT_PREFERRED_MTU +#define MYNEWT_VAL_BLE_ATT_PREFERRED_MTU (256) +#endif + +#ifndef MYNEWT_VAL_BLE_ATT_SVR_FIND_INFO +#define MYNEWT_VAL_BLE_ATT_SVR_FIND_INFO (1) +#endif + +#ifndef MYNEWT_VAL_BLE_ATT_SVR_FIND_TYPE +#define MYNEWT_VAL_BLE_ATT_SVR_FIND_TYPE (1) +#endif + +#ifndef MYNEWT_VAL_BLE_ATT_SVR_INDICATE +#define MYNEWT_VAL_BLE_ATT_SVR_INDICATE (1) +#endif + +#ifndef MYNEWT_VAL_BLE_ATT_SVR_MAX_PREP_ENTRIES +#define MYNEWT_VAL_BLE_ATT_SVR_MAX_PREP_ENTRIES (64) +#endif + +#ifndef MYNEWT_VAL_BLE_ATT_SVR_NOTIFY +#define MYNEWT_VAL_BLE_ATT_SVR_NOTIFY (1) +#endif + +#ifndef MYNEWT_VAL_BLE_ATT_SVR_NOTIFY_MULTI +#define MYNEWT_VAL_BLE_ATT_SVR_NOTIFY_MULTI (MYNEWT_VAL_BLE_ATT_SVR_NOTIFY && (MYNEWT_VAL_BLE_VERSION >= 52)) +#endif + +#ifndef MYNEWT_VAL_BLE_ATT_SVR_QUEUED_WRITE +#define MYNEWT_VAL_BLE_ATT_SVR_QUEUED_WRITE (1) +#endif + +#ifndef MYNEWT_VAL_BLE_ATT_SVR_QUEUED_WRITE_TMO +#define MYNEWT_VAL_BLE_ATT_SVR_QUEUED_WRITE_TMO (30000) +#endif + +#ifndef MYNEWT_VAL_BLE_ATT_SVR_READ +#define MYNEWT_VAL_BLE_ATT_SVR_READ (1) +#endif + +#ifndef MYNEWT_VAL_BLE_ATT_SVR_READ_BLOB +#define MYNEWT_VAL_BLE_ATT_SVR_READ_BLOB (1) +#endif + +#ifndef MYNEWT_VAL_BLE_ATT_SVR_READ_GROUP_TYPE +#define MYNEWT_VAL_BLE_ATT_SVR_READ_GROUP_TYPE (1) +#endif + +#ifndef MYNEWT_VAL_BLE_ATT_SVR_READ_MULT +#define MYNEWT_VAL_BLE_ATT_SVR_READ_MULT (1) +#endif + +#ifndef MYNEWT_VAL_BLE_ATT_SVR_READ_TYPE +#define MYNEWT_VAL_BLE_ATT_SVR_READ_TYPE (1) +#endif + +#ifndef MYNEWT_VAL_BLE_ATT_SVR_SIGNED_WRITE +#define MYNEWT_VAL_BLE_ATT_SVR_SIGNED_WRITE (1) +#endif + +#ifndef MYNEWT_VAL_BLE_ATT_SVR_WRITE +#define MYNEWT_VAL_BLE_ATT_SVR_WRITE (1) +#endif + +#ifndef MYNEWT_VAL_BLE_ATT_SVR_WRITE_NO_RSP +#define MYNEWT_VAL_BLE_ATT_SVR_WRITE_NO_RSP (1) +#endif + +#ifndef MYNEWT_VAL_BLE_AUDIO_MAX_CODEC_RECORDS +#define MYNEWT_VAL_BLE_AUDIO_MAX_CODEC_RECORDS (0) +#endif + +#ifndef MYNEWT_VAL_BLE_EATT_CHAN_NUM +#define MYNEWT_VAL_BLE_EATT_CHAN_NUM (0) +#endif + +#ifndef MYNEWT_VAL_BLE_EATT_LOG_LVL +#define MYNEWT_VAL_BLE_EATT_LOG_LVL (1) +#endif + +#ifndef MYNEWT_VAL_BLE_EATT_LOG_MOD +#define MYNEWT_VAL_BLE_EATT_LOG_MOD (27) +#endif + +#ifndef MYNEWT_VAL_BLE_EATT_MTU +#define MYNEWT_VAL_BLE_EATT_MTU (128) +#endif + +#ifndef MYNEWT_VAL_BLE_GAP_MAX_PENDING_CONN_PARAM_UPDATE +#define MYNEWT_VAL_BLE_GAP_MAX_PENDING_CONN_PARAM_UPDATE (1) +#endif + +#ifndef MYNEWT_VAL_BLE_GATT_DISC_ALL_CHRS +#define MYNEWT_VAL_BLE_GATT_DISC_ALL_CHRS (MYNEWT_VAL_BLE_ROLE_CENTRAL) +#endif + +#ifndef MYNEWT_VAL_BLE_GATT_DISC_ALL_DSCS +#define MYNEWT_VAL_BLE_GATT_DISC_ALL_DSCS (MYNEWT_VAL_BLE_ROLE_CENTRAL) +#endif + +#ifndef MYNEWT_VAL_BLE_GATT_DISC_ALL_SVCS +#define MYNEWT_VAL_BLE_GATT_DISC_ALL_SVCS (MYNEWT_VAL_BLE_ROLE_CENTRAL) +#endif + +#ifndef MYNEWT_VAL_BLE_GATT_DISC_CHR_UUID +#define MYNEWT_VAL_BLE_GATT_DISC_CHR_UUID (MYNEWT_VAL_BLE_ROLE_CENTRAL) +#endif + +#ifndef MYNEWT_VAL_BLE_GATT_DISC_SVC_UUID +#define MYNEWT_VAL_BLE_GATT_DISC_SVC_UUID (MYNEWT_VAL_BLE_ROLE_CENTRAL) +#endif + +#ifndef MYNEWT_VAL_BLE_GATT_FIND_INC_SVCS +#define MYNEWT_VAL_BLE_GATT_FIND_INC_SVCS (MYNEWT_VAL_BLE_ROLE_CENTRAL) +#endif + +#ifndef MYNEWT_VAL_BLE_GATT_INDICATE +#define MYNEWT_VAL_BLE_GATT_INDICATE (1) +#endif + +#ifndef MYNEWT_VAL_BLE_GATT_MAX_PROCS +#define MYNEWT_VAL_BLE_GATT_MAX_PROCS (4) +#endif + +#ifndef MYNEWT_VAL_BLE_GATT_NOTIFY +#define MYNEWT_VAL_BLE_GATT_NOTIFY (1) +#endif + +#ifndef MYNEWT_VAL_BLE_GATT_NOTIFY_MULTIPLE +#define MYNEWT_VAL_BLE_GATT_NOTIFY_MULTIPLE ((MYNEWT_VAL_BLE_VERSION >= 52)) +#endif + +#ifndef MYNEWT_VAL_BLE_GATT_READ +#define MYNEWT_VAL_BLE_GATT_READ (MYNEWT_VAL_BLE_ROLE_CENTRAL) +#endif + +#ifndef MYNEWT_VAL_BLE_GATT_READ_LONG +#define MYNEWT_VAL_BLE_GATT_READ_LONG (MYNEWT_VAL_BLE_ROLE_CENTRAL) +#endif + +#ifndef MYNEWT_VAL_BLE_GATT_READ_MAX_ATTRS +#define MYNEWT_VAL_BLE_GATT_READ_MAX_ATTRS (8) +#endif + +#ifndef MYNEWT_VAL_BLE_GATT_READ_MULT +#define MYNEWT_VAL_BLE_GATT_READ_MULT (MYNEWT_VAL_BLE_ROLE_CENTRAL) +#endif + +#ifndef MYNEWT_VAL_BLE_GATT_READ_MULT_VAR +#define MYNEWT_VAL_BLE_GATT_READ_MULT_VAR (MYNEWT_VAL_BLE_ROLE_CENTRAL && (MYNEWT_VAL_BLE_VERSION >= 52)) +#endif + +#ifndef MYNEWT_VAL_BLE_GATT_READ_UUID +#define MYNEWT_VAL_BLE_GATT_READ_UUID (MYNEWT_VAL_BLE_ROLE_CENTRAL) +#endif + +#ifndef MYNEWT_VAL_BLE_GATT_RESUME_RATE +#define MYNEWT_VAL_BLE_GATT_RESUME_RATE (1000) +#endif + +#ifndef MYNEWT_VAL_BLE_GATT_SIGNED_WRITE +#define MYNEWT_VAL_BLE_GATT_SIGNED_WRITE (MYNEWT_VAL_BLE_ROLE_CENTRAL) +#endif + +#ifndef MYNEWT_VAL_BLE_GATT_WRITE +#define MYNEWT_VAL_BLE_GATT_WRITE (MYNEWT_VAL_BLE_ROLE_CENTRAL) +#endif + +#ifndef MYNEWT_VAL_BLE_GATT_WRITE_LONG +#define MYNEWT_VAL_BLE_GATT_WRITE_LONG (MYNEWT_VAL_BLE_ROLE_CENTRAL) +#endif + +#ifndef MYNEWT_VAL_BLE_GATT_WRITE_MAX_ATTRS +#define MYNEWT_VAL_BLE_GATT_WRITE_MAX_ATTRS (4) +#endif + +#ifndef MYNEWT_VAL_BLE_GATT_WRITE_NO_RSP +#define MYNEWT_VAL_BLE_GATT_WRITE_NO_RSP (MYNEWT_VAL_BLE_ROLE_CENTRAL) +#endif + +#ifndef MYNEWT_VAL_BLE_GATT_WRITE_RELIABLE +#define MYNEWT_VAL_BLE_GATT_WRITE_RELIABLE (MYNEWT_VAL_BLE_ROLE_CENTRAL) +#endif + +#ifndef MYNEWT_VAL_BLE_HOST +#define MYNEWT_VAL_BLE_HOST (1) +#endif + +#ifndef MYNEWT_VAL_BLE_HS_AUTO_START +#define MYNEWT_VAL_BLE_HS_AUTO_START (1) +#endif + +#ifndef MYNEWT_VAL_BLE_HS_DEBUG +#define MYNEWT_VAL_BLE_HS_DEBUG (0) +#endif + +#ifndef MYNEWT_VAL_BLE_HS_EXT_ADV_LEGACY_INSTANCE +#define MYNEWT_VAL_BLE_HS_EXT_ADV_LEGACY_INSTANCE (0) +#endif + +#ifndef MYNEWT_VAL_BLE_HS_FLOW_CTRL +#define MYNEWT_VAL_BLE_HS_FLOW_CTRL (0) +#endif + +#ifndef MYNEWT_VAL_BLE_HS_FLOW_CTRL_ITVL +#define MYNEWT_VAL_BLE_HS_FLOW_CTRL_ITVL (1000) +#endif + +#ifndef MYNEWT_VAL_BLE_HS_FLOW_CTRL_THRESH +#define MYNEWT_VAL_BLE_HS_FLOW_CTRL_THRESH (2) +#endif + +#ifndef MYNEWT_VAL_BLE_HS_FLOW_CTRL_TX_ON_DISCONNECT +#define MYNEWT_VAL_BLE_HS_FLOW_CTRL_TX_ON_DISCONNECT (0) +#endif + +#ifndef MYNEWT_VAL_BLE_HS_GAP_UNHANDLED_HCI_EVENT +#define MYNEWT_VAL_BLE_HS_GAP_UNHANDLED_HCI_EVENT (0) +#endif + +#ifndef MYNEWT_VAL_BLE_HS_LOG_LVL +#define MYNEWT_VAL_BLE_HS_LOG_LVL (1) +#endif + +#ifndef MYNEWT_VAL_BLE_HS_LOG_MOD +#define MYNEWT_VAL_BLE_HS_LOG_MOD (4) +#endif + +#ifndef MYNEWT_VAL_BLE_HS_PHONY_HCI_ACKS +#define MYNEWT_VAL_BLE_HS_PHONY_HCI_ACKS (0) +#endif + +#ifndef MYNEWT_VAL_BLE_HS_REQUIRE_OS +#define MYNEWT_VAL_BLE_HS_REQUIRE_OS (1) +#endif + +#ifndef MYNEWT_VAL_BLE_HS_STOP_ON_SHUTDOWN +#define MYNEWT_VAL_BLE_HS_STOP_ON_SHUTDOWN (1) +#endif + +#ifndef MYNEWT_VAL_BLE_HS_STOP_ON_SHUTDOWN_TIMEOUT +#define MYNEWT_VAL_BLE_HS_STOP_ON_SHUTDOWN_TIMEOUT (2000) +#endif + +#ifndef MYNEWT_VAL_BLE_HS_SYSINIT_STAGE +#define MYNEWT_VAL_BLE_HS_SYSINIT_STAGE (200) +#endif + +#ifndef MYNEWT_VAL_BLE_L2CAP_COC_MAX_NUM +#define MYNEWT_VAL_BLE_L2CAP_COC_MAX_NUM (0) +#endif + +#ifndef MYNEWT_VAL_BLE_L2CAP_COC_MPS +#define MYNEWT_VAL_BLE_L2CAP_COC_MPS (MYNEWT_VAL_MSYS_1_BLOCK_SIZE-8) +#endif + +#ifndef MYNEWT_VAL_BLE_L2CAP_COC_SDU_BUFF_COUNT +#define MYNEWT_VAL_BLE_L2CAP_COC_SDU_BUFF_COUNT (1) +#endif + +#ifndef MYNEWT_VAL_BLE_L2CAP_ENHANCED_COC +#define MYNEWT_VAL_BLE_L2CAP_ENHANCED_COC (0) +#endif + +#ifndef MYNEWT_VAL_BLE_L2CAP_JOIN_RX_FRAGS +#define MYNEWT_VAL_BLE_L2CAP_JOIN_RX_FRAGS (1) +#endif + +#ifndef MYNEWT_VAL_BLE_L2CAP_MAX_CHANS +#define MYNEWT_VAL_BLE_L2CAP_MAX_CHANS (3*MYNEWT_VAL_BLE_MAX_CONNECTIONS) +#endif + +#ifndef MYNEWT_VAL_BLE_L2CAP_RX_FRAG_TIMEOUT +#define MYNEWT_VAL_BLE_L2CAP_RX_FRAG_TIMEOUT (30000) +#endif + +#ifndef MYNEWT_VAL_BLE_L2CAP_SIG_MAX_PROCS +#define MYNEWT_VAL_BLE_L2CAP_SIG_MAX_PROCS (1) +#endif + +#ifndef MYNEWT_VAL_BLE_ISO_MAX_BIGS +#define MYNEWT_VAL_BLE_ISO_MAX_BIGS (MYNEWT_VAL_BLE_MULTI_ADV_INSTANCES) +#endif + +#ifndef MYNEWT_VAL_BLE_ISO_MAX_BISES +#define MYNEWT_VAL_BLE_ISO_MAX_BISES (4) +#endif + +/* Overridden by @apache-mynewt-nimble/porting/targets/linux_blemesh (defined by @apache-mynewt-nimble/nimble/host) */ +#ifndef MYNEWT_VAL_BLE_MESH +#define MYNEWT_VAL_BLE_MESH (1) +#endif + +#ifndef MYNEWT_VAL_BLE_RPA_TIMEOUT +#define MYNEWT_VAL_BLE_RPA_TIMEOUT (300) +#endif + +#ifndef MYNEWT_VAL_BLE_SM_BONDING +#define MYNEWT_VAL_BLE_SM_BONDING (0) +#endif + +#ifndef MYNEWT_VAL_BLE_SM_CSIS_SIRK +#define MYNEWT_VAL_BLE_SM_CSIS_SIRK (0) +#endif + +#ifndef MYNEWT_VAL_BLE_SM_IO_CAP +#define MYNEWT_VAL_BLE_SM_IO_CAP (BLE_HS_IO_NO_INPUT_OUTPUT) +#endif + +#ifndef MYNEWT_VAL_BLE_SM_KEYPRESS +#define MYNEWT_VAL_BLE_SM_KEYPRESS (0) +#endif + +#ifndef MYNEWT_VAL_BLE_SM_LEGACY +#define MYNEWT_VAL_BLE_SM_LEGACY (1) +#endif + +#ifndef MYNEWT_VAL_BLE_SM_LVL +#define MYNEWT_VAL_BLE_SM_LVL (0) +#endif + +#ifndef MYNEWT_VAL_BLE_SM_MAX_PROCS +#define MYNEWT_VAL_BLE_SM_MAX_PROCS (1) +#endif + +#ifndef MYNEWT_VAL_BLE_SM_MITM +#define MYNEWT_VAL_BLE_SM_MITM (0) +#endif + +#ifndef MYNEWT_VAL_BLE_SM_OOB_DATA_FLAG +#define MYNEWT_VAL_BLE_SM_OOB_DATA_FLAG (0) +#endif + +#ifndef MYNEWT_VAL_BLE_SM_OUR_KEY_DIST +#define MYNEWT_VAL_BLE_SM_OUR_KEY_DIST (0) +#endif + +/* Overridden by @apache-mynewt-nimble/nimble/host (defined by @apache-mynewt-nimble/nimble/host) */ +#ifndef MYNEWT_VAL_BLE_SM_SC +#define MYNEWT_VAL_BLE_SM_SC (1) +#endif + +#ifndef MYNEWT_VAL_BLE_SM_SC_DEBUG_KEYS +#define MYNEWT_VAL_BLE_SM_SC_DEBUG_KEYS (0) +#endif + +#ifndef MYNEWT_VAL_BLE_SM_SC_ONLY +#define MYNEWT_VAL_BLE_SM_SC_ONLY (0) +#endif + +#ifndef MYNEWT_VAL_BLE_SM_THEIR_KEY_DIST +#define MYNEWT_VAL_BLE_SM_THEIR_KEY_DIST (0) +#endif + +#ifndef MYNEWT_VAL_BLE_STORE_MAX_BONDS +#define MYNEWT_VAL_BLE_STORE_MAX_BONDS (3) +#endif + +#ifndef MYNEWT_VAL_BLE_STORE_MAX_CCCDS +#define MYNEWT_VAL_BLE_STORE_MAX_CCCDS (8) +#endif + +/*** @apache-mynewt-nimble/nimble/host/mesh */ +#ifndef MYNEWT_VAL_BLE_MESH_ACCESS_LAYER_MSG +#define MYNEWT_VAL_BLE_MESH_ACCESS_LAYER_MSG (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_ACCESS_LOG_LVL +#define MYNEWT_VAL_BLE_MESH_ACCESS_LOG_LVL (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_ACCESS_LOG_MOD +#define MYNEWT_VAL_BLE_MESH_ACCESS_LOG_MOD (10) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_ADV +#define MYNEWT_VAL_BLE_MESH_ADV (1) +#endif + +/* Overridden by @apache-mynewt-nimble/porting/targets/linux_blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ +#ifndef MYNEWT_VAL_BLE_MESH_ADV_BUF_COUNT +#define MYNEWT_VAL_BLE_MESH_ADV_BUF_COUNT (20) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_ADV_EXT +#define MYNEWT_VAL_BLE_MESH_ADV_EXT (0) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_ADV_LEGACY +#define MYNEWT_VAL_BLE_MESH_ADV_LEGACY (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_ADV_LOG_LVL +#define MYNEWT_VAL_BLE_MESH_ADV_LOG_LVL (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_ADV_LOG_MOD +#define MYNEWT_VAL_BLE_MESH_ADV_LOG_MOD (11) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_ADV_STACK_SIZE +#define MYNEWT_VAL_BLE_MESH_ADV_STACK_SIZE (768) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_ADV_TASK_PRIO +#define MYNEWT_VAL_BLE_MESH_ADV_TASK_PRIO (9) +#endif + +/* Overridden by @apache-mynewt-nimble/porting/targets/linux_blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ +#ifndef MYNEWT_VAL_BLE_MESH_APP_KEY_COUNT +#define MYNEWT_VAL_BLE_MESH_APP_KEY_COUNT (4) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_BEACON_ENABLED +#define MYNEWT_VAL_BLE_MESH_BEACON_ENABLED (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_BEACON_LOG_LVL +#define MYNEWT_VAL_BLE_MESH_BEACON_LOG_LVL (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_BEACON_LOG_MOD +#define MYNEWT_VAL_BLE_MESH_BEACON_LOG_MOD (12) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_CDB +#define MYNEWT_VAL_BLE_MESH_CDB (0) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_CDB_APP_KEY_COUNT +#define MYNEWT_VAL_BLE_MESH_CDB_APP_KEY_COUNT (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_CDB_NODE_COUNT +#define MYNEWT_VAL_BLE_MESH_CDB_NODE_COUNT (8) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_CDB_SUBNET_COUNT +#define MYNEWT_VAL_BLE_MESH_CDB_SUBNET_COUNT (1) +#endif + +/* Overridden by @apache-mynewt-nimble/porting/targets/linux_blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ +#ifndef MYNEWT_VAL_BLE_MESH_CFG_CLI +#define MYNEWT_VAL_BLE_MESH_CFG_CLI (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_CRPL +#define MYNEWT_VAL_BLE_MESH_CRPL (10) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_CRYPTO_LOG_LVL +#define MYNEWT_VAL_BLE_MESH_CRYPTO_LOG_LVL (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_CRYPTO_LOG_MOD +#define MYNEWT_VAL_BLE_MESH_CRYPTO_LOG_MOD (13) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_DEBUG_CDB +#define MYNEWT_VAL_BLE_MESH_DEBUG_CDB (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_DEBUG_CFG +#define MYNEWT_VAL_BLE_MESH_DEBUG_CFG (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_DEBUG_USE_ID_ADDR +#define MYNEWT_VAL_BLE_MESH_DEBUG_USE_ID_ADDR (0) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_DEFAULT_TTL +#define MYNEWT_VAL_BLE_MESH_DEFAULT_TTL (7) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_DEVICE_NAME +#define MYNEWT_VAL_BLE_MESH_DEVICE_NAME "nimble-mesh-node" +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_DEV_UUID +#define MYNEWT_VAL_BLE_MESH_DEV_UUID (((uint8_t[16]) {0x11, 0x22, 0})) +#endif + +/* Overridden by @apache-mynewt-nimble/porting/targets/linux_blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ +#ifndef MYNEWT_VAL_BLE_MESH_FRIEND +#define MYNEWT_VAL_BLE_MESH_FRIEND (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_FRIEND_ENABLED +#define MYNEWT_VAL_BLE_MESH_FRIEND_ENABLED (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_FRIEND_LOG_LVL +#define MYNEWT_VAL_BLE_MESH_FRIEND_LOG_LVL (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_FRIEND_LOG_MOD +#define MYNEWT_VAL_BLE_MESH_FRIEND_LOG_MOD (14) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_FRIEND_LPN_COUNT +#define MYNEWT_VAL_BLE_MESH_FRIEND_LPN_COUNT (2) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_FRIEND_QUEUE_SIZE +#define MYNEWT_VAL_BLE_MESH_FRIEND_QUEUE_SIZE (16) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_FRIEND_RECV_WIN +#define MYNEWT_VAL_BLE_MESH_FRIEND_RECV_WIN (255) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_FRIEND_SEG_RX +#define MYNEWT_VAL_BLE_MESH_FRIEND_SEG_RX (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_FRIEND_SUB_LIST_SIZE +#define MYNEWT_VAL_BLE_MESH_FRIEND_SUB_LIST_SIZE (3) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_GATT +#define MYNEWT_VAL_BLE_MESH_GATT (1) +#endif + +/* Overridden by @apache-mynewt-nimble/porting/targets/linux_blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ +#ifndef MYNEWT_VAL_BLE_MESH_GATT_PROXY +#define MYNEWT_VAL_BLE_MESH_GATT_PROXY (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_GATT_PROXY_ENABLED +#define MYNEWT_VAL_BLE_MESH_GATT_PROXY_ENABLED (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_GATT_SERVER +#define MYNEWT_VAL_BLE_MESH_GATT_SERVER (0) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_HEALTH_CLI +#define MYNEWT_VAL_BLE_MESH_HEALTH_CLI (0) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_HEARTBEAT_LOG_LVL +#define MYNEWT_VAL_BLE_MESH_HEARTBEAT_LOG_LVL (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_HEARTBEAT_LOG_MOD +#define MYNEWT_VAL_BLE_MESH_HEARTBEAT_LOG_MOD (26) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_IVU_DIVIDER +#define MYNEWT_VAL_BLE_MESH_IVU_DIVIDER (4) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_IV_UPDATE_SEQ_LIMIT +#define MYNEWT_VAL_BLE_MESH_IV_UPDATE_SEQ_LIMIT (0x800000) +#endif + +/* Overridden by @apache-mynewt-nimble/porting/targets/linux_blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ +#ifndef MYNEWT_VAL_BLE_MESH_IV_UPDATE_TEST +#define MYNEWT_VAL_BLE_MESH_IV_UPDATE_TEST (1) +#endif + +/* Overridden by @apache-mynewt-nimble/porting/targets/linux_blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ +#ifndef MYNEWT_VAL_BLE_MESH_LABEL_COUNT +#define MYNEWT_VAL_BLE_MESH_LABEL_COUNT (2) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_LOG_LVL +#define MYNEWT_VAL_BLE_MESH_LOG_LVL (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_LOG_MOD +#define MYNEWT_VAL_BLE_MESH_LOG_MOD (9) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_LOOPBACK_BUFS +#define MYNEWT_VAL_BLE_MESH_LOOPBACK_BUFS (3) +#endif + +/* Overridden by @apache-mynewt-nimble/porting/targets/linux_blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ +#ifndef MYNEWT_VAL_BLE_MESH_LOW_POWER +#define MYNEWT_VAL_BLE_MESH_LOW_POWER (0) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_LOW_POWER_LOG_LVL +#define MYNEWT_VAL_BLE_MESH_LOW_POWER_LOG_LVL (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_LOW_POWER_LOG_MOD +#define MYNEWT_VAL_BLE_MESH_LOW_POWER_LOG_MOD (15) +#endif + +/* Overridden by @apache-mynewt-nimble/porting/targets/linux_blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ +#ifndef MYNEWT_VAL_BLE_MESH_LPN_AUTO +#define MYNEWT_VAL_BLE_MESH_LPN_AUTO (0) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_LPN_AUTO_TIMEOUT +#define MYNEWT_VAL_BLE_MESH_LPN_AUTO_TIMEOUT (15) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_LPN_ESTABLISHMENT +#define MYNEWT_VAL_BLE_MESH_LPN_ESTABLISHMENT (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_LPN_GROUPS +#define MYNEWT_VAL_BLE_MESH_LPN_GROUPS (10) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_LPN_INIT_POLL_TIMEOUT +#define MYNEWT_VAL_BLE_MESH_LPN_INIT_POLL_TIMEOUT (MYNEWT_VAL_BLE_MESH_LPN_POLL_TIMEOUT) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_LPN_MIN_QUEUE_SIZE +#define MYNEWT_VAL_BLE_MESH_LPN_MIN_QUEUE_SIZE (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_LPN_POLL_TIMEOUT +#define MYNEWT_VAL_BLE_MESH_LPN_POLL_TIMEOUT (300) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_LPN_RECV_DELAY +#define MYNEWT_VAL_BLE_MESH_LPN_RECV_DELAY (100) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_LPN_RECV_WIN_FACTOR +#define MYNEWT_VAL_BLE_MESH_LPN_RECV_WIN_FACTOR (0) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_LPN_RETRY_TIMEOUT +#define MYNEWT_VAL_BLE_MESH_LPN_RETRY_TIMEOUT (8) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_LPN_RSSI_FACTOR +#define MYNEWT_VAL_BLE_MESH_LPN_RSSI_FACTOR (0) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_LPN_SCAN_LATENCY +#define MYNEWT_VAL_BLE_MESH_LPN_SCAN_LATENCY (10) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_LPN_SUB_ALL_NODES_ADDR +#define MYNEWT_VAL_BLE_MESH_LPN_SUB_ALL_NODES_ADDR (0) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_MODEL_EXTENSIONS +#define MYNEWT_VAL_BLE_MESH_MODEL_EXTENSIONS (0) +#endif + +/* Overridden by @apache-mynewt-nimble/porting/targets/linux_blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ +#ifndef MYNEWT_VAL_BLE_MESH_MODEL_GROUP_COUNT +#define MYNEWT_VAL_BLE_MESH_MODEL_GROUP_COUNT (2) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_MODEL_KEY_COUNT +#define MYNEWT_VAL_BLE_MESH_MODEL_KEY_COUNT (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_MODEL_LOG_LVL +#define MYNEWT_VAL_BLE_MESH_MODEL_LOG_LVL (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_MODEL_LOG_MOD +#define MYNEWT_VAL_BLE_MESH_MODEL_LOG_MOD (16) +#endif + +/* Overridden by @apache-mynewt-nimble/porting/targets/linux_blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ +#ifndef MYNEWT_VAL_BLE_MESH_MODEL_VND_MSG_CID_FORCE +#define MYNEWT_VAL_BLE_MESH_MODEL_VND_MSG_CID_FORCE (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_MSG_CACHE_SIZE +#define MYNEWT_VAL_BLE_MESH_MSG_CACHE_SIZE (10) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_NETWORK_TRANSMIT_COUNT +#define MYNEWT_VAL_BLE_MESH_NETWORK_TRANSMIT_COUNT (2) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_NETWORK_TRANSMIT_INTERVAL +#define MYNEWT_VAL_BLE_MESH_NETWORK_TRANSMIT_INTERVAL (20) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_NET_BUF_USER_DATA_SIZE +#define MYNEWT_VAL_BLE_MESH_NET_BUF_USER_DATA_SIZE (4) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_NET_KEYS_LOG_LVL +#define MYNEWT_VAL_BLE_MESH_NET_KEYS_LOG_LVL (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_NET_KEYS_LOG_MOD +#define MYNEWT_VAL_BLE_MESH_NET_KEYS_LOG_MOD (23) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_NET_LOG_LVL +#define MYNEWT_VAL_BLE_MESH_NET_LOG_LVL (2) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_NET_LOG_MOD +#define MYNEWT_VAL_BLE_MESH_NET_LOG_MOD (17) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_NODE_ID_TIMEOUT +#define MYNEWT_VAL_BLE_MESH_NODE_ID_TIMEOUT (60) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_OOB_INPUT_ACTIONS +#define MYNEWT_VAL_BLE_MESH_OOB_INPUT_ACTIONS (((BT_MESH_NO_INPUT))) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_OOB_INPUT_SIZE +#define MYNEWT_VAL_BLE_MESH_OOB_INPUT_SIZE (4) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_OOB_OUTPUT_ACTIONS +#define MYNEWT_VAL_BLE_MESH_OOB_OUTPUT_ACTIONS (((BT_MESH_DISPLAY_NUMBER))) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_OOB_OUTPUT_SIZE +#define MYNEWT_VAL_BLE_MESH_OOB_OUTPUT_SIZE (4) +#endif + +/* Overridden by @apache-mynewt-nimble/porting/targets/linux_blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ +#ifndef MYNEWT_VAL_BLE_MESH_PB_ADV +#define MYNEWT_VAL_BLE_MESH_PB_ADV (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_PB_ADV_RETRANS_TIMEOUT +#define MYNEWT_VAL_BLE_MESH_PB_ADV_RETRANS_TIMEOUT (500) +#endif + +/* Overridden by @apache-mynewt-nimble/porting/targets/linux_blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ +#ifndef MYNEWT_VAL_BLE_MESH_PB_GATT +#define MYNEWT_VAL_BLE_MESH_PB_GATT (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_PB_GATT_USE_DEVICE_NAME +#define MYNEWT_VAL_BLE_MESH_PB_GATT_USE_DEVICE_NAME (1) +#endif + +/* Overridden by @apache-mynewt-nimble/porting/targets/linux_blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ +#ifndef MYNEWT_VAL_BLE_MESH_PROV +#define MYNEWT_VAL_BLE_MESH_PROV (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_PROVISIONER +#define MYNEWT_VAL_BLE_MESH_PROVISIONER (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_PROVISIONER_LOG_LVL +#define MYNEWT_VAL_BLE_MESH_PROVISIONER_LOG_LVL (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_PROVISIONER_LOG_MOD +#define MYNEWT_VAL_BLE_MESH_PROVISIONER_LOG_MOD (25) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_PROV_DEVICE +#define MYNEWT_VAL_BLE_MESH_PROV_DEVICE (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_PROV_DEVICE_LOG_LVL +#define MYNEWT_VAL_BLE_MESH_PROV_DEVICE_LOG_LVL (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_PROV_DEVICE_LOG_MOD +#define MYNEWT_VAL_BLE_MESH_PROV_DEVICE_LOG_MOD (24) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_PROV_LOG_LVL +#define MYNEWT_VAL_BLE_MESH_PROV_LOG_LVL (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_PROV_LOG_MOD +#define MYNEWT_VAL_BLE_MESH_PROV_LOG_MOD (18) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_PROV_OOB_PUBLIC_KEY +#define MYNEWT_VAL_BLE_MESH_PROV_OOB_PUBLIC_KEY (0) +#endif + +/* Overridden by @apache-mynewt-nimble/nimble/host/mesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ +#ifndef MYNEWT_VAL_BLE_MESH_PROXY +#define MYNEWT_VAL_BLE_MESH_PROXY (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_PROXY_FILTER_SIZE +#define MYNEWT_VAL_BLE_MESH_PROXY_FILTER_SIZE (3) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_PROXY_LOG_LVL +#define MYNEWT_VAL_BLE_MESH_PROXY_LOG_LVL (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_PROXY_LOG_MOD +#define MYNEWT_VAL_BLE_MESH_PROXY_LOG_MOD (19) +#endif + +/* Overridden by @apache-mynewt-nimble/nimble/host/mesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ +#ifndef MYNEWT_VAL_BLE_MESH_PROXY_MSG_LEN +#define MYNEWT_VAL_BLE_MESH_PROXY_MSG_LEN (33) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_PROXY_USE_DEVICE_NAME +#define MYNEWT_VAL_BLE_MESH_PROXY_USE_DEVICE_NAME (0) +#endif + +/* Overridden by @apache-mynewt-nimble/porting/targets/linux_blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ +#ifndef MYNEWT_VAL_BLE_MESH_RELAY +#define MYNEWT_VAL_BLE_MESH_RELAY (1) +#endif + +/* Value copied from BLE_MESH_RELAY */ +#ifndef MYNEWT_VAL_BLE_MESH_RELAY_ENABLED +#define MYNEWT_VAL_BLE_MESH_RELAY_ENABLED (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_RELAY_RETRANSMIT_COUNT +#define MYNEWT_VAL_BLE_MESH_RELAY_RETRANSMIT_COUNT (2) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_RELAY_RETRANSMIT_INTERVAL +#define MYNEWT_VAL_BLE_MESH_RELAY_RETRANSMIT_INTERVAL (20) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_RPL_LOG_LVL +#define MYNEWT_VAL_BLE_MESH_RPL_LOG_LVL (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_RPL_LOG_MOD +#define MYNEWT_VAL_BLE_MESH_RPL_LOG_MOD (22) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_RPL_STORE_TIMEOUT +#define MYNEWT_VAL_BLE_MESH_RPL_STORE_TIMEOUT (5) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_RX_SEG_MAX +#define MYNEWT_VAL_BLE_MESH_RX_SEG_MAX (3) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_RX_SEG_MSG_COUNT +#define MYNEWT_VAL_BLE_MESH_RX_SEG_MSG_COUNT (2) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_SEG_BUFS +#define MYNEWT_VAL_BLE_MESH_SEG_BUFS (64) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_SEG_RETRANSMIT_ATTEMPTS +#define MYNEWT_VAL_BLE_MESH_SEG_RETRANSMIT_ATTEMPTS (4) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_SEQ_STORE_RATE +#define MYNEWT_VAL_BLE_MESH_SEQ_STORE_RATE (128) +#endif + +/* Overridden by @apache-mynewt-nimble/porting/targets/linux_blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ +#ifndef MYNEWT_VAL_BLE_MESH_SETTINGS +#define MYNEWT_VAL_BLE_MESH_SETTINGS (0) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_SETTINGS_LOG_LVL +#define MYNEWT_VAL_BLE_MESH_SETTINGS_LOG_LVL (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_SETTINGS_LOG_MOD +#define MYNEWT_VAL_BLE_MESH_SETTINGS_LOG_MOD (20) +#endif + +/* Overridden by @apache-mynewt-nimble/porting/targets/linux_blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ +#ifndef MYNEWT_VAL_BLE_MESH_SHELL +#define MYNEWT_VAL_BLE_MESH_SHELL (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_SHELL_MODELS +#define MYNEWT_VAL_BLE_MESH_SHELL_MODELS (0) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_STORE_TIMEOUT +#define MYNEWT_VAL_BLE_MESH_STORE_TIMEOUT (2) +#endif + +/* Overridden by @apache-mynewt-nimble/porting/targets/linux_blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ +#ifndef MYNEWT_VAL_BLE_MESH_SUBNET_COUNT +#define MYNEWT_VAL_BLE_MESH_SUBNET_COUNT (2) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_SYSINIT_STAGE +#define MYNEWT_VAL_BLE_MESH_SYSINIT_STAGE (500) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_SYSINIT_STAGE_SHELL +#define MYNEWT_VAL_BLE_MESH_SYSINIT_STAGE_SHELL (1000) +#endif + +/* Overridden by @apache-mynewt-nimble/porting/targets/linux_blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ +#ifndef MYNEWT_VAL_BLE_MESH_TESTING +#define MYNEWT_VAL_BLE_MESH_TESTING (0) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_TRANS_LOG_LVL +#define MYNEWT_VAL_BLE_MESH_TRANS_LOG_LVL (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_TRANS_LOG_MOD +#define MYNEWT_VAL_BLE_MESH_TRANS_LOG_MOD (21) +#endif + +/* Overridden by @apache-mynewt-nimble/porting/targets/linux_blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */ +#ifndef MYNEWT_VAL_BLE_MESH_TX_SEG_MAX +#define MYNEWT_VAL_BLE_MESH_TX_SEG_MAX (6) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_TX_SEG_MSG_COUNT +#define MYNEWT_VAL_BLE_MESH_TX_SEG_MSG_COUNT (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_TX_SEG_RETRANS_COUNT +#define MYNEWT_VAL_BLE_MESH_TX_SEG_RETRANS_COUNT (4) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_TX_SEG_RETRANS_TIMEOUT_GROUP +#define MYNEWT_VAL_BLE_MESH_TX_SEG_RETRANS_TIMEOUT_GROUP (50) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_TX_SEG_RETRANS_TIMEOUT_UNICAST +#define MYNEWT_VAL_BLE_MESH_TX_SEG_RETRANS_TIMEOUT_UNICAST (400) +#endif + +#ifndef MYNEWT_VAL_BLE_MESH_UNPROV_BEACON_INT +#define MYNEWT_VAL_BLE_MESH_UNPROV_BEACON_INT (5) +#endif + +/*** @apache-mynewt-nimble/nimble/host/services/ans */ +#ifndef MYNEWT_VAL_BLE_SVC_ANS_NEW_ALERT_CAT +#define MYNEWT_VAL_BLE_SVC_ANS_NEW_ALERT_CAT (0) +#endif + +#ifndef MYNEWT_VAL_BLE_SVC_ANS_SYSINIT_STAGE +#define MYNEWT_VAL_BLE_SVC_ANS_SYSINIT_STAGE (303) +#endif + +#ifndef MYNEWT_VAL_BLE_SVC_ANS_UNR_ALERT_CAT +#define MYNEWT_VAL_BLE_SVC_ANS_UNR_ALERT_CAT (0) +#endif + +/*** @apache-mynewt-nimble/nimble/host/services/bas */ +#ifndef MYNEWT_VAL_BLE_SVC_BAS_BATTERY_LEVEL_NOTIFY_ENABLE +#define MYNEWT_VAL_BLE_SVC_BAS_BATTERY_LEVEL_NOTIFY_ENABLE (1) +#endif + +#ifndef MYNEWT_VAL_BLE_SVC_BAS_BATTERY_LEVEL_READ_PERM +#define MYNEWT_VAL_BLE_SVC_BAS_BATTERY_LEVEL_READ_PERM (0) +#endif + +#ifndef MYNEWT_VAL_BLE_SVC_BAS_SYSINIT_STAGE +#define MYNEWT_VAL_BLE_SVC_BAS_SYSINIT_STAGE (303) +#endif + +/*** @apache-mynewt-nimble/nimble/host/services/dis */ +#ifndef MYNEWT_VAL_BLE_SVC_DIS_DEFAULT_READ_PERM +#define MYNEWT_VAL_BLE_SVC_DIS_DEFAULT_READ_PERM (-1) +#endif + +#ifndef MYNEWT_VAL_BLE_SVC_DIS_FIRMWARE_REVISION_DEFAULT +#define MYNEWT_VAL_BLE_SVC_DIS_FIRMWARE_REVISION_DEFAULT (NULL) +#endif + +/* Value copied from BLE_SVC_DIS_DEFAULT_READ_PERM */ +#ifndef MYNEWT_VAL_BLE_SVC_DIS_FIRMWARE_REVISION_READ_PERM +#define MYNEWT_VAL_BLE_SVC_DIS_FIRMWARE_REVISION_READ_PERM (-1) +#endif + +#ifndef MYNEWT_VAL_BLE_SVC_DIS_HARDWARE_REVISION_DEFAULT +#define MYNEWT_VAL_BLE_SVC_DIS_HARDWARE_REVISION_DEFAULT (NULL) +#endif + +/* Value copied from BLE_SVC_DIS_DEFAULT_READ_PERM */ +#ifndef MYNEWT_VAL_BLE_SVC_DIS_HARDWARE_REVISION_READ_PERM +#define MYNEWT_VAL_BLE_SVC_DIS_HARDWARE_REVISION_READ_PERM (-1) +#endif + +#ifndef MYNEWT_VAL_BLE_SVC_DIS_MANUFACTURER_NAME_DEFAULT +#define MYNEWT_VAL_BLE_SVC_DIS_MANUFACTURER_NAME_DEFAULT (NULL) +#endif + +/* Value copied from BLE_SVC_DIS_DEFAULT_READ_PERM */ +#ifndef MYNEWT_VAL_BLE_SVC_DIS_MANUFACTURER_NAME_READ_PERM +#define MYNEWT_VAL_BLE_SVC_DIS_MANUFACTURER_NAME_READ_PERM (-1) +#endif + +#ifndef MYNEWT_VAL_BLE_SVC_DIS_MODEL_NUMBER_DEFAULT +#define MYNEWT_VAL_BLE_SVC_DIS_MODEL_NUMBER_DEFAULT "Apache Mynewt NimBLE" +#endif + +#ifndef MYNEWT_VAL_BLE_SVC_DIS_MODEL_NUMBER_READ_PERM +#define MYNEWT_VAL_BLE_SVC_DIS_MODEL_NUMBER_READ_PERM (0) +#endif + +#ifndef MYNEWT_VAL_BLE_SVC_DIS_SERIAL_NUMBER_DEFAULT +#define MYNEWT_VAL_BLE_SVC_DIS_SERIAL_NUMBER_DEFAULT (NULL) +#endif + +/* Value copied from BLE_SVC_DIS_DEFAULT_READ_PERM */ +#ifndef MYNEWT_VAL_BLE_SVC_DIS_SERIAL_NUMBER_READ_PERM +#define MYNEWT_VAL_BLE_SVC_DIS_SERIAL_NUMBER_READ_PERM (-1) +#endif + +#ifndef MYNEWT_VAL_BLE_SVC_DIS_SOFTWARE_REVISION_DEFAULT +#define MYNEWT_VAL_BLE_SVC_DIS_SOFTWARE_REVISION_DEFAULT (NULL) +#endif + +/* Value copied from BLE_SVC_DIS_DEFAULT_READ_PERM */ +#ifndef MYNEWT_VAL_BLE_SVC_DIS_SOFTWARE_REVISION_READ_PERM +#define MYNEWT_VAL_BLE_SVC_DIS_SOFTWARE_REVISION_READ_PERM (-1) +#endif + +#ifndef MYNEWT_VAL_BLE_SVC_DIS_SYSINIT_STAGE +#define MYNEWT_VAL_BLE_SVC_DIS_SYSINIT_STAGE (303) +#endif + +#ifndef MYNEWT_VAL_BLE_SVC_DIS_SYSTEM_ID_DEFAULT +#define MYNEWT_VAL_BLE_SVC_DIS_SYSTEM_ID_DEFAULT (NULL) +#endif + +/* Value copied from BLE_SVC_DIS_DEFAULT_READ_PERM */ +#ifndef MYNEWT_VAL_BLE_SVC_DIS_SYSTEM_ID_READ_PERM +#define MYNEWT_VAL_BLE_SVC_DIS_SYSTEM_ID_READ_PERM (-1) +#endif + +/*** @apache-mynewt-nimble/nimble/host/services/gap */ +#ifndef MYNEWT_VAL_BLE_SVC_GAP_APPEARANCE +#define MYNEWT_VAL_BLE_SVC_GAP_APPEARANCE (0) +#endif + +#ifndef MYNEWT_VAL_BLE_SVC_GAP_APPEARANCE_WRITE_PERM +#define MYNEWT_VAL_BLE_SVC_GAP_APPEARANCE_WRITE_PERM (-1) +#endif + +#ifndef MYNEWT_VAL_BLE_SVC_GAP_CENTRAL_ADDRESS_RESOLUTION +#define MYNEWT_VAL_BLE_SVC_GAP_CENTRAL_ADDRESS_RESOLUTION (-1) +#endif + +#ifndef MYNEWT_VAL_BLE_SVC_GAP_DEVICE_NAME +#define MYNEWT_VAL_BLE_SVC_GAP_DEVICE_NAME "nimble" +#endif + +#ifndef MYNEWT_VAL_BLE_SVC_GAP_DEVICE_NAME_MAX_LENGTH +#define MYNEWT_VAL_BLE_SVC_GAP_DEVICE_NAME_MAX_LENGTH (31) +#endif + +#ifndef MYNEWT_VAL_BLE_SVC_GAP_DEVICE_NAME_WRITE_PERM +#define MYNEWT_VAL_BLE_SVC_GAP_DEVICE_NAME_WRITE_PERM (-1) +#endif + +#ifndef MYNEWT_VAL_BLE_SVC_GAP_PPCP_MAX_CONN_INTERVAL +#define MYNEWT_VAL_BLE_SVC_GAP_PPCP_MAX_CONN_INTERVAL (0) +#endif + +#ifndef MYNEWT_VAL_BLE_SVC_GAP_PPCP_MIN_CONN_INTERVAL +#define MYNEWT_VAL_BLE_SVC_GAP_PPCP_MIN_CONN_INTERVAL (0) +#endif + +#ifndef MYNEWT_VAL_BLE_SVC_GAP_PPCP_SLAVE_LATENCY +#define MYNEWT_VAL_BLE_SVC_GAP_PPCP_SLAVE_LATENCY (0) +#endif + +#ifndef MYNEWT_VAL_BLE_SVC_GAP_PPCP_SUPERVISION_TMO +#define MYNEWT_VAL_BLE_SVC_GAP_PPCP_SUPERVISION_TMO (0) +#endif + +#ifndef MYNEWT_VAL_BLE_SVC_GAP_SYSINIT_STAGE +#define MYNEWT_VAL_BLE_SVC_GAP_SYSINIT_STAGE (301) +#endif + +/*** @apache-mynewt-nimble/nimble/host/services/gatt */ +#ifndef MYNEWT_VAL_BLE_SVC_GATT_SYSINIT_STAGE +#define MYNEWT_VAL_BLE_SVC_GATT_SYSINIT_STAGE (302) +#endif + +/*** @apache-mynewt-nimble/nimble/host/services/ias */ +#ifndef MYNEWT_VAL_BLE_SVC_IAS_SYSINIT_STAGE +#define MYNEWT_VAL_BLE_SVC_IAS_SYSINIT_STAGE (303) +#endif + +/*** @apache-mynewt-nimble/nimble/host/services/ipss */ +#ifndef MYNEWT_VAL_BLE_SVC_IPSS_SYSINIT_STAGE +#define MYNEWT_VAL_BLE_SVC_IPSS_SYSINIT_STAGE (303) +#endif + +/*** @apache-mynewt-nimble/nimble/host/services/lls */ +#ifndef MYNEWT_VAL_BLE_SVC_LLS_SYSINIT_STAGE +#define MYNEWT_VAL_BLE_SVC_LLS_SYSINIT_STAGE (303) +#endif + +/*** @apache-mynewt-nimble/nimble/host/services/tps */ +#ifndef MYNEWT_VAL_BLE_SVC_TPS_SYSINIT_STAGE +#define MYNEWT_VAL_BLE_SVC_TPS_SYSINIT_STAGE (303) +#endif + +/*** @apache-mynewt-nimble/nimble/transport */ +#undef MYNEWT_VAL_BLE_ACL_BUF_COUNT + +#undef MYNEWT_VAL_BLE_ACL_BUF_SIZE + +#undef MYNEWT_VAL_BLE_HCI_BRIDGE + +#undef MYNEWT_VAL_BLE_HCI_EVT_BUF_SIZE + +#undef MYNEWT_VAL_BLE_HCI_EVT_HI_BUF_COUNT + +#undef MYNEWT_VAL_BLE_HCI_EVT_LO_BUF_COUNT + +#undef MYNEWT_VAL_BLE_HCI_TRANSPORT + +#ifndef MYNEWT_VAL_BLE_MONITOR_CONSOLE_BUFFER_SIZE +#define MYNEWT_VAL_BLE_MONITOR_CONSOLE_BUFFER_SIZE (128) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_RTT +#define MYNEWT_VAL_BLE_MONITOR_RTT (0) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFERED +#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFERED (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_NAME +#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_NAME "btmonitor" +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_SIZE +#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_SIZE (256) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_UART +#define MYNEWT_VAL_BLE_MONITOR_UART (0) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_UART_BAUDRATE +#define MYNEWT_VAL_BLE_MONITOR_UART_BAUDRATE (1000000) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_UART_BUFFER_SIZE +#define MYNEWT_VAL_BLE_MONITOR_UART_BUFFER_SIZE (64) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_UART_DEV +#define MYNEWT_VAL_BLE_MONITOR_UART_DEV "uart0" +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT +#define MYNEWT_VAL_BLE_TRANSPORT (1) +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT_ACL_COUNT +#define MYNEWT_VAL_BLE_TRANSPORT_ACL_COUNT (10) +#endif + +/* Value copied from BLE_TRANSPORT_ACL_COUNT */ +#ifndef MYNEWT_VAL_BLE_TRANSPORT_ACL_FROM_HS_COUNT +#define MYNEWT_VAL_BLE_TRANSPORT_ACL_FROM_HS_COUNT (10) +#endif + +/* Value copied from BLE_TRANSPORT_ACL_COUNT */ +#ifndef MYNEWT_VAL_BLE_TRANSPORT_ACL_FROM_LL_COUNT +#define MYNEWT_VAL_BLE_TRANSPORT_ACL_FROM_LL_COUNT (10) +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT_ACL_SIZE +#define MYNEWT_VAL_BLE_TRANSPORT_ACL_SIZE (251) +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT_EVT_COUNT +#define MYNEWT_VAL_BLE_TRANSPORT_EVT_COUNT (4) +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT_EVT_DISCARDABLE_COUNT +#define MYNEWT_VAL_BLE_TRANSPORT_EVT_DISCARDABLE_COUNT (16) +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT_EVT_SIZE +#define MYNEWT_VAL_BLE_TRANSPORT_EVT_SIZE (70) +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT_HS__cdc +#define MYNEWT_VAL_BLE_TRANSPORT_HS__cdc (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_HS__custom +#define MYNEWT_VAL_BLE_TRANSPORT_HS__custom (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_HS__dialog_cmac +#define MYNEWT_VAL_BLE_TRANSPORT_HS__dialog_cmac (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_HS__native +#define MYNEWT_VAL_BLE_TRANSPORT_HS__native (1) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_HS__nrf5340 +#define MYNEWT_VAL_BLE_TRANSPORT_HS__nrf5340 (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_HS__uart +#define MYNEWT_VAL_BLE_TRANSPORT_HS__uart (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_HS__usb +#define MYNEWT_VAL_BLE_TRANSPORT_HS__usb (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_HS +#define MYNEWT_VAL_BLE_TRANSPORT_HS (1) +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT_ISO_COUNT +#define MYNEWT_VAL_BLE_TRANSPORT_ISO_COUNT (10) +#endif + +/* Value copied from BLE_TRANSPORT_ISO_COUNT */ +#ifndef MYNEWT_VAL_BLE_TRANSPORT_ISO_FROM_HS_COUNT +#define MYNEWT_VAL_BLE_TRANSPORT_ISO_FROM_HS_COUNT (10) +#endif + +/* Value copied from BLE_TRANSPORT_ISO_COUNT */ +#ifndef MYNEWT_VAL_BLE_TRANSPORT_ISO_FROM_LL_COUNT +#define MYNEWT_VAL_BLE_TRANSPORT_ISO_FROM_LL_COUNT (10) +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT_ISO_SIZE +#define MYNEWT_VAL_BLE_TRANSPORT_ISO_SIZE (300) +#endif + +/* Overridden by @apache-mynewt-nimble/porting/targets/linux_blemesh (defined by @apache-mynewt-nimble/nimble/transport) */ +#ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__apollo3 +#define MYNEWT_VAL_BLE_TRANSPORT_LL__apollo3 (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__custom +#define MYNEWT_VAL_BLE_TRANSPORT_LL__custom (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__dialog_cmac +#define MYNEWT_VAL_BLE_TRANSPORT_LL__dialog_cmac (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__emspi +#define MYNEWT_VAL_BLE_TRANSPORT_LL__emspi (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__native +#define MYNEWT_VAL_BLE_TRANSPORT_LL__native (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__nrf5340 +#define MYNEWT_VAL_BLE_TRANSPORT_LL__nrf5340 (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__socket +#define MYNEWT_VAL_BLE_TRANSPORT_LL__socket (1) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__uart_ll +#define MYNEWT_VAL_BLE_TRANSPORT_LL__uart_ll (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_LL +#define MYNEWT_VAL_BLE_TRANSPORT_LL (1) +#endif + +/*** @apache-mynewt-nimble/nimble/transport/socket */ +#ifndef MYNEWT_VAL_BLE_SOCK_CLI_SYSINIT_STAGE +#define MYNEWT_VAL_BLE_SOCK_CLI_SYSINIT_STAGE (500) +#endif + +#ifndef MYNEWT_VAL_BLE_SOCK_LINUX_DEV +#define MYNEWT_VAL_BLE_SOCK_LINUX_DEV (0) +#endif + +/* Overridden by @apache-mynewt-nimble/porting/targets/linux_blemesh (defined by @apache-mynewt-nimble/nimble/transport/socket) */ +#ifndef MYNEWT_VAL_BLE_SOCK_STACK_SIZE +#define MYNEWT_VAL_BLE_SOCK_STACK_SIZE (1028) +#endif + +/* Overridden by @apache-mynewt-nimble/porting/targets/linux_blemesh (defined by @apache-mynewt-nimble/nimble/transport/socket) */ +#ifndef MYNEWT_VAL_BLE_SOCK_TASK_PRIO +#define MYNEWT_VAL_BLE_SOCK_TASK_PRIO (3) +#endif + +#ifndef MYNEWT_VAL_BLE_SOCK_TCP_PORT +#define MYNEWT_VAL_BLE_SOCK_TCP_PORT (14433) +#endif + +/* Overridden by @apache-mynewt-nimble/porting/targets/linux_blemesh (defined by @apache-mynewt-nimble/nimble/transport/socket) */ +#ifndef MYNEWT_VAL_BLE_SOCK_USE_LINUX_BLUE +#define MYNEWT_VAL_BLE_SOCK_USE_LINUX_BLUE (1) +#endif + +#ifndef MYNEWT_VAL_BLE_SOCK_USE_NUTTX +#define MYNEWT_VAL_BLE_SOCK_USE_NUTTX (0) +#endif + +/* Overridden by @apache-mynewt-nimble/porting/targets/linux_blemesh (defined by @apache-mynewt-nimble/nimble/transport/socket) */ +#ifndef MYNEWT_VAL_BLE_SOCK_USE_TCP +#define MYNEWT_VAL_BLE_SOCK_USE_TCP (0) +#endif + +/*** newt */ +#ifndef MYNEWT_VAL_APP_NAME +#define MYNEWT_VAL_APP_NAME "dummy_app" +#endif + +#ifndef MYNEWT_VAL_APP_dummy_app +#define MYNEWT_VAL_APP_dummy_app (1) +#endif + +#ifndef MYNEWT_VAL_ARCH_NAME +#define MYNEWT_VAL_ARCH_NAME "sim" +#endif + +#ifndef MYNEWT_VAL_ARCH_sim +#define MYNEWT_VAL_ARCH_sim (1) +#endif + +#ifndef MYNEWT_VAL_BSP_NAME +#define MYNEWT_VAL_BSP_NAME "native" +#endif + +#ifndef MYNEWT_VAL_BSP_native +#define MYNEWT_VAL_BSP_native (1) +#endif + +#ifndef MYNEWT_VAL_NEWT_FEATURE_LOGCFG +#define MYNEWT_VAL_NEWT_FEATURE_LOGCFG (1) +#endif + +#ifndef MYNEWT_VAL_NEWT_FEATURE_SYSDOWN +#define MYNEWT_VAL_NEWT_FEATURE_SYSDOWN (1) +#endif + +#ifndef MYNEWT_VAL_TARGET_NAME +#define MYNEWT_VAL_TARGET_NAME "linux_blemesh" +#endif + +#ifndef MYNEWT_VAL_TARGET_linux_blemesh +#define MYNEWT_VAL_TARGET_linux_blemesh (1) +#endif + +/*** Included packages */ +#define MYNEWT_PKG_apache_mynewt_core__compiler_sim 1 +#define MYNEWT_PKG_apache_mynewt_core__crypto_tinycrypt 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_bsp_native 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_drivers_flash_enc_flash 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_drivers_flash_enc_flash_ef_tinycrypt 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_drivers_trng 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_drivers_trng_trng_sw 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_drivers_uart 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_drivers_uart_uart_hal 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_hal 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_mcu_native 1 +#define MYNEWT_PKG_apache_mynewt_core__kernel_os 1 +#define MYNEWT_PKG_apache_mynewt_core__kernel_sim 1 +#define MYNEWT_PKG_apache_mynewt_core__net_ip_mn_socket 1 +#define MYNEWT_PKG_apache_mynewt_core__net_ip_native_sockets 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_console_stub 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_defs 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_flash_map 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_log_common 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_log_modlog 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_log_stub 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_stats_stub 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_sys 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_sysdown 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_sysinit 1 +#define MYNEWT_PKG_apache_mynewt_core__util_mem 1 +#define MYNEWT_PKG_apache_mynewt_core__util_rwlock 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_mesh 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_ans 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_bas 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_dis 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_gap 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_gatt 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_ias 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_ipss 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_lls 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_tps 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_transport 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_transport_socket 1 +#define MYNEWT_PKG_apache_mynewt_nimble__porting_npl_mynewt 1 +#define MYNEWT_PKG_apache_mynewt_nimble__porting_targets_dummy_app 1 +#define MYNEWT_PKG_apache_mynewt_nimble__porting_targets_linux_blemesh 1 + +/*** Included APIs */ +#define MYNEWT_API_TRNG_HW_IMPL 1 +#define MYNEWT_API_ble_transport 1 +#define MYNEWT_API_console 1 +#define MYNEWT_API_log 1 +#define MYNEWT_API_stats 1 + +#endif diff --git a/porting/examples/linux_blemesh_shell/include/sysflash/sysflash.h b/porting/examples/linux_blemesh_shell/include/sysflash/sysflash.h new file mode 100644 index 0000000000..2f4d843f4c --- /dev/null +++ b/porting/examples/linux_blemesh_shell/include/sysflash/sysflash.h @@ -0,0 +1,51 @@ +/** + * This file was generated by Apache newt version: 1.12.0-dev + */ + +#ifndef H_MYNEWT_SYSFLASH_ +#define H_MYNEWT_SYSFLASH_ + +#include "flash_map/flash_map.h" + +#define FLASH_AREA_COUNT 6 + +/** + * This flash map definition is used for two purposes: + * 1. To locate the meta area, which contains the true flash map definition. + * 2. As a fallback in case the meta area cannot be read from flash. + */ +extern const struct flash_area sysflash_map_dflt[FLASH_AREA_COUNT]; + +/* Flash map was defined in @apache-mynewt-core/hw/bsp/native */ + +#define FLASH_AREA_BOOTLOADER 0 +#define FLASH_AREA_BOOTLOADER_DEVICE 0 +#define FLASH_AREA_BOOTLOADER_OFFSET 0x00000000 +#define FLASH_AREA_BOOTLOADER_SIZE 16384 + +#define FLASH_AREA_IMAGE_0 1 +#define FLASH_AREA_IMAGE_0_DEVICE 0 +#define FLASH_AREA_IMAGE_0_OFFSET 0x00020000 +#define FLASH_AREA_IMAGE_0_SIZE 393216 + +#define FLASH_AREA_IMAGE_1 2 +#define FLASH_AREA_IMAGE_1_DEVICE 0 +#define FLASH_AREA_IMAGE_1_OFFSET 0x00080000 +#define FLASH_AREA_IMAGE_1_SIZE 393216 + +#define FLASH_AREA_IMAGE_SCRATCH 3 +#define FLASH_AREA_IMAGE_SCRATCH_DEVICE 0 +#define FLASH_AREA_IMAGE_SCRATCH_OFFSET 0x000e0000 +#define FLASH_AREA_IMAGE_SCRATCH_SIZE 131072 + +#define FLASH_AREA_REBOOT_LOG 16 +#define FLASH_AREA_REBOOT_LOG_DEVICE 0 +#define FLASH_AREA_REBOOT_LOG_OFFSET 0x00004000 +#define FLASH_AREA_REBOOT_LOG_SIZE 16384 + +#define FLASH_AREA_NFFS 17 +#define FLASH_AREA_NFFS_DEVICE 0 +#define FLASH_AREA_NFFS_OFFSET 0x00008000 +#define FLASH_AREA_NFFS_SIZE 32768 + +#endif diff --git a/porting/examples/linux_blemesh_shell/shell/console_port.c b/porting/examples/linux_blemesh_shell/shell/console_port.c new file mode 100644 index 0000000000..3ed21ba2b1 --- /dev/null +++ b/porting/examples/linux_blemesh_shell/shell/console_port.c @@ -0,0 +1,88 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +#include +#include "nimble/nimble_npl.h" +#include "shell/shell.h" + +static struct ble_npl_task mesh_input_task; +static struct ble_npl_event shell_evt; + +struct os_eventq * avail_queue; +static ble_npl_event_fn *shell_ev_cb; + +void +console_set_queues(struct os_eventq *avail, struct os_eventq *lines) +{ + avail_queue = avail; +} + +void +console_set_event_cb(ble_npl_event_fn *cb) +{ + shell_ev_cb = cb; +} + +static void +mesh_shell_evt_add(char *cmd) +{ + struct ble_npl_event *ev = &shell_evt; + + if (ev->ev_queued) { + printf("Wait last cmd be handled...\n"); + return; + } + + ble_npl_event_init(ev, shell_ev_cb, cmd); + + ble_npl_eventq_put(avail_queue, ev); +} + +static void * +console_input_thread(void *args) +{ + char line[128]; + + while (1) { + printf("\n\nmesh>"); + fgets(line, sizeof(line), stdin); + int len = strlen(line); + if (len > 0 && (line[len-1] == '\n')) { + line[len-1] = '\0'; + --len; + } + + if (len > 0) { + mesh_shell_evt_add(line); + } + } + + return NULL; +} + +int +console_init() +{ + int i; + + ble_npl_task_init(&mesh_input_task, "mesh_input", console_input_thread, + NULL, TASK_DEFAULT_PRIORITY, BLE_NPL_TIME_FOREVER, + TASK_DEFAULT_STACK, TASK_DEFAULT_STACK_SIZE); + + return 0; +} diff --git a/porting/examples/linux_blemesh_shell/shell/shell_port.c b/porting/examples/linux_blemesh_shell/shell/shell_port.c new file mode 100644 index 0000000000..bd9af6d3b9 --- /dev/null +++ b/porting/examples/linux_blemesh_shell/shell/shell_port.c @@ -0,0 +1,230 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +#include +#include +#include "nimble/nimble_npl.h" +#include "shell/shell.h" +#include "console/console.h" +#include "console/console_port.h" + +static const struct shell_cmd *def_commands; + +int +shell_register(const char *module_name, const struct shell_cmd *commands) +{ + def_commands = commands; + return 0; +} + +void +shell_register_app_cmd_handler(shell_cmd_func_t handler) +{ +} + +void +shell_register_prompt_handler(shell_prompt_function_t handler) +{ +} + +void +shell_register_default_module(const char *name) +{ +} + +void +shell_evq_set(struct os_eventq *evq) +{ + console_set_queues(evq, NULL); + console_set_event_cb(handle_shell_evt); +} + +void +print_prompt(struct streamer *streamer) +{ + console_printf(">mesh\n"); +} + +static size_t +line2argv(char *str, char *argv[], size_t size, struct streamer *streamer) +{ + size_t argc = 0; + + if (!strlen(str)) { + return 0; + } + + while (*str && *str == ' ') { + str++; + } + + if (!*str) { + return 0; + } + + argv[argc++] = str; + + while ((str = strchr(str, ' '))) { + *str++ = '\0'; + + while (*str && *str == ' ') { + str++; + } + + if (!*str) { + break; + } + + argv[argc++] = str; + + if (argc == size) { + fprintf(stderr, "Too many parameters (max %zu)\n", size - 1); + return 0; + } + } + + /* keep it POSIX style where argv[argc] is required to be NULL */ + argv[argc] = NULL; + + return argc; +} + +int +show_cmd_help(char *cmd, struct streamer *streamer) +{ + const struct shell_cmd *command; + + for (int i = 0; def_commands[i].sc_cmd; i++) { + if (!cmd) { + command = &def_commands[i]; + } else if (!strcmp(cmd, def_commands[i].sc_cmd)) { + command = &def_commands[i]; + } else { + continue; + } + + if (command->help) { + console_printf("%s: %s\n", command->sc_cmd, command->help->usage ?: ""); + } else { + console_printf("%s\n", command->sc_cmd); + } + } + + return 0; +} + +int +shell_exec(int argc, char **argv, struct streamer *streamer) +{ + const struct shell_cmd *cmd = NULL; + const char *command = argv[0]; + size_t argc_offset = 0; + int rc; + + if (!strcmp(command, "help")) { + if (argc >= 2) { + return show_cmd_help(argv[1], NULL); + } else { + return show_cmd_help(NULL, NULL); + } + } + + for (int i = 0; def_commands[i].sc_cmd; i++) { + if (!strcmp(command, def_commands[i].sc_cmd)) { + cmd = &def_commands[i]; + } + } + + if (!cmd) { + console_printf("Unrecognized command: %s\n", argv[0]); + console_printf("Type 'help' for list of available commands\n"); + print_prompt(streamer); + return BLE_NPL_ENOENT; + } + + /* Execute callback with arguments */ + if (!cmd->sc_ext) { + rc = cmd->sc_cmd_func(argc - argc_offset, &argv[argc_offset]); + } else { + rc = cmd->sc_cmd_ext_func(cmd, argc - argc_offset, &argv[argc_offset], streamer); + } + if (rc < 0) { + show_cmd_help(argv[0], streamer); + } + + print_prompt(streamer); + + return rc; +} + +static void +shell_process_command(char *line, struct streamer *streamer) +{ + char *argv[MYNEWT_VAL(SHELL_CMD_ARGC_MAX) + 1]; + size_t argc; + + argc = line2argv(line, argv, MYNEWT_VAL(SHELL_CMD_ARGC_MAX) + 1, streamer); + if (!argc) { + print_prompt(streamer); + return; + } + + shell_exec(argc, argv, streamer); +} + +void +handle_shell_evt(struct os_event *ev) +{ + char *line; + + if (!ev) { + print_prompt(NULL); + return; + } + + line = ev->ev_arg; + if (!line) { + print_prompt(NULL); + return; + } + + shell_process_command(line, NULL); + + ev->ev_queued = 0; +} + +#if MYNEWT_VAL(SHELL_MGMT) +int +shell_nlip_input_register(shell_nlip_input_func_t nf, void *arg) +{ + return 0; +} +int +shell_nlip_output(struct os_mbuf *m) +{ + return 0; +} +#endif + +#if MYNEWT_VAL(SHELL_COMPAT) +int +shell_cmd_register(const struct shell_cmd *sc) +{ + return 0; +} +#endif diff --git a/porting/examples/linux_blemesh_shell/src/ble.c b/porting/examples/linux_blemesh_shell/src/ble.c new file mode 100644 index 0000000000..c380ac88d5 --- /dev/null +++ b/porting/examples/linux_blemesh_shell/src/ble.c @@ -0,0 +1,503 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include "mesh/mesh.h" +#include "console/console.h" + +/* BLE */ +#include "nimble/nimble_port.h" +#include "nimble/ble.h" +#include "host/ble_hs.h" +#include "services/gap/ble_svc_gap.h" +#include "mesh/glue.h" +#include "shell/shell.h" +#include "console/console_port.h" + +#define BT_DBG_ENABLED (MYNEWT_VAL(BLE_MESH_DEBUG)) + +/* Company ID */ +#define CID_VENDOR 0x05C3 +#define STANDARD_TEST_ID 0x00 +#define TEST_ID 0x01 +static int recent_test_id = STANDARD_TEST_ID; + +#define FAULT_ARR_SIZE 2 + +static bool has_reg_fault = true; + +static int +fault_get_cur(struct bt_mesh_model *model, + uint8_t *test_id, + uint16_t *company_id, + uint8_t *faults, + uint8_t *fault_count) +{ + uint8_t reg_faults[FAULT_ARR_SIZE] = { [0 ... FAULT_ARR_SIZE-1] = 0xff }; + + console_printf("fault_get_cur() has_reg_fault %u\n", has_reg_fault); + + *test_id = recent_test_id; + *company_id = CID_VENDOR; + + *fault_count = MIN(*fault_count, sizeof(reg_faults)); + memcpy(faults, reg_faults, *fault_count); + + return 0; +} + +static int +fault_get_reg(struct bt_mesh_model *model, + uint16_t company_id, + uint8_t *test_id, + uint8_t *faults, + uint8_t *fault_count) +{ + if (company_id != CID_VENDOR) { + return -BLE_HS_EINVAL; + } + + console_printf("fault_get_reg() has_reg_fault %u\n", has_reg_fault); + + *test_id = recent_test_id; + + if (has_reg_fault) { + uint8_t reg_faults[FAULT_ARR_SIZE] = { [0 ... FAULT_ARR_SIZE-1] = 0xff }; + + *fault_count = MIN(*fault_count, sizeof(reg_faults)); + memcpy(faults, reg_faults, *fault_count); + } else { + *fault_count = 0; + } + + return 0; +} + +static int +fault_clear(struct bt_mesh_model *model, uint16_t company_id) +{ + if (company_id != CID_VENDOR) { + return -BLE_HS_EINVAL; + } + + has_reg_fault = false; + + return 0; +} + +static int +fault_test(struct bt_mesh_model *model, uint8_t test_id, uint16_t company_id) +{ + if (company_id != CID_VENDOR) { + return -BLE_HS_EINVAL; + } + + if (test_id != STANDARD_TEST_ID && test_id != TEST_ID) { + return -BLE_HS_EINVAL; + } + + recent_test_id = test_id; + has_reg_fault = true; + bt_mesh_fault_update(bt_mesh_model_elem(model)); + + return 0; +} + +static const struct bt_mesh_health_srv_cb health_srv_cb = { + .fault_get_cur = &fault_get_cur, + .fault_get_reg = &fault_get_reg, + .fault_clear = &fault_clear, + .fault_test = &fault_test, +}; + +static struct bt_mesh_health_srv health_srv = { + .cb = &health_srv_cb, +}; + +static struct bt_mesh_model_pub health_pub; + +static void +health_pub_init(void) +{ + health_pub.msg = BT_MESH_HEALTH_FAULT_MSG(0); +} + +static struct bt_mesh_model_pub gen_level_pub; +static struct bt_mesh_model_pub gen_onoff_pub; + +static uint8_t gen_on_off_state; +static int16_t gen_level_state; + +static int +gen_onoff_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx) +{ + struct os_mbuf *msg = NET_BUF_SIMPLE(3); + uint8_t *status; + int rc; + + console_printf("#mesh-onoff STATUS\n"); + + bt_mesh_model_msg_init(msg, BT_MESH_MODEL_OP_2(0x82, 0x04)); + status = net_buf_simple_add(msg, 1); + *status = gen_on_off_state; + + rc = bt_mesh_model_send(model, ctx, msg, NULL, NULL); + if (rc) { + console_printf("#mesh-onoff STATUS: send status failed\n"); + } + + os_mbuf_free_chain(msg); + return rc; +} + +static int +gen_onoff_get(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) +{ + console_printf("#mesh-onoff GET\n"); + + return gen_onoff_status(model, ctx); +} + +static int +gen_onoff_set(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) +{ + console_printf("#mesh-onoff SET\n"); + + gen_on_off_state = buf->om_data[0]; + + return gen_onoff_status(model, ctx); +} + +static int +gen_onoff_set_unack(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) +{ + console_printf("#mesh-onoff SET-UNACK\n"); + + gen_on_off_state = buf->om_data[0]; + return 0; +} + +static const struct bt_mesh_model_op gen_onoff_op[] = { + { BT_MESH_MODEL_OP_2(0x82, 0x01), 0, gen_onoff_get }, + { BT_MESH_MODEL_OP_2(0x82, 0x02), 2, gen_onoff_set }, + { BT_MESH_MODEL_OP_2(0x82, 0x03), 2, gen_onoff_set_unack }, + BT_MESH_MODEL_OP_END, +}; + +static void +gen_level_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx) +{ + struct os_mbuf *msg = NET_BUF_SIMPLE(4); + + console_printf("#mesh-level STATUS\n"); + + bt_mesh_model_msg_init(msg, BT_MESH_MODEL_OP_2(0x82, 0x08)); + net_buf_simple_add_le16(msg, gen_level_state); + + if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { + console_printf("#mesh-level STATUS: send status failed\n"); + } + + os_mbuf_free_chain(msg); +} + +static int +gen_level_get(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) +{ + console_printf("#mesh-level GET\n"); + + gen_level_status(model, ctx); + return 0; +} + +static int +gen_level_set(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) +{ + int16_t level; + + level = (int16_t) net_buf_simple_pull_le16(buf); + console_printf("#mesh-level SET: level=%d\n", level); + + gen_level_status(model, ctx); + + gen_level_state = level; + console_printf("#mesh-level: level=%d\n", gen_level_state); + return 0; +} + +static int +gen_level_set_unack(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) +{ + int16_t level; + + level = (int16_t) net_buf_simple_pull_le16(buf); + console_printf("#mesh-level SET-UNACK: level=%d\n", level); + + gen_level_state = level; + console_printf("#mesh-level: level=%d\n", gen_level_state); + return 0; +} + +static int +gen_delta_set(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) +{ + int16_t delta_level; + + delta_level = (int16_t) net_buf_simple_pull_le16(buf); + console_printf("#mesh-level DELTA-SET: delta_level=%d\n", delta_level); + + gen_level_status(model, ctx); + + gen_level_state += delta_level; + console_printf("#mesh-level: level=%d\n", gen_level_state); + return 0; +} + +static int +gen_delta_set_unack(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) +{ + int16_t delta_level; + + delta_level = (int16_t) net_buf_simple_pull_le16(buf); + console_printf("#mesh-level DELTA-SET: delta_level=%d\n", delta_level); + + gen_level_state += delta_level; + console_printf("#mesh-level: level=%d\n", gen_level_state); + return 0; +} + +static int +gen_move_set(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) +{ + return 0; +} + +static int +gen_move_set_unack(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) +{ + return 0; +} + +static const struct bt_mesh_model_op gen_level_op[] = { + { BT_MESH_MODEL_OP_2(0x82, 0x05), 0, gen_level_get }, + { BT_MESH_MODEL_OP_2(0x82, 0x06), 3, gen_level_set }, + { BT_MESH_MODEL_OP_2(0x82, 0x07), 3, gen_level_set_unack }, + { BT_MESH_MODEL_OP_2(0x82, 0x09), 5, gen_delta_set }, + { BT_MESH_MODEL_OP_2(0x82, 0x0a), 5, gen_delta_set_unack }, + { BT_MESH_MODEL_OP_2(0x82, 0x0b), 3, gen_move_set }, + { BT_MESH_MODEL_OP_2(0x82, 0x0c), 3, gen_move_set_unack }, + BT_MESH_MODEL_OP_END, +}; + +static struct bt_mesh_model root_models[] = { + BT_MESH_MODEL_CFG_SRV, + BT_MESH_MODEL_HEALTH_SRV(&health_srv, &health_pub), + BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_ONOFF_SRV, gen_onoff_op, + &gen_onoff_pub, NULL), + BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_LEVEL_SRV, gen_level_op, + &gen_level_pub, NULL), +}; + +static struct bt_mesh_model_pub vnd_model_pub; + +static int +vnd_model_recv(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) +{ + struct os_mbuf *msg = NET_BUF_SIMPLE(3); + int rc; + + console_printf("#vendor-model-recv\n"); + + console_printf("data:%s len:%d\n", bt_hex(buf->om_data, buf->om_len), + buf->om_len); + + bt_mesh_model_msg_init(msg, BT_MESH_MODEL_OP_3(0x01, CID_VENDOR)); + os_mbuf_append(msg, buf->om_data, buf->om_len); + + rc = bt_mesh_model_send(model, ctx, msg, NULL, NULL); + if (rc) { + console_printf("#vendor-model-recv: send rsp failed\n"); + } + + os_mbuf_free_chain(msg); + return rc; +} + +static const struct bt_mesh_model_op vnd_model_op[] = { + { BT_MESH_MODEL_OP_3(0x01, CID_VENDOR), 0, vnd_model_recv }, + BT_MESH_MODEL_OP_END, +}; + +static struct bt_mesh_model vnd_models[] = { + BT_MESH_MODEL_VND(CID_VENDOR, BT_MESH_MODEL_ID_GEN_ONOFF_SRV, vnd_model_op, + &vnd_model_pub, NULL), +}; + +static struct bt_mesh_elem elements[] = { + BT_MESH_ELEM(0, root_models, vnd_models), +}; + +static const struct bt_mesh_comp comp = { + .cid = CID_VENDOR, + .elem = elements, + .elem_count = ARRAY_SIZE(elements), +}; + +static int +output_number(bt_mesh_output_action_t action, uint32_t number) +{ + console_printf("!!! app laer: output OOB Number: %u\n", number); + + return 0; +} + +static void +prov_complete(uint16_t net_idx, uint16_t addr) +{ + console_printf("Local node provisioned, primary address 0x%04x\n", addr); +} + +static const uint8_t dev_uuid[16] = MYNEWT_VAL(BLE_MESH_DEV_UUID); + +static const struct bt_mesh_prov prov = { + .uuid = dev_uuid, + .output_size = 0, + .output_actions = 0, + .output_number = output_number, + .complete = prov_complete, +}; + +static void +blemesh_on_reset(int reason) +{ + BLE_HS_LOG(ERROR, "Resetting state; reason=%d\n", reason); +} + +void mesh_initialized(void); + + +#include "mesh/glue.h" +#include "mesh/testing.h" + + +void +net_recv_ev(uint8_t ttl, uint8_t ctl, uint16_t src, uint16_t dst, + const void *payload, size_t payload_len) +{ + console_printf("Received net packet: ttl 0x%02x ctl 0x%02x src 0x%04x " + "dst 0x%04x " "payload_len %d\n", ttl, ctl, src, dst, + payload_len); +} + +static void +model_bound_cb(uint16_t addr, struct bt_mesh_model *model, + uint16_t key_idx) +{ + console_printf("Model bound: remote addr 0x%04x key_idx 0x%04x model %p\n", + addr, key_idx, model); +} + +static void +model_unbound_cb(uint16_t addr, struct bt_mesh_model *model, + uint16_t key_idx) +{ + console_printf("Model unbound: remote addr 0x%04x key_idx 0x%04x " + "model %p\n", addr, key_idx, model); +} + +static void +invalid_bearer_cb(uint8_t opcode) +{ + console_printf("Invalid bearer: opcode 0x%02x\n", opcode); +} + +static void +incomp_timer_exp_cb(void) +{ + console_printf("Incomplete timer expired\n"); +} + +static struct bt_test_cb bt_test_cb = { + .mesh_net_recv = net_recv_ev, + .mesh_model_bound = model_bound_cb, + .mesh_model_unbound = model_unbound_cb, + .mesh_prov_invalid_bearer = invalid_bearer_cb, + .mesh_trans_incomp_timer_exp = incomp_timer_exp_cb, +}; + + +static void +blemesh_on_sync(void) +{ + int err; + + console_printf("Bluetooth initialized\n"); + + console_printf("Init mesh and shell task now.\n"); + ble_mesh_shell_init(); + + /* init mesh node. it call bt_mesh_init. */ + cmd_mesh_init(0, NULL); + + console_printf("Start mesh adv task.\n"); + mesh_initialized(); + + if (IS_ENABLED(CONFIG_BT_TESTING)) { + bt_test_cb_register(&bt_test_cb); + } + + console_init(); +} + +void +nimble_host_task(void *param) +{ + health_pub_init(); + + /* Initialize the NimBLE host configuration. */ + ble_hs_cfg.reset_cb = blemesh_on_reset; + ble_hs_cfg.sync_cb = blemesh_on_sync; + ble_hs_cfg.store_status_cb = ble_store_util_status_rr; + + nimble_port_run(); +} diff --git a/porting/examples/linux_blemesh_shell/src/main.c b/porting/examples/linux_blemesh_shell/src/main.c new file mode 100644 index 0000000000..734f716ba6 --- /dev/null +++ b/porting/examples/linux_blemesh_shell/src/main.c @@ -0,0 +1,106 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include +#include +#include + +#include +#include "nimble/nimble_npl.h" +#include "nimble/nimble_port.h" + +#include "mesh/glue.h" +#include "mesh/porting.h" + +#include "services/gap/ble_svc_gap.h" +#include "services/gatt/ble_svc_gatt.h" + +static struct ble_npl_task s_task_host; +static struct ble_npl_task s_task_hci; +static struct ble_npl_task s_task_mesh_adv; + +void nimble_host_task(void *param); +void ble_hci_sock_ack_handler(void *param); +void ble_hci_sock_init(void); +void ble_hci_sock_set_device(int dev); +void ble_store_ram_init(void); + +#define TASK_DEFAULT_PRIORITY 1 +#define TASK_DEFAULT_STACK NULL +#define TASK_DEFAULT_STACK_SIZE 400 + +void * +ble_hci_sock_task(void *param) +{ + ble_hci_sock_ack_handler(param); + return NULL; +} + +void * +ble_host_task(void *param) +{ + nimble_host_task(param); + return NULL; +} + +void * +ble_mesh_adv_task(void *param) +{ + mesh_adv_thread(param); + return NULL; +} + +void +mesh_initialized(void) +{ + ble_npl_task_init(&s_task_mesh_adv, "ble_mesh_adv", ble_mesh_adv_task, + NULL, TASK_DEFAULT_PRIORITY, BLE_NPL_TIME_FOREVER, + TASK_DEFAULT_STACK, TASK_DEFAULT_STACK_SIZE); +} + +int +main(int argc, char *argv[]) +{ + int ret = 0; + + /* allow to specify custom hci */ + if (argc > 1) { + ble_hci_sock_set_device(atoi(argv[1])); + } + + nimble_port_init(); + + ble_svc_gap_init(); + ble_svc_gatt_init(); + bt_mesh_register_gatt(); + + /* XXX Need to have template for store */ + ble_store_ram_init(); + + ble_npl_task_init(&s_task_hci, "hci_sock", ble_hci_sock_task, + NULL, TASK_DEFAULT_PRIORITY, BLE_NPL_TIME_FOREVER, + TASK_DEFAULT_STACK, TASK_DEFAULT_STACK_SIZE); + + /* Create task which handles default event queue for host stack. */ + ble_npl_task_init(&s_task_host, "ble_host", ble_host_task, + NULL, TASK_DEFAULT_PRIORITY, BLE_NPL_TIME_FOREVER, + TASK_DEFAULT_STACK, TASK_DEFAULT_STACK_SIZE); + + pthread_exit(&ret); +} diff --git a/porting/examples/nuttx/Make.defs b/porting/examples/nuttx/Make.defs index f35d428e82..94a2a3e1d9 100644 --- a/porting/examples/nuttx/Make.defs +++ b/porting/examples/nuttx/Make.defs @@ -48,8 +48,7 @@ INC = \ INCLUDES := $(addprefix -I, $(INC)) -CFLAGS += \ - $(NIMBLE_CFLAGS) \ +CFLAGS += \ $(INCLUDES) \ $(TINYCRYPT_CFLAGS) \ -DNIMBLE_CFG_CONTROLLER=0 -DOS_CFG_ALIGN_4=4 -DOS_CFG_ALIGNMENT=4 \ diff --git a/porting/examples/nuttx/include/logcfg/logcfg.h b/porting/examples/nuttx/include/logcfg/logcfg.h deleted file mode 100644 index 837cdeac1f..0000000000 --- a/porting/examples/nuttx/include/logcfg/logcfg.h +++ /dev/null @@ -1,32 +0,0 @@ -/** - * This file was generated by Apache newt version: 1.9.0-dev - */ - -#ifndef H_MYNEWT_LOGCFG_ -#define H_MYNEWT_LOGCFG_ - -#include "modlog/modlog.h" -#include "log_common/log_common.h" - -#define BLE_HS_LOG_DEBUG(...) IGNORE(__VA_ARGS__) -#define BLE_HS_LOG_INFO(...) MODLOG_INFO(4, __VA_ARGS__) -#define BLE_HS_LOG_WARN(...) MODLOG_WARN(4, __VA_ARGS__) -#define BLE_HS_LOG_ERROR(...) MODLOG_ERROR(4, __VA_ARGS__) -#define BLE_HS_LOG_CRITICAL(...) MODLOG_CRITICAL(4, __VA_ARGS__) -#define BLE_HS_LOG_DISABLED(...) MODLOG_DISABLED(4, __VA_ARGS__) - -#define DFLT_LOG_DEBUG(...) IGNORE(__VA_ARGS__) -#define DFLT_LOG_INFO(...) MODLOG_INFO(0, __VA_ARGS__) -#define DFLT_LOG_WARN(...) MODLOG_WARN(0, __VA_ARGS__) -#define DFLT_LOG_ERROR(...) MODLOG_ERROR(0, __VA_ARGS__) -#define DFLT_LOG_CRITICAL(...) MODLOG_CRITICAL(0, __VA_ARGS__) -#define DFLT_LOG_DISABLED(...) MODLOG_DISABLED(0, __VA_ARGS__) - -#define MFG_LOG_DEBUG(...) IGNORE(__VA_ARGS__) -#define MFG_LOG_INFO(...) IGNORE(__VA_ARGS__) -#define MFG_LOG_WARN(...) IGNORE(__VA_ARGS__) -#define MFG_LOG_ERROR(...) IGNORE(__VA_ARGS__) -#define MFG_LOG_CRITICAL(...) IGNORE(__VA_ARGS__) -#define MFG_LOG_DISABLED(...) MODLOG_DISABLED(128, __VA_ARGS__) - -#endif diff --git a/porting/examples/nuttx/include/syscfg/syscfg.h b/porting/examples/nuttx/include/syscfg/syscfg.h index c8ad4e4976..d751e85677 100644 --- a/porting/examples/nuttx/include/syscfg/syscfg.h +++ b/porting/examples/nuttx/include/syscfg/syscfg.h @@ -1,103 +1,104 @@ -/** - * This file was generated by Apache newt version: 1.9.0-dev +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. */ #ifndef H_MYNEWT_SYSCFG_ #define H_MYNEWT_SYSCFG_ -/** - * This macro exists to ensure code includes this header when needed. If code - * checks the existence of a setting directly via ifdef without including this - * header, the setting macro will silently evaluate to 0. In contrast, an - * attempt to use these macros without including this header will result in a - * compiler error. - */ #define MYNEWT_VAL(_name) MYNEWT_VAL_ ## _name #define MYNEWT_VAL_CHOICE(_name, _val) MYNEWT_VAL_ ## _name ## __ ## _val - -/*** Repository @apache-mynewt-core info */ -#ifndef MYNEWT_VAL_REPO_HASH_APACHE_MYNEWT_CORE -#define MYNEWT_VAL_REPO_HASH_APACHE_MYNEWT_CORE ("4d75fc41bd7ead84638ebbfad4841d5effb296dd") +#ifndef MYNEWT_VAL_TINYCRYPT_SYSINIT_STAGE +#define MYNEWT_VAL_TINYCRYPT_SYSINIT_STAGE (200) #endif -#ifndef MYNEWT_VAL_REPO_VERSION_APACHE_MYNEWT_CORE -#define MYNEWT_VAL_REPO_VERSION_APACHE_MYNEWT_CORE ("0.0.1") +#ifndef MYNEWT_VAL_TINYCRYPT_UECC_RNG_TRNG_DEV_NAME +#define MYNEWT_VAL_TINYCRYPT_UECC_RNG_TRNG_DEV_NAME "trng" #endif -/*** Repository @apache-mynewt-mcumgr info */ -#ifndef MYNEWT_VAL_REPO_HASH_APACHE_MYNEWT_MCUMGR -#define MYNEWT_VAL_REPO_HASH_APACHE_MYNEWT_MCUMGR ("8d087a7e0e5485394419d10051606c92d68d2111") +#ifndef MYNEWT_VAL_TINYCRYPT_UECC_RNG_USE_TRNG +#define MYNEWT_VAL_TINYCRYPT_UECC_RNG_USE_TRNG (0) #endif -#ifndef MYNEWT_VAL_REPO_VERSION_APACHE_MYNEWT_MCUMGR -#define MYNEWT_VAL_REPO_VERSION_APACHE_MYNEWT_MCUMGR ("0.0.0") +#ifndef MYNEWT_VAL_BSP_SIMULATED +#define MYNEWT_VAL_BSP_SIMULATED (1) #endif -/*** Repository @apache-mynewt-nimble info */ -#ifndef MYNEWT_VAL_REPO_HASH_APACHE_MYNEWT_NIMBLE -#define MYNEWT_VAL_REPO_HASH_APACHE_MYNEWT_NIMBLE ("37dceb35df57ff41a6c31f79290512df2fde7064") +#ifndef MYNEWT_VAL_HAL_ENABLE_SOFTWARE_BREAKPOINTS +#define MYNEWT_VAL_HAL_ENABLE_SOFTWARE_BREAKPOINTS (1) #endif -#ifndef MYNEWT_VAL_REPO_VERSION_APACHE_MYNEWT_NIMBLE -#define MYNEWT_VAL_REPO_VERSION_APACHE_MYNEWT_NIMBLE ("0.0.0") +#ifndef MYNEWT_VAL_HAL_FLASH_MAX_DEVICE_COUNT +#define MYNEWT_VAL_HAL_FLASH_MAX_DEVICE_COUNT (0) #endif -/*** Repository @mcuboot info */ -#ifndef MYNEWT_VAL_REPO_HASH_MCUBOOT -#define MYNEWT_VAL_REPO_HASH_MCUBOOT ("03d96ad1f6dd77d47ffca72ade9377acb8559115-dirty") +#ifndef MYNEWT_VAL_HAL_FLASH_VERIFY_BUF_SZ +#define MYNEWT_VAL_HAL_FLASH_VERIFY_BUF_SZ (16) #endif -#ifndef MYNEWT_VAL_REPO_VERSION_MCUBOOT -#define MYNEWT_VAL_REPO_VERSION_MCUBOOT ("0.0.0") +#ifndef MYNEWT_VAL_HAL_FLASH_VERIFY_ERASES +#define MYNEWT_VAL_HAL_FLASH_VERIFY_ERASES (0) #endif -/*** Repository @my_project info */ -#ifndef MYNEWT_VAL_REPO_HASH_MY_PROJECT -#define MYNEWT_VAL_REPO_HASH_MY_PROJECT ("37dceb35df57ff41a6c31f79290512df2fde7064") +#ifndef MYNEWT_VAL_HAL_FLASH_VERIFY_WRITES +#define MYNEWT_VAL_HAL_FLASH_VERIFY_WRITES (0) #endif -#ifndef MYNEWT_VAL_REPO_VERSION_MY_PROJECT -#define MYNEWT_VAL_REPO_VERSION_MY_PROJECT ("0.0.0") +#ifndef MYNEWT_VAL_HAL_SBRK +#define MYNEWT_VAL_HAL_SBRK (1) #endif +#ifndef MYNEWT_VAL_HAL_SYSTEM_RESET_CB +#define MYNEWT_VAL_HAL_SYSTEM_RESET_CB (0) +#endif - -/*** @apache-mynewt-core/crypto/tinycrypt */ -#ifndef MYNEWT_VAL_TINYCRYPT_SYSINIT_STAGE -#define MYNEWT_VAL_TINYCRYPT_SYSINIT_STAGE (200) +#ifndef MYNEWT_VAL_I2C_0 +#define MYNEWT_VAL_I2C_0 (0) #endif -#ifndef MYNEWT_VAL_TINYCRYPT_UECC_RNG_TRNG_DEV_NAME -#define MYNEWT_VAL_TINYCRYPT_UECC_RNG_TRNG_DEV_NAME ("trng") +#ifndef MYNEWT_VAL_MCU_FLASH_MIN_WRITE_SIZE +#define MYNEWT_VAL_MCU_FLASH_MIN_WRITE_SIZE (1) #endif -#ifndef MYNEWT_VAL_TINYCRYPT_UECC_RNG_USE_TRNG -#define MYNEWT_VAL_TINYCRYPT_UECC_RNG_USE_TRNG (0) +#ifndef MYNEWT_VAL_MCU_FLASH_STYLE_NORDIC +#define MYNEWT_VAL_MCU_FLASH_STYLE_NORDIC (0) #endif -/*** @apache-mynewt-core/hw/hal */ -#ifndef MYNEWT_VAL_HAL_ENABLE_SOFTWARE_BREAKPOINTS -#define MYNEWT_VAL_HAL_ENABLE_SOFTWARE_BREAKPOINTS (1) +#ifndef MYNEWT_VAL_MCU_FLASH_STYLE_ST +#define MYNEWT_VAL_MCU_FLASH_STYLE_ST (1) #endif -#ifndef MYNEWT_VAL_HAL_FLASH_VERIFY_BUF_SZ -#define MYNEWT_VAL_HAL_FLASH_VERIFY_BUF_SZ (16) +#ifndef MYNEWT_VAL_MCU_NATIVE +#define MYNEWT_VAL_MCU_NATIVE (1) #endif -#ifndef MYNEWT_VAL_HAL_FLASH_VERIFY_ERASES -#define MYNEWT_VAL_HAL_FLASH_VERIFY_ERASES (0) +#ifndef MYNEWT_VAL_MCU_NATIVE_USE_SIGNALS +#define MYNEWT_VAL_MCU_NATIVE_USE_SIGNALS (1) #endif -#ifndef MYNEWT_VAL_HAL_FLASH_VERIFY_WRITES -#define MYNEWT_VAL_HAL_FLASH_VERIFY_WRITES (0) +#ifndef MYNEWT_VAL_MCU_TIMER_POLLER_PRIO +#define MYNEWT_VAL_MCU_TIMER_POLLER_PRIO (0) #endif -#ifndef MYNEWT_VAL_HAL_SYSTEM_RESET_CB -#define MYNEWT_VAL_HAL_SYSTEM_RESET_CB (0) +#ifndef MYNEWT_VAL_MCU_UART_POLLER_PRIO +#define MYNEWT_VAL_MCU_UART_POLLER_PRIO (1) #endif -/*** @apache-mynewt-core/kernel/os */ #ifndef MYNEWT_VAL_FLOAT_USER #define MYNEWT_VAL_FLOAT_USER (0) #endif @@ -142,6 +143,10 @@ #define MYNEWT_VAL_OS_COREDUMP (0) #endif +#ifndef MYNEWT_VAL_OS_COREDUMP_CB +#define MYNEWT_VAL_OS_COREDUMP_CB (0) +#endif + #ifndef MYNEWT_VAL_OS_CPUTIME_FREQ #define MYNEWT_VAL_OS_CPUTIME_FREQ (1000000) #endif @@ -151,7 +156,7 @@ #endif #ifndef MYNEWT_VAL_OS_CRASH_FILE_LINE -#define MYNEWT_VAL_OS_CRASH_FILE_LINE (0) +#define MYNEWT_VAL_OS_CRASH_FILE_LINE (1) #endif #ifndef MYNEWT_VAL_OS_CRASH_LOG @@ -178,6 +183,10 @@ #define MYNEWT_VAL_OS_DEBUG_MODE (0) #endif +#ifndef MYNEWT_VAL_OS_DEFAULT_IRQ_CB +#define MYNEWT_VAL_OS_DEFAULT_IRQ_CB (0) +#endif + #ifndef MYNEWT_VAL_OS_EVENTQ_DEBUG #define MYNEWT_VAL_OS_EVENTQ_DEBUG (0) #endif @@ -191,7 +200,7 @@ #endif #ifndef MYNEWT_VAL_OS_IDLE_TICKLESS_MS_MIN -#define MYNEWT_VAL_OS_IDLE_TICKLESS_MS_MIN (100) +#define MYNEWT_VAL_OS_IDLE_TICKLESS_MS_MIN (1) #endif #ifndef MYNEWT_VAL_OS_MAIN_STACK_SIZE @@ -258,6 +267,10 @@ #define MYNEWT_VAL_OS_TASK_RUN_TIME_CPUTIME (0) #endif +#ifndef MYNEWT_VAL_OS_TICKS_PER_SEC +#define MYNEWT_VAL_OS_TICKS_PER_SEC (100) +#endif + #ifndef MYNEWT_VAL_OS_TIME_DEBUG #define MYNEWT_VAL_OS_TIME_DEBUG (0) #endif @@ -274,29 +287,56 @@ #define MYNEWT_VAL_WATCHDOG_INTERVAL (30000) #endif -/*** @apache-mynewt-core/sys/console/stub */ +#ifndef MYNEWT_VAL_NATIVE_SOCKETS_MAX +#define MYNEWT_VAL_NATIVE_SOCKETS_MAX (8) +#endif + +#ifndef MYNEWT_VAL_NATIVE_SOCKETS_MAX_UDP +#define MYNEWT_VAL_NATIVE_SOCKETS_MAX_UDP (2048) +#endif + +#ifndef MYNEWT_VAL_NATIVE_SOCKETS_POLL_INTERVAL_MS +#define MYNEWT_VAL_NATIVE_SOCKETS_POLL_INTERVAL_MS (200) +#endif + +#undef MYNEWT_VAL_NATIVE_SOCKETS_POLL_ITVL + +#ifndef MYNEWT_VAL_NATIVE_SOCKETS_PRIO +#define MYNEWT_VAL_NATIVE_SOCKETS_PRIO (2) +#endif + +#ifndef MYNEWT_VAL_NATIVE_SOCKETS_STACK_SZ +#define MYNEWT_VAL_NATIVE_SOCKETS_STACK_SZ (4096) +#endif + +#ifndef MYNEWT_VAL_NATIVE_SOCKETS_SYSINIT_STAGE +#define MYNEWT_VAL_NATIVE_SOCKETS_SYSINIT_STAGE (200) +#endif + #ifndef MYNEWT_VAL_CONSOLE_UART_BAUD #define MYNEWT_VAL_CONSOLE_UART_BAUD (115200) #endif #ifndef MYNEWT_VAL_CONSOLE_UART_DEV -#define MYNEWT_VAL_CONSOLE_UART_DEV ("uart0") +#define MYNEWT_VAL_CONSOLE_UART_DEV "uart0" #endif #ifndef MYNEWT_VAL_CONSOLE_UART_FLOW_CONTROL #define MYNEWT_VAL_CONSOLE_UART_FLOW_CONTROL (UART_FLOW_CTL_NONE) #endif -/*** @apache-mynewt-core/sys/flash_map */ #ifndef MYNEWT_VAL_FLASH_MAP_MAX_AREAS #define MYNEWT_VAL_FLASH_MAP_MAX_AREAS (10) #endif +#ifndef MYNEWT_VAL_FLASH_MAP_SUPPORT_MFG +#define MYNEWT_VAL_FLASH_MAP_SUPPORT_MFG (0) +#endif + #ifndef MYNEWT_VAL_FLASH_MAP_SYSINIT_STAGE -#define MYNEWT_VAL_FLASH_MAP_SYSINIT_STAGE (2) +#define MYNEWT_VAL_FLASH_MAP_SYSINIT_STAGE (9) #endif -/*** @apache-mynewt-core/sys/log/common */ #ifndef MYNEWT_VAL_DFLT_LOG_LVL #define MYNEWT_VAL_DFLT_LOG_LVL (1) #endif @@ -309,7 +349,6 @@ #define MYNEWT_VAL_LOG_GLOBAL_IDX (1) #endif -/*** @apache-mynewt-core/sys/log/modlog */ #ifndef MYNEWT_VAL_MODLOG_CONSOLE_DFLT #define MYNEWT_VAL_MODLOG_CONSOLE_DFLT (1) #endif @@ -330,7 +369,6 @@ #define MYNEWT_VAL_MODLOG_SYSINIT_STAGE (100) #endif -/*** @apache-mynewt-core/sys/log/stub */ #ifndef MYNEWT_VAL_LOG_CONSOLE #define MYNEWT_VAL_LOG_CONSOLE (1) #endif @@ -343,34 +381,14 @@ #define MYNEWT_VAL_LOG_FCB_SLOT1 (0) #endif -/* Overridden by @apache-mynewt-nimble/porting/targets/nuttx (defined by @apache-mynewt-core/sys/log/stub) */ #ifndef MYNEWT_VAL_LOG_LEVEL #define MYNEWT_VAL_LOG_LEVEL (2) #endif -/*** @apache-mynewt-core/sys/mfg */ -#ifndef MYNEWT_VAL_MFG_LOG_LVL -#define MYNEWT_VAL_MFG_LOG_LVL (15) -#endif - -#ifndef MYNEWT_VAL_MFG_LOG_MODULE -#define MYNEWT_VAL_MFG_LOG_MODULE (128) -#endif - -#ifndef MYNEWT_VAL_MFG_MAX_MMRS -#define MYNEWT_VAL_MFG_MAX_MMRS (2) -#endif - -#ifndef MYNEWT_VAL_MFG_SYSINIT_STAGE -#define MYNEWT_VAL_MFG_SYSINIT_STAGE (100) -#endif - -/*** @apache-mynewt-core/sys/sys */ #ifndef MYNEWT_VAL_DEBUG_PANIC_ENABLED #define MYNEWT_VAL_DEBUG_PANIC_ENABLED (1) #endif -/*** @apache-mynewt-core/sys/sysdown */ #ifndef MYNEWT_VAL_SYSDOWN_CONSTRAIN_DOWN #define MYNEWT_VAL_SYSDOWN_CONSTRAIN_DOWN (1) #endif @@ -387,25 +405,30 @@ #define MYNEWT_VAL_SYSDOWN_TIMEOUT_MS (10000) #endif -/*** @apache-mynewt-core/sys/sysinit */ #ifndef MYNEWT_VAL_SYSINIT_CONSTRAIN_INIT #define MYNEWT_VAL_SYSINIT_CONSTRAIN_INIT (1) #endif #ifndef MYNEWT_VAL_SYSINIT_PANIC_FILE_LINE -#define MYNEWT_VAL_SYSINIT_PANIC_FILE_LINE (0) +#define MYNEWT_VAL_SYSINIT_PANIC_FILE_LINE (1) #endif #ifndef MYNEWT_VAL_SYSINIT_PANIC_MESSAGE -#define MYNEWT_VAL_SYSINIT_PANIC_MESSAGE (0) +#define MYNEWT_VAL_SYSINIT_PANIC_MESSAGE (1) #endif -/*** @apache-mynewt-core/util/rwlock */ #ifndef MYNEWT_VAL_RWLOCK_DEBUG #define MYNEWT_VAL_RWLOCK_DEBUG (0) #endif -/*** @apache-mynewt-nimble/nimble */ +#ifndef MYNEWT_VAL_BLE_CHANNEL_SOUNDING +#define MYNEWT_VAL_BLE_CHANNEL_SOUNDING (0) +#endif + +#ifndef MYNEWT_VAL_BLE_CONN_SUBRATING +#define MYNEWT_VAL_BLE_CONN_SUBRATING (0) +#endif + #ifndef MYNEWT_VAL_BLE_EXT_ADV #define MYNEWT_VAL_BLE_EXT_ADV (0) #endif @@ -414,10 +437,26 @@ #define MYNEWT_VAL_BLE_EXT_ADV_MAX_SIZE (31) #endif +#ifndef MYNEWT_VAL_BLE_HCI_VS +#define MYNEWT_VAL_BLE_HCI_VS (0) +#endif + +#ifndef MYNEWT_VAL_BLE_HCI_VS_OCF_OFFSET +#define MYNEWT_VAL_BLE_HCI_VS_OCF_OFFSET (0) +#endif + #ifndef MYNEWT_VAL_BLE_ISO #define MYNEWT_VAL_BLE_ISO (0) #endif +#ifndef MYNEWT_VAL_BLE_ISO_BROADCAST_SINK +#define MYNEWT_VAL_BLE_ISO_BROADCAST_SINK (0) +#endif + +#ifndef MYNEWT_VAL_BLE_ISO_BROADCAST_SOURCE +#define MYNEWT_VAL_BLE_ISO_BROADCAST_SOURCE (0) +#endif + #ifndef MYNEWT_VAL_BLE_ISO_TEST #define MYNEWT_VAL_BLE_ISO_TEST (0) #endif @@ -438,10 +477,26 @@ #define MYNEWT_VAL_BLE_PERIODIC_ADV (0) #endif +#ifndef MYNEWT_VAL_BLE_PERIODIC_ADV_SYNC_BIGINFO_REPORTS +#define MYNEWT_VAL_BLE_PERIODIC_ADV_SYNC_BIGINFO_REPORTS (0) +#endif + #ifndef MYNEWT_VAL_BLE_PERIODIC_ADV_SYNC_TRANSFER #define MYNEWT_VAL_BLE_PERIODIC_ADV_SYNC_TRANSFER (0) #endif +#ifndef MYNEWT_VAL_BLE_PHY_2M +#define MYNEWT_VAL_BLE_PHY_2M (0) +#endif + +#ifndef MYNEWT_VAL_BLE_PHY_CODED +#define MYNEWT_VAL_BLE_PHY_CODED (0) +#endif + +#ifndef MYNEWT_VAL_BLE_POWER_CONTROL +#define MYNEWT_VAL_BLE_POWER_CONTROL (0) +#endif + #ifndef MYNEWT_VAL_BLE_ROLE_BROADCASTER #define MYNEWT_VAL_BLE_ROLE_BROADCASTER (1) #endif @@ -466,7 +521,6 @@ #define MYNEWT_VAL_BLE_WHITELIST (1) #endif -/*** @apache-mynewt-nimble/nimble/host */ #ifndef MYNEWT_VAL_BLE_ATT_PREFERRED_MTU #define MYNEWT_VAL_BLE_ATT_PREFERRED_MTU (256) #endif @@ -491,6 +545,10 @@ #define MYNEWT_VAL_BLE_ATT_SVR_NOTIFY (1) #endif +#ifndef MYNEWT_VAL_BLE_ATT_SVR_NOTIFY_MULTI +#define MYNEWT_VAL_BLE_ATT_SVR_NOTIFY_MULTI (MYNEWT_VAL_BLE_ATT_SVR_NOTIFY && (MYNEWT_VAL_BLE_VERSION >= 52)) +#endif + #ifndef MYNEWT_VAL_BLE_ATT_SVR_QUEUED_WRITE #define MYNEWT_VAL_BLE_ATT_SVR_QUEUED_WRITE (1) #endif @@ -531,6 +589,26 @@ #define MYNEWT_VAL_BLE_ATT_SVR_WRITE_NO_RSP (1) #endif +#ifndef MYNEWT_VAL_BLE_AUDIO +#define MYNEWT_VAL_BLE_AUDIO (0) +#endif + +#ifndef MYNEWT_VAL_BLE_EATT_CHAN_NUM +#define MYNEWT_VAL_BLE_EATT_CHAN_NUM (0) +#endif + +#ifndef MYNEWT_VAL_BLE_EATT_LOG_LVL +#define MYNEWT_VAL_BLE_EATT_LOG_LVL (1) +#endif + +#ifndef MYNEWT_VAL_BLE_EATT_LOG_MOD +#define MYNEWT_VAL_BLE_EATT_LOG_MOD (27) +#endif + +#ifndef MYNEWT_VAL_BLE_EATT_MTU +#define MYNEWT_VAL_BLE_EATT_MTU (128) +#endif + #ifndef MYNEWT_VAL_BLE_GAP_MAX_PENDING_CONN_PARAM_UPDATE #define MYNEWT_VAL_BLE_GAP_MAX_PENDING_CONN_PARAM_UPDATE (1) #endif @@ -571,6 +649,10 @@ #define MYNEWT_VAL_BLE_GATT_NOTIFY (1) #endif +#ifndef MYNEWT_VAL_BLE_GATT_NOTIFY_MULTIPLE +#define MYNEWT_VAL_BLE_GATT_NOTIFY_MULTIPLE ((MYNEWT_VAL_BLE_VERSION >= 52)) +#endif + #ifndef MYNEWT_VAL_BLE_GATT_READ #define MYNEWT_VAL_BLE_GATT_READ (MYNEWT_VAL_BLE_ROLE_CENTRAL) #endif @@ -587,6 +669,10 @@ #define MYNEWT_VAL_BLE_GATT_READ_MULT (MYNEWT_VAL_BLE_ROLE_CENTRAL) #endif +#ifndef MYNEWT_VAL_BLE_GATT_READ_MULT_VAR +#define MYNEWT_VAL_BLE_GATT_READ_MULT_VAR (MYNEWT_VAL_BLE_ROLE_CENTRAL && (MYNEWT_VAL_BLE_VERSION >= 52)) +#endif + #ifndef MYNEWT_VAL_BLE_GATT_READ_UUID #define MYNEWT_VAL_BLE_GATT_READ_UUID (MYNEWT_VAL_BLE_ROLE_CENTRAL) #endif @@ -631,6 +717,10 @@ #define MYNEWT_VAL_BLE_HS_DEBUG (0) #endif +#ifndef MYNEWT_VAL_BLE_HS_EXT_ADV_LEGACY_INSTANCE +#define MYNEWT_VAL_BLE_HS_EXT_ADV_LEGACY_INSTANCE (0) +#endif + #ifndef MYNEWT_VAL_BLE_HS_FLOW_CTRL #define MYNEWT_VAL_BLE_HS_FLOW_CTRL (0) #endif @@ -647,6 +737,10 @@ #define MYNEWT_VAL_BLE_HS_FLOW_CTRL_TX_ON_DISCONNECT (0) #endif +#ifndef MYNEWT_VAL_BLE_HS_GAP_UNHANDLED_HCI_EVENT +#define MYNEWT_VAL_BLE_HS_GAP_UNHANDLED_HCI_EVENT (0) +#endif + #ifndef MYNEWT_VAL_BLE_HS_LOG_LVL #define MYNEWT_VAL_BLE_HS_LOG_LVL (1) #endif @@ -675,6 +769,14 @@ #define MYNEWT_VAL_BLE_HS_SYSINIT_STAGE (200) #endif +#ifndef MYNEWT_VAL_BLE_ISO_MAX_BIGS +#define MYNEWT_VAL_BLE_ISO_MAX_BIGS (MYNEWT_VAL_BLE_MULTI_ADV_INSTANCES) +#endif + +#ifndef MYNEWT_VAL_BLE_ISO_MAX_BISES +#define MYNEWT_VAL_BLE_ISO_MAX_BISES (4) +#endif + #ifndef MYNEWT_VAL_BLE_L2CAP_COC_MAX_NUM #define MYNEWT_VAL_BLE_L2CAP_COC_MAX_NUM (0) #endif @@ -683,6 +785,10 @@ #define MYNEWT_VAL_BLE_L2CAP_COC_MPS (MYNEWT_VAL_MSYS_1_BLOCK_SIZE-8) #endif +#ifndef MYNEWT_VAL_BLE_L2CAP_COC_SDU_BUFF_COUNT +#define MYNEWT_VAL_BLE_L2CAP_COC_SDU_BUFF_COUNT (1) +#endif + #ifndef MYNEWT_VAL_BLE_L2CAP_ENHANCED_COC #define MYNEWT_VAL_BLE_L2CAP_ENHANCED_COC (0) #endif @@ -707,42 +813,6 @@ #define MYNEWT_VAL_BLE_MESH (0) #endif -#ifndef MYNEWT_VAL_BLE_MONITOR_CONSOLE_BUFFER_SIZE -#define MYNEWT_VAL_BLE_MONITOR_CONSOLE_BUFFER_SIZE (128) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_RTT -#define MYNEWT_VAL_BLE_MONITOR_RTT (0) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFERED -#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFERED (1) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_NAME -#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_NAME ("btmonitor") -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_SIZE -#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_SIZE (256) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_UART -#define MYNEWT_VAL_BLE_MONITOR_UART (0) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_UART_BAUDRATE -#define MYNEWT_VAL_BLE_MONITOR_UART_BAUDRATE (1000000) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_UART_BUFFER_SIZE -#define MYNEWT_VAL_BLE_MONITOR_UART_BUFFER_SIZE (64) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_UART_DEV -#define MYNEWT_VAL_BLE_MONITOR_UART_DEV ("uart0") -#endif - #ifndef MYNEWT_VAL_BLE_RPA_TIMEOUT #define MYNEWT_VAL_BLE_RPA_TIMEOUT (300) #endif @@ -751,6 +821,10 @@ #define MYNEWT_VAL_BLE_SM_BONDING (0) #endif +#ifndef MYNEWT_VAL_BLE_SM_CSIS_SIRK +#define MYNEWT_VAL_BLE_SM_CSIS_SIRK (0) +#endif + #ifndef MYNEWT_VAL_BLE_SM_IO_CAP #define MYNEWT_VAL_BLE_SM_IO_CAP (BLE_HS_IO_NO_INPUT_OUTPUT) #endif @@ -759,11 +833,14 @@ #define MYNEWT_VAL_BLE_SM_KEYPRESS (0) #endif -/* Overridden by @apache-mynewt-nimble/porting/targets/nuttx (defined by @apache-mynewt-nimble/nimble/host) */ #ifndef MYNEWT_VAL_BLE_SM_LEGACY #define MYNEWT_VAL_BLE_SM_LEGACY (1) #endif +#ifndef MYNEWT_VAL_BLE_SM_LVL +#define MYNEWT_VAL_BLE_SM_LVL (0) +#endif + #ifndef MYNEWT_VAL_BLE_SM_MAX_PROCS #define MYNEWT_VAL_BLE_SM_MAX_PROCS (1) #endif @@ -780,23 +857,18 @@ #define MYNEWT_VAL_BLE_SM_OUR_KEY_DIST (0) #endif -/* Overridden by @apache-mynewt-nimble/porting/targets/nuttx (defined by @apache-mynewt-nimble/nimble/host) */ #ifndef MYNEWT_VAL_BLE_SM_SC #define MYNEWT_VAL_BLE_SM_SC (1) #endif -#ifndef MYNEWT_VAL_BLE_SM_SC_ONLY -#define MYNEWT_VAL_BLE_SM_SC_ONLY (0) -#endif - -#ifndef MYNEWT_VAL_BLE_SM_SC_LVL -#define MYNEWT_VAL_BLE_SM_SC_LVL (0) -#endif - #ifndef MYNEWT_VAL_BLE_SM_SC_DEBUG_KEYS #define MYNEWT_VAL_BLE_SM_SC_DEBUG_KEYS (0) #endif +#ifndef MYNEWT_VAL_BLE_SM_SC_ONLY +#define MYNEWT_VAL_BLE_SM_SC_ONLY (0) +#endif + #ifndef MYNEWT_VAL_BLE_SM_THEIR_KEY_DIST #define MYNEWT_VAL_BLE_SM_THEIR_KEY_DIST (0) #endif @@ -809,7 +881,6 @@ #define MYNEWT_VAL_BLE_STORE_MAX_CCCDS (8) #endif -/*** @apache-mynewt-nimble/nimble/host/services/ans */ #ifndef MYNEWT_VAL_BLE_SVC_ANS_NEW_ALERT_CAT #define MYNEWT_VAL_BLE_SVC_ANS_NEW_ALERT_CAT (0) #endif @@ -822,7 +893,6 @@ #define MYNEWT_VAL_BLE_SVC_ANS_UNR_ALERT_CAT (0) #endif -/*** @apache-mynewt-nimble/nimble/host/services/bas */ #ifndef MYNEWT_VAL_BLE_SVC_BAS_BATTERY_LEVEL_NOTIFY_ENABLE #define MYNEWT_VAL_BLE_SVC_BAS_BATTERY_LEVEL_NOTIFY_ENABLE (1) #endif @@ -835,7 +905,6 @@ #define MYNEWT_VAL_BLE_SVC_BAS_SYSINIT_STAGE (303) #endif -/*** @apache-mynewt-nimble/nimble/host/services/dis */ #ifndef MYNEWT_VAL_BLE_SVC_DIS_DEFAULT_READ_PERM #define MYNEWT_VAL_BLE_SVC_DIS_DEFAULT_READ_PERM (-1) #endif @@ -844,7 +913,6 @@ #define MYNEWT_VAL_BLE_SVC_DIS_FIRMWARE_REVISION_DEFAULT (NULL) #endif -/* Value copied from BLE_SVC_DIS_DEFAULT_READ_PERM */ #ifndef MYNEWT_VAL_BLE_SVC_DIS_FIRMWARE_REVISION_READ_PERM #define MYNEWT_VAL_BLE_SVC_DIS_FIRMWARE_REVISION_READ_PERM (-1) #endif @@ -853,7 +921,6 @@ #define MYNEWT_VAL_BLE_SVC_DIS_HARDWARE_REVISION_DEFAULT (NULL) #endif -/* Value copied from BLE_SVC_DIS_DEFAULT_READ_PERM */ #ifndef MYNEWT_VAL_BLE_SVC_DIS_HARDWARE_REVISION_READ_PERM #define MYNEWT_VAL_BLE_SVC_DIS_HARDWARE_REVISION_READ_PERM (-1) #endif @@ -862,13 +929,12 @@ #define MYNEWT_VAL_BLE_SVC_DIS_MANUFACTURER_NAME_DEFAULT (NULL) #endif -/* Value copied from BLE_SVC_DIS_DEFAULT_READ_PERM */ #ifndef MYNEWT_VAL_BLE_SVC_DIS_MANUFACTURER_NAME_READ_PERM #define MYNEWT_VAL_BLE_SVC_DIS_MANUFACTURER_NAME_READ_PERM (-1) #endif #ifndef MYNEWT_VAL_BLE_SVC_DIS_MODEL_NUMBER_DEFAULT -#define MYNEWT_VAL_BLE_SVC_DIS_MODEL_NUMBER_DEFAULT ("Apache Mynewt NimBLE") +#define MYNEWT_VAL_BLE_SVC_DIS_MODEL_NUMBER_DEFAULT "Apache Mynewt NimBLE" #endif #ifndef MYNEWT_VAL_BLE_SVC_DIS_MODEL_NUMBER_READ_PERM @@ -879,7 +945,6 @@ #define MYNEWT_VAL_BLE_SVC_DIS_SERIAL_NUMBER_DEFAULT (NULL) #endif -/* Value copied from BLE_SVC_DIS_DEFAULT_READ_PERM */ #ifndef MYNEWT_VAL_BLE_SVC_DIS_SERIAL_NUMBER_READ_PERM #define MYNEWT_VAL_BLE_SVC_DIS_SERIAL_NUMBER_READ_PERM (-1) #endif @@ -888,7 +953,6 @@ #define MYNEWT_VAL_BLE_SVC_DIS_SOFTWARE_REVISION_DEFAULT (NULL) #endif -/* Value copied from BLE_SVC_DIS_DEFAULT_READ_PERM */ #ifndef MYNEWT_VAL_BLE_SVC_DIS_SOFTWARE_REVISION_READ_PERM #define MYNEWT_VAL_BLE_SVC_DIS_SOFTWARE_REVISION_READ_PERM (-1) #endif @@ -901,12 +965,10 @@ #define MYNEWT_VAL_BLE_SVC_DIS_SYSTEM_ID_DEFAULT (NULL) #endif -/* Value copied from BLE_SVC_DIS_DEFAULT_READ_PERM */ #ifndef MYNEWT_VAL_BLE_SVC_DIS_SYSTEM_ID_READ_PERM #define MYNEWT_VAL_BLE_SVC_DIS_SYSTEM_ID_READ_PERM (-1) #endif -/*** @apache-mynewt-nimble/nimble/host/services/gap */ #ifndef MYNEWT_VAL_BLE_SVC_GAP_APPEARANCE #define MYNEWT_VAL_BLE_SVC_GAP_APPEARANCE (0) #endif @@ -920,7 +982,7 @@ #endif #ifndef MYNEWT_VAL_BLE_SVC_GAP_DEVICE_NAME -#define MYNEWT_VAL_BLE_SVC_GAP_DEVICE_NAME ("nimble") +#define MYNEWT_VAL_BLE_SVC_GAP_DEVICE_NAME "nimble" #endif #ifndef MYNEWT_VAL_BLE_SVC_GAP_DEVICE_NAME_MAX_LENGTH @@ -951,56 +1013,179 @@ #define MYNEWT_VAL_BLE_SVC_GAP_SYSINIT_STAGE (301) #endif -/*** @apache-mynewt-nimble/nimble/host/services/gatt */ #ifndef MYNEWT_VAL_BLE_SVC_GATT_SYSINIT_STAGE #define MYNEWT_VAL_BLE_SVC_GATT_SYSINIT_STAGE (302) #endif -/*** @apache-mynewt-nimble/nimble/host/services/ias */ #ifndef MYNEWT_VAL_BLE_SVC_IAS_SYSINIT_STAGE #define MYNEWT_VAL_BLE_SVC_IAS_SYSINIT_STAGE (303) #endif -/*** @apache-mynewt-nimble/nimble/host/services/ipss */ #ifndef MYNEWT_VAL_BLE_SVC_IPSS_SYSINIT_STAGE #define MYNEWT_VAL_BLE_SVC_IPSS_SYSINIT_STAGE (303) #endif -/*** @apache-mynewt-nimble/nimble/host/services/lls */ #ifndef MYNEWT_VAL_BLE_SVC_LLS_SYSINIT_STAGE #define MYNEWT_VAL_BLE_SVC_LLS_SYSINIT_STAGE (303) #endif -/*** @apache-mynewt-nimble/nimble/host/services/tps */ #ifndef MYNEWT_VAL_BLE_SVC_TPS_SYSINIT_STAGE #define MYNEWT_VAL_BLE_SVC_TPS_SYSINIT_STAGE (303) #endif -/*** @apache-mynewt-nimble/nimble/transport/socket */ -#ifndef MYNEWT_VAL_BLE_ACL_BUF_COUNT -#define MYNEWT_VAL_BLE_ACL_BUF_COUNT (24) +#undef MYNEWT_VAL_BLE_ACL_BUF_COUNT + +#undef MYNEWT_VAL_BLE_ACL_BUF_SIZE + +#undef MYNEWT_VAL_BLE_HCI_BRIDGE + +#undef MYNEWT_VAL_BLE_HCI_EVT_BUF_SIZE + +#undef MYNEWT_VAL_BLE_HCI_EVT_HI_BUF_COUNT + +#undef MYNEWT_VAL_BLE_HCI_EVT_LO_BUF_COUNT + +#undef MYNEWT_VAL_BLE_HCI_TRANSPORT + +#ifndef MYNEWT_VAL_BLE_MONITOR_CONSOLE_BUFFER_SIZE +#define MYNEWT_VAL_BLE_MONITOR_CONSOLE_BUFFER_SIZE (128) #endif -#ifndef MYNEWT_VAL_BLE_ACL_BUF_SIZE -#define MYNEWT_VAL_BLE_ACL_BUF_SIZE (255) +#ifndef MYNEWT_VAL_BLE_MONITOR_RTT +#define MYNEWT_VAL_BLE_MONITOR_RTT (0) #endif -#ifndef MYNEWT_VAL_BLE_HCI_ACL_OUT_COUNT -#define MYNEWT_VAL_BLE_HCI_ACL_OUT_COUNT (12) +#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFERED +#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFERED (1) #endif -#ifndef MYNEWT_VAL_BLE_HCI_EVT_BUF_SIZE -#define MYNEWT_VAL_BLE_HCI_EVT_BUF_SIZE (70) +#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_NAME +#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_NAME "btmonitor" #endif -#ifndef MYNEWT_VAL_BLE_HCI_EVT_HI_BUF_COUNT -#define MYNEWT_VAL_BLE_HCI_EVT_HI_BUF_COUNT (8) +#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_SIZE +#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_SIZE (256) #endif -#ifndef MYNEWT_VAL_BLE_HCI_EVT_LO_BUF_COUNT -#define MYNEWT_VAL_BLE_HCI_EVT_LO_BUF_COUNT (8) +#ifndef MYNEWT_VAL_BLE_MONITOR_UART +#define MYNEWT_VAL_BLE_MONITOR_UART (0) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_UART_BAUDRATE +#define MYNEWT_VAL_BLE_MONITOR_UART_BAUDRATE (1000000) #endif +#ifndef MYNEWT_VAL_BLE_MONITOR_UART_BUFFER_SIZE +#define MYNEWT_VAL_BLE_MONITOR_UART_BUFFER_SIZE (64) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_UART_DEV +#define MYNEWT_VAL_BLE_MONITOR_UART_DEV "uart0" +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT +#define MYNEWT_VAL_BLE_TRANSPORT (1) +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT_ACL_COUNT +#define MYNEWT_VAL_BLE_TRANSPORT_ACL_COUNT (10) +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT_ACL_FROM_HS_COUNT +#define MYNEWT_VAL_BLE_TRANSPORT_ACL_FROM_HS_COUNT (10) +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT_ACL_FROM_LL_COUNT +#define MYNEWT_VAL_BLE_TRANSPORT_ACL_FROM_LL_COUNT (10) +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT_ACL_SIZE +#define MYNEWT_VAL_BLE_TRANSPORT_ACL_SIZE (251) +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT_EVT_COUNT +#define MYNEWT_VAL_BLE_TRANSPORT_EVT_COUNT (4) +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT_EVT_DISCARDABLE_COUNT +#define MYNEWT_VAL_BLE_TRANSPORT_EVT_DISCARDABLE_COUNT (16) +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT_EVT_SIZE +#define MYNEWT_VAL_BLE_TRANSPORT_EVT_SIZE (70) +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT_HS__cdc +#define MYNEWT_VAL_BLE_TRANSPORT_HS__cdc (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_HS__custom +#define MYNEWT_VAL_BLE_TRANSPORT_HS__custom (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_HS__dialog_cmac +#define MYNEWT_VAL_BLE_TRANSPORT_HS__dialog_cmac (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_HS__native +#define MYNEWT_VAL_BLE_TRANSPORT_HS__native (1) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_HS__nrf5340 +#define MYNEWT_VAL_BLE_TRANSPORT_HS__nrf5340 (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_HS__uart +#define MYNEWT_VAL_BLE_TRANSPORT_HS__uart (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_HS__usb +#define MYNEWT_VAL_BLE_TRANSPORT_HS__usb (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_HS +#define MYNEWT_VAL_BLE_TRANSPORT_HS (1) +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT_ISO_COUNT +#define MYNEWT_VAL_BLE_TRANSPORT_ISO_COUNT (10) +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT_ISO_FROM_HS_COUNT +#define MYNEWT_VAL_BLE_TRANSPORT_ISO_FROM_HS_COUNT (10) +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT_ISO_FROM_LL_COUNT +#define MYNEWT_VAL_BLE_TRANSPORT_ISO_FROM_LL_COUNT (10) +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT_ISO_SIZE +#define MYNEWT_VAL_BLE_TRANSPORT_ISO_SIZE (300) +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__apollo3 +#define MYNEWT_VAL_BLE_TRANSPORT_LL__apollo3 (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__custom +#define MYNEWT_VAL_BLE_TRANSPORT_LL__custom (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__dialog_cmac +#define MYNEWT_VAL_BLE_TRANSPORT_LL__dialog_cmac (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__emspi +#define MYNEWT_VAL_BLE_TRANSPORT_LL__emspi (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__native +#define MYNEWT_VAL_BLE_TRANSPORT_LL__native (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__nrf5340 +#define MYNEWT_VAL_BLE_TRANSPORT_LL__nrf5340 (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__socket +#define MYNEWT_VAL_BLE_TRANSPORT_LL__socket (1) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__uart_ll +#define MYNEWT_VAL_BLE_TRANSPORT_LL__uart_ll (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_LL +#define MYNEWT_VAL_BLE_TRANSPORT_LL (1) +#endif + +#undef MYNEWT_VAL_BLE_TRANSPORT_RX_TASK_STACK_SIZE + #ifndef MYNEWT_VAL_BLE_SOCK_CLI_SYSINIT_STAGE #define MYNEWT_VAL_BLE_SOCK_CLI_SYSINIT_STAGE (500) #endif @@ -1009,12 +1194,10 @@ #define MYNEWT_VAL_BLE_SOCK_LINUX_DEV (0) #endif -/* Overridden by @apache-mynewt-nimble/porting/targets/nuttx (defined by @apache-mynewt-nimble/nimble/transport/socket) */ #ifndef MYNEWT_VAL_BLE_SOCK_STACK_SIZE #define MYNEWT_VAL_BLE_SOCK_STACK_SIZE (1028) #endif -/* Overridden by @apache-mynewt-nimble/porting/targets/nuttx (defined by @apache-mynewt-nimble/nimble/transport/socket) */ #ifndef MYNEWT_VAL_BLE_SOCK_TASK_PRIO #define MYNEWT_VAL_BLE_SOCK_TASK_PRIO (3) #endif @@ -1023,24 +1206,20 @@ #define MYNEWT_VAL_BLE_SOCK_TCP_PORT (14433) #endif -/* Overridden by @apache-mynewt-nimble/porting/targets/nuttx (defined by @apache-mynewt-nimble/nimble/transport/socket) */ #ifndef MYNEWT_VAL_BLE_SOCK_USE_LINUX_BLUE #define MYNEWT_VAL_BLE_SOCK_USE_LINUX_BLUE (0) #endif -/* Overridden by @apache-mynewt-nimble/porting/targets/nuttx (defined by @apache-mynewt-nimble/nimble/transport/socket) */ #ifndef MYNEWT_VAL_BLE_SOCK_USE_NUTTX #define MYNEWT_VAL_BLE_SOCK_USE_NUTTX (1) #endif -/* Overridden by @apache-mynewt-nimble/porting/targets/nuttx (defined by @apache-mynewt-nimble/nimble/transport/socket) */ #ifndef MYNEWT_VAL_BLE_SOCK_USE_TCP #define MYNEWT_VAL_BLE_SOCK_USE_TCP (0) #endif -/*** newt */ #ifndef MYNEWT_VAL_APP_NAME -#define MYNEWT_VAL_APP_NAME ("dummy_app") +#define MYNEWT_VAL_APP_NAME "dummy_app" #endif #ifndef MYNEWT_VAL_APP_dummy_app @@ -1048,19 +1227,19 @@ #endif #ifndef MYNEWT_VAL_ARCH_NAME -#define MYNEWT_VAL_ARCH_NAME ("dummy") +#define MYNEWT_VAL_ARCH_NAME "sim" #endif -#ifndef MYNEWT_VAL_ARCH_dummy -#define MYNEWT_VAL_ARCH_dummy (1) +#ifndef MYNEWT_VAL_ARCH_sim +#define MYNEWT_VAL_ARCH_sim (1) #endif #ifndef MYNEWT_VAL_BSP_NAME -#define MYNEWT_VAL_BSP_NAME ("dummy_bsp") +#define MYNEWT_VAL_BSP_NAME "native" #endif -#ifndef MYNEWT_VAL_BSP_dummy_bsp -#define MYNEWT_VAL_BSP_dummy_bsp (1) +#ifndef MYNEWT_VAL_BSP_native +#define MYNEWT_VAL_BSP_native (1) #endif #ifndef MYNEWT_VAL_NEWT_FEATURE_LOGCFG @@ -1072,11 +1251,61 @@ #endif #ifndef MYNEWT_VAL_TARGET_NAME -#define MYNEWT_VAL_TARGET_NAME ("nuttx") +#define MYNEWT_VAL_TARGET_NAME "nuttx" #endif #ifndef MYNEWT_VAL_TARGET_nuttx #define MYNEWT_VAL_TARGET_nuttx (1) #endif +#define MYNEWT_PKG_apache_mynewt_core__compiler_sim 1 +#define MYNEWT_PKG_apache_mynewt_core__crypto_tinycrypt 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_bsp_native 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_drivers_flash_enc_flash 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_drivers_flash_enc_flash_ef_tinycrypt 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_drivers_trng 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_drivers_trng_trng_sw 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_drivers_uart 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_drivers_uart_uart_hal 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_hal 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_mcu_native 1 +#define MYNEWT_PKG_apache_mynewt_core__kernel_os 1 +#define MYNEWT_PKG_apache_mynewt_core__kernel_sim 1 +#define MYNEWT_PKG_apache_mynewt_core__net_ip_mn_socket 1 +#define MYNEWT_PKG_apache_mynewt_core__net_ip_native_sockets 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_console_stub 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_defs 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_flash_map 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_log_common 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_log_modlog 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_log_stub 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_stats_stub 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_sys 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_sysdown 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_sysinit 1 +#define MYNEWT_PKG_apache_mynewt_core__util_mem 1 +#define MYNEWT_PKG_apache_mynewt_core__util_rwlock 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_ans 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_bas 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_dis 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_gap 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_gatt 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_ias 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_ipss 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_lls 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_tps 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_transport 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_transport_socket 1 +#define MYNEWT_PKG_apache_mynewt_nimble__porting_npl_mynewt 1 +#define MYNEWT_PKG_apache_mynewt_nimble__porting_targets_dummy_app 1 +#define MYNEWT_PKG_apache_mynewt_nimble__porting_targets_nuttx 1 + +#define MYNEWT_API_TRNG_HW_IMPL 1 +#define MYNEWT_API_ble_transport 1 +#define MYNEWT_API_console 1 +#define MYNEWT_API_log 1 +#define MYNEWT_API_stats 1 + #endif diff --git a/porting/examples/nuttx/include/sysflash/sysflash.h b/porting/examples/nuttx/include/sysflash/sysflash.h deleted file mode 100644 index ab1341b25d..0000000000 --- a/porting/examples/nuttx/include/sysflash/sysflash.h +++ /dev/null @@ -1,24 +0,0 @@ -/** - * This file was generated by Apache newt version: 1.9.0-dev - */ - -#ifndef H_MYNEWT_SYSFLASH_ -#define H_MYNEWT_SYSFLASH_ - -#include "flash_map/flash_map.h" - -/** - * This flash map definition is used for two purposes: - * 1. To locate the meta area, which contains the true flash map definition. - * 2. As a fallback in case the meta area cannot be read from flash. - */ -extern const struct flash_area sysflash_map_dflt[6]; - -#define FLASH_AREA_BOOTLOADER 0 -#define FLASH_AREA_IMAGE_0 1 -#define FLASH_AREA_IMAGE_1 2 -#define FLASH_AREA_IMAGE_SCRATCH 3 -#define FLASH_AREA_REBOOT_LOG 16 -#define FLASH_AREA_NFFS 17 - -#endif diff --git a/porting/examples/nuttx/main.c b/porting/examples/nuttx/main.c index 82582573ad..bd731105df 100644 --- a/porting/examples/nuttx/main.c +++ b/porting/examples/nuttx/main.c @@ -22,9 +22,12 @@ #include #include #include +#include +#include +#include +#include "netutils/netinit.h" -#include #include "nimble/nimble_npl.h" #include "nimble/nimble_port.h" @@ -40,7 +43,6 @@ static struct ble_npl_task s_task_hci; void nimble_host_task(void *param); void ble_hci_sock_ack_handler(void *param); -void ble_hci_sock_init(void); void ble_hci_sock_set_device(int dev); void ble_store_ram_init(void); @@ -71,12 +73,21 @@ int main(int argc, char *argv[]) ble_hci_sock_set_device(atoi(argv[1])); } +#ifndef CONFIG_NSH_ARCHINIT + /* Perform architecture-specific initialization */ + + boardctl(BOARDIOC_INIT, 0); +#endif + +#ifndef CONFIG_NSH_NETINIT + /* Bring up the network */ + + netinit_bringup(); +#endif + printf("port init\n"); nimble_port_init(); - printf("hci init\n"); - ble_hci_sock_init(); - /* This example provides GATT Alert service */ printf("gap init\n"); ble_svc_gap_init(); @@ -96,8 +107,8 @@ int main(int argc, char *argv[]) printf("hci_sock task init\n"); ret = ble_npl_task_init(&s_task_hci, "hci_sock", ble_hci_sock_task, - NULL, TASK_DEFAULT_PRIORITY, BLE_NPL_TIME_FOREVER, - TASK_DEFAULT_STACK, TASK_DEFAULT_STACK_SIZE); + NULL, TASK_DEFAULT_PRIORITY, BLE_NPL_TIME_FOREVER, + TASK_DEFAULT_STACK, TASK_DEFAULT_STACK_SIZE); if (ret != 0) { @@ -107,8 +118,8 @@ int main(int argc, char *argv[]) /* Create task which handles default event queue for host stack. */ printf("ble_host task init\n"); ret = ble_npl_task_init(&s_task_host, "ble_host", ble_host_task, - NULL, TASK_DEFAULT_PRIORITY, BLE_NPL_TIME_FOREVER, - TASK_DEFAULT_STACK, TASK_DEFAULT_STACK_SIZE); + NULL, TASK_DEFAULT_PRIORITY, BLE_NPL_TIME_FOREVER, + TASK_DEFAULT_STACK, TASK_DEFAULT_STACK_SIZE); if (ret != 0) diff --git a/porting/nimble/Makefile.defs b/porting/nimble/Makefile.defs index 5bab893fde..ad458970fe 100644 --- a/porting/nimble/Makefile.defs +++ b/porting/nimble/Makefile.defs @@ -19,7 +19,10 @@ ifeq (,$(NIMBLE_ROOT)) $(error NIMBLE_ROOT shall be defined) endif -NIMBLE_CFLAGS := +# For now this is required as there are places in NimBLE +# assumingthat pointer is 4 bytes long. +NIMBLE_CFLAGS := -m32 +NIMBLE_LDFLAGS := -m32 NIMBLE_INCLUDE := \ $(NIMBLE_ROOT)/nimble/include \ @@ -35,6 +38,7 @@ NIMBLE_INCLUDE := \ $(NIMBLE_ROOT)/nimble/host/services/tps/include \ $(NIMBLE_ROOT)/nimble/host/store/ram/include \ $(NIMBLE_ROOT)/nimble/host/util/include \ + $(NIMBLE_ROOT)/nimble/transport/include \ $(NIMBLE_ROOT)/porting/nimble/include \ $(NULL) @@ -52,6 +56,7 @@ NIMBLE_SRC := \ $(filter-out $(NIMBLE_IGNORE), $(wildcard $(NIMBLE_ROOT)/nimble/host/services/lls/src/*.c)) \ $(filter-out $(NIMBLE_IGNORE), $(wildcard $(NIMBLE_ROOT)/nimble/host/services/tps/src/*.c)) \ $(filter-out $(NIMBLE_IGNORE), $(wildcard $(NIMBLE_ROOT)/nimble/host/store/ram/src/*.c)) \ + $(filter-out $(NIMBLE_IGNORE), $(wildcard $(NIMBLE_ROOT)/nimble/transport/src/*.c)) \ $(NULL) ifneq (,$(NIMBLE_CFG_CONTROLLER)) diff --git a/porting/nimble/include/hal/hal_system.h b/porting/nimble/include/hal/hal_system.h new file mode 100644 index 0000000000..fa0255a68c --- /dev/null +++ b/porting/nimble/include/hal/hal_system.h @@ -0,0 +1,110 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + +/** + * @addtogroup HAL + * @{ + * @defgroup HALSystem HAL System + * @{ + */ + +#ifndef H_HAL_SYSTEM_ +#define H_HAL_SYSTEM_ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * System reset. + */ +void hal_system_reset(void) __attribute((noreturn)); + +/** + * Called by bootloader to start loaded program. + */ +void hal_system_start(void *img_start) __attribute((noreturn)); + +/** + * Called by split app loader to start the app program. + */ +void hal_system_restart(void *img_start) __attribute((noreturn)); + +/** + * Returns non-zero if there is a HW debugger attached. + */ +int hal_debugger_connected(void); + +/** + * Reboot reason + */ +enum hal_reset_reason { + /** Power on Reset */ + HAL_RESET_POR = 1, + /** Caused by Reset Pin */ + HAL_RESET_PIN = 2, + /** Caused by Watchdog */ + HAL_RESET_WATCHDOG = 3, + /** Soft reset, either system reset or crash */ + HAL_RESET_SOFT = 4, + /** Low supply voltage */ + HAL_RESET_BROWNOUT = 5, + /** Restart due to user request */ + HAL_RESET_REQUESTED = 6, + /** System Off, wakeup on external interrupt*/ + HAL_RESET_SYS_OFF_INT = 7, + /** Restart due to DFU */ + HAL_RESET_DFU = 8, +}; + +/** + * Return the reboot reason + * + * @return A reboot reason + */ +enum hal_reset_reason hal_reset_cause(void); + +/** + * Return the reboot reason as a string + * + * @return String describing previous reset reason + */ +const char *hal_reset_cause_str(void); + +/** + * Starts clocks needed by system + */ +void hal_system_clock_start(void); + +/** + * Reset callback to be called before an reset happens inside hal_system_reset() + */ +void hal_system_reset_cb(void); + +#ifdef __cplusplus +} +#endif + +#endif /* H_HAL_SYSTEM_ */ + +/** + * @} HALSystem + * @} HAL + */ diff --git a/porting/nimble/include/log_common/ignore.h b/porting/nimble/include/log_common/ignore.h deleted file mode 100644 index 46282a0298..0000000000 --- a/porting/nimble/include/log_common/ignore.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef H_IGNORE_ -#define H_IGNORE_ - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * These macros prevent the "set but not used" warnings for log writes below - * the log level. - */ - -#define IGN_1(X) ((void)(X)) -#define IGN_2(X, ...) ((void)(X));IGN_1(__VA_ARGS__) -#define IGN_3(X, ...) ((void)(X));IGN_2(__VA_ARGS__) -#define IGN_4(X, ...) ((void)(X));IGN_3(__VA_ARGS__) -#define IGN_5(X, ...) ((void)(X));IGN_4(__VA_ARGS__) -#define IGN_6(X, ...) ((void)(X));IGN_5(__VA_ARGS__) -#define IGN_7(X, ...) ((void)(X));IGN_6(__VA_ARGS__) -#define IGN_8(X, ...) ((void)(X));IGN_7(__VA_ARGS__) -#define IGN_9(X, ...) ((void)(X));IGN_8(__VA_ARGS__) -#define IGN_10(X, ...) ((void)(X));IGN_9(__VA_ARGS__) -#define IGN_11(X, ...) ((void)(X));IGN_10(__VA_ARGS__) -#define IGN_12(X, ...) ((void)(X));IGN_11(__VA_ARGS__) -#define IGN_13(X, ...) ((void)(X));IGN_12(__VA_ARGS__) -#define IGN_14(X, ...) ((void)(X));IGN_13(__VA_ARGS__) -#define IGN_15(X, ...) ((void)(X));IGN_14(__VA_ARGS__) -#define IGN_16(X, ...) ((void)(X));IGN_15(__VA_ARGS__) -#define IGN_17(X, ...) ((void)(X));IGN_16(__VA_ARGS__) -#define IGN_18(X, ...) ((void)(X));IGN_17(__VA_ARGS__) -#define IGN_19(X, ...) ((void)(X));IGN_18(__VA_ARGS__) -#define IGN_20(X, ...) ((void)(X));IGN_19(__VA_ARGS__) - -#define GET_MACRO(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, \ - _13, _14, _15, _16, _17, _18, _19, _20, NAME, ...) NAME -#define IGNORE(...) \ - GET_MACRO(__VA_ARGS__, IGN_20, IGN_19, IGN_18, IGN_17, IGN_16, IGN_15, \ - IGN_14, IGN_13, IGN_12, IGN_11, IGN_10, IGN_9, IGN_8, IGN_7, \ - IGN_6, IGN_5, IGN_4, IGN_3, IGN_2, IGN_1)(__VA_ARGS__) - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/porting/nimble/include/log_common/log_common.h b/porting/nimble/include/log_common/log_common.h deleted file mode 100644 index ed590b6b0a..0000000000 --- a/porting/nimble/include/log_common/log_common.h +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef H_LOG_COMMON_ -#define H_LOG_COMMON_ - -#include -#include "log_common/ignore.h" - -#ifdef __cplusplus -extern "C" { -#endif - -struct log; - -#define LOG_VERSION_V3 3 - -#define LOG_TYPE_STREAM (0) -#define LOG_TYPE_MEMORY (1) -#define LOG_TYPE_STORAGE (2) - -#define LOG_LEVEL_DEBUG (0) -#define LOG_LEVEL_INFO (1) -#define LOG_LEVEL_WARN (2) -#define LOG_LEVEL_ERROR (3) -#define LOG_LEVEL_CRITICAL (4) -/* Up to 10 custom log levels. */ -#define LOG_LEVEL_MAX (15) - -#define LOG_LEVEL_STR(level) \ - (LOG_LEVEL_DEBUG == level ? "DEBUG" :\ - (LOG_LEVEL_INFO == level ? "INFO" :\ - (LOG_LEVEL_WARN == level ? "WARN" :\ - (LOG_LEVEL_ERROR == level ? "ERROR" :\ - (LOG_LEVEL_CRITICAL == level ? "CRITICAL" :\ - "UNKNOWN"))))) - -/* XXX: These module IDs are defined for backwards compatibility. Application - * code should use the syscfg settings directly. These defines will be removed - * in a future release. - */ -#define LOG_MODULE_DEFAULT 0 -#define LOG_MODULE_OS 1 -#define LOG_MODULE_NEWTMGR 2 -#define LOG_MODULE_NIMBLE_CTLR 3 -#define LOG_MODULE_NIMBLE_HOST 4 -#define LOG_MODULE_NFFS 5 -#define LOG_MODULE_REBOOT 6 -#define LOG_MODULE_IOTIVITY 7 -#define LOG_MODULE_TEST 8 - -#define LOG_MODULE_PERUSER 64 -#define LOG_MODULE_MAX (255) - -#define LOG_ETYPE_STRING (0) -#define LOG_ETYPE_CBOR (1) -#define LOG_ETYPE_BINARY (2) - -/* UTC Timestamp for Jan 2016 00:00:00 */ -#define UTC01_01_2016 1451606400 - -#define LOG_NAME_MAX_LEN (64) - -#ifndef MYNEWT_VAL_LOG_LEVEL -#define LOG_SYSLEVEL ((uint8_t)LOG_LEVEL_MAX) -#else -#define LOG_SYSLEVEL ((uint8_t)MYNEWT_VAL_LOG_LEVEL) -#endif - -/** - * @brief Determines if a log module will accept an entry with a given level. - * - * A log entry is only accepted if its level is less than or equal to both: - * o Global log level setting (LOG_LEVEL), and - * o The specified module log level - * - * @param mod_level The module's minimum log level. - * @param entry_level The level of the entry to be logged. - * - * @return true if the entry would be logged; - * false otherwise. - */ -#define LOG_MOD_LEVEL_IS_ACTIVE(mod_level, entry_level) \ - (LOG_LEVEL <= (entry_level) && (mod_level) <= (entry_level)) - -/* Newtmgr Log opcodes */ -#define LOGS_NMGR_OP_READ (0) -#define LOGS_NMGR_OP_CLEAR (1) -#define LOGS_NMGR_OP_APPEND (2) -#define LOGS_NMGR_OP_MODULE_LIST (3) -#define LOGS_NMGR_OP_LEVEL_LIST (4) -#define LOGS_NMGR_OP_LOGS_LIST (5) -#define LOGS_NMGR_OP_SET_WATERMARK (6) -#define LOGS_NMGR_OP_MODLEVEL (8) - -#define LOG_PRINTF_MAX_ENTRY_LEN (128) - -/* Global log info */ -struct log_info { -#if MYNEWT_VAL(LOG_GLOBAL_IDX) - uint32_t li_next_index; -#endif - uint8_t li_version; -}; - -extern struct log_info g_log_info; - -/** @typedef log_append_cb - * @brief Callback that is executed each time the corresponding log is appended - * to. - * - * @param log The log that was just appended to. - * @param idx The index of newly appended log entry. - */ -typedef void log_append_cb(struct log *log, uint32_t idx); - -/** @typdef log_notify_rotate_cb - * @brief Callback that is executed each time we are about to rotate a log. - * - * @param log The log that is about to rotate - */ -typedef void log_notify_rotate_cb(const struct log *log); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/porting/nimble/include/logcfg/logcfg.h b/porting/nimble/include/logcfg/logcfg.h deleted file mode 100644 index 837cdeac1f..0000000000 --- a/porting/nimble/include/logcfg/logcfg.h +++ /dev/null @@ -1,32 +0,0 @@ -/** - * This file was generated by Apache newt version: 1.9.0-dev - */ - -#ifndef H_MYNEWT_LOGCFG_ -#define H_MYNEWT_LOGCFG_ - -#include "modlog/modlog.h" -#include "log_common/log_common.h" - -#define BLE_HS_LOG_DEBUG(...) IGNORE(__VA_ARGS__) -#define BLE_HS_LOG_INFO(...) MODLOG_INFO(4, __VA_ARGS__) -#define BLE_HS_LOG_WARN(...) MODLOG_WARN(4, __VA_ARGS__) -#define BLE_HS_LOG_ERROR(...) MODLOG_ERROR(4, __VA_ARGS__) -#define BLE_HS_LOG_CRITICAL(...) MODLOG_CRITICAL(4, __VA_ARGS__) -#define BLE_HS_LOG_DISABLED(...) MODLOG_DISABLED(4, __VA_ARGS__) - -#define DFLT_LOG_DEBUG(...) IGNORE(__VA_ARGS__) -#define DFLT_LOG_INFO(...) MODLOG_INFO(0, __VA_ARGS__) -#define DFLT_LOG_WARN(...) MODLOG_WARN(0, __VA_ARGS__) -#define DFLT_LOG_ERROR(...) MODLOG_ERROR(0, __VA_ARGS__) -#define DFLT_LOG_CRITICAL(...) MODLOG_CRITICAL(0, __VA_ARGS__) -#define DFLT_LOG_DISABLED(...) MODLOG_DISABLED(0, __VA_ARGS__) - -#define MFG_LOG_DEBUG(...) IGNORE(__VA_ARGS__) -#define MFG_LOG_INFO(...) IGNORE(__VA_ARGS__) -#define MFG_LOG_WARN(...) IGNORE(__VA_ARGS__) -#define MFG_LOG_ERROR(...) IGNORE(__VA_ARGS__) -#define MFG_LOG_CRITICAL(...) IGNORE(__VA_ARGS__) -#define MFG_LOG_DISABLED(...) MODLOG_DISABLED(128, __VA_ARGS__) - -#endif diff --git a/porting/nimble/include/modlog/modlog.h b/porting/nimble/include/modlog/modlog.h deleted file mode 100644 index 0390461069..0000000000 --- a/porting/nimble/include/modlog/modlog.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef H_MODLOG_ -#define H_MODLOG_ - -#include - -#include "log_common/log_common.h" -#include "log/log.h" - -#define MODLOG_MODULE_DFLT 255 - -#if MYNEWT_VAL(LOG_LEVEL) <= LOG_LEVEL_DEBUG || defined __DOXYGEN__ -#define MODLOG_DEBUG(ml_mod_, ml_msg_, ...) \ - printf((ml_msg_), ##__VA_ARGS__) -#else -#define MODLOG_DEBUG(ml_mod_, ...) IGNORE(__VA_ARGS__) -#endif - -#if MYNEWT_VAL(LOG_LEVEL) <= LOG_LEVEL_INFO || defined __DOXYGEN__ -#define MODLOG_INFO(ml_mod_, ml_msg_, ...) \ - printf((ml_msg_), ##__VA_ARGS__) -#else -#define MODLOG_INFO(ml_mod_, ...) IGNORE(__VA_ARGS__) -#endif - -#if MYNEWT_VAL(LOG_LEVEL) <= LOG_LEVEL_WARN || defined __DOXYGEN__ -#define MODLOG_WARN(ml_mod_, ml_msg_, ...) \ - printf((ml_msg_), ##__VA_ARGS__) -#else -#define MODLOG_WARN(ml_mod_, ...) IGNORE(__VA_ARGS__) -#endif - -#if MYNEWT_VAL(LOG_LEVEL) <= LOG_LEVEL_ERROR || defined __DOXYGEN__ -#define MODLOG_ERROR(ml_mod_, ml_msg_, ...) \ - printf((ml_msg_), ##__VA_ARGS__) -#else -#define MODLOG_ERROR(ml_mod_, ...) IGNORE(__VA_ARGS__) -#endif - -#if MYNEWT_VAL(LOG_LEVEL) <= LOG_LEVEL_CRITICAL || defined __DOXYGEN__ -#define MODLOG_CRITICAL(ml_mod_, ml_msg_, ...) \ - printf((ml_msg_), ##__VA_ARGS__) -#else -#define MODLOG_CRITICAL(ml_mod_, ...) IGNORE(__VA_ARGS__) -#endif - -#define MODLOG(ml_lvl_, ml_mod_, ...) \ - MODLOG_ ## ml_lvl_((ml_mod_), __VA_ARGS__) - -#endif diff --git a/porting/nimble/include/os/os.h b/porting/nimble/include/os/os.h index f7a7ef9c58..da7427f6e0 100644 --- a/porting/nimble/include/os/os.h +++ b/porting/nimble/include/os/os.h @@ -26,14 +26,6 @@ extern "C" { #endif -#ifndef min -#define min(a, b) ((a)<(b)?(a):(b)) -#endif - -#ifndef max -#define max(a, b) ((a)>(b)?(a):(b)) -#endif - #include "syscfg/syscfg.h" #include "nimble/nimble_npl.h" diff --git a/porting/nimble/include/os/os_mbuf.h b/porting/nimble/include/os/os_mbuf.h index 771ea76159..81fcab9d0f 100644 --- a/porting/nimble/include/os/os_mbuf.h +++ b/porting/nimble/include/os/os_mbuf.h @@ -53,6 +53,9 @@ struct os_mbuf_pool { */ struct os_mempool *omp_pool; + /** + * Next mbuf pool in the list + */ STAILQ_ENTRY(os_mbuf_pool) omp_next; }; @@ -70,6 +73,9 @@ struct os_mbuf_pkthdr { */ uint16_t omp_flags; + /** + * Next mbuf packet header in the list + */ STAILQ_ENTRY(os_mbuf_pkthdr) omp_next; }; @@ -99,6 +105,9 @@ struct os_mbuf { */ struct os_mbuf_pool *om_omp; + /** + * Next mbuf in the list + */ SLIST_ENTRY(os_mbuf) om_next; /** @@ -111,22 +120,23 @@ struct os_mbuf { * Structure representing a queue of mbufs. */ struct os_mqueue { + /** A queue of mbuf packet headers. */ STAILQ_HEAD(, os_mbuf_pkthdr) mq_head; /** Event to post when new buffers are available on the queue. */ struct ble_npl_event mq_ev; }; -/* +/** * Given a flag number, provide the mask for it * - * @param __n The number of the flag in the mask + * @param __n The number of the flag in the mask */ #define OS_MBUF_F_MASK(__n) (1 << (__n)) -/* +/** * Checks whether a given mbuf is a packet header mbuf * - * @param __om The mbuf to check + * @param __om The mbuf to check */ #define OS_MBUF_IS_PKTHDR(__om) \ ((__om)->om_pkthdr_len >= sizeof (struct os_mbuf_pkthdr)) @@ -148,8 +158,8 @@ struct os_mqueue { /** * Access the data of a mbuf, and cast it to type * - * @param __om The mbuf to access, and cast - * @param __type The type to cast it to + * @param __om The mbuf to access, and cast + * @param __type The type to cast it to */ #define OS_MBUF_DATA(__om, __type) \ (__type) ((__om)->om_data) @@ -189,7 +199,7 @@ _os_mbuf_leadingspace(struct os_mbuf *om) } leadingspace = (uint16_t) (OS_MBUF_DATA(om, uint8_t *) - - ((uint8_t *) &om->om_databuf[0] + startoff)); + ((uint8_t *) &om->om_databuf[0] + startoff)); return (leadingspace); } @@ -201,10 +211,10 @@ _os_mbuf_leadingspace(struct os_mbuf *om) * Works on both packet header, and regular mbufs, as it accounts * for the additional space allocated to the packet header. * - * @param __omp Is the mbuf pool (which contains packet header length.) - * @param __om Is the mbuf in that pool to get the leadingspace for + * @param __om The mbuf in that pool to get the leading + * space for * - * @return Amount of leading space available in the mbuf + * @return Amount of leading space available in the mbuf */ #define OS_MBUF_LEADINGSPACE(__om) _os_mbuf_leadingspace(__om) @@ -220,7 +230,7 @@ _os_mbuf_trailingspace(struct os_mbuf *om) omp = om->om_omp; return (&om->om_databuf[0] + omp->omp_databuf_len) - - (om->om_data + om->om_len); + (om->om_data + om->om_len); } /** @endcond */ @@ -229,10 +239,10 @@ _os_mbuf_trailingspace(struct os_mbuf *om) * Returns the trailing space (space at the end) of the mbuf. * Works on both packet header and regular mbufs. * - * @param __omp The mbuf pool for this mbuf - * @param __om Is the mbuf in that pool to get trailing space for + * @param __om The mbuf in that pool to get the trailing + * space for * - * @return The amount of trailing space available in the mbuf + * @return Amount of trailing space available in the mbuf */ #define OS_MBUF_TRAILINGSPACE(__om) _os_mbuf_trailingspace(__om) @@ -259,11 +269,12 @@ int os_mqueue_init(struct os_mqueue *mq, ble_npl_event_fn *ev_cb, void *arg); /** * Remove and return a single mbuf from the mbuf queue. Does not block. * - * @param mq The mbuf queue to pull an element off of. + * @param mq The mbuf queue to pull an element off of. * - * @return The next mbuf in the queue, or NULL if queue has no mbufs. + * @return The next mbuf in the queue; + * NULL if queue has no mbufs. */ -struct os_mbuf *os_mqueue_get(struct os_mqueue *); +struct os_mbuf *os_mqueue_get(struct os_mqueue *mq); /** * Adds a packet (i.e. packet header mbuf) to an mqueue. The event associated @@ -271,11 +282,12 @@ struct os_mbuf *os_mqueue_get(struct os_mqueue *); * * @param mq The mbuf queue to append the mbuf to. * @param evq The event queue to post an event to. - * @param m The mbuf to append to the mbuf queue. + * @param om The mbuf to append to the mbuf queue. * * @return 0 on success, non-zero on failure. */ -int os_mqueue_put(struct os_mqueue *, struct ble_npl_eventq *, struct os_mbuf *); +int os_mqueue_put(struct os_mqueue *mq, struct ble_npl_eventq *evq, + struct os_mbuf *om); /** * MSYS is a system level mbuf registry. Allows the system to share @@ -289,20 +301,24 @@ int os_mqueue_put(struct os_mqueue *, struct ble_npl_eventq *, struct os_mbuf *) * os_msys_register() registers a mbuf pool with MSYS, and allows MSYS to * allocate mbufs out of it. * - * @param new_pool The pool to register with MSYS + * @param new_pool The pool to register with MSYS * - * @return 0 on success, non-zero on failure + * @return 0 on success; + * non-zero on failure */ -int os_msys_register(struct os_mbuf_pool *); +int os_msys_register(struct os_mbuf_pool *new_pool); /** * Allocate a mbuf from msys. Based upon the data size requested, * os_msys_get() will choose the mbuf pool that has the best fit. * - * @param dsize The estimated size of the data being stored in the mbuf - * @param leadingspace The amount of leadingspace to allocate in the mbuf + * @param dsize The estimated size of the data being stored in + * the mbuf + * @param leadingspace The amount of leadingspace to allocate in + * the mbuf * - * @return A freshly allocated mbuf on success, NULL on failure. + * @return A freshly allocated mbuf on success; + * NULL on failure. */ struct os_mbuf *os_msys_get(uint16_t dsize, uint16_t leadingspace); @@ -315,72 +331,77 @@ void os_msys_reset(void); * Allocate a packet header structure from the MSYS pool. See * os_msys_register() for a description of MSYS. * - * @param dsize The estimated size of the data being stored in the mbuf - * @param user_hdr_len The length to allocate for the packet header structure + * @param dsize The estimated size of the data being stored in + * the mbuf + * @param user_hdr_len The length to allocate for the packet header + * structure * - * @return A freshly allocated mbuf on success, NULL on failure. + * @return A freshly allocated mbuf on success; + * NULL on failure. */ struct os_mbuf *os_msys_get_pkthdr(uint16_t dsize, uint16_t user_hdr_len); /** * Count the number of blocks in all the mbuf pools that are allocated. * - * @return total number of blocks allocated in Msys + * @return total number of blocks allocated in Msys */ int os_msys_count(void); /** * Return the number of free blocks in Msys * - * @return Number of free blocks available in Msys + * @return Number of free blocks available in Msys */ int os_msys_num_free(void); /** * Initialize a pool of mbufs. * - * @param omp The mbuf pool to initialize - * @param mp The memory pool that will hold this mbuf pool - * @param buf_len The length of the buffer itself. - * @param nbufs The number of buffers in the pool + * @param omp The mbuf pool to initialize + * @param mp The memory pool that will hold this mbuf pool + * @param buf_len The length of the buffer itself. + * @param nbufs The number of buffers in the pool * - * @return 0 on success, error code on failure. + * @return 0 on success; + * error code on failure. */ -int os_mbuf_pool_init(struct os_mbuf_pool *, struct os_mempool *mp, - uint16_t, uint16_t); - +int os_mbuf_pool_init(struct os_mbuf_pool *omp, struct os_mempool *mp, + uint16_t buf_len, uint16_t nbufs); /** * Get an mbuf from the mbuf pool. The mbuf is allocated, and initialized * prior to being returned. * - * @param omp The mbuf pool to return the packet from - * @param leadingspace The amount of leadingspace to put before the data - * section by default. + * @param omp The mbuf pool to return the packet from + * @param leadingspace The amount of leadingspace to put before the + * data section by default. * - * @return An initialized mbuf on success, and NULL on failure. + * @return An initialized mbuf on success; + * NULL on failure. */ -struct os_mbuf *os_mbuf_get(struct os_mbuf_pool *omp, uint16_t); +struct os_mbuf *os_mbuf_get(struct os_mbuf_pool *omp, uint16_t leadingspace); /** * Allocate a new packet header mbuf out of the os_mbuf_pool. * - * @param omp The mbuf pool to allocate out of - * @param user_pkthdr_len The packet header length to reserve for the caller. + * @param omp The mbuf pool to allocate out of + * @param user_pkthdr_len The packet header length to reserve for the + * caller. * - * @return A freshly allocated mbuf on success, NULL on failure. + * @return A freshly allocated mbuf on success; + * NULL on failure. */ struct os_mbuf *os_mbuf_get_pkthdr(struct os_mbuf_pool *omp, - uint8_t pkthdr_len); + uint8_t user_pkthdr_len); /** * Duplicate a chain of mbufs. Return the start of the duplicated chain. * - * @param omp The mbuf pool to duplicate out of - * @param om The mbuf chain to duplicate + * @param om The mbuf chain to duplicate * - * @return A pointer to the new chain of mbufs + * @return A pointer to the new chain of mbufs */ -struct os_mbuf *os_mbuf_dup(struct os_mbuf *m); +struct os_mbuf *os_mbuf_dup(struct os_mbuf *om); /** * Locates the specified absolute offset within an mbuf chain. The offset @@ -399,11 +420,11 @@ struct os_mbuf *os_mbuf_off(const struct os_mbuf *om, int off, uint16_t *out_off); -/* +/** * Copy data from an mbuf chain starting "off" bytes from the beginning, * continuing for "len" bytes, into the indicated buffer. * - * @param m The mbuf chain to copy from + * @param om The mbuf chain to copy from * @param off The offset into the mbuf chain to begin copying from * @param len The length of the data to copy * @param dst The destination buffer to copy into @@ -411,7 +432,7 @@ struct os_mbuf *os_mbuf_off(const struct os_mbuf *om, int off, * @return 0 on success; * -1 if the mbuf does not contain enough data. */ -int os_mbuf_copydata(const struct os_mbuf *m, int off, int len, void *dst); +int os_mbuf_copydata(const struct os_mbuf *om, int off, int len, void *dst); /** * @brief Calculates the length of an mbuf chain. @@ -430,13 +451,14 @@ uint16_t os_mbuf_len(const struct os_mbuf *om); /** * Append data onto a mbuf * - * @param om The mbuf to append the data onto - * @param data The data to append onto the mbuf - * @param len The length of the data to append + * @param om The mbuf to append the data onto + * @param data The data to append onto the mbuf + * @param len The length of the data to append * - * @return 0 on success, and an error code on failure + * @return 0 on success; + * an error code on failure */ -int os_mbuf_append(struct os_mbuf *m, const void *, uint16_t); +int os_mbuf_append(struct os_mbuf *om, const void *data, uint16_t len); /** * Reads data from one mbuf and appends it to another. On error, the specified @@ -459,20 +481,21 @@ int os_mbuf_appendfrom(struct os_mbuf *dst, const struct os_mbuf *src, /** * Release a mbuf back to the pool * - * @param omp The Mbuf pool to release back to - * @param om The Mbuf to release back to the pool + * @param om The Mbuf to release back to the pool * - * @return 0 on success, -1 on failure + * @return 0 on success; + * -1 on failure */ -int os_mbuf_free(struct os_mbuf *mb); +int os_mbuf_free(struct os_mbuf *om); /** * Free a chain of mbufs * - * @param omp The mbuf pool to free the chain of mbufs into - * @param om The starting mbuf of the chain to free back into the pool + * @param om The starting mbuf of the chain to free back into + * the pool * - * @return 0 on success, -1 on failure + * @return 0 on success; + * -1 on failure */ int os_mbuf_free_chain(struct os_mbuf *om); @@ -480,12 +503,12 @@ int os_mbuf_free_chain(struct os_mbuf *om); * Adjust the length of a mbuf, trimming either from the head or the tail * of the mbuf. * - * @param mp The mbuf chain to adjust - * @param req_len The length to trim from the mbuf. If positive, trims - * from the head of the mbuf, if negative, trims from the - * tail of the mbuf. + * @param om The mbuf chain to adjust + * @param req_len The length to trim from the mbuf. If positive, + * trims from the head of the mbuf, if + * negative, trims from the tail of the mbuf. */ -void os_mbuf_adj(struct os_mbuf *mp, int req_len); +void os_mbuf_adj(struct os_mbuf *om, int req_len); /** @@ -535,7 +558,6 @@ int os_mbuf_cmpm(const struct os_mbuf *om1, uint16_t offset1, * * The specified mbuf chain does not need to contain a packet header. * - * @param omp The mbuf pool to allocate from. * @param om The head of the mbuf chain. * @param len The number of bytes to prepend. * @@ -563,7 +585,6 @@ struct os_mbuf *os_mbuf_prepend_pullup(struct os_mbuf *om, uint16_t len); * it is extended as necessary. If the destination mbuf contains a packet * header, the header length is updated. * - * @param omp The mbuf pool to allocate from. * @param om The mbuf chain to copy into. * @param off The offset within the chain to copy to. * @param src The source buffer to copy from. @@ -590,7 +611,6 @@ void os_mbuf_concat(struct os_mbuf *first, struct os_mbuf *second); * appended to the chain. It is an error to request more data than can fit in * a single buffer. * - * @param omp * @param om The head of the chain to extend. * @param len The number of bytes to extend by. * @@ -609,11 +629,12 @@ void *os_mbuf_extend(struct os_mbuf *om, uint16_t len); * extra bytes to the contiguous region, in an attempt to avoid being * called next time. * - * @param omp The mbuf pool to take the mbufs out of - * @param om The mbuf chain to make contiguous - * @param len The number of bytes in the chain to make contiguous + * @param om The mbuf chain to make contiguous + * @param len The number of bytes in the chain to make + * contiguous * - * @return The contiguous mbuf chain on success, NULL on failure. + * @return The contiguous mbuf chain on success; + * NULL on failure. */ struct os_mbuf *os_mbuf_pullup(struct os_mbuf *om, uint16_t len); @@ -656,10 +677,10 @@ int os_mbuf_widen(struct os_mbuf *om, uint16_t off, uint16_t len); * header it is discarded. If m1 is NULL, NULL is returned and * m2 is left untouched. * - * @param m1 Pointer to first mbuf chain to pack - * @param m2 Pointer to second mbuf chain to pack + * @param m1 Pointer to first mbuf chain to pack + * @param m2 Pointer to second mbuf chain to pack * - * @return struct os_mbuf* Pointer to resulting mbuf chain + * @return Pointer to resulting mbuf chain */ struct os_mbuf *os_mbuf_pack_chains(struct os_mbuf *m1, struct os_mbuf *m2); diff --git a/porting/nimble/include/os/os_mempool.h b/porting/nimble/include/os/os_mempool.h index 71d77065ae..d4c3313a3f 100644 --- a/porting/nimble/include/os/os_mempool.h +++ b/porting/nimble/include/os/os_mempool.h @@ -43,6 +43,7 @@ extern "C" { * caller. */ struct os_memblock { + /** Next memory block in the list. */ SLIST_ENTRY(os_memblock) mb_next; }; @@ -66,8 +67,10 @@ struct os_mempool { /** Bitmap of OS_MEMPOOL_F_[...] values. */ uint8_t mp_flags; /** Address of memory buffer used by pool */ - uint32_t mp_membuf_addr; + uintptr_t mp_membuf_addr; + /** Next memory pool in the list. */ STAILQ_ENTRY(os_mempool) mp_list; + /** Head of the list of memory blocks. */ SLIST_HEAD(,os_memblock); /** Name for memory block */ char *name; @@ -102,14 +105,19 @@ struct os_mempool_ext; typedef os_error_t os_mempool_put_fn(struct os_mempool_ext *ome, void *data, void *arg); +/** Extended memory pool. */ struct os_mempool_ext { + /** Standard memory pool. */ struct os_mempool mpe_mp; - /* Callback that is executed immediately when a block is freed. */ + /** Callback that is executed immediately when a block is freed. */ os_mempool_put_fn *mpe_put_cb; + + /** Optional argument passed to the callback function. */ void *mpe_put_arg; }; +/** Length of the name of memory pool */ #define OS_MEMPOOL_INFO_NAME_LEN (32) /** @@ -132,15 +140,30 @@ struct os_mempool_info { /** * Get information about the next system memory pool. * - * @param mempool The current memory pool, or NULL if starting iteration. - * @param info A pointer to the structure to return memory pool information - * into. + * @param mp The current memory pool, or NULL if starting + * iteration. + * @param omi A pointer to the structure to return memory pool + * information into. * - * @return The next memory pool in the list to get information about, or NULL - * when at the last memory pool. + * @return The next memory pool in the list to get + * information about; + * NULL when at the last memory pool. */ -struct os_mempool *os_mempool_info_get_next(struct os_mempool *, - struct os_mempool_info *); +struct os_mempool *os_mempool_info_get_next(struct os_mempool *mp, + struct os_mempool_info *omi); + +/** + * Get information system memory pool by name. + * + * @param mempool_name The name of mempool. + * @param info A pointer to the structure to return memory pool + * information into, can be NULL. + * + * @return The memory pool found; + * NULL when there is no such memory pool. + */ +struct os_mempool *os_mempool_get(const char *mempool_name, + struct os_mempool_info *info); /* * To calculate size of the memory buffer needed for the pool. NOTE: This size @@ -148,11 +171,10 @@ struct os_mempool *os_mempool_info_get_next(struct os_mempool *, * the memory pool. */ #if MYNEWT_VAL(OS_MEMPOOL_GUARD) -/* - * Leave extra 4 bytes of guard area at the end. - */ +/** Leave extra 4 bytes of guard area at the end. */ #define OS_MEMPOOL_BLOCK_SZ(sz) ((sz) + sizeof(os_membuf_t)) #else +/** Size of a memory pool block. */ #define OS_MEMPOOL_BLOCK_SZ(sz) (sz) #endif #if (OS_ALIGNMENT == 4) @@ -164,7 +186,9 @@ typedef __uint128_t os_membuf_t; #else #error "Unhandled `OS_ALIGNMENT` for `os_membuf_t`" #endif /* OS_ALIGNMENT == * */ -#define OS_MEMPOOL_SIZE(n,blksize) ((((blksize) + ((OS_ALIGNMENT)-1)) / (OS_ALIGNMENT)) * (n)) + +/** The total size of a memory pool, including alignment. */ +#define OS_MEMPOOL_SIZE(n,blksize) (((OS_MEMPOOL_BLOCK_SZ(blksize) + ((OS_ALIGNMENT)-1)) / (OS_ALIGNMENT)) * (n)) /** Calculates the number of bytes required to initialize a memory pool. */ #define OS_MEMPOOL_BYTES(n,blksize) \ @@ -173,13 +197,14 @@ typedef __uint128_t os_membuf_t; /** * Initialize a memory pool. * - * @param mp Pointer to a pointer to a mempool - * @param blocks The number of blocks in the pool - * @param blocks_size The size of the block, in bytes. - * @param membuf Pointer to memory to contain blocks. - * @param name Name of the pool. + * @param mp Pointer to a pointer to a mempool + * @param blocks The number of blocks in the pool + * @param block_size The size of the block, in bytes. + * @param membuf Pointer to memory to contain blocks. + * @param name Name of the pool. * - * @return os_error_t + * @return 0 on success; + * Non-zero error code on failure. */ os_error_t os_mempool_init(struct os_mempool *mp, uint16_t blocks, uint32_t block_size, void *membuf, char *name); @@ -189,13 +214,14 @@ os_error_t os_mempool_init(struct os_mempool *mp, uint16_t blocks, * are not specified when this function is called; they are assigned manually * after initialization. * - * @param mpe The extended memory pool to initialize. - * @param blocks The number of blocks in the pool. - * @param block_size The size of each block, in bytes. - * @param membuf Pointer to memory to contain blocks. - * @param name Name of the pool. + * @param mpe The extended memory pool to initialize. + * @param blocks The number of blocks in the pool. + * @param block_size The size of each block, in bytes. + * @param membuf Pointer to memory to contain blocks. + * @param name Name of the pool. * - * @return os_error_t + * @return 0 on success; + * Non-zero error code on failure. */ os_error_t os_mempool_ext_init(struct os_mempool_ext *mpe, uint16_t blocks, uint32_t block_size, void *membuf, char *name); @@ -214,9 +240,10 @@ os_error_t os_mempool_unregister(struct os_mempool *mp); /** * Clears a memory pool. * - * @param mp The mempool to clear. + * @param mp The mempool to clear. * - * @return os_error_t + * @return 0 on success; + * Non-zero error code on failure. */ os_error_t os_mempool_clear(struct os_mempool *mp); @@ -246,9 +273,10 @@ int os_memblock_from(const struct os_mempool *mp, const void *block_addr); /** * Get a memory block from a memory pool * - * @param mp Pointer to the memory pool + * @param mp Pointer to the memory pool * - * @return void* Pointer to block if available; NULL otherwise + * @return Pointer to block if available; + * NULL otherwise */ void *os_memblock_get(struct os_mempool *mp); @@ -257,20 +285,22 @@ void *os_memblock_get(struct os_mempool *mp); * This function should only be called from a put callback to free a block * without causing infinite recursion. * - * @param mp Pointer to memory pool - * @param block_addr Pointer to memory block + * @param mp Pointer to memory pool + * @param block_addr Pointer to memory block * - * @return os_error_t + * @return 0 on success; + * Non-zero error code on failure. */ os_error_t os_memblock_put_from_cb(struct os_mempool *mp, void *block_addr); /** * Puts the memory block back into the pool * - * @param mp Pointer to memory pool - * @param block_addr Pointer to memory block + * @param mp Pointer to memory pool + * @param block_addr Pointer to memory block * - * @return os_error_t + * @return 0 on success; + * Non-zero error code on failure. */ os_error_t os_memblock_put(struct os_mempool *mp, void *block_addr); diff --git a/porting/nimble/include/os/queue.h b/porting/nimble/include/os/queue.h index c19edb113c..ed05c619d6 100644 --- a/porting/nimble/include/os/queue.h +++ b/porting/nimble/include/os/queue.h @@ -1,4 +1,6 @@ -/* +/*- + * SPDX-License-Identifier: BSD-3-Clause + * * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * @@ -10,7 +12,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -27,19 +29,16 @@ * SUCH DAMAGE. * * @(#)queue.h 8.5 (Berkeley) 8/20/94 - * $FreeBSD: src/sys/sys/queue.h,v 1.32.2.7 2002/04/17 14:21:02 des Exp $ */ -#ifndef _QUEUE_H_ -#define _QUEUE_H_ +#ifndef _SYS_QUEUE_H_ +#define _SYS_QUEUE_H_ -#ifdef __cplusplus -extern "C" { -#endif +#include /* - * This file defines five types of data structures: singly-linked lists, - * singly-linked tail queues, lists, tail queues, and circular queues. + * This file defines four types of data structures: singly-linked lists, + * singly-linked tail queues, lists and tail queues. * * A singly-linked list is headed by a single forward pointer. The elements * are singly linked for minimum space and pointer manipulation overhead at @@ -67,7 +66,7 @@ extern "C" { * so that an arbitrary element can be removed without a need to * traverse the list. New elements can be added to the list before * or after an existing element or at the head of the list. A list - * may only be traversed in the forward direction. + * may be traversed in either direction. * * A tail queue is headed by a pair of pointers, one to the head of the * list and the other to the tail of the list. The elements are doubly @@ -76,99 +75,246 @@ extern "C" { * after an existing element, at the head of the list, or at the end of * the list. A tail queue may be traversed in either direction. * - * A circle queue is headed by a pair of pointers, one to the head of the - * list and the other to the tail of the list. The elements are doubly - * linked so that an arbitrary element can be removed without a need to - * traverse the list. New elements can be added to the list before or after - * an existing element, at the head of the list, or at the end of the list. - * A circle queue may be traversed in either direction, but has a more - * complex end of list detection. - * * For details on the use of these macros, see the queue(3) manual page. * + * Below is a summary of implemented functions where: + * + means the macro is available + * - means the macro is not available + * s means the macro is available but is slow (runs in O(n) time) * - * SLIST LIST STAILQ TAILQ CIRCLEQ - * _HEAD + + + + + - * _HEAD_INITIALIZER + + + + + - * _ENTRY + + + + + - * _INIT + + + + + - * _EMPTY + + + + + - * _FIRST + + + + + - * _NEXT + + + + + - * _PREV - - - + + - * _LAST - - + + + - * _FOREACH + + + + + - * _FOREACH_REVERSE - - - + + - * _INSERT_HEAD + + + + + - * _INSERT_BEFORE - + - + + - * _INSERT_AFTER + + + + + - * _INSERT_TAIL - - + + + - * _REMOVE_HEAD + - + - - - * _REMOVE + + + + + + * SLIST LIST STAILQ TAILQ + * _HEAD + + + + + * _CLASS_HEAD + + + + + * _HEAD_INITIALIZER + + + + + * _ENTRY + + + + + * _CLASS_ENTRY + + + + + * _INIT + + + + + * _EMPTY + + + + + * _END + + + + + * _FIRST + + + + + * _NEXT + + + + + * _PREV - + - + + * _LAST - - + + + * _LAST_FAST - - - + + * _FOREACH + + + + + * _FOREACH_FROM + + + + + * _FOREACH_SAFE + + + + + * _FOREACH_FROM_SAFE + + + + + * _FOREACH_REVERSE - - - + + * _FOREACH_REVERSE_FROM - - - + + * _FOREACH_REVERSE_SAFE - - - + + * _FOREACH_REVERSE_FROM_SAFE - - - + + * _INSERT_HEAD + + + + + * _INSERT_BEFORE - + - + + * _INSERT_AFTER + + + + + * _INSERT_TAIL - - + + + * _CONCAT s s + + + * _REMOVE_AFTER + - + - + * _REMOVE_HEAD + + + + + * _REMOVE s + s + + * _REPLACE - + - + + * _SWAP + + + + * */ +#ifndef __containerof +#define __containerof CONTAINER_OF +#endif + +#ifdef QUEUE_MACRO_DEBUG +#warn Use QUEUE_MACRO_DEBUG_TRACE and/or QUEUE_MACRO_DEBUG_TRASH +#define QUEUE_MACRO_DEBUG_TRACE +#define QUEUE_MACRO_DEBUG_TRASH +#endif + +#ifdef QUEUE_MACRO_DEBUG_TRACE +/* Store the last 2 places the queue element or head was altered */ +struct qm_trace { + unsigned long lastline; + unsigned long prevline; + const char *lastfile; + const char *prevfile; +}; + +#define TRACEBUF struct qm_trace trace; +#define TRACEBUF_INITIALIZER { __LINE__, 0, __FILE__, NULL } , + +#define QMD_TRACE_HEAD(head) do { \ + (head)->trace.prevline = (head)->trace.lastline; \ + (head)->trace.prevfile = (head)->trace.lastfile; \ + (head)->trace.lastline = __LINE__; \ + (head)->trace.lastfile = __FILE__; \ +} while (0) + +#define QMD_TRACE_ELEM(elem) do { \ + (elem)->trace.prevline = (elem)->trace.lastline; \ + (elem)->trace.prevfile = (elem)->trace.lastfile; \ + (elem)->trace.lastline = __LINE__; \ + (elem)->trace.lastfile = __FILE__; \ +} while (0) + +#else /* !QUEUE_MACRO_DEBUG_TRACE */ +#define QMD_TRACE_ELEM(elem) +#define QMD_TRACE_HEAD(head) +#define TRACEBUF +#define TRACEBUF_INITIALIZER +#endif /* QUEUE_MACRO_DEBUG_TRACE */ + +#ifdef QUEUE_MACRO_DEBUG_TRASH +#define QMD_SAVELINK(name, link) void **name = (void *)&(link) +#define TRASHIT(x) do {(x) = (void *)-1;} while (0) +#define QMD_IS_TRASHED(x) ((x) == (void *)(intptr_t)-1) +#else /* !QUEUE_MACRO_DEBUG_TRASH */ +#define QMD_SAVELINK(name, link) +#define TRASHIT(x) +#define QMD_IS_TRASHED(x) 0 +#endif /* QUEUE_MACRO_DEBUG_TRASH */ + +#ifdef __cplusplus +/* + * In C++ there can be structure lists and class lists: + */ +#define QUEUE_TYPEOF(type) type +#else +#define QUEUE_TYPEOF(type) struct type +#endif + /* * Singly-linked List declarations. */ -#define SLIST_HEAD(name, type) \ -struct name { \ - struct type *slh_first; /* first element */ \ +#define SLIST_HEAD(name, type) \ +struct name { \ + struct type *slh_first; /* first element */ \ +} + +#define SLIST_CLASS_HEAD(name, type) \ +struct name { \ + class type *slh_first; /* first element */ \ } -#define SLIST_HEAD_INITIALIZER(head) \ - { NULL } +#define SLIST_HEAD_INITIALIZER(head) \ + { NULL } -#define SLIST_ENTRY(type) \ -struct { \ - struct type *sle_next; /* next element */ \ +#define SLIST_ENTRY(type) \ +struct { \ + struct type *sle_next; /* next element */ \ +} + +#define SLIST_CLASS_ENTRY(type) \ +struct { \ + class type *sle_next; /* next element */ \ } /* * Singly-linked List functions. */ -#define SLIST_EMPTY(head) ((head)->slh_first == NULL) +#if (defined(_KERNEL) && defined(INVARIANTS)) +#define QMD_SLIST_CHECK_PREVPTR(prevp, elm) do { \ + if (*(prevp) != (elm)) \ + panic("Bad prevptr *(%p) == %p != %p", \ + (prevp), *(prevp), (elm)); \ +} while (0) +#else +#define QMD_SLIST_CHECK_PREVPTR(prevp, elm) +#endif -#define SLIST_FIRST(head) ((head)->slh_first) +#define SLIST_CONCAT(head1, head2, type, field) do { \ + QUEUE_TYPEOF(type) *curelm = SLIST_FIRST(head1); \ + if (curelm == NULL) { \ + if ((SLIST_FIRST(head1) = SLIST_FIRST(head2)) != NULL) \ + SLIST_INIT(head2); \ + } else if (SLIST_FIRST(head2) != NULL) { \ + while (SLIST_NEXT(curelm, field) != NULL) \ + curelm = SLIST_NEXT(curelm, field); \ + SLIST_NEXT(curelm, field) = SLIST_FIRST(head2); \ + SLIST_INIT(head2); \ + } \ +} while (0) + +#define SLIST_EMPTY(head) ((head)->slh_first == NULL) -#define SLIST_FOREACH(var, head, field) \ - for ((var) = SLIST_FIRST((head)); \ - (var); \ - (var) = SLIST_NEXT((var), field)) +#define SLIST_FIRST(head) ((head)->slh_first) -#define SLIST_INIT(head) do { \ - SLIST_FIRST((head)) = NULL; \ +#define SLIST_FOREACH(var, head, field) \ + for ((var) = SLIST_FIRST((head)); \ + (var); \ + (var) = SLIST_NEXT((var), field)) + +#define SLIST_FOREACH_FROM(var, head, field) \ + for ((var) = ((var) ? (var) : SLIST_FIRST((head))); \ + (var); \ + (var) = SLIST_NEXT((var), field)) + +#define SLIST_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = SLIST_FIRST((head)); \ + (var) && ((tvar) = SLIST_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define SLIST_FOREACH_FROM_SAFE(var, head, field, tvar) \ + for ((var) = ((var) ? (var) : SLIST_FIRST((head))); \ + (var) && ((tvar) = SLIST_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define SLIST_FOREACH_PREVPTR(var, varp, head, field) \ + for ((varp) = &SLIST_FIRST((head)); \ + ((var) = *(varp)) != NULL; \ + (varp) = &SLIST_NEXT((var), field)) + +#define SLIST_INIT(head) do { \ + SLIST_FIRST((head)) = NULL; \ +} while (0) + +#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ + SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \ + SLIST_NEXT((slistelm), field) = (elm); \ } while (0) -#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ - SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \ - SLIST_NEXT((slistelm), field) = (elm); \ +#define SLIST_INSERT_HEAD(head, elm, field) do { \ + SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \ + SLIST_FIRST((head)) = (elm); \ +} while (0) + +#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) + +#define SLIST_REMOVE(head, elm, type, field) do { \ + if (SLIST_FIRST((head)) == (elm)) { \ + SLIST_REMOVE_HEAD((head), field); \ + } \ + else { \ + QUEUE_TYPEOF(type) *curelm = SLIST_FIRST(head); \ + while (SLIST_NEXT(curelm, field) != (elm)) \ + curelm = SLIST_NEXT(curelm, field); \ + SLIST_REMOVE_AFTER(curelm, field); \ + } \ } while (0) -#define SLIST_INSERT_HEAD(head, elm, field) do { \ - SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \ - SLIST_FIRST((head)) = (elm); \ +#define SLIST_REMOVE_AFTER(elm, field) do { \ + QMD_SAVELINK(oldnext, SLIST_NEXT(elm, field)->field.sle_next); \ + SLIST_NEXT(elm, field) = \ + SLIST_NEXT(SLIST_NEXT(elm, field), field); \ + TRASHIT(*oldnext); \ } while (0) -#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) +#define SLIST_REMOVE_HEAD(head, field) do { \ + QMD_SAVELINK(oldnext, SLIST_FIRST(head)->field.sle_next); \ + SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \ + TRASHIT(*oldnext); \ +} while (0) -#define SLIST_REMOVE(head, elm, type, field) do { \ - if (SLIST_FIRST((head)) == (elm)) { \ - SLIST_REMOVE_HEAD((head), field); \ - } \ - else { \ - struct type *curelm = SLIST_FIRST((head)); \ - while (SLIST_NEXT(curelm, field) != (elm)) \ - curelm = SLIST_NEXT(curelm, field); \ - SLIST_NEXT(curelm, field) = \ - SLIST_NEXT(SLIST_NEXT(curelm, field), field); \ - } \ +#define SLIST_REMOVE_PREVPTR(prevp, elm, field) do { \ + QMD_SLIST_CHECK_PREVPTR(prevp, elm); \ + *(prevp) = SLIST_NEXT(elm, field); \ + TRASHIT((elm)->field.sle_next); \ } while (0) -#define SLIST_REMOVE_HEAD(head, field) do { \ - SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \ +#define SLIST_SWAP(head1, head2, type) do { \ + QUEUE_TYPEOF(type) *swap_first = SLIST_FIRST(head1); \ + SLIST_FIRST(head1) = SLIST_FIRST(head2); \ + SLIST_FIRST(head2) = swap_first; \ } while (0) +#define SLIST_END(head) NULL + /* * Singly-linked Tail queue declarations. */ @@ -178,6 +324,12 @@ struct name { \ struct type **stqh_last;/* addr of last next element */ \ } +#define STAILQ_CLASS_HEAD(name, type) \ +struct name { \ + class type *stqh_first; /* first element */ \ + class type **stqh_last; /* addr of last next element */ \ +} + #define STAILQ_HEAD_INITIALIZER(head) \ { NULL, &(head).stqh_first } @@ -186,9 +338,22 @@ struct { \ struct type *stqe_next; /* next element */ \ } +#define STAILQ_CLASS_ENTRY(type) \ +struct { \ + class type *stqe_next; /* next element */ \ +} + /* * Singly-linked Tail queue functions. */ +#define STAILQ_CONCAT(head1, head2) do { \ + if (!STAILQ_EMPTY((head2))) { \ + *(head1)->stqh_last = (head2)->stqh_first; \ + (head1)->stqh_last = (head2)->stqh_last; \ + STAILQ_INIT((head2)); \ + } \ +} while (0) + #define STAILQ_EMPTY(head) ((head)->stqh_first == NULL) #define STAILQ_FIRST(head) ((head)->stqh_first) @@ -198,6 +363,21 @@ struct { \ (var); \ (var) = STAILQ_NEXT((var), field)) +#define STAILQ_FOREACH_FROM(var, head, field) \ + for ((var) = ((var) ? (var) : STAILQ_FIRST((head))); \ + (var); \ + (var) = STAILQ_NEXT((var), field)) + +#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = STAILQ_FIRST((head)); \ + (var) && ((tvar) = STAILQ_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define STAILQ_FOREACH_FROM_SAFE(var, head, field, tvar) \ + for ((var) = ((var) ? (var) : STAILQ_FIRST((head))); \ + (var) && ((tvar) = STAILQ_NEXT((var), field), 1); \ + (var) = (tvar)) + #define STAILQ_INIT(head) do { \ STAILQ_FIRST((head)) = NULL; \ (head)->stqh_last = &STAILQ_FIRST((head)); \ @@ -222,25 +402,30 @@ struct { \ } while (0) #define STAILQ_LAST(head, type, field) \ - (STAILQ_EMPTY(head) ? \ - NULL : \ - ((struct type *) \ - ((char *)((head)->stqh_last) - offsetof(struct type, field)))) + (STAILQ_EMPTY((head)) ? NULL : \ + __containerof((head)->stqh_last, \ + QUEUE_TYPEOF(type), field.stqe_next)) #define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next) #define STAILQ_REMOVE(head, elm, type, field) do { \ + QMD_SAVELINK(oldnext, (elm)->field.stqe_next); \ if (STAILQ_FIRST((head)) == (elm)) { \ - STAILQ_REMOVE_HEAD(head, field); \ + STAILQ_REMOVE_HEAD((head), field); \ } \ else { \ - struct type *curelm = STAILQ_FIRST((head)); \ + QUEUE_TYPEOF(type) *curelm = STAILQ_FIRST(head); \ while (STAILQ_NEXT(curelm, field) != (elm)) \ curelm = STAILQ_NEXT(curelm, field); \ - if ((STAILQ_NEXT(curelm, field) = \ - STAILQ_NEXT(STAILQ_NEXT(curelm, field), field)) == NULL)\ - (head)->stqh_last = &STAILQ_NEXT((curelm), field);\ + STAILQ_REMOVE_AFTER(head, curelm, field); \ } \ + TRASHIT(*oldnext); \ +} while (0) + +#define STAILQ_REMOVE_AFTER(head, elm, field) do { \ + if ((STAILQ_NEXT(elm, field) = \ + STAILQ_NEXT(STAILQ_NEXT(elm, field), field)) == NULL) \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ } while (0) #define STAILQ_REMOVE_HEAD(head, field) do { \ @@ -249,16 +434,21 @@ struct { \ (head)->stqh_last = &STAILQ_FIRST((head)); \ } while (0) -#define STAILQ_REMOVE_HEAD_UNTIL(head, elm, field) do { \ - if ((STAILQ_FIRST((head)) = STAILQ_NEXT((elm), field)) == NULL) \ - (head)->stqh_last = &STAILQ_FIRST((head)); \ +#define STAILQ_SWAP(head1, head2, type) do { \ + QUEUE_TYPEOF(type) *swap_first = STAILQ_FIRST(head1); \ + QUEUE_TYPEOF(type) **swap_last = (head1)->stqh_last; \ + STAILQ_FIRST(head1) = STAILQ_FIRST(head2); \ + (head1)->stqh_last = (head2)->stqh_last; \ + STAILQ_FIRST(head2) = swap_first; \ + (head2)->stqh_last = swap_last; \ + if (STAILQ_EMPTY(head1)) \ + (head1)->stqh_last = &STAILQ_FIRST(head1); \ + if (STAILQ_EMPTY(head2)) \ + (head2)->stqh_last = &STAILQ_FIRST(head2); \ } while (0) -#define STAILQ_REMOVE_AFTER(head, elm, field) do { \ - if ((STAILQ_NEXT(elm, field) = \ - STAILQ_NEXT(STAILQ_NEXT(elm, field), field)) == NULL) \ - (head)->stqh_last = &STAILQ_NEXT((elm), field); \ -} while (0) +#define STAILQ_END(head) NULL + /* * List declarations. @@ -268,6 +458,11 @@ struct name { \ struct type *lh_first; /* first element */ \ } +#define LIST_CLASS_HEAD(name, type) \ +struct name { \ + class type *lh_first; /* first element */ \ +} + #define LIST_HEAD_INITIALIZER(head) \ { NULL } @@ -277,10 +472,75 @@ struct { \ struct type **le_prev; /* address of previous next element */ \ } +#define LIST_CLASS_ENTRY(type) \ +struct { \ + class type *le_next; /* next element */ \ + class type **le_prev; /* address of previous next element */ \ +} + /* * List functions. */ +#if (defined(_KERNEL) && defined(INVARIANTS)) +/* + * QMD_LIST_CHECK_HEAD(LIST_HEAD *head, LIST_ENTRY NAME) + * + * If the list is non-empty, validates that the first element of the list + * points back at 'head.' + */ +#define QMD_LIST_CHECK_HEAD(head, field) do { \ + if (LIST_FIRST((head)) != NULL && \ + LIST_FIRST((head))->field.le_prev != \ + &LIST_FIRST((head))) \ + panic("Bad list head %p first->prev != head", (head)); \ +} while (0) + +/* + * QMD_LIST_CHECK_NEXT(TYPE *elm, LIST_ENTRY NAME) + * + * If an element follows 'elm' in the list, validates that the next element + * points back at 'elm.' + */ +#define QMD_LIST_CHECK_NEXT(elm, field) do { \ + if (LIST_NEXT((elm), field) != NULL && \ + LIST_NEXT((elm), field)->field.le_prev != \ + &((elm)->field.le_next)) \ + panic("Bad link elm %p next->prev != elm", (elm)); \ +} while (0) + +/* + * QMD_LIST_CHECK_PREV(TYPE *elm, LIST_ENTRY NAME) + * + * Validates that the previous element (or head of the list) points to 'elm.' + */ +#define QMD_LIST_CHECK_PREV(elm, field) do { \ + if (*(elm)->field.le_prev != (elm)) \ + panic("Bad link elm %p prev->next != elm", (elm)); \ +} while (0) +#else +#define QMD_LIST_CHECK_HEAD(head, field) +#define QMD_LIST_CHECK_NEXT(elm, field) +#define QMD_LIST_CHECK_PREV(elm, field) +#endif /* (_KERNEL && INVARIANTS) */ + +#define LIST_CONCAT(head1, head2, type, field) do { \ + QUEUE_TYPEOF(type) *curelm = LIST_FIRST(head1); \ + if (curelm == NULL) { \ + if ((LIST_FIRST(head1) = LIST_FIRST(head2)) != NULL) { \ + LIST_FIRST(head2)->field.le_prev = \ + &LIST_FIRST((head1)); \ + LIST_INIT(head2); \ + } \ + } else if (LIST_FIRST(head2) != NULL) { \ + while (LIST_NEXT(curelm, field) != NULL) \ + curelm = LIST_NEXT(curelm, field); \ + LIST_NEXT(curelm, field) = LIST_FIRST(head2); \ + LIST_FIRST(head2)->field.le_prev = &LIST_NEXT(curelm, field);\ + LIST_INIT(head2); \ + } \ +} while (0) + #define LIST_EMPTY(head) ((head)->lh_first == NULL) #define LIST_FIRST(head) ((head)->lh_first) @@ -290,11 +550,27 @@ struct { \ (var); \ (var) = LIST_NEXT((var), field)) +#define LIST_FOREACH_FROM(var, head, field) \ + for ((var) = ((var) ? (var) : LIST_FIRST((head))); \ + (var); \ + (var) = LIST_NEXT((var), field)) + +#define LIST_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = LIST_FIRST((head)); \ + (var) && ((tvar) = LIST_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define LIST_FOREACH_FROM_SAFE(var, head, field, tvar) \ + for ((var) = ((var) ? (var) : LIST_FIRST((head))); \ + (var) && ((tvar) = LIST_NEXT((var), field), 1); \ + (var) = (tvar)) + #define LIST_INIT(head) do { \ LIST_FIRST((head)) = NULL; \ } while (0) #define LIST_INSERT_AFTER(listelm, elm, field) do { \ + QMD_LIST_CHECK_NEXT(listelm, field); \ if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\ LIST_NEXT((listelm), field)->field.le_prev = \ &LIST_NEXT((elm), field); \ @@ -303,6 +579,7 @@ struct { \ } while (0) #define LIST_INSERT_BEFORE(listelm, elm, field) do { \ + QMD_LIST_CHECK_PREV(listelm, field); \ (elm)->field.le_prev = (listelm)->field.le_prev; \ LIST_NEXT((elm), field) = (listelm); \ *(listelm)->field.le_prev = (elm); \ @@ -310,6 +587,7 @@ struct { \ } while (0) #define LIST_INSERT_HEAD(head, elm, field) do { \ + QMD_LIST_CHECK_HEAD((head), field); \ if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \ LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\ LIST_FIRST((head)) = (elm); \ @@ -318,13 +596,54 @@ struct { \ #define LIST_NEXT(elm, field) ((elm)->field.le_next) +#define LIST_PREV(elm, head, type, field) \ + ((elm)->field.le_prev == &LIST_FIRST((head)) ? NULL : \ + __containerof((elm)->field.le_prev, \ + QUEUE_TYPEOF(type), field.le_next)) + +#define LIST_REMOVE_HEAD(head, field) \ + LIST_REMOVE(LIST_FIRST(head), field) + #define LIST_REMOVE(elm, field) do { \ + QMD_SAVELINK(oldnext, (elm)->field.le_next); \ + QMD_SAVELINK(oldprev, (elm)->field.le_prev); \ + QMD_LIST_CHECK_NEXT(elm, field); \ + QMD_LIST_CHECK_PREV(elm, field); \ if (LIST_NEXT((elm), field) != NULL) \ - LIST_NEXT((elm), field)->field.le_prev = \ + LIST_NEXT((elm), field)->field.le_prev = \ (elm)->field.le_prev; \ *(elm)->field.le_prev = LIST_NEXT((elm), field); \ + TRASHIT(*oldnext); \ + TRASHIT(*oldprev); \ } while (0) +#define LIST_REPLACE(elm, elm2, field) do { \ + QMD_SAVELINK(oldnext, (elm)->field.le_next); \ + QMD_SAVELINK(oldprev, (elm)->field.le_prev); \ + QMD_LIST_CHECK_NEXT(elm, field); \ + QMD_LIST_CHECK_PREV(elm, field); \ + LIST_NEXT((elm2), field) = LIST_NEXT((elm), field); \ + if (LIST_NEXT((elm2), field) != NULL) \ + LIST_NEXT((elm2), field)->field.le_prev = \ + &(elm2)->field.le_next; \ + (elm2)->field.le_prev = (elm)->field.le_prev; \ + *(elm2)->field.le_prev = (elm2); \ + TRASHIT(*oldnext); \ + TRASHIT(*oldprev); \ +} while (0) + +#define LIST_SWAP(head1, head2, type, field) do { \ + QUEUE_TYPEOF(type) *swap_tmp = LIST_FIRST(head1); \ + LIST_FIRST((head1)) = LIST_FIRST((head2)); \ + LIST_FIRST((head2)) = swap_tmp; \ + if ((swap_tmp = LIST_FIRST((head1))) != NULL) \ + swap_tmp->field.le_prev = &LIST_FIRST((head1)); \ + if ((swap_tmp = LIST_FIRST((head2))) != NULL) \ + swap_tmp->field.le_prev = &LIST_FIRST((head2)); \ +} while (0) + +#define LIST_END(head) NULL + /* * Tail queue declarations. */ @@ -332,20 +651,100 @@ struct { \ struct name { \ struct type *tqh_first; /* first element */ \ struct type **tqh_last; /* addr of last next element */ \ + TRACEBUF \ +} + +#define TAILQ_CLASS_HEAD(name, type) \ +struct name { \ + class type *tqh_first; /* first element */ \ + class type **tqh_last; /* addr of last next element */ \ + TRACEBUF \ } #define TAILQ_HEAD_INITIALIZER(head) \ - { NULL, &(head).tqh_first } + { NULL, &(head).tqh_first, TRACEBUF_INITIALIZER } #define TAILQ_ENTRY(type) \ struct { \ struct type *tqe_next; /* next element */ \ struct type **tqe_prev; /* address of previous next element */ \ + TRACEBUF \ +} + +#define TAILQ_CLASS_ENTRY(type) \ +struct { \ + class type *tqe_next; /* next element */ \ + class type **tqe_prev; /* address of previous next element */ \ + TRACEBUF \ } /* * Tail queue functions. */ +#if (defined(_KERNEL) && defined(INVARIANTS)) +/* + * QMD_TAILQ_CHECK_HEAD(TAILQ_HEAD *head, TAILQ_ENTRY NAME) + * + * If the tailq is non-empty, validates that the first element of the tailq + * points back at 'head.' + */ +#define QMD_TAILQ_CHECK_HEAD(head, field) do { \ + if (!TAILQ_EMPTY(head) && \ + TAILQ_FIRST((head))->field.tqe_prev != \ + &TAILQ_FIRST((head))) \ + panic("Bad tailq head %p first->prev != head", (head)); \ +} while (0) + +/* + * QMD_TAILQ_CHECK_TAIL(TAILQ_HEAD *head, TAILQ_ENTRY NAME) + * + * Validates that the tail of the tailq is a pointer to pointer to NULL. + */ +#define QMD_TAILQ_CHECK_TAIL(head, field) do { \ + if (*(head)->tqh_last != NULL) \ + panic("Bad tailq NEXT(%p->tqh_last) != NULL", (head)); \ +} while (0) + +/* + * QMD_TAILQ_CHECK_NEXT(TYPE *elm, TAILQ_ENTRY NAME) + * + * If an element follows 'elm' in the tailq, validates that the next element + * points back at 'elm.' + */ +#define QMD_TAILQ_CHECK_NEXT(elm, field) do { \ + if (TAILQ_NEXT((elm), field) != NULL && \ + TAILQ_NEXT((elm), field)->field.tqe_prev != \ + &((elm)->field.tqe_next)) \ + panic("Bad link elm %p next->prev != elm", (elm)); \ +} while (0) + +/* + * QMD_TAILQ_CHECK_PREV(TYPE *elm, TAILQ_ENTRY NAME) + * + * Validates that the previous element (or head of the tailq) points to 'elm.' + */ +#define QMD_TAILQ_CHECK_PREV(elm, field) do { \ + if (*(elm)->field.tqe_prev != (elm)) \ + panic("Bad link elm %p prev->next != elm", (elm)); \ +} while (0) +#else +#define QMD_TAILQ_CHECK_HEAD(head, field) +#define QMD_TAILQ_CHECK_TAIL(head, headname) +#define QMD_TAILQ_CHECK_NEXT(elm, field) +#define QMD_TAILQ_CHECK_PREV(elm, field) +#endif /* (_KERNEL && INVARIANTS) */ + +#define TAILQ_CONCAT(head1, head2, field) do { \ + if (!TAILQ_EMPTY(head2)) { \ + *(head1)->tqh_last = (head2)->tqh_first; \ + (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \ + (head1)->tqh_last = (head2)->tqh_last; \ + TAILQ_INIT((head2)); \ + QMD_TRACE_HEAD(head1); \ + QMD_TRACE_HEAD(head2); \ + } \ +} while (0) + #define TAILQ_EMPTY(head) ((head)->tqh_first == NULL) #define TAILQ_FIRST(head) ((head)->tqh_first) @@ -355,34 +754,74 @@ struct { \ (var); \ (var) = TAILQ_NEXT((var), field)) +#define TAILQ_FOREACH_FROM(var, head, field) \ + for ((var) = ((var) ? (var) : TAILQ_FIRST((head))); \ + (var); \ + (var) = TAILQ_NEXT((var), field)) + +#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = TAILQ_FIRST((head)); \ + (var) && ((tvar) = TAILQ_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define TAILQ_FOREACH_FROM_SAFE(var, head, field, tvar) \ + for ((var) = ((var) ? (var) : TAILQ_FIRST((head))); \ + (var) && ((tvar) = TAILQ_NEXT((var), field), 1); \ + (var) = (tvar)) + #define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ for ((var) = TAILQ_LAST((head), headname); \ (var); \ (var) = TAILQ_PREV((var), headname, field)) +#define TAILQ_FOREACH_REVERSE_FROM(var, head, headname, field) \ + for ((var) = ((var) ? (var) : TAILQ_LAST((head), headname)); \ + (var); \ + (var) = TAILQ_PREV((var), headname, field)) + +#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \ + for ((var) = TAILQ_LAST((head), headname); \ + (var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \ + (var) = (tvar)) + +#define TAILQ_FOREACH_REVERSE_FROM_SAFE(var, head, headname, field, tvar)\ + for ((var) = ((var) ? (var) : TAILQ_LAST((head), headname)); \ + (var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \ + (var) = (tvar)) + #define TAILQ_INIT(head) do { \ TAILQ_FIRST((head)) = NULL; \ (head)->tqh_last = &TAILQ_FIRST((head)); \ + QMD_TRACE_HEAD(head); \ } while (0) #define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + QMD_TAILQ_CHECK_NEXT(listelm, field); \ if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\ - TAILQ_NEXT((elm), field)->field.tqe_prev = \ + TAILQ_NEXT((elm), field)->field.tqe_prev = \ &TAILQ_NEXT((elm), field); \ - else \ + else { \ (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + QMD_TRACE_HEAD(head); \ + } \ TAILQ_NEXT((listelm), field) = (elm); \ (elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \ + QMD_TRACE_ELEM(&(elm)->field); \ + QMD_TRACE_ELEM(&(listelm)->field); \ } while (0) #define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ + QMD_TAILQ_CHECK_PREV(listelm, field); \ (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ TAILQ_NEXT((elm), field) = (listelm); \ *(listelm)->field.tqe_prev = (elm); \ (listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \ + QMD_TRACE_ELEM(&(elm)->field); \ + QMD_TRACE_ELEM(&(listelm)->field); \ } while (0) #define TAILQ_INSERT_HEAD(head, elm, field) do { \ + QMD_TAILQ_CHECK_HEAD(head, field); \ if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \ TAILQ_FIRST((head))->field.tqe_prev = \ &TAILQ_NEXT((elm), field); \ @@ -390,133 +829,98 @@ struct { \ (head)->tqh_last = &TAILQ_NEXT((elm), field); \ TAILQ_FIRST((head)) = (elm); \ (elm)->field.tqe_prev = &TAILQ_FIRST((head)); \ + QMD_TRACE_HEAD(head); \ + QMD_TRACE_ELEM(&(elm)->field); \ } while (0) #define TAILQ_INSERT_TAIL(head, elm, field) do { \ + QMD_TAILQ_CHECK_TAIL(head, field); \ TAILQ_NEXT((elm), field) = NULL; \ (elm)->field.tqe_prev = (head)->tqh_last; \ *(head)->tqh_last = (elm); \ (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + QMD_TRACE_HEAD(head); \ + QMD_TRACE_ELEM(&(elm)->field); \ } while (0) #define TAILQ_LAST(head, headname) \ (*(((struct headname *)((head)->tqh_last))->tqh_last)) +/* + * The FAST function is fast in that it causes no data access other + * then the access to the head. The standard LAST function above + * will cause a data access of both the element you want and + * the previous element. FAST is very useful for instances when + * you may want to prefetch the last data element. + */ +#define TAILQ_LAST_FAST(head, type, field) \ + (TAILQ_EMPTY(head) ? NULL : __containerof((head)->tqh_last, QUEUE_TYPEOF(type), field.tqe_next)) + #define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) #define TAILQ_PREV(elm, headname, field) \ (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) +#define TAILQ_PREV_FAST(elm, head, type, field) \ + ((elm)->field.tqe_prev == &(head)->tqh_first ? NULL : \ + __containerof((elm)->field.tqe_prev, QUEUE_TYPEOF(type), field.tqe_next)) + +#define TAILQ_REMOVE_HEAD(head, field) \ + TAILQ_REMOVE(head, TAILQ_FIRST(head), field) + #define TAILQ_REMOVE(head, elm, field) do { \ + QMD_SAVELINK(oldnext, (elm)->field.tqe_next); \ + QMD_SAVELINK(oldprev, (elm)->field.tqe_prev); \ + QMD_TAILQ_CHECK_NEXT(elm, field); \ + QMD_TAILQ_CHECK_PREV(elm, field); \ if ((TAILQ_NEXT((elm), field)) != NULL) \ - TAILQ_NEXT((elm), field)->field.tqe_prev = \ + TAILQ_NEXT((elm), field)->field.tqe_prev = \ (elm)->field.tqe_prev; \ - else \ + else { \ (head)->tqh_last = (elm)->field.tqe_prev; \ + QMD_TRACE_HEAD(head); \ + } \ *(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \ + TRASHIT(*oldnext); \ + TRASHIT(*oldprev); \ + QMD_TRACE_ELEM(&(elm)->field); \ } while (0) -/* - * Circular queue declarations. - */ -#define CIRCLEQ_HEAD(name, type) \ -struct name { \ - struct type *cqh_first; /* first element */ \ - struct type *cqh_last; /* last element */ \ -} - -#define CIRCLEQ_HEAD_INITIALIZER(head) \ - { (void *)&(head), (void *)&(head) } - -#define CIRCLEQ_ENTRY(type) \ -struct { \ - struct type *cqe_next; /* next element */ \ - struct type *cqe_prev; /* previous element */ \ -} - -/* - * Circular queue functions. - */ -#define CIRCLEQ_EMPTY(head) ((head)->cqh_first == (void *)(head)) - -#define CIRCLEQ_FIRST(head) ((head)->cqh_first) - -#define CIRCLEQ_FOREACH(var, head, field) \ - for ((var) = CIRCLEQ_FIRST((head)); \ - (var) != (void *)(head) || ((var) = NULL); \ - (var) = CIRCLEQ_NEXT((var), field)) - -#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \ - for ((var) = CIRCLEQ_LAST((head)); \ - (var) != (void *)(head) || ((var) = NULL); \ - (var) = CIRCLEQ_PREV((var), field)) - -#define CIRCLEQ_INIT(head) do { \ - CIRCLEQ_FIRST((head)) = (void *)(head); \ - CIRCLEQ_LAST((head)) = (void *)(head); \ -} while (0) - -#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ - CIRCLEQ_NEXT((elm), field) = CIRCLEQ_NEXT((listelm), field); \ - CIRCLEQ_PREV((elm), field) = (listelm); \ - if (CIRCLEQ_NEXT((listelm), field) == (void *)(head)) \ - CIRCLEQ_LAST((head)) = (elm); \ - else \ - CIRCLEQ_PREV(CIRCLEQ_NEXT((listelm), field), field) = (elm);\ - CIRCLEQ_NEXT((listelm), field) = (elm); \ -} while (0) - -#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \ - CIRCLEQ_NEXT((elm), field) = (listelm); \ - CIRCLEQ_PREV((elm), field) = CIRCLEQ_PREV((listelm), field); \ - if (CIRCLEQ_PREV((listelm), field) == (void *)(head)) \ - CIRCLEQ_FIRST((head)) = (elm); \ - else \ - CIRCLEQ_NEXT(CIRCLEQ_PREV((listelm), field), field) = (elm);\ - CIRCLEQ_PREV((listelm), field) = (elm); \ +#define TAILQ_REPLACE(head, elm, elm2, field) do { \ + QMD_SAVELINK(oldnext, (elm)->field.tqe_next); \ + QMD_SAVELINK(oldprev, (elm)->field.tqe_prev); \ + QMD_TAILQ_CHECK_NEXT(elm, field); \ + QMD_TAILQ_CHECK_PREV(elm, field); \ + TAILQ_NEXT((elm2), field) = TAILQ_NEXT((elm), field); \ + if (TAILQ_NEXT((elm2), field) != TAILQ_END(head)) \ + TAILQ_NEXT((elm2), field)->field.tqe_prev = \ + &(elm2)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm2)->field.tqe_next; \ + (elm2)->field.tqe_prev = (elm)->field.tqe_prev; \ + *(elm2)->field.tqe_prev = (elm2); \ + TRASHIT(*oldnext); \ + TRASHIT(*oldprev); \ + QMD_TRACE_ELEM(&(elm)->field); \ } while (0) -#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \ - CIRCLEQ_NEXT((elm), field) = CIRCLEQ_FIRST((head)); \ - CIRCLEQ_PREV((elm), field) = (void *)(head); \ - if (CIRCLEQ_LAST((head)) == (void *)(head)) \ - CIRCLEQ_LAST((head)) = (elm); \ +#define TAILQ_SWAP(head1, head2, type, field) do { \ + QUEUE_TYPEOF(type) *swap_first = (head1)->tqh_first; \ + QUEUE_TYPEOF(type) **swap_last = (head1)->tqh_last; \ + (head1)->tqh_first = (head2)->tqh_first; \ + (head1)->tqh_last = (head2)->tqh_last; \ + (head2)->tqh_first = swap_first; \ + (head2)->tqh_last = swap_last; \ + if ((swap_first = (head1)->tqh_first) != NULL) \ + swap_first->field.tqe_prev = &(head1)->tqh_first; \ else \ - CIRCLEQ_PREV(CIRCLEQ_FIRST((head)), field) = (elm); \ - CIRCLEQ_FIRST((head)) = (elm); \ -} while (0) - -#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \ - CIRCLEQ_NEXT((elm), field) = (void *)(head); \ - CIRCLEQ_PREV((elm), field) = CIRCLEQ_LAST((head)); \ - if (CIRCLEQ_FIRST((head)) == (void *)(head)) \ - CIRCLEQ_FIRST((head)) = (elm); \ - else \ - CIRCLEQ_NEXT(CIRCLEQ_LAST((head)), field) = (elm); \ - CIRCLEQ_LAST((head)) = (elm); \ -} while (0) - -#define CIRCLEQ_LAST(head) ((head)->cqh_last) - -#define CIRCLEQ_NEXT(elm,field) ((elm)->field.cqe_next) - -#define CIRCLEQ_PREV(elm,field) ((elm)->field.cqe_prev) - -#define CIRCLEQ_REMOVE(head, elm, field) do { \ - if (CIRCLEQ_NEXT((elm), field) == (void *)(head)) \ - CIRCLEQ_LAST((head)) = CIRCLEQ_PREV((elm), field); \ - else \ - CIRCLEQ_PREV(CIRCLEQ_NEXT((elm), field), field) = \ - CIRCLEQ_PREV((elm), field); \ - if (CIRCLEQ_PREV((elm), field) == (void *)(head)) \ - CIRCLEQ_FIRST((head)) = CIRCLEQ_NEXT((elm), field); \ + (head1)->tqh_last = &(head1)->tqh_first; \ + if ((swap_first = (head2)->tqh_first) != NULL) \ + swap_first->field.tqe_prev = &(head2)->tqh_first; \ else \ - CIRCLEQ_NEXT(CIRCLEQ_PREV((elm), field), field) = \ - CIRCLEQ_NEXT((elm), field); \ + (head2)->tqh_last = &(head2)->tqh_first; \ } while (0) -#ifdef __cplusplus -} -#endif +#define TAILQ_END(head) NULL #endif /* !_SYS_QUEUE_H_ */ diff --git a/porting/nimble/include/syscfg/syscfg.h b/porting/nimble/include/syscfg/syscfg.h index cfc10edb54..35d18efe70 100644 --- a/porting/nimble/include/syscfg/syscfg.h +++ b/porting/nimble/include/syscfg/syscfg.h @@ -1,38 +1,52 @@ -/** - * This file was generated by Apache newt version: 1.9.0-dev +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. */ #ifndef H_MYNEWT_SYSCFG_ #define H_MYNEWT_SYSCFG_ -/** - * This macro exists to ensure code includes this header when needed. If code - * checks the existence of a setting directly via ifdef without including this - * header, the setting macro will silently evaluate to 0. In contrast, an - * attempt to use these macros without including this header will result in a - * compiler error. - */ #define MYNEWT_VAL(_name) MYNEWT_VAL_ ## _name #define MYNEWT_VAL_CHOICE(_name, _val) MYNEWT_VAL_ ## _name ## __ ## _val -/*** @apache-mynewt-core/crypto/tinycrypt */ #ifndef MYNEWT_VAL_TINYCRYPT_SYSINIT_STAGE #define MYNEWT_VAL_TINYCRYPT_SYSINIT_STAGE (200) #endif #ifndef MYNEWT_VAL_TINYCRYPT_UECC_RNG_TRNG_DEV_NAME -#define MYNEWT_VAL_TINYCRYPT_UECC_RNG_TRNG_DEV_NAME ("trng") +#define MYNEWT_VAL_TINYCRYPT_UECC_RNG_TRNG_DEV_NAME "trng" #endif #ifndef MYNEWT_VAL_TINYCRYPT_UECC_RNG_USE_TRNG #define MYNEWT_VAL_TINYCRYPT_UECC_RNG_USE_TRNG (0) #endif -/*** @apache-mynewt-core/hw/hal */ +#ifndef MYNEWT_VAL_BSP_SIMULATED +#define MYNEWT_VAL_BSP_SIMULATED (1) +#endif + #ifndef MYNEWT_VAL_HAL_ENABLE_SOFTWARE_BREAKPOINTS #define MYNEWT_VAL_HAL_ENABLE_SOFTWARE_BREAKPOINTS (1) #endif +#ifndef MYNEWT_VAL_HAL_FLASH_MAX_DEVICE_COUNT +#define MYNEWT_VAL_HAL_FLASH_MAX_DEVICE_COUNT (0) +#endif + #ifndef MYNEWT_VAL_HAL_FLASH_VERIFY_BUF_SZ #define MYNEWT_VAL_HAL_FLASH_VERIFY_BUF_SZ (16) #endif @@ -45,11 +59,46 @@ #define MYNEWT_VAL_HAL_FLASH_VERIFY_WRITES (0) #endif +#ifndef MYNEWT_VAL_HAL_SBRK +#define MYNEWT_VAL_HAL_SBRK (1) +#endif + #ifndef MYNEWT_VAL_HAL_SYSTEM_RESET_CB #define MYNEWT_VAL_HAL_SYSTEM_RESET_CB (0) #endif -/*** @apache-mynewt-core/kernel/os */ +#ifndef MYNEWT_VAL_I2C_0 +#define MYNEWT_VAL_I2C_0 (0) +#endif + +#ifndef MYNEWT_VAL_MCU_FLASH_MIN_WRITE_SIZE +#define MYNEWT_VAL_MCU_FLASH_MIN_WRITE_SIZE (1) +#endif + +#ifndef MYNEWT_VAL_MCU_FLASH_STYLE_NORDIC +#define MYNEWT_VAL_MCU_FLASH_STYLE_NORDIC (0) +#endif + +#ifndef MYNEWT_VAL_MCU_FLASH_STYLE_ST +#define MYNEWT_VAL_MCU_FLASH_STYLE_ST (1) +#endif + +#ifndef MYNEWT_VAL_MCU_NATIVE +#define MYNEWT_VAL_MCU_NATIVE (1) +#endif + +#ifndef MYNEWT_VAL_MCU_NATIVE_USE_SIGNALS +#define MYNEWT_VAL_MCU_NATIVE_USE_SIGNALS (1) +#endif + +#ifndef MYNEWT_VAL_MCU_TIMER_POLLER_PRIO +#define MYNEWT_VAL_MCU_TIMER_POLLER_PRIO (0) +#endif + +#ifndef MYNEWT_VAL_MCU_UART_POLLER_PRIO +#define MYNEWT_VAL_MCU_UART_POLLER_PRIO (1) +#endif + #ifndef MYNEWT_VAL_FLOAT_USER #define MYNEWT_VAL_FLOAT_USER (0) #endif @@ -94,6 +143,10 @@ #define MYNEWT_VAL_OS_COREDUMP (0) #endif +#ifndef MYNEWT_VAL_OS_COREDUMP_CB +#define MYNEWT_VAL_OS_COREDUMP_CB (0) +#endif + #ifndef MYNEWT_VAL_OS_CPUTIME_FREQ #define MYNEWT_VAL_OS_CPUTIME_FREQ (1000000) #endif @@ -103,7 +156,7 @@ #endif #ifndef MYNEWT_VAL_OS_CRASH_FILE_LINE -#define MYNEWT_VAL_OS_CRASH_FILE_LINE (0) +#define MYNEWT_VAL_OS_CRASH_FILE_LINE (1) #endif #ifndef MYNEWT_VAL_OS_CRASH_LOG @@ -130,6 +183,10 @@ #define MYNEWT_VAL_OS_DEBUG_MODE (0) #endif +#ifndef MYNEWT_VAL_OS_DEFAULT_IRQ_CB +#define MYNEWT_VAL_OS_DEFAULT_IRQ_CB (0) +#endif + #ifndef MYNEWT_VAL_OS_EVENTQ_DEBUG #define MYNEWT_VAL_OS_EVENTQ_DEBUG (0) #endif @@ -143,7 +200,7 @@ #endif #ifndef MYNEWT_VAL_OS_IDLE_TICKLESS_MS_MIN -#define MYNEWT_VAL_OS_IDLE_TICKLESS_MS_MIN (100) +#define MYNEWT_VAL_OS_IDLE_TICKLESS_MS_MIN (1) #endif #ifndef MYNEWT_VAL_OS_MAIN_STACK_SIZE @@ -210,6 +267,10 @@ #define MYNEWT_VAL_OS_TASK_RUN_TIME_CPUTIME (0) #endif +#ifndef MYNEWT_VAL_OS_TICKS_PER_SEC +#define MYNEWT_VAL_OS_TICKS_PER_SEC (100) +#endif + #ifndef MYNEWT_VAL_OS_TIME_DEBUG #define MYNEWT_VAL_OS_TIME_DEBUG (0) #endif @@ -226,29 +287,56 @@ #define MYNEWT_VAL_WATCHDOG_INTERVAL (30000) #endif -/*** @apache-mynewt-core/sys/console/stub */ +#ifndef MYNEWT_VAL_NATIVE_SOCKETS_MAX +#define MYNEWT_VAL_NATIVE_SOCKETS_MAX (8) +#endif + +#ifndef MYNEWT_VAL_NATIVE_SOCKETS_MAX_UDP +#define MYNEWT_VAL_NATIVE_SOCKETS_MAX_UDP (2048) +#endif + +#ifndef MYNEWT_VAL_NATIVE_SOCKETS_POLL_INTERVAL_MS +#define MYNEWT_VAL_NATIVE_SOCKETS_POLL_INTERVAL_MS (200) +#endif + +#undef MYNEWT_VAL_NATIVE_SOCKETS_POLL_ITVL + +#ifndef MYNEWT_VAL_NATIVE_SOCKETS_PRIO +#define MYNEWT_VAL_NATIVE_SOCKETS_PRIO (2) +#endif + +#ifndef MYNEWT_VAL_NATIVE_SOCKETS_STACK_SZ +#define MYNEWT_VAL_NATIVE_SOCKETS_STACK_SZ (4096) +#endif + +#ifndef MYNEWT_VAL_NATIVE_SOCKETS_SYSINIT_STAGE +#define MYNEWT_VAL_NATIVE_SOCKETS_SYSINIT_STAGE (200) +#endif + #ifndef MYNEWT_VAL_CONSOLE_UART_BAUD #define MYNEWT_VAL_CONSOLE_UART_BAUD (115200) #endif #ifndef MYNEWT_VAL_CONSOLE_UART_DEV -#define MYNEWT_VAL_CONSOLE_UART_DEV ("uart0") +#define MYNEWT_VAL_CONSOLE_UART_DEV "uart0" #endif #ifndef MYNEWT_VAL_CONSOLE_UART_FLOW_CONTROL #define MYNEWT_VAL_CONSOLE_UART_FLOW_CONTROL (UART_FLOW_CTL_NONE) #endif -/*** @apache-mynewt-core/sys/flash_map */ #ifndef MYNEWT_VAL_FLASH_MAP_MAX_AREAS #define MYNEWT_VAL_FLASH_MAP_MAX_AREAS (10) #endif +#ifndef MYNEWT_VAL_FLASH_MAP_SUPPORT_MFG +#define MYNEWT_VAL_FLASH_MAP_SUPPORT_MFG (0) +#endif + #ifndef MYNEWT_VAL_FLASH_MAP_SYSINIT_STAGE -#define MYNEWT_VAL_FLASH_MAP_SYSINIT_STAGE (2) +#define MYNEWT_VAL_FLASH_MAP_SYSINIT_STAGE (9) #endif -/*** @apache-mynewt-core/sys/log/common */ #ifndef MYNEWT_VAL_DFLT_LOG_LVL #define MYNEWT_VAL_DFLT_LOG_LVL (1) #endif @@ -261,7 +349,6 @@ #define MYNEWT_VAL_LOG_GLOBAL_IDX (1) #endif -/*** @apache-mynewt-core/sys/log/modlog */ #ifndef MYNEWT_VAL_MODLOG_CONSOLE_DFLT #define MYNEWT_VAL_MODLOG_CONSOLE_DFLT (1) #endif @@ -282,7 +369,6 @@ #define MYNEWT_VAL_MODLOG_SYSINIT_STAGE (100) #endif -/*** @apache-mynewt-core/sys/log/stub */ #ifndef MYNEWT_VAL_LOG_CONSOLE #define MYNEWT_VAL_LOG_CONSOLE (1) #endif @@ -299,29 +385,10 @@ #define MYNEWT_VAL_LOG_LEVEL (255) #endif -/*** @apache-mynewt-core/sys/mfg */ -#ifndef MYNEWT_VAL_MFG_LOG_LVL -#define MYNEWT_VAL_MFG_LOG_LVL (15) -#endif - -#ifndef MYNEWT_VAL_MFG_LOG_MODULE -#define MYNEWT_VAL_MFG_LOG_MODULE (128) -#endif - -#ifndef MYNEWT_VAL_MFG_MAX_MMRS -#define MYNEWT_VAL_MFG_MAX_MMRS (2) -#endif - -#ifndef MYNEWT_VAL_MFG_SYSINIT_STAGE -#define MYNEWT_VAL_MFG_SYSINIT_STAGE (100) -#endif - -/*** @apache-mynewt-core/sys/sys */ #ifndef MYNEWT_VAL_DEBUG_PANIC_ENABLED #define MYNEWT_VAL_DEBUG_PANIC_ENABLED (1) #endif -/*** @apache-mynewt-core/sys/sysdown */ #ifndef MYNEWT_VAL_SYSDOWN_CONSTRAIN_DOWN #define MYNEWT_VAL_SYSDOWN_CONSTRAIN_DOWN (1) #endif @@ -338,25 +405,30 @@ #define MYNEWT_VAL_SYSDOWN_TIMEOUT_MS (10000) #endif -/*** @apache-mynewt-core/sys/sysinit */ #ifndef MYNEWT_VAL_SYSINIT_CONSTRAIN_INIT #define MYNEWT_VAL_SYSINIT_CONSTRAIN_INIT (1) #endif #ifndef MYNEWT_VAL_SYSINIT_PANIC_FILE_LINE -#define MYNEWT_VAL_SYSINIT_PANIC_FILE_LINE (0) +#define MYNEWT_VAL_SYSINIT_PANIC_FILE_LINE (1) #endif #ifndef MYNEWT_VAL_SYSINIT_PANIC_MESSAGE -#define MYNEWT_VAL_SYSINIT_PANIC_MESSAGE (0) +#define MYNEWT_VAL_SYSINIT_PANIC_MESSAGE (1) #endif -/*** @apache-mynewt-core/util/rwlock */ #ifndef MYNEWT_VAL_RWLOCK_DEBUG #define MYNEWT_VAL_RWLOCK_DEBUG (0) #endif -/*** @apache-mynewt-nimble/nimble */ +#ifndef MYNEWT_VAL_BLE_CHANNEL_SOUNDING +#define MYNEWT_VAL_BLE_CHANNEL_SOUNDING (0) +#endif + +#ifndef MYNEWT_VAL_BLE_CONN_SUBRATING +#define MYNEWT_VAL_BLE_CONN_SUBRATING (0) +#endif + #ifndef MYNEWT_VAL_BLE_EXT_ADV #define MYNEWT_VAL_BLE_EXT_ADV (0) #endif @@ -365,10 +437,26 @@ #define MYNEWT_VAL_BLE_EXT_ADV_MAX_SIZE (31) #endif +#ifndef MYNEWT_VAL_BLE_HCI_VS +#define MYNEWT_VAL_BLE_HCI_VS (0) +#endif + +#ifndef MYNEWT_VAL_BLE_HCI_VS_OCF_OFFSET +#define MYNEWT_VAL_BLE_HCI_VS_OCF_OFFSET (0) +#endif + #ifndef MYNEWT_VAL_BLE_ISO #define MYNEWT_VAL_BLE_ISO (0) #endif +#ifndef MYNEWT_VAL_BLE_ISO_BROADCAST_SINK +#define MYNEWT_VAL_BLE_ISO_BROADCAST_SINK (0) +#endif + +#ifndef MYNEWT_VAL_BLE_ISO_BROADCAST_SOURCE +#define MYNEWT_VAL_BLE_ISO_BROADCAST_SOURCE (0) +#endif + #ifndef MYNEWT_VAL_BLE_ISO_TEST #define MYNEWT_VAL_BLE_ISO_TEST (0) #endif @@ -389,10 +477,26 @@ #define MYNEWT_VAL_BLE_PERIODIC_ADV (0) #endif +#ifndef MYNEWT_VAL_BLE_PERIODIC_ADV_SYNC_BIGINFO_REPORTS +#define MYNEWT_VAL_BLE_PERIODIC_ADV_SYNC_BIGINFO_REPORTS (0) +#endif + #ifndef MYNEWT_VAL_BLE_PERIODIC_ADV_SYNC_TRANSFER #define MYNEWT_VAL_BLE_PERIODIC_ADV_SYNC_TRANSFER (0) #endif +#ifndef MYNEWT_VAL_BLE_PHY_2M +#define MYNEWT_VAL_BLE_PHY_2M (0) +#endif + +#ifndef MYNEWT_VAL_BLE_PHY_CODED +#define MYNEWT_VAL_BLE_PHY_CODED (0) +#endif + +#ifndef MYNEWT_VAL_BLE_POWER_CONTROL +#define MYNEWT_VAL_BLE_POWER_CONTROL (0) +#endif + #ifndef MYNEWT_VAL_BLE_ROLE_BROADCASTER #define MYNEWT_VAL_BLE_ROLE_BROADCASTER (1) #endif @@ -417,7 +521,6 @@ #define MYNEWT_VAL_BLE_WHITELIST (1) #endif -/*** @apache-mynewt-nimble/nimble/host */ #ifndef MYNEWT_VAL_BLE_ATT_PREFERRED_MTU #define MYNEWT_VAL_BLE_ATT_PREFERRED_MTU (256) #endif @@ -442,6 +545,10 @@ #define MYNEWT_VAL_BLE_ATT_SVR_NOTIFY (1) #endif +#ifndef MYNEWT_VAL_BLE_ATT_SVR_NOTIFY_MULTI +#define MYNEWT_VAL_BLE_ATT_SVR_NOTIFY_MULTI (MYNEWT_VAL_BLE_ATT_SVR_NOTIFY && (MYNEWT_VAL_BLE_VERSION >= 52)) +#endif + #ifndef MYNEWT_VAL_BLE_ATT_SVR_QUEUED_WRITE #define MYNEWT_VAL_BLE_ATT_SVR_QUEUED_WRITE (1) #endif @@ -482,6 +589,26 @@ #define MYNEWT_VAL_BLE_ATT_SVR_WRITE_NO_RSP (1) #endif +#ifndef MYNEWT_VAL_BLE_AUDIO +#define MYNEWT_VAL_BLE_AUDIO (0) +#endif + +#ifndef MYNEWT_VAL_BLE_EATT_CHAN_NUM +#define MYNEWT_VAL_BLE_EATT_CHAN_NUM (0) +#endif + +#ifndef MYNEWT_VAL_BLE_EATT_LOG_LVL +#define MYNEWT_VAL_BLE_EATT_LOG_LVL (1) +#endif + +#ifndef MYNEWT_VAL_BLE_EATT_LOG_MOD +#define MYNEWT_VAL_BLE_EATT_LOG_MOD (27) +#endif + +#ifndef MYNEWT_VAL_BLE_EATT_MTU +#define MYNEWT_VAL_BLE_EATT_MTU (128) +#endif + #ifndef MYNEWT_VAL_BLE_GAP_MAX_PENDING_CONN_PARAM_UPDATE #define MYNEWT_VAL_BLE_GAP_MAX_PENDING_CONN_PARAM_UPDATE (1) #endif @@ -522,6 +649,10 @@ #define MYNEWT_VAL_BLE_GATT_NOTIFY (1) #endif +#ifndef MYNEWT_VAL_BLE_GATT_NOTIFY_MULTIPLE +#define MYNEWT_VAL_BLE_GATT_NOTIFY_MULTIPLE ((MYNEWT_VAL_BLE_VERSION >= 52)) +#endif + #ifndef MYNEWT_VAL_BLE_GATT_READ #define MYNEWT_VAL_BLE_GATT_READ (MYNEWT_VAL_BLE_ROLE_CENTRAL) #endif @@ -538,6 +669,10 @@ #define MYNEWT_VAL_BLE_GATT_READ_MULT (MYNEWT_VAL_BLE_ROLE_CENTRAL) #endif +#ifndef MYNEWT_VAL_BLE_GATT_READ_MULT_VAR +#define MYNEWT_VAL_BLE_GATT_READ_MULT_VAR (MYNEWT_VAL_BLE_ROLE_CENTRAL && (MYNEWT_VAL_BLE_VERSION >= 52)) +#endif + #ifndef MYNEWT_VAL_BLE_GATT_READ_UUID #define MYNEWT_VAL_BLE_GATT_READ_UUID (MYNEWT_VAL_BLE_ROLE_CENTRAL) #endif @@ -582,6 +717,10 @@ #define MYNEWT_VAL_BLE_HS_DEBUG (0) #endif +#ifndef MYNEWT_VAL_BLE_HS_EXT_ADV_LEGACY_INSTANCE +#define MYNEWT_VAL_BLE_HS_EXT_ADV_LEGACY_INSTANCE (0) +#endif + #ifndef MYNEWT_VAL_BLE_HS_FLOW_CTRL #define MYNEWT_VAL_BLE_HS_FLOW_CTRL (0) #endif @@ -598,6 +737,10 @@ #define MYNEWT_VAL_BLE_HS_FLOW_CTRL_TX_ON_DISCONNECT (0) #endif +#ifndef MYNEWT_VAL_BLE_HS_GAP_UNHANDLED_HCI_EVENT +#define MYNEWT_VAL_BLE_HS_GAP_UNHANDLED_HCI_EVENT (0) +#endif + #ifndef MYNEWT_VAL_BLE_HS_LOG_LVL #define MYNEWT_VAL_BLE_HS_LOG_LVL (1) #endif @@ -626,6 +769,14 @@ #define MYNEWT_VAL_BLE_HS_SYSINIT_STAGE (200) #endif +#ifndef MYNEWT_VAL_BLE_ISO_MAX_BIGS +#define MYNEWT_VAL_BLE_ISO_MAX_BIGS (MYNEWT_VAL_BLE_MULTI_ADV_INSTANCES) +#endif + +#ifndef MYNEWT_VAL_BLE_ISO_MAX_BISES +#define MYNEWT_VAL_BLE_ISO_MAX_BISES (4) +#endif + #ifndef MYNEWT_VAL_BLE_L2CAP_COC_MAX_NUM #define MYNEWT_VAL_BLE_L2CAP_COC_MAX_NUM (0) #endif @@ -634,6 +785,10 @@ #define MYNEWT_VAL_BLE_L2CAP_COC_MPS (MYNEWT_VAL_MSYS_1_BLOCK_SIZE-8) #endif +#ifndef MYNEWT_VAL_BLE_L2CAP_COC_SDU_BUFF_COUNT +#define MYNEWT_VAL_BLE_L2CAP_COC_SDU_BUFF_COUNT (1) +#endif + #ifndef MYNEWT_VAL_BLE_L2CAP_ENHANCED_COC #define MYNEWT_VAL_BLE_L2CAP_ENHANCED_COC (0) #endif @@ -658,42 +813,6 @@ #define MYNEWT_VAL_BLE_MESH (0) #endif -#ifndef MYNEWT_VAL_BLE_MONITOR_CONSOLE_BUFFER_SIZE -#define MYNEWT_VAL_BLE_MONITOR_CONSOLE_BUFFER_SIZE (128) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_RTT -#define MYNEWT_VAL_BLE_MONITOR_RTT (0) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFERED -#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFERED (1) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_NAME -#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_NAME ("btmonitor") -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_SIZE -#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_SIZE (256) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_UART -#define MYNEWT_VAL_BLE_MONITOR_UART (0) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_UART_BAUDRATE -#define MYNEWT_VAL_BLE_MONITOR_UART_BAUDRATE (1000000) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_UART_BUFFER_SIZE -#define MYNEWT_VAL_BLE_MONITOR_UART_BUFFER_SIZE (64) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_UART_DEV -#define MYNEWT_VAL_BLE_MONITOR_UART_DEV ("uart0") -#endif - #ifndef MYNEWT_VAL_BLE_RPA_TIMEOUT #define MYNEWT_VAL_BLE_RPA_TIMEOUT (300) #endif @@ -702,6 +821,10 @@ #define MYNEWT_VAL_BLE_SM_BONDING (0) #endif +#ifndef MYNEWT_VAL_BLE_SM_CSIS_SIRK +#define MYNEWT_VAL_BLE_SM_CSIS_SIRK (0) +#endif + #ifndef MYNEWT_VAL_BLE_SM_IO_CAP #define MYNEWT_VAL_BLE_SM_IO_CAP (BLE_HS_IO_NO_INPUT_OUTPUT) #endif @@ -714,6 +837,10 @@ #define MYNEWT_VAL_BLE_SM_LEGACY (1) #endif +#ifndef MYNEWT_VAL_BLE_SM_LVL +#define MYNEWT_VAL_BLE_SM_LVL (0) +#endif + #ifndef MYNEWT_VAL_BLE_SM_MAX_PROCS #define MYNEWT_VAL_BLE_SM_MAX_PROCS (1) #endif @@ -734,18 +861,14 @@ #define MYNEWT_VAL_BLE_SM_SC (0) #endif -#ifndef MYNEWT_VAL_BLE_SM_SC_ONLY -#define MYNEWT_VAL_BLE_SM_SC_ONLY (0) -#endif - -#ifndef MYNEWT_VAL_BLE_SM_SC_LVL -#define MYNEWT_VAL_BLE_SM_SC_LVL (0) -#endif - #ifndef MYNEWT_VAL_BLE_SM_SC_DEBUG_KEYS #define MYNEWT_VAL_BLE_SM_SC_DEBUG_KEYS (0) #endif +#ifndef MYNEWT_VAL_BLE_SM_SC_ONLY +#define MYNEWT_VAL_BLE_SM_SC_ONLY (0) +#endif + #ifndef MYNEWT_VAL_BLE_SM_THEIR_KEY_DIST #define MYNEWT_VAL_BLE_SM_THEIR_KEY_DIST (0) #endif @@ -758,7 +881,6 @@ #define MYNEWT_VAL_BLE_STORE_MAX_CCCDS (8) #endif -/*** @apache-mynewt-nimble/nimble/host/services/ans */ #ifndef MYNEWT_VAL_BLE_SVC_ANS_NEW_ALERT_CAT #define MYNEWT_VAL_BLE_SVC_ANS_NEW_ALERT_CAT (0) #endif @@ -771,7 +893,6 @@ #define MYNEWT_VAL_BLE_SVC_ANS_UNR_ALERT_CAT (0) #endif -/*** @apache-mynewt-nimble/nimble/host/services/bas */ #ifndef MYNEWT_VAL_BLE_SVC_BAS_BATTERY_LEVEL_NOTIFY_ENABLE #define MYNEWT_VAL_BLE_SVC_BAS_BATTERY_LEVEL_NOTIFY_ENABLE (1) #endif @@ -784,7 +905,6 @@ #define MYNEWT_VAL_BLE_SVC_BAS_SYSINIT_STAGE (303) #endif -/*** @apache-mynewt-nimble/nimble/host/services/dis */ #ifndef MYNEWT_VAL_BLE_SVC_DIS_DEFAULT_READ_PERM #define MYNEWT_VAL_BLE_SVC_DIS_DEFAULT_READ_PERM (-1) #endif @@ -793,7 +913,6 @@ #define MYNEWT_VAL_BLE_SVC_DIS_FIRMWARE_REVISION_DEFAULT (NULL) #endif -/* Value copied from BLE_SVC_DIS_DEFAULT_READ_PERM */ #ifndef MYNEWT_VAL_BLE_SVC_DIS_FIRMWARE_REVISION_READ_PERM #define MYNEWT_VAL_BLE_SVC_DIS_FIRMWARE_REVISION_READ_PERM (-1) #endif @@ -802,7 +921,6 @@ #define MYNEWT_VAL_BLE_SVC_DIS_HARDWARE_REVISION_DEFAULT (NULL) #endif -/* Value copied from BLE_SVC_DIS_DEFAULT_READ_PERM */ #ifndef MYNEWT_VAL_BLE_SVC_DIS_HARDWARE_REVISION_READ_PERM #define MYNEWT_VAL_BLE_SVC_DIS_HARDWARE_REVISION_READ_PERM (-1) #endif @@ -811,13 +929,12 @@ #define MYNEWT_VAL_BLE_SVC_DIS_MANUFACTURER_NAME_DEFAULT (NULL) #endif -/* Value copied from BLE_SVC_DIS_DEFAULT_READ_PERM */ #ifndef MYNEWT_VAL_BLE_SVC_DIS_MANUFACTURER_NAME_READ_PERM #define MYNEWT_VAL_BLE_SVC_DIS_MANUFACTURER_NAME_READ_PERM (-1) #endif #ifndef MYNEWT_VAL_BLE_SVC_DIS_MODEL_NUMBER_DEFAULT -#define MYNEWT_VAL_BLE_SVC_DIS_MODEL_NUMBER_DEFAULT ("Apache Mynewt NimBLE") +#define MYNEWT_VAL_BLE_SVC_DIS_MODEL_NUMBER_DEFAULT "Apache Mynewt NimBLE" #endif #ifndef MYNEWT_VAL_BLE_SVC_DIS_MODEL_NUMBER_READ_PERM @@ -828,7 +945,6 @@ #define MYNEWT_VAL_BLE_SVC_DIS_SERIAL_NUMBER_DEFAULT (NULL) #endif -/* Value copied from BLE_SVC_DIS_DEFAULT_READ_PERM */ #ifndef MYNEWT_VAL_BLE_SVC_DIS_SERIAL_NUMBER_READ_PERM #define MYNEWT_VAL_BLE_SVC_DIS_SERIAL_NUMBER_READ_PERM (-1) #endif @@ -837,7 +953,6 @@ #define MYNEWT_VAL_BLE_SVC_DIS_SOFTWARE_REVISION_DEFAULT (NULL) #endif -/* Value copied from BLE_SVC_DIS_DEFAULT_READ_PERM */ #ifndef MYNEWT_VAL_BLE_SVC_DIS_SOFTWARE_REVISION_READ_PERM #define MYNEWT_VAL_BLE_SVC_DIS_SOFTWARE_REVISION_READ_PERM (-1) #endif @@ -850,12 +965,10 @@ #define MYNEWT_VAL_BLE_SVC_DIS_SYSTEM_ID_DEFAULT (NULL) #endif -/* Value copied from BLE_SVC_DIS_DEFAULT_READ_PERM */ #ifndef MYNEWT_VAL_BLE_SVC_DIS_SYSTEM_ID_READ_PERM #define MYNEWT_VAL_BLE_SVC_DIS_SYSTEM_ID_READ_PERM (-1) #endif -/*** @apache-mynewt-nimble/nimble/host/services/gap */ #ifndef MYNEWT_VAL_BLE_SVC_GAP_APPEARANCE #define MYNEWT_VAL_BLE_SVC_GAP_APPEARANCE (0) #endif @@ -869,7 +982,7 @@ #endif #ifndef MYNEWT_VAL_BLE_SVC_GAP_DEVICE_NAME -#define MYNEWT_VAL_BLE_SVC_GAP_DEVICE_NAME ("nimble") +#define MYNEWT_VAL_BLE_SVC_GAP_DEVICE_NAME "nimble" #endif #ifndef MYNEWT_VAL_BLE_SVC_GAP_DEVICE_NAME_MAX_LENGTH @@ -900,56 +1013,179 @@ #define MYNEWT_VAL_BLE_SVC_GAP_SYSINIT_STAGE (301) #endif -/*** @apache-mynewt-nimble/nimble/host/services/gatt */ #ifndef MYNEWT_VAL_BLE_SVC_GATT_SYSINIT_STAGE #define MYNEWT_VAL_BLE_SVC_GATT_SYSINIT_STAGE (302) #endif -/*** @apache-mynewt-nimble/nimble/host/services/ias */ #ifndef MYNEWT_VAL_BLE_SVC_IAS_SYSINIT_STAGE #define MYNEWT_VAL_BLE_SVC_IAS_SYSINIT_STAGE (303) #endif -/*** @apache-mynewt-nimble/nimble/host/services/ipss */ #ifndef MYNEWT_VAL_BLE_SVC_IPSS_SYSINIT_STAGE #define MYNEWT_VAL_BLE_SVC_IPSS_SYSINIT_STAGE (303) #endif -/*** @apache-mynewt-nimble/nimble/host/services/lls */ #ifndef MYNEWT_VAL_BLE_SVC_LLS_SYSINIT_STAGE #define MYNEWT_VAL_BLE_SVC_LLS_SYSINIT_STAGE (303) #endif -/*** @apache-mynewt-nimble/nimble/host/services/tps */ #ifndef MYNEWT_VAL_BLE_SVC_TPS_SYSINIT_STAGE #define MYNEWT_VAL_BLE_SVC_TPS_SYSINIT_STAGE (303) #endif -/*** @apache-mynewt-nimble/nimble/transport/socket */ -#ifndef MYNEWT_VAL_BLE_ACL_BUF_COUNT -#define MYNEWT_VAL_BLE_ACL_BUF_COUNT (24) +#undef MYNEWT_VAL_BLE_ACL_BUF_COUNT + +#undef MYNEWT_VAL_BLE_ACL_BUF_SIZE + +#undef MYNEWT_VAL_BLE_HCI_BRIDGE + +#undef MYNEWT_VAL_BLE_HCI_EVT_BUF_SIZE + +#undef MYNEWT_VAL_BLE_HCI_EVT_HI_BUF_COUNT + +#undef MYNEWT_VAL_BLE_HCI_EVT_LO_BUF_COUNT + +#undef MYNEWT_VAL_BLE_HCI_TRANSPORT + +#ifndef MYNEWT_VAL_BLE_MONITOR_CONSOLE_BUFFER_SIZE +#define MYNEWT_VAL_BLE_MONITOR_CONSOLE_BUFFER_SIZE (128) #endif -#ifndef MYNEWT_VAL_BLE_ACL_BUF_SIZE -#define MYNEWT_VAL_BLE_ACL_BUF_SIZE (255) +#ifndef MYNEWT_VAL_BLE_MONITOR_RTT +#define MYNEWT_VAL_BLE_MONITOR_RTT (0) #endif -#ifndef MYNEWT_VAL_BLE_HCI_ACL_OUT_COUNT -#define MYNEWT_VAL_BLE_HCI_ACL_OUT_COUNT (12) +#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFERED +#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFERED (1) #endif -#ifndef MYNEWT_VAL_BLE_HCI_EVT_BUF_SIZE -#define MYNEWT_VAL_BLE_HCI_EVT_BUF_SIZE (70) +#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_NAME +#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_NAME "btmonitor" #endif -#ifndef MYNEWT_VAL_BLE_HCI_EVT_HI_BUF_COUNT -#define MYNEWT_VAL_BLE_HCI_EVT_HI_BUF_COUNT (8) +#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_SIZE +#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_SIZE (256) #endif -#ifndef MYNEWT_VAL_BLE_HCI_EVT_LO_BUF_COUNT -#define MYNEWT_VAL_BLE_HCI_EVT_LO_BUF_COUNT (8) +#ifndef MYNEWT_VAL_BLE_MONITOR_UART +#define MYNEWT_VAL_BLE_MONITOR_UART (0) #endif +#ifndef MYNEWT_VAL_BLE_MONITOR_UART_BAUDRATE +#define MYNEWT_VAL_BLE_MONITOR_UART_BAUDRATE (1000000) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_UART_BUFFER_SIZE +#define MYNEWT_VAL_BLE_MONITOR_UART_BUFFER_SIZE (64) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_UART_DEV +#define MYNEWT_VAL_BLE_MONITOR_UART_DEV "uart0" +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT +#define MYNEWT_VAL_BLE_TRANSPORT (1) +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT_ACL_COUNT +#define MYNEWT_VAL_BLE_TRANSPORT_ACL_COUNT (10) +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT_ACL_FROM_HS_COUNT +#define MYNEWT_VAL_BLE_TRANSPORT_ACL_FROM_HS_COUNT (10) +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT_ACL_FROM_LL_COUNT +#define MYNEWT_VAL_BLE_TRANSPORT_ACL_FROM_LL_COUNT (10) +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT_ACL_SIZE +#define MYNEWT_VAL_BLE_TRANSPORT_ACL_SIZE (251) +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT_EVT_COUNT +#define MYNEWT_VAL_BLE_TRANSPORT_EVT_COUNT (4) +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT_EVT_DISCARDABLE_COUNT +#define MYNEWT_VAL_BLE_TRANSPORT_EVT_DISCARDABLE_COUNT (16) +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT_EVT_SIZE +#define MYNEWT_VAL_BLE_TRANSPORT_EVT_SIZE (70) +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT_HS__cdc +#define MYNEWT_VAL_BLE_TRANSPORT_HS__cdc (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_HS__custom +#define MYNEWT_VAL_BLE_TRANSPORT_HS__custom (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_HS__dialog_cmac +#define MYNEWT_VAL_BLE_TRANSPORT_HS__dialog_cmac (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_HS__native +#define MYNEWT_VAL_BLE_TRANSPORT_HS__native (1) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_HS__nrf5340 +#define MYNEWT_VAL_BLE_TRANSPORT_HS__nrf5340 (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_HS__uart +#define MYNEWT_VAL_BLE_TRANSPORT_HS__uart (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_HS__usb +#define MYNEWT_VAL_BLE_TRANSPORT_HS__usb (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_HS +#define MYNEWT_VAL_BLE_TRANSPORT_HS (1) +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT_ISO_COUNT +#define MYNEWT_VAL_BLE_TRANSPORT_ISO_COUNT (10) +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT_ISO_FROM_HS_COUNT +#define MYNEWT_VAL_BLE_TRANSPORT_ISO_FROM_HS_COUNT (10) +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT_ISO_FROM_LL_COUNT +#define MYNEWT_VAL_BLE_TRANSPORT_ISO_FROM_LL_COUNT (10) +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT_ISO_SIZE +#define MYNEWT_VAL_BLE_TRANSPORT_ISO_SIZE (300) +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__apollo3 +#define MYNEWT_VAL_BLE_TRANSPORT_LL__apollo3 (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__custom +#define MYNEWT_VAL_BLE_TRANSPORT_LL__custom (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__dialog_cmac +#define MYNEWT_VAL_BLE_TRANSPORT_LL__dialog_cmac (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__emspi +#define MYNEWT_VAL_BLE_TRANSPORT_LL__emspi (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__native +#define MYNEWT_VAL_BLE_TRANSPORT_LL__native (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__nrf5340 +#define MYNEWT_VAL_BLE_TRANSPORT_LL__nrf5340 (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__socket +#define MYNEWT_VAL_BLE_TRANSPORT_LL__socket (1) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__uart_ll +#define MYNEWT_VAL_BLE_TRANSPORT_LL__uart_ll (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_LL +#define MYNEWT_VAL_BLE_TRANSPORT_LL (1) +#endif + +#undef MYNEWT_VAL_BLE_TRANSPORT_RX_TASK_STACK_SIZE + #ifndef MYNEWT_VAL_BLE_SOCK_CLI_SYSINIT_STAGE #define MYNEWT_VAL_BLE_SOCK_CLI_SYSINIT_STAGE (500) #endif @@ -971,16 +1207,19 @@ #endif #ifndef MYNEWT_VAL_BLE_SOCK_USE_LINUX_BLUE -#define MYNEWT_VAL_BLE_SOCK_USE_LINUX_BLUE (0) +#define MYNEWT_VAL_BLE_SOCK_USE_LINUX_BLUE (1) +#endif + +#ifndef MYNEWT_VAL_BLE_SOCK_USE_NUTTX +#define MYNEWT_VAL_BLE_SOCK_USE_NUTTX (0) #endif #ifndef MYNEWT_VAL_BLE_SOCK_USE_TCP -#define MYNEWT_VAL_BLE_SOCK_USE_TCP (1) +#define MYNEWT_VAL_BLE_SOCK_USE_TCP (0) #endif -/*** newt */ #ifndef MYNEWT_VAL_APP_NAME -#define MYNEWT_VAL_APP_NAME ("dummy_app") +#define MYNEWT_VAL_APP_NAME "dummy_app" #endif #ifndef MYNEWT_VAL_APP_dummy_app @@ -988,19 +1227,19 @@ #endif #ifndef MYNEWT_VAL_ARCH_NAME -#define MYNEWT_VAL_ARCH_NAME ("dummy") +#define MYNEWT_VAL_ARCH_NAME "sim" #endif -#ifndef MYNEWT_VAL_ARCH_dummy -#define MYNEWT_VAL_ARCH_dummy (1) +#ifndef MYNEWT_VAL_ARCH_sim +#define MYNEWT_VAL_ARCH_sim (1) #endif #ifndef MYNEWT_VAL_BSP_NAME -#define MYNEWT_VAL_BSP_NAME ("dummy_bsp") +#define MYNEWT_VAL_BSP_NAME "native" #endif -#ifndef MYNEWT_VAL_BSP_dummy_bsp -#define MYNEWT_VAL_BSP_dummy_bsp (1) +#ifndef MYNEWT_VAL_BSP_native +#define MYNEWT_VAL_BSP_native (1) #endif #ifndef MYNEWT_VAL_NEWT_FEATURE_LOGCFG @@ -1012,11 +1251,61 @@ #endif #ifndef MYNEWT_VAL_TARGET_NAME -#define MYNEWT_VAL_TARGET_NAME ("porting_default") +#define MYNEWT_VAL_TARGET_NAME "porting_default" #endif #ifndef MYNEWT_VAL_TARGET_porting_default #define MYNEWT_VAL_TARGET_porting_default (1) #endif +#define MYNEWT_PKG_apache_mynewt_core__compiler_sim 1 +#define MYNEWT_PKG_apache_mynewt_core__crypto_tinycrypt 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_bsp_native 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_drivers_flash_enc_flash 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_drivers_flash_enc_flash_ef_tinycrypt 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_drivers_trng 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_drivers_trng_trng_sw 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_drivers_uart 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_drivers_uart_uart_hal 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_hal 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_mcu_native 1 +#define MYNEWT_PKG_apache_mynewt_core__kernel_os 1 +#define MYNEWT_PKG_apache_mynewt_core__kernel_sim 1 +#define MYNEWT_PKG_apache_mynewt_core__net_ip_mn_socket 1 +#define MYNEWT_PKG_apache_mynewt_core__net_ip_native_sockets 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_console_stub 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_defs 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_flash_map 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_log_common 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_log_modlog 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_log_stub 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_stats_stub 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_sys 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_sysdown 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_sysinit 1 +#define MYNEWT_PKG_apache_mynewt_core__util_mem 1 +#define MYNEWT_PKG_apache_mynewt_core__util_rwlock 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_ans 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_bas 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_dis 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_gap 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_gatt 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_ias 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_ipss 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_lls 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_tps 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_transport 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_transport_socket 1 +#define MYNEWT_PKG_apache_mynewt_nimble__porting_npl_mynewt 1 +#define MYNEWT_PKG_apache_mynewt_nimble__porting_targets_dummy_app 1 +#define MYNEWT_PKG_apache_mynewt_nimble__porting_targets_porting_default 1 + +#define MYNEWT_API_TRNG_HW_IMPL 1 +#define MYNEWT_API_ble_transport 1 +#define MYNEWT_API_console 1 +#define MYNEWT_API_log 1 +#define MYNEWT_API_stats 1 + #endif diff --git a/porting/nimble/include/sysflash/sysflash.h b/porting/nimble/include/sysflash/sysflash.h deleted file mode 100644 index ab1341b25d..0000000000 --- a/porting/nimble/include/sysflash/sysflash.h +++ /dev/null @@ -1,24 +0,0 @@ -/** - * This file was generated by Apache newt version: 1.9.0-dev - */ - -#ifndef H_MYNEWT_SYSFLASH_ -#define H_MYNEWT_SYSFLASH_ - -#include "flash_map/flash_map.h" - -/** - * This flash map definition is used for two purposes: - * 1. To locate the meta area, which contains the true flash map definition. - * 2. As a fallback in case the meta area cannot be read from flash. - */ -extern const struct flash_area sysflash_map_dflt[6]; - -#define FLASH_AREA_BOOTLOADER 0 -#define FLASH_AREA_IMAGE_0 1 -#define FLASH_AREA_IMAGE_1 2 -#define FLASH_AREA_IMAGE_SCRATCH 3 -#define FLASH_AREA_REBOOT_LOG 16 -#define FLASH_AREA_NFFS 17 - -#endif diff --git a/porting/nimble/include/sysinit/sysinit.h b/porting/nimble/include/sysinit/sysinit.h index d2a806ab86..3ff5334b01 100644 --- a/porting/nimble/include/sysinit/sysinit.h +++ b/porting/nimble/include/sysinit/sysinit.h @@ -28,7 +28,8 @@ extern "C" { #define SYSINIT_ASSERT_ACTIVE() -#define SYSINIT_PANIC_ASSERT(rc) assert(rc); +#define SYSINIT_PANIC_ASSERT(rc) assert(rc) +#define SYSINIT_PANIC_ASSERT_MSG(rc, msg) assert(rc) #ifdef __cplusplus } diff --git a/porting/nimble/pkg.yml b/porting/nimble/pkg.yml index d56c90dbed..c538bc4c6a 100644 --- a/porting/nimble/pkg.yml +++ b/porting/nimble/pkg.yml @@ -20,7 +20,7 @@ pkg.name: porting/nimble pkg.type: app pkg.description: Stub for NimBLE porting -pkg.author: "Apache Mynewt " +pkg.author: "Apache Mynewt " pkg.homepage: "http://mynewt.apache.org/" pkg.keywords: @@ -40,4 +40,4 @@ pkg.deps: # No need to build files from this package pkg.ign_files: - - ".*\\.c" \ No newline at end of file + - ".*\\.c" diff --git a/porting/nimble/src/hal_timer.c b/porting/nimble/src/hal_timer.c index aa78bf9a28..21ba8ca77a 100644 --- a/porting/nimble/src/hal_timer.c +++ b/porting/nimble/src/hal_timer.c @@ -184,7 +184,7 @@ nrf_timer_set_ocmp(struct nrf52_hal_timer *bsptimer, uint32_t expiry) } else { rtctimer->INTENCLR = RTC_INTENCLR_TICK_Msk; - if (delta_t < (1UL << 24)) { + if (delta_t < (1L << 24)) { rtctimer->CC[NRF_RTC_TIMER_CC_INT] = expiry & 0x00ffffff; } else { /* CC too far ahead. Just make sure we set compare far ahead */ @@ -541,7 +541,7 @@ hal_timer_init(int timer_num, void *cfg) #ifndef RIOT_VERSION NVIC_SetPriority(irq_num, (1 << __NVIC_PRIO_BITS) - 1); #endif -#if MYNEWT +#ifdef MYNEWT NVIC_SetVector(irq_num, (uint32_t)irq_isr); #else ble_npl_hw_set_isr(irq_num, irq_isr); diff --git a/porting/nimble/src/nimble_port.c b/porting/nimble/src/nimble_port.c index d4824d0b37..cfb288549b 100644 --- a/porting/nimble/src/nimble_port.c +++ b/porting/nimble/src/nimble_port.c @@ -22,15 +22,19 @@ #include "sysinit/sysinit.h" #include "host/ble_hs.h" #include "nimble/nimble_port.h" +#include "nimble/transport.h" #if NIMBLE_CFG_CONTROLLER #include "controller/ble_ll.h" -#include "transport/ram/ble_hci_ram.h" +#include "os/os_cputime.h" #endif static struct ble_npl_eventq g_eventq_dflt; extern void os_msys_init(void); extern void os_mempool_module_init(void); +#if NIMBLE_CFG_CONTROLLER +extern void ble_ll_init(void); +#endif void nimble_port_init(void) @@ -40,17 +44,25 @@ nimble_port_init(void) /* Initialize the global memory pool */ os_mempool_module_init(); os_msys_init(); + +#if NIMBLE_CFG_CONTROLLER + ble_ll_init(); +#endif + + /* Initialize transport */ + ble_transport_init(); /* Initialize the host */ - ble_hs_init(); + ble_transport_hs_init(); #if NIMBLE_CFG_CONTROLLER - ble_hci_ram_init(); #ifndef RIOT_VERSION hal_timer_init(5, NULL); os_cputime_init(32768); #endif - ble_ll_init(); #endif + + /* Initialize the controller */ + ble_transport_ll_init(); } void diff --git a/porting/nimble/src/os_mbuf.c b/porting/nimble/src/os_mbuf.c index cebdb29f78..93126c62d3 100644 --- a/porting/nimble/src/os_mbuf.c +++ b/porting/nimble/src/os_mbuf.c @@ -41,15 +41,20 @@ #include #include -/** - * @addtogroup OSKernel - * @{ - * @defgroup OSMqueue Queue of Mbufs - * @{ - */ +#ifndef min +#define min(a, b) ((a) < (b) ? (a) : (b)) +#endif + +#ifndef max +#define max(a, b) ((a) > (b) ? (a) : (b)) +#endif + +#include "syscfg/syscfg.h" +#if !MYNEWT_VAL(OS_SYSVIEW_TRACE_MBUF) +#define OS_TRACE_DISABLE_FILE_API +#endif + -STAILQ_HEAD(, os_mbuf_pool) g_msys_pool_list = - STAILQ_HEAD_INITIALIZER(g_msys_pool_list); int @@ -89,19 +94,19 @@ os_mqueue_get(struct os_mqueue *mq) } int -os_mqueue_put(struct os_mqueue *mq, struct ble_npl_eventq *evq, struct os_mbuf *m) +os_mqueue_put(struct os_mqueue *mq, struct ble_npl_eventq *evq, struct os_mbuf *om) { struct os_mbuf_pkthdr *mp; os_sr_t sr; int rc; /* Can only place the head of a chained mbuf on the queue. */ - if (!OS_MBUF_IS_PKTHDR(m)) { + if (!OS_MBUF_IS_PKTHDR(om)) { rc = OS_EINVAL; goto err; } - mp = OS_MBUF_PKTHDR(m); + mp = OS_MBUF_PKTHDR(om); OS_ENTER_CRITICAL(sr); STAILQ_INSERT_TAIL(&mq->mq_head, mp, omp_next); @@ -117,118 +122,6 @@ os_mqueue_put(struct os_mqueue *mq, struct ble_npl_eventq *evq, struct os_mbuf * return (rc); } -int -os_msys_register(struct os_mbuf_pool *new_pool) -{ - struct os_mbuf_pool *pool; - - pool = NULL; - STAILQ_FOREACH(pool, &g_msys_pool_list, omp_next) { - if (new_pool->omp_databuf_len > pool->omp_databuf_len) { - break; - } - } - - if (pool) { - STAILQ_INSERT_AFTER(&g_msys_pool_list, pool, new_pool, omp_next); - } else { - STAILQ_INSERT_TAIL(&g_msys_pool_list, new_pool, omp_next); - } - - return (0); -} - -void -os_msys_reset(void) -{ - STAILQ_INIT(&g_msys_pool_list); -} - -static struct os_mbuf_pool * -_os_msys_find_pool(uint16_t dsize) -{ - struct os_mbuf_pool *pool; - - pool = NULL; - STAILQ_FOREACH(pool, &g_msys_pool_list, omp_next) { - if (dsize <= pool->omp_databuf_len) { - break; - } - } - - if (!pool) { - pool = STAILQ_LAST(&g_msys_pool_list, os_mbuf_pool, omp_next); - } - - return (pool); -} - - -struct os_mbuf * -os_msys_get(uint16_t dsize, uint16_t leadingspace) -{ - struct os_mbuf *m; - struct os_mbuf_pool *pool; - - pool = _os_msys_find_pool(dsize); - if (!pool) { - goto err; - } - - m = os_mbuf_get(pool, leadingspace); - return (m); -err: - return (NULL); -} - -struct os_mbuf * -os_msys_get_pkthdr(uint16_t dsize, uint16_t user_hdr_len) -{ - uint16_t total_pkthdr_len; - struct os_mbuf *m; - struct os_mbuf_pool *pool; - - total_pkthdr_len = user_hdr_len + sizeof(struct os_mbuf_pkthdr); - pool = _os_msys_find_pool(dsize + total_pkthdr_len); - if (!pool) { - goto err; - } - - m = os_mbuf_get_pkthdr(pool, user_hdr_len); - return (m); -err: - return (NULL); -} - -int -os_msys_count(void) -{ - struct os_mbuf_pool *omp; - int total; - - total = 0; - STAILQ_FOREACH(omp, &g_msys_pool_list, omp_next) { - total += omp->omp_pool->mp_num_blocks; - } - - return total; -} - -int -os_msys_num_free(void) -{ - struct os_mbuf_pool *omp; - int total; - - total = 0; - STAILQ_FOREACH(omp, &g_msys_pool_list, omp_next) { - total += omp->omp_pool->mp_num_free; - } - - return total; -} - - int os_mbuf_pool_init(struct os_mbuf_pool *omp, struct os_mempool *mp, uint16_t buf_len, uint16_t nbufs) @@ -244,8 +137,8 @@ os_mbuf_get(struct os_mbuf_pool *omp, uint16_t leadingspace) { struct os_mbuf *om; - os_trace_api_u32x2(OS_TRACE_ID_MBUF_GET, (uint32_t)omp, - (uint32_t)(uintptr_t)leadingspace); + os_trace_api_u32x2(OS_TRACE_ID_MBUF_GET, (uintptr_t)omp, + (uint32_t)leadingspace); if (leadingspace > omp->omp_databuf_len) { om = NULL; @@ -265,7 +158,7 @@ os_mbuf_get(struct os_mbuf_pool *omp, uint16_t leadingspace) om->om_omp = omp; done: - os_trace_api_ret_u32(OS_TRACE_ID_MBUF_GET, (uint32_t)(uintptr_t)om); + os_trace_api_ret_u32(OS_TRACE_ID_MBUF_GET, (uintptr_t)om); return om; } @@ -276,7 +169,7 @@ os_mbuf_get_pkthdr(struct os_mbuf_pool *omp, uint8_t user_pkthdr_len) struct os_mbuf_pkthdr *pkthdr; struct os_mbuf *om; - os_trace_api_u32x2(OS_TRACE_ID_MBUF_GET_PKTHDR, (uint32_t)(uintptr_t)omp, + os_trace_api_u32x2(OS_TRACE_ID_MBUF_GET_PKTHDR, (uintptr_t)omp, (uint32_t)user_pkthdr_len); /* User packet header must fit inside mbuf */ @@ -298,7 +191,7 @@ os_mbuf_get_pkthdr(struct os_mbuf_pool *omp, uint8_t user_pkthdr_len) } done: - os_trace_api_ret_u32(OS_TRACE_ID_MBUF_GET_PKTHDR, (uint32_t)(uintptr_t)om); + os_trace_api_ret_u32(OS_TRACE_ID_MBUF_GET_PKTHDR, (uintptr_t)om); return om; } @@ -307,7 +200,7 @@ os_mbuf_free(struct os_mbuf *om) { int rc; - os_trace_api_u32(OS_TRACE_ID_MBUF_FREE, (uint32_t)(uintptr_t)om); + os_trace_api_u32(OS_TRACE_ID_MBUF_FREE, (uintptr_t)om); if (om->om_omp != NULL) { rc = os_memblock_put(om->om_omp->omp_pool, om); @@ -329,7 +222,7 @@ os_mbuf_free_chain(struct os_mbuf *om) struct os_mbuf *next; int rc; - os_trace_api_u32(OS_TRACE_ID_MBUF_FREE_CHAIN, (uint32_t)(uintptr_t)om); + os_trace_api_u32(OS_TRACE_ID_MBUF_FREE_CHAIN, (uintptr_t)om); while (om != NULL) { next = SLIST_NEXT(om, om_next); @@ -491,12 +384,13 @@ os_mbuf_dup(struct os_mbuf *om) struct os_mbuf *head; struct os_mbuf *copy; - omp = om->om_omp; - head = NULL; copy = NULL; for (; om != NULL; om = SLIST_NEXT(om, om_next)) { + + omp = om->om_omp; + if (head) { SLIST_NEXT(copy, om_next) = os_mbuf_get(omp, OS_MBUF_LEADINGSPACE(om)); @@ -557,7 +451,7 @@ os_mbuf_off(const struct os_mbuf *om, int off, uint16_t *out_off) } int -os_mbuf_copydata(const struct os_mbuf *m, int off, int len, void *dst) +os_mbuf_copydata(const struct os_mbuf *om, int off, int len, void *dst) { unsigned int count; uint8_t *udst; @@ -569,36 +463,38 @@ os_mbuf_copydata(const struct os_mbuf *m, int off, int len, void *dst) udst = dst; while (off > 0) { - if (!m) { + if (!om) { return (-1); } - if (off < m->om_len) + if (off < om->om_len) { break; - off -= m->om_len; - m = SLIST_NEXT(m, om_next); + } + off -= om->om_len; + om = SLIST_NEXT(om, om_next); } - while (len > 0 && m != NULL) { - count = min(m->om_len - off, len); - memcpy(udst, m->om_data + off, count); + while (len > 0 && om != NULL) { + count = min(om->om_len - off, len); + memcpy(udst, om->om_data + off, count); len -= count; udst += count; off = 0; - m = SLIST_NEXT(m, om_next); + om = SLIST_NEXT(om, om_next); } return (len > 0 ? -1 : 0); } void -os_mbuf_adj(struct os_mbuf *mp, int req_len) +os_mbuf_adj(struct os_mbuf *om, int req_len) { int len = req_len; struct os_mbuf *m; int count; - if ((m = mp) == NULL) + if ((m = om) == NULL) { return; + } if (len >= 0) { /* * Trim from head. @@ -614,8 +510,9 @@ os_mbuf_adj(struct os_mbuf *mp, int req_len) len = 0; } } - if (OS_MBUF_IS_PKTHDR(mp)) - OS_MBUF_PKTHDR(mp)->omp_len -= (req_len - len); + if (OS_MBUF_IS_PKTHDR(om)) { + OS_MBUF_PKTHDR(om)->omp_len -= (req_len - len); + } } else { /* * Trim from tail. Scan the mbuf chain, @@ -634,8 +531,9 @@ os_mbuf_adj(struct os_mbuf *mp, int req_len) } if (m->om_len >= len) { m->om_len -= len; - if (OS_MBUF_IS_PKTHDR(mp)) - OS_MBUF_PKTHDR(mp)->omp_len -= len; + if (OS_MBUF_IS_PKTHDR(om)) { + OS_MBUF_PKTHDR(om)->omp_len -= len; + } return; } count -= len; @@ -646,7 +544,7 @@ os_mbuf_adj(struct os_mbuf *mp, int req_len) * Find the mbuf with last data, adjust its length, * and toss data from remaining mbufs on chain. */ - m = mp; + m = om; if (OS_MBUF_IS_PKTHDR(m)) OS_MBUF_PKTHDR(m)->omp_len = count; for (; m; m = SLIST_NEXT(m, om_next)) { @@ -1242,4 +1140,4 @@ os_mbuf_pack_chains(struct os_mbuf *m1, struct os_mbuf *m2) } return m1; -} \ No newline at end of file +} diff --git a/porting/nimble/src/os_mempool.c b/porting/nimble/src/os_mempool.c index 09d5e35263..9800d88087 100644 --- a/porting/nimble/src/os_mempool.c +++ b/porting/nimble/src/os_mempool.c @@ -32,8 +32,8 @@ #if MYNEWT_VAL(OS_MEMPOOL_GUARD) #define OS_MEMPOOL_TRUE_BLOCK_SIZE(mp) \ (((mp)->mp_flags & OS_MEMPOOL_F_EXT) ? \ - OS_MEM_TRUE_BLOCK_SIZE(mp->mp_block_size) : \ - (OS_MEM_TRUE_BLOCK_SIZE(mp->mp_block_size) + sizeof(os_membuf_t))) + OS_MEM_TRUE_BLOCK_SIZE(mp->mp_block_size) : \ + (OS_MEM_TRUE_BLOCK_SIZE(mp->mp_block_size) + sizeof(os_membuf_t))) #else #define OS_MEMPOOL_TRUE_BLOCK_SIZE(mp) OS_MEM_TRUE_BLOCK_SIZE(mp->mp_block_size) #endif @@ -95,7 +95,7 @@ os_mempool_guard(const struct os_mempool *mp, void *start) if ((mp->mp_flags & OS_MEMPOOL_F_EXT) == 0) { tgt = (uint32_t *)((uintptr_t)start + - OS_MEM_TRUE_BLOCK_SIZE(mp->mp_block_size)); + OS_MEM_TRUE_BLOCK_SIZE(mp->mp_block_size)); *tgt = OS_MEMPOOL_GUARD_PATTERN; } } @@ -107,7 +107,7 @@ os_mempool_guard_check(const struct os_mempool *mp, void *start) if ((mp->mp_flags & OS_MEMPOOL_F_EXT) == 0) { tgt = (uint32_t *)((uintptr_t)start + - OS_MEM_TRUE_BLOCK_SIZE(mp->mp_block_size)); + OS_MEM_TRUE_BLOCK_SIZE(mp->mp_block_size)); assert(*tgt == OS_MEMPOOL_GUARD_PATTERN); } } @@ -139,7 +139,7 @@ os_mempool_init_internal(struct os_mempool *mp, uint16_t blocks, /* Blocks need to be sized properly and memory buffer should be * aligned */ - if (((uint32_t)(uintptr_t)membuf & (OS_ALIGNMENT - 1)) != 0) { + if (((uintptr_t)membuf & (OS_ALIGNMENT - 1)) != 0) { return OS_MEM_NOT_ALIGNED; } } @@ -150,7 +150,7 @@ os_mempool_init_internal(struct os_mempool *mp, uint16_t blocks, mp->mp_min_free = blocks; mp->mp_flags = flags; mp->mp_num_blocks = blocks; - mp->mp_membuf_addr = (uint32_t)(uintptr_t)membuf; + mp->mp_membuf_addr = (uintptr_t)membuf; mp->name = name; SLIST_FIRST(mp) = membuf; @@ -261,10 +261,10 @@ os_mempool_clear(struct os_mempool *mp) mp->mp_min_free = mp->mp_num_blocks; os_mempool_poison(mp, (void *)mp->mp_membuf_addr); os_mempool_guard(mp, (void *)mp->mp_membuf_addr); - SLIST_FIRST(mp) = (void *)(uintptr_t)mp->mp_membuf_addr; + SLIST_FIRST(mp) = (void *)mp->mp_membuf_addr; /* Chain the memory blocks to the free list */ - block_addr = (uint8_t *)(uintptr_t)mp->mp_membuf_addr; + block_addr = (uint8_t *)mp->mp_membuf_addr; block_ptr = (struct os_memblock *)block_addr; blocks = mp->mp_num_blocks; @@ -304,23 +304,20 @@ int os_memblock_from(const struct os_mempool *mp, const void *block_addr) { uint32_t true_block_size; - uintptr_t baddr32; - uint32_t end; + uintptr_t baddr; + uintptr_t end; - static_assert(sizeof block_addr == sizeof baddr32, - "Pointer to void must be 32-bits."); - - baddr32 = (uint32_t)(uintptr_t)block_addr; + baddr = (uintptr_t)block_addr; true_block_size = OS_MEMPOOL_TRUE_BLOCK_SIZE(mp); end = mp->mp_membuf_addr + (mp->mp_num_blocks * true_block_size); /* Check that the block is in the memory buffer range. */ - if ((baddr32 < mp->mp_membuf_addr) || (baddr32 >= end)) { + if ((baddr < mp->mp_membuf_addr) || (baddr >= end)) { return 0; } /* All freed blocks should be on true block size boundaries! */ - if (((baddr32 - mp->mp_membuf_addr) % true_block_size) != 0) { + if (((baddr - mp->mp_membuf_addr) % true_block_size) != 0) { return 0; } @@ -333,7 +330,7 @@ os_memblock_get(struct os_mempool *mp) os_sr_t sr; struct os_memblock *block; - os_trace_api_u32(OS_TRACE_ID_MEMBLOCK_GET, (uint32_t)(uintptr_t)mp); + os_trace_api_u32(OS_TRACE_ID_MEMBLOCK_GET, (uintptr_t)mp); /* Check to make sure they passed in a memory pool (or something) */ block = NULL; @@ -361,7 +358,7 @@ os_memblock_get(struct os_mempool *mp) } } - os_trace_api_ret_u32(OS_TRACE_ID_MEMBLOCK_GET, (uint32_t)(uintptr_t)block); + os_trace_api_ret_u32(OS_TRACE_ID_MEMBLOCK_GET, (uintptr_t)block); return (void *)block; } @@ -372,8 +369,8 @@ os_memblock_put_from_cb(struct os_mempool *mp, void *block_addr) os_sr_t sr; struct os_memblock *block; - os_trace_api_u32x2(OS_TRACE_ID_MEMBLOCK_PUT_FROM_CB, (uint32_t)(uintptr_t)mp, - (uint32_t)(uintptr_t)block_addr); + os_trace_api_u32x2(OS_TRACE_ID_MEMBLOCK_PUT_FROM_CB, (uintptr_t)mp, + (uintptr_t)block_addr); os_mempool_guard_check(mp, block_addr); os_mempool_poison(mp, block_addr); @@ -403,10 +400,11 @@ os_memblock_put(struct os_mempool *mp, void *block_addr) os_error_t ret; #if MYNEWT_VAL(OS_MEMPOOL_CHECK) struct os_memblock *block; + int sr; #endif - os_trace_api_u32x2(OS_TRACE_ID_MEMBLOCK_PUT, (uint32_t)(uintptr_t)mp, - (uint32_t)(uintptr_t)block_addr); + os_trace_api_u32x2(OS_TRACE_ID_MEMBLOCK_PUT, (uintptr_t)mp, + (uintptr_t)block_addr); /* Make sure parameters are valid */ if ((mp == NULL) || (block_addr == NULL)) { @@ -421,9 +419,12 @@ os_memblock_put(struct os_mempool *mp, void *block_addr) /* * Check for duplicate free. */ + OS_ENTER_CRITICAL(sr); SLIST_FOREACH(block, mp, mb_next) { assert(block != (struct os_memblock *)block_addr); } + OS_EXIT_CRITICAL(sr); + #endif /* If this is an extended mempool with a put callback, call the callback * instead of freeing the block directly. @@ -469,8 +470,34 @@ os_mempool_info_get_next(struct os_mempool *mp, struct os_mempool_info *omi) return (cur); } +struct os_mempool * +os_mempool_get(const char *mempool_name, struct os_mempool_info *info) +{ + struct os_mempool *mp; + + mp = STAILQ_FIRST(&g_os_mempool_list); + while (mp) { + if (strcmp(mempool_name, mp->name) == 0) { + break; + } + mp = STAILQ_NEXT(mp, mp_list); + } + + if (mp != NULL && info != NULL) { + info->omi_block_size = mp->mp_block_size; + info->omi_num_blocks = mp->mp_num_blocks; + info->omi_num_free = mp->mp_num_free; + info->omi_min_free = mp->mp_min_free; + info->omi_name[0] = '\0'; + strncat(info->omi_name, mp->name, sizeof(info->omi_name) - 1); + } + + return mp; +} + void os_mempool_module_init(void) { STAILQ_INIT(&g_os_mempool_list); } + diff --git a/porting/nimble/src/os_msys_init.c b/porting/nimble/src/os_msys.c similarity index 59% rename from porting/nimble/src/os_msys_init.c rename to porting/nimble/src/os_msys.c index d22ae351f3..7f1069fab0 100644 --- a/porting/nimble/src/os_msys_init.c +++ b/porting/nimble/src/os_msys.c @@ -22,7 +22,7 @@ #include "mem/mem.h" #include "sysinit/sysinit.h" -static STAILQ_HEAD(, os_mbuf_pool) g_msys_pool_list = +static STAILQ_HEAD(os_mbuf_list, os_mbuf_pool) g_msys_pool_list = STAILQ_HEAD_INITIALIZER(g_msys_pool_list); #if MYNEWT_VAL(MSYS_1_BLOCK_COUNT) > 0 @@ -55,6 +55,147 @@ static struct os_mempool os_msys_2_mempool; static struct os_sanity_check os_msys_sc; #endif +int +os_msys_register(struct os_mbuf_pool *new_pool) +{ + struct os_mbuf_pool *pool; + struct os_mbuf_pool *prev; + + /* We want to have order from smallest to biggest mempool. */ + prev = NULL; + pool = NULL; + STAILQ_FOREACH(pool, &g_msys_pool_list, omp_next) { + if (new_pool->omp_databuf_len < pool->omp_databuf_len) { + break; + } + prev = pool; + } + + if (prev) { + STAILQ_INSERT_AFTER(&g_msys_pool_list, prev, new_pool, omp_next); + } else { + STAILQ_INSERT_HEAD(&g_msys_pool_list, new_pool, omp_next); + } + + return (0); +} + +void +os_msys_reset(void) +{ + STAILQ_INIT(&g_msys_pool_list); +} + +static struct os_mbuf_pool *os_msys_find_pool(uint16_t dsize); + +static struct os_mbuf_pool * +os_msys_find_biggest_pool(void) +{ + return os_msys_find_pool(0xFFFF); +} + +static struct os_mbuf_pool * +os_msys_find_pool(uint16_t dsize) +{ + struct os_mbuf_pool *pool; + struct os_mbuf_pool *pool_with_free_blocks = NULL; + uint16_t pool_free_blocks; + + STAILQ_FOREACH(pool, &g_msys_pool_list, omp_next) { + pool_free_blocks = pool->omp_pool->mp_num_free; + if (pool_free_blocks != 0) { + pool_with_free_blocks = pool; + if (dsize <= pool->omp_databuf_len) { + break; + } + } + } + + return pool_with_free_blocks; +} + + +struct os_mbuf * +os_msys_get(uint16_t dsize, uint16_t leadingspace) +{ + struct os_mbuf *m; + struct os_mbuf_pool *pool; + + /* If dsize = 0 that means user has no idea how big block size is needed, + * therefore lets find for him the biggest one + */ + if (dsize == 0) { + pool = os_msys_find_biggest_pool(); + } else { + pool = os_msys_find_pool(dsize); + } + + if (!pool) { + goto err; + } + + m = os_mbuf_get(pool, leadingspace); + return (m); +err: + return (NULL); +} + +struct os_mbuf * +os_msys_get_pkthdr(uint16_t dsize, uint16_t user_hdr_len) +{ + uint16_t total_pkthdr_len; + struct os_mbuf *m; + struct os_mbuf_pool *pool; + + total_pkthdr_len = user_hdr_len + sizeof(struct os_mbuf_pkthdr); + + /* If dsize = 0 that means user has no idea how big block size is needed, + * therefore lets find for him the biggest one + */ + if (dsize == 0) { + pool = os_msys_find_biggest_pool(); + } else { + pool = os_msys_find_pool(dsize + total_pkthdr_len); + } + + if (!pool) { + goto err; + } + + m = os_mbuf_get_pkthdr(pool, user_hdr_len); + return (m); +err: + return (NULL); +} + +int +os_msys_count(void) +{ + struct os_mbuf_pool *omp; + int total; + + total = 0; + STAILQ_FOREACH(omp, &g_msys_pool_list, omp_next) { + total += omp->omp_pool->mp_num_blocks; + } + + return total; +} + +int +os_msys_num_free(void) +{ + struct os_mbuf_pool *omp; + int total; + + total = 0; + STAILQ_FOREACH(omp, &g_msys_pool_list, omp_next) { + total += omp->omp_pool->mp_num_free; + } + + return total; +} + #if OS_MSYS_SANITY_ENABLED /** @@ -153,4 +294,12 @@ os_msys_init(void) rc = os_sanity_check_register(&os_msys_sc); SYSINIT_PANIC_ASSERT(rc == 0); #endif -} \ No newline at end of file +} + +#if MYNEWT_VAL(SELFTEST) +struct os_mbuf_list * +get_msys_pool_list(void) +{ + return &g_msys_pool_list; +} +#endif diff --git a/nimble/transport/dialog_cmac/src/ble_hci_cmac_priv.h b/porting/npl/dummy/include/nimble/nimble_npl_os_log.h similarity index 76% rename from nimble/transport/dialog_cmac/src/ble_hci_cmac_priv.h rename to porting/npl/dummy/include/nimble/nimble_npl_os_log.h index 451053c303..7391c7435a 100644 --- a/nimble/transport/dialog_cmac/src/ble_hci_cmac_priv.h +++ b/porting/npl/dummy/include/nimble/nimble_npl_os_log.h @@ -17,13 +17,11 @@ * under the License. */ -#ifndef _BLE_HCI_CMAC_PRIV_H_ -#define _BLE_HCI_CMAC_PRIV_H_ +#ifndef _NIMBLE_NPL_OS_LOG_H_ +#define _NIMBLE_NPL_OS_LOG_H_ -#include "os/os_mbuf.h" +#define BLE_NPL_LOG_IMPL(lvl) \ + static inline void _BLE_NPL_LOG_CAT(BLE_NPL_LOG_MODULE, \ + _BLE_NPL_LOG_CAT(_, lvl))(const char *fmt, ...) { } -struct os_mbuf *ble_hci_cmac_alloc_acl_mbuf(void); - -void ble_hci_trans_notify_free(void); - -#endif /* _BLE_HCI_CMAC_PRIV_H_ */ +#endif /* _NIMBLE_NPL_OS_LOG_H_ */ diff --git a/porting/npl/dummy/src/hci_dummy.c b/porting/npl/dummy/src/hci_dummy.c deleted file mode 100644 index 78fffe951b..0000000000 --- a/porting/npl/dummy/src/hci_dummy.c +++ /dev/null @@ -1,250 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#include -#include -#include -#include "syscfg/syscfg.h" -#include "sysinit/sysinit.h" -#include "os/os_mempool.h" -#include "nimble/ble.h" -#include "nimble/ble_hci_trans.h" -#include "nimble/hci_common.h" - -/* HCI packet types */ -#define HCI_PKT_CMD 0x01 -#define HCI_PKT_ACL 0x02 -#define HCI_PKT_EVT 0x04 -#define HCI_PKT_GTL 0x05 - -/* Buffers for HCI commands data */ -static uint8_t trans_buf_cmd[BLE_HCI_TRANS_CMD_SZ]; -static uint8_t trans_buf_cmd_allocd; - -/* Buffers for HCI events data */ -static uint8_t trans_buf_evt_hi_pool_buf[ OS_MEMPOOL_BYTES( - MYNEWT_VAL(BLE_HCI_EVT_HI_BUF_COUNT), - MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE)) ]; -static struct os_mempool trans_buf_evt_hi_pool; -static uint8_t trans_buf_evt_lo_pool_buf[ OS_MEMPOOL_BYTES( - MYNEWT_VAL(BLE_HCI_EVT_LO_BUF_COUNT), - MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE)) ]; -static struct os_mempool trans_buf_evt_lo_pool; - -/* Buffers for HCI ACL data */ -#define ACL_POOL_BLOCK_SIZE OS_ALIGN(MYNEWT_VAL(BLE_ACL_BUF_SIZE) + \ - BLE_MBUF_MEMBLOCK_OVERHEAD + \ - BLE_HCI_DATA_HDR_SZ, OS_ALIGNMENT) -static uint8_t trans_buf_acl_pool_buf[ OS_MEMPOOL_BYTES( - MYNEWT_VAL(BLE_ACL_BUF_COUNT), - ACL_POOL_BLOCK_SIZE) ]; -static struct os_mempool trans_buf_acl_pool; -static struct os_mbuf_pool trans_buf_acl_mbuf_pool; - -/* Host interface */ -static ble_hci_trans_rx_cmd_fn *trans_rx_cmd_cb; -static void *trans_rx_cmd_arg; -static ble_hci_trans_rx_acl_fn *trans_rx_acl_cb; -static void *trans_rx_acl_arg; - -/* Called by NimBLE host to reset HCI transport state (i.e. on host reset) */ -int -ble_hci_trans_reset(void) -{ - return 0; -} - -/* Called by NimBLE host to setup callbacks from HCI transport */ -void -ble_hci_trans_cfg_hs(ble_hci_trans_rx_cmd_fn *cmd_cb, void *cmd_arg, - ble_hci_trans_rx_acl_fn *acl_cb, void *acl_arg) -{ - trans_rx_cmd_cb = cmd_cb; - trans_rx_cmd_arg = cmd_arg; - trans_rx_acl_cb = acl_cb; - trans_rx_acl_arg = acl_arg; -} - -/* - * Called by NimBLE host to allocate buffer for HCI Command packet. - * Called by HCI transport to allocate buffer for HCI Event packet. - */ -uint8_t * -ble_hci_trans_buf_alloc(int type) -{ - uint8_t *buf; - - switch (type) { - case BLE_HCI_TRANS_BUF_CMD: - assert(!trans_buf_cmd_allocd); - trans_buf_cmd_allocd = 1; - buf = trans_buf_cmd; - break; - case BLE_HCI_TRANS_BUF_EVT_HI: - buf = os_memblock_get(&trans_buf_evt_hi_pool); - if (buf) { - break; - } - /* no break */ - case BLE_HCI_TRANS_BUF_EVT_LO: - buf = os_memblock_get(&trans_buf_evt_lo_pool); - break; - default: - assert(0); - buf = NULL; - } - - return buf; -} - -/* - * Called by NimBLE host to free buffer allocated for HCI Event packet. - * Called by HCI transport to free buffer allocated for HCI Command packet. - */ -void -ble_hci_trans_buf_free(uint8_t *buf) -{ - int rc; - - if (buf == trans_buf_cmd) { - assert(trans_buf_cmd_allocd); - trans_buf_cmd_allocd = 0; - } else if (os_memblock_from(&trans_buf_evt_hi_pool, buf)) { - rc = os_memblock_put(&trans_buf_evt_hi_pool, buf); - assert(rc == 0); - } else { - assert(os_memblock_from(&trans_buf_evt_lo_pool, buf)); - rc = os_memblock_put(&trans_buf_evt_lo_pool, buf); - assert(rc == 0); - } -} - -/* Called by NimBLE host to send HCI Command packet over HCI transport */ -int -ble_hci_trans_hs_cmd_tx(uint8_t *cmd) -{ - uint8_t *buf = cmd; - - /* - * TODO Send HCI Command packet somewhere. - * Buffer pointed by 'cmd' contains complete HCI Command packet as defined - * by Core spec. - */ - - ble_hci_trans_buf_free(buf); - - return 0; -} - -/* Called by NimBLE host to send HCI ACL Data packet over HCI transport */ -int -ble_hci_trans_hs_acl_tx(struct os_mbuf *om) -{ - uint8_t *buf = om->om_data; - - /* - * TODO Send HCI ACL Data packet somewhere. - * mbuf pointed by 'om' contains complete HCI ACL Data packet as defined - * by Core spec. - */ - (void)buf; - - os_mbuf_free_chain(om); - - return 0; -} - -/* Called by application to send HCI ACL Data packet to host */ -int -hci_transport_send_acl_to_host(uint8_t *buf, uint16_t size) -{ - struct os_mbuf *trans_mbuf; - int rc; - - trans_mbuf = os_mbuf_get_pkthdr(&trans_buf_acl_mbuf_pool, - sizeof(struct ble_mbuf_hdr)); - os_mbuf_append(trans_mbuf, buf, size); - rc = trans_rx_acl_cb(trans_mbuf, trans_rx_acl_arg); - - return rc; -} - -/* Called by application to send HCI Event packet to host */ -int -hci_transport_send_evt_to_host(uint8_t *buf, uint8_t size) -{ - uint8_t *trans_buf; - int rc; - - /* Allocate LE Advertising Report Event from lo pool only */ - if ((buf[0] == BLE_HCI_EVCODE_LE_META) && - (buf[2] == BLE_HCI_LE_SUBEV_ADV_RPT)) { - trans_buf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_LO); - if (!trans_buf) { - /* Skip advertising report if we're out of memory */ - return 0; - } - } else { - trans_buf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); - } - - memcpy(trans_buf, buf, size); - - rc = trans_rx_cmd_cb(trans_buf, trans_rx_cmd_arg); - if (rc != 0) { - ble_hci_trans_buf_free(trans_buf); - } - - return rc; -} - -/* Called by application to initialize transport structures */ -int -hci_transport_init(void) -{ - int rc; - - trans_buf_cmd_allocd = 0; - - rc = os_mempool_init(&trans_buf_acl_pool, MYNEWT_VAL(BLE_ACL_BUF_COUNT), - ACL_POOL_BLOCK_SIZE, trans_buf_acl_pool_buf, - "dummy_hci_acl_pool"); - SYSINIT_PANIC_ASSERT(rc == 0); - - rc = os_mbuf_pool_init(&trans_buf_acl_mbuf_pool, &trans_buf_acl_pool, - ACL_POOL_BLOCK_SIZE, - MYNEWT_VAL(BLE_ACL_BUF_COUNT)); - SYSINIT_PANIC_ASSERT(rc == 0); - - rc = os_mempool_init(&trans_buf_evt_hi_pool, - MYNEWT_VAL(BLE_HCI_EVT_HI_BUF_COUNT), - MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE), - trans_buf_evt_hi_pool_buf, - "dummy_hci_hci_evt_hi_pool"); - SYSINIT_PANIC_ASSERT(rc == 0); - - rc = os_mempool_init(&trans_buf_evt_lo_pool, - MYNEWT_VAL(BLE_HCI_EVT_LO_BUF_COUNT), - MYNEWT_VAL(BLE_HCI_EVT_BUF_SIZE), - trans_buf_evt_lo_pool_buf, - "dummy_hci_hci_evt_lo_pool"); - SYSINIT_PANIC_ASSERT(rc == 0); - - return 0; -} diff --git a/porting/npl/dummy/src/npl_os_dummy.c b/porting/npl/dummy/src/npl_os_dummy.c index a522531fa3..059e1a689a 100644 --- a/porting/npl/dummy/src/npl_os_dummy.c +++ b/porting/npl/dummy/src/npl_os_dummy.c @@ -41,6 +41,7 @@ ble_npl_eventq_init(struct ble_npl_eventq *evq) struct ble_npl_event * ble_npl_eventq_get(struct ble_npl_eventq *evq, ble_npl_time_t tmo) { + return NULL; } void diff --git a/porting/npl/freertos/include/nimble/nimble_npl_os.h b/porting/npl/freertos/include/nimble/nimble_npl_os.h index 00f64ba2d7..44d216c879 100644 --- a/porting/npl/freertos/include/nimble/nimble_npl_os.h +++ b/porting/npl/freertos/include/nimble/nimble_npl_os.h @@ -65,6 +65,8 @@ struct ble_npl_sem { SemaphoreHandle_t handle; }; +extern volatile uint32_t s_critical_nesting; + /* * Simple APIs are just defined as static inline below, but some are a bit more * complex or require some global state variables and thus are defined in .c @@ -282,14 +284,23 @@ static inline uint32_t ble_npl_hw_enter_critical(void) { vPortEnterCritical(); + s_critical_nesting++; return 0; } static inline void ble_npl_hw_exit_critical(uint32_t ctx) { + if (s_critical_nesting > 0) { + s_critical_nesting--; + } vPortExitCritical(); +} +static inline bool +ble_npl_hw_is_in_critical(void) +{ + return (s_critical_nesting > 0); } #ifdef __cplusplus diff --git a/porting/npl/freertos/include/nimble/nimble_npl_os_log.h b/porting/npl/freertos/include/nimble/nimble_npl_os_log.h new file mode 100644 index 0000000000..24315a21a7 --- /dev/null +++ b/porting/npl/freertos/include/nimble/nimble_npl_os_log.h @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _NIMBLE_NPL_OS_LOG_H_ +#define _NIMBLE_NPL_OS_LOG_H_ + +#include +#include + +/* Example on how to use macro to generate module logging functions */ +#define BLE_NPL_LOG_IMPL(lvl) \ + static inline void _BLE_NPL_LOG_CAT(BLE_NPL_LOG_MODULE, \ + _BLE_NPL_LOG_CAT(_, lvl))(const char *fmt, ...)\ + { \ + va_list args; \ + va_start(args, fmt); \ + vprintf(fmt, args); \ + va_end(args); \ + } + +#endif /* _NIMBLE_NPL_OS_LOG_H_ */ diff --git a/porting/npl/freertos/include/nimble/npl_freertos.h b/porting/npl/freertos/include/nimble/npl_freertos.h index a7b1c4aa79..24441adfa0 100644 --- a/porting/npl/freertos/include/nimble/npl_freertos.h +++ b/porting/npl/freertos/include/nimble/npl_freertos.h @@ -24,8 +24,6 @@ extern "C" { #endif -struct ble_npl_eventq *npl_freertos_eventq_dflt_get(void); - struct ble_npl_event *npl_freertos_eventq_get(struct ble_npl_eventq *evq, ble_npl_time_t tmo); diff --git a/porting/npl/freertos/src/npl_os_freertos.c b/porting/npl/freertos/src/npl_os_freertos.c index ecc5cd7b1e..584333c318 100644 --- a/porting/npl/freertos/src/npl_os_freertos.c +++ b/porting/npl/freertos/src/npl_os_freertos.c @@ -22,6 +22,13 @@ #include #include "nimble/nimble_npl.h" +/* Include the file that defines the SCB for your HW. */ +#ifdef NIMBLE_NPL_OS_EXTRA_INCLUDE +#include NIMBLE_NPL_OS_EXTRA_INCLUDE +#endif + +volatile uint32_t s_critical_nesting = 0; + static inline bool in_isr(void) { diff --git a/porting/npl/linux/include/nimble/nimble_npl_os.h b/porting/npl/linux/include/nimble/nimble_npl_os.h index bdd3988699..0006f8b407 100644 --- a/porting/npl/linux/include/nimble/nimble_npl_os.h +++ b/porting/npl/linux/include/nimble/nimble_npl_os.h @@ -23,6 +23,7 @@ #include #include #include +#include #include "os_types.h" @@ -30,21 +31,15 @@ extern "C" { #endif -#define BLE_NPL_OS_ALIGNMENT 4 +#define BLE_NPL_OS_ALIGNMENT (__WORDSIZE / 8) -#define BLE_NPL_TIME_FOREVER INT32_MAX +#define BLE_NPL_TIME_FOREVER UINT32_MAX -#define SYSINIT_PANIC_MSG(msg) __assert_fail(msg, __FILE__, __LINE__, __func__) - -#define SYSINIT_PANIC_ASSERT_MSG(rc, msg) do \ -{ \ - if (!(rc)) { \ - SYSINIT_PANIC_MSG(msg); \ - } \ -} while (0) +struct ble_npl_eventq *ble_npl_eventq_dflt_get(void); +void ble_npl_eventq_run(struct ble_npl_eventq *evq); #ifdef __cplusplus } #endif -#endif /* _NPL_H_ */ +#endif /* _NPL_H_ */ diff --git a/porting/npl/linux/include/nimble/nimble_npl_os_log.h b/porting/npl/linux/include/nimble/nimble_npl_os_log.h new file mode 100644 index 0000000000..2e359f878d --- /dev/null +++ b/porting/npl/linux/include/nimble/nimble_npl_os_log.h @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _NIMBLE_NPL_OS_LOG_H_ +#define _NIMBLE_NPL_OS_LOG_H_ + +#include +#include + +/* Example on how to use macro to generate module logging functions */ +#define BLE_NPL_LOG_IMPL(lvl) \ + static inline void _BLE_NPL_LOG_CAT( \ + BLE_NPL_LOG_MODULE, _BLE_NPL_LOG_CAT(_, lvl))(const char *fmt, ...) \ + { \ + va_list args; \ + va_start(args, fmt); \ + vprintf(fmt, args); \ + va_end(args); \ + } + +#endif /* _NIMBLE_NPL_OS_LOG_H_ */ diff --git a/porting/npl/linux/include/nimble/os_types.h b/porting/npl/linux/include/nimble/os_types.h index a5d8bf5486..fa92cd1821 100644 --- a/porting/npl/linux/include/nimble/os_types.h +++ b/porting/npl/linux/include/nimble/os_types.h @@ -21,7 +21,6 @@ #define _NPL_OS_TYPES_H #include -#include #include #include #include @@ -33,50 +32,49 @@ typedef uint32_t ble_npl_time_t; typedef int32_t ble_npl_stime_t; -//typedef int os_sr_t; typedef int ble_npl_stack_t; - struct ble_npl_event { - uint8_t ev_queued; - ble_npl_event_fn *ev_cb; - void *ev_arg; + uint8_t ev_queued; + ble_npl_event_fn *ev_cb; + void *ev_arg; }; struct ble_npl_eventq { - void *q; + void *q; }; struct ble_npl_callout { - struct ble_npl_event c_ev; - struct ble_npl_eventq *c_evq; - uint32_t c_ticks; - timer_t c_timer; - bool c_active; + struct ble_npl_event c_ev; + struct ble_npl_eventq *c_evq; + uint32_t c_ticks; + timer_t c_timer; + bool c_active; }; struct ble_npl_mutex { - pthread_mutex_t lock; - pthread_mutexattr_t attr; - struct timespec wait; + pthread_mutex_t lock; + pthread_mutexattr_t attr; + struct timespec wait; }; struct ble_npl_sem { - sem_t lock; + sem_t lock; }; struct ble_npl_task { - pthread_t handle; - pthread_attr_t attr; - struct sched_param param; - const char* name; + pthread_t handle; + pthread_attr_t attr; + struct sched_param param; + const char *name; }; typedef void *(*ble_npl_task_func_t)(void *); -int ble_npl_task_init(struct ble_npl_task *t, const char *name, ble_npl_task_func_t func, - void *arg, uint8_t prio, ble_npl_time_t sanity_itvl, - ble_npl_stack_t *stack_bottom, uint16_t stack_size); +int ble_npl_task_init(struct ble_npl_task *t, const char *name, + ble_npl_task_func_t func, void *arg, uint8_t prio, + ble_npl_time_t sanity_itvl, + ble_npl_stack_t *stack_bottom, uint16_t stack_size); int ble_npl_task_remove(struct ble_npl_task *t); @@ -84,4 +82,4 @@ uint8_t ble_npl_task_count(void); void ble_npl_task_yield(void); -#endif // _NPL_OS_TYPES_H +#endif /* _NPL_OS_TYPES_H */ diff --git a/porting/npl/linux/src/os_atomic.c b/porting/npl/linux/src/os_atomic.c index 3aaec08ada..531c4a2749 100644 --- a/porting/npl/linux/src/os_atomic.c +++ b/porting/npl/linux/src/os_atomic.c @@ -17,20 +17,28 @@ * under the License. */ +#define __USE_GNU + #include #include #include "nimble/nimble_npl.h" -static pthread_mutex_t s_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; +static struct ble_npl_mutex s_mutex; +static uint8_t s_mutex_inited = 0; uint32_t ble_npl_hw_enter_critical(void) { - pthread_mutex_lock(&s_mutex); + if( !s_mutex_inited ) { + ble_npl_mutex_init(&s_mutex); + s_mutex_inited = 1; + } + + pthread_mutex_lock(&s_mutex.lock); return 0; } void ble_npl_hw_exit_critical(uint32_t ctx) { - pthread_mutex_unlock(&s_mutex); + pthread_mutex_unlock(&s_mutex.lock); } diff --git a/porting/npl/linux/src/os_callout.c b/porting/npl/linux/src/os_callout.c index d3091fa9c8..90c190cefd 100644 --- a/porting/npl/linux/src/os_callout.c +++ b/porting/npl/linux/src/os_callout.c @@ -31,8 +31,10 @@ static void ble_npl_callout_timer_cb(union sigval sv) { struct ble_npl_callout *c = (struct ble_npl_callout *)sv.sival_ptr; + assert(c); + c->c_active = false; if (c->c_evq) { ble_npl_eventq_put(c->c_evq, &c->c_ev); } else { @@ -40,12 +42,11 @@ ble_npl_callout_timer_cb(union sigval sv) } } -void ble_npl_callout_init(struct ble_npl_callout *c, - struct ble_npl_eventq *evq, - ble_npl_event_fn *ev_cb, - void *ev_arg) +void +ble_npl_callout_init(struct ble_npl_callout *c, struct ble_npl_eventq *evq, + ble_npl_event_fn *ev_cb, void *ev_arg) { - struct sigevent event; + struct sigevent event; /* Initialize the callout. */ memset(c, 0, sizeof(*c)); @@ -55,29 +56,32 @@ void ble_npl_callout_init(struct ble_npl_callout *c, c->c_active = false; event.sigev_notify = SIGEV_THREAD; - event.sigev_value.sival_ptr = c; // put callout obj in signal args + event.sigev_value.sival_ptr = c; // put callout obj in signal args event.sigev_notify_function = ble_npl_callout_timer_cb; event.sigev_notify_attributes = NULL; timer_create(CLOCK_REALTIME, &event, &c->c_timer); } -bool ble_npl_callout_is_active(struct ble_npl_callout *c) +bool +ble_npl_callout_is_active(struct ble_npl_callout *c) { - // TODO: seek native posix method to determine whether timer_t is active. - // TODO: fix bug where one-shot timer is still active after fired. + /* TODO: seek native posix method to determine whether timer_t is active. + * TODO: fix bug where one-shot timer is still active after fired. + */ return c->c_active; } -int ble_npl_callout_inited(struct ble_npl_callout *c) +int +ble_npl_callout_inited(struct ble_npl_callout *c) { return (c->c_timer != NULL); } -ble_npl_error_t ble_npl_callout_reset(struct ble_npl_callout *c, - ble_npl_time_t ticks) +ble_npl_error_t +ble_npl_callout_reset(struct ble_npl_callout *c, ble_npl_time_t ticks) { - struct itimerspec its; + struct itimerspec its; if (ticks < 0) { return BLE_NPL_EINVAL; @@ -90,7 +94,7 @@ ble_npl_error_t ble_npl_callout_reset(struct ble_npl_callout *c, c->c_ticks = ble_npl_time_get() + ticks; its.it_interval.tv_sec = 0; - its.it_interval.tv_nsec = 0; // one shot + its.it_interval.tv_nsec = 0; // one shot its.it_value.tv_sec = (ticks / 1000); its.it_value.tv_nsec = (ticks % 1000) * 1000000; // expiration its.it_value.tv_nsec %= 1000000000; @@ -100,16 +104,17 @@ ble_npl_error_t ble_npl_callout_reset(struct ble_npl_callout *c, return BLE_NPL_OK; } -int ble_npl_callout_queued(struct ble_npl_callout *c) +int +ble_npl_callout_queued(struct ble_npl_callout *c) { struct itimerspec its; timer_gettime(c->c_timer, &its); - return ((its.it_value.tv_sec > 0) || - (its.it_value.tv_nsec > 0)); + return ((its.it_value.tv_sec > 0) || (its.it_value.tv_nsec > 0)); } -void ble_npl_callout_stop(struct ble_npl_callout *c) +void +ble_npl_callout_stop(struct ble_npl_callout *c) { if (!ble_npl_callout_inited(c)) { return; @@ -137,13 +142,12 @@ ble_npl_callout_set_arg(struct ble_npl_callout *co, void *arg) } uint32_t -ble_npl_callout_remaining_ticks(struct ble_npl_callout *co, - ble_npl_time_t now) +ble_npl_callout_remaining_ticks(struct ble_npl_callout *co, ble_npl_time_t now) { ble_npl_time_t rt; uint32_t exp; - struct itimerspec its; + timer_gettime(co->c_timer, &its); exp = its.it_value.tv_sec * 1000; diff --git a/porting/npl/linux/src/os_mutex.c b/porting/npl/linux/src/os_mutex.c index c7d6190e89..3d3a72ef12 100644 --- a/porting/npl/linux/src/os_mutex.c +++ b/porting/npl/linux/src/os_mutex.c @@ -31,7 +31,7 @@ ble_npl_mutex_init(struct ble_npl_mutex *mu) } pthread_mutexattr_init(&mu->attr); - pthread_mutexattr_settype(&mu->attr, PTHREAD_MUTEX_RECURSIVE_NP); + pthread_mutexattr_settype(&mu->attr, PTHREAD_MUTEX_RECURSIVE); pthread_mutex_init(&mu->lock, &mu->attr); return BLE_NPL_OK; @@ -71,6 +71,14 @@ ble_npl_mutex_pend(struct ble_npl_mutex *mu, uint32_t timeout) mu->wait.tv_sec += timeout / 1000; mu->wait.tv_nsec += (timeout % 1000) * 1000000; + /* struct timespec tv_nsec holds nanosecond and allowed range is + * 0 - 999999999, otherwise pthread_mutex_timedlock returns EINVAL + */ + if (mu->wait.tv_nsec >= 1000000000) { + mu->wait.tv_sec += mu->wait.tv_nsec / 1000000000; + mu->wait.tv_nsec = mu->wait.tv_nsec % 1000000000; + } + err = pthread_mutex_timedlock(&mu->lock, &mu->wait); if (err == ETIMEDOUT) { return BLE_NPL_TIMEOUT; diff --git a/porting/npl/linux/src/os_sem.c b/porting/npl/linux/src/os_sem.c index e3434af5a1..be43c64991 100644 --- a/porting/npl/linux/src/os_sem.c +++ b/porting/npl/linux/src/os_sem.c @@ -71,9 +71,14 @@ ble_npl_sem_pend(struct ble_npl_sem *sem, uint32_t timeout) wait.tv_sec += timeout / 1000; wait.tv_nsec += (timeout % 1000) * 1000000; - err = sem_timedwait(&sem->lock, &wait); - if (err && errno == ETIMEDOUT) { - return BLE_NPL_TIMEOUT; + while ((err = sem_timedwait(&sem->lock, &wait)) != 0) { + switch (errno) { + case EINTR: + continue; + case ETIMEDOUT: + return BLE_NPL_TIMEOUT; + } + break; } } diff --git a/porting/npl/linux/src/os_task.c b/porting/npl/linux/src/os_task.c index fe6c2df11c..c34507f150 100644 --- a/porting/npl/linux/src/os_task.c +++ b/porting/npl/linux/src/os_task.c @@ -17,6 +17,8 @@ * under the License. */ +#include + #include "os/os.h" #include "nimble/nimble_npl.h" @@ -32,23 +34,22 @@ extern "C" { * and sets the task as ready to run, and inserts it into the operating * system scheduler. * - * @param t The task to initialize - * @param name The name of the task to initialize - * @param func The task function to call - * @param arg The argument to pass to this task function - * @param prio The priority at which to run this task - * @param sanity_itvl The time at which this task should check in with the - * sanity task. OS_WAIT_FOREVER means never check in - * here. - * @param stack_bottom A pointer to the bottom of a task's stack - * @param stack_size The overall size of the task's stack. + * @param t The task to initialize + * @param name The name of the task to initialize + * @param func The task function to call + * @param arg The argument to pass to this task function + * @param prio The priority at which to run this task + * @param sanity_itvl The time at which this task should check in with the + * sanity task. OS_WAIT_FOREVER means never check in here. + * @param stack_bottom A pointer to the bottom of a task's stack + * @param stack_size The overall size of the task's stack. * * @return 0 on success, non-zero on failure. */ int ble_npl_task_init(struct ble_npl_task *t, const char *name, ble_npl_task_func_t func, - void *arg, uint8_t prio, ble_npl_time_t sanity_itvl, - ble_npl_stack_t *stack_bottom, uint16_t stack_size) + void *arg, uint8_t prio, ble_npl_time_t sanity_itvl, + ble_npl_stack_t *stack_bottom, uint16_t stack_size) { int err; if ((t == NULL) || (func == NULL)) { @@ -56,14 +57,21 @@ ble_npl_task_init(struct ble_npl_task *t, const char *name, ble_npl_task_func_t } err = pthread_attr_init(&t->attr); - if (err) return err; - err = pthread_attr_getschedparam (&t->attr, &t->param); - if (err) return err; + if (err) + return err; + + err = pthread_attr_getschedparam(&t->attr, &t->param); + if (err) + return err; + err = pthread_attr_setschedpolicy(&t->attr, SCHED_RR); - if (err) return err; + if (err) + return err; + t->param.sched_priority = prio; - err = pthread_attr_setschedparam (&t->attr, &t->param); - if (err) return err; + err = pthread_attr_setschedparam(&t->attr, &t->param); + if (err) + return err; t->name = name; err = pthread_create(&t->handle, &t->attr, func, arg); @@ -99,14 +107,16 @@ ble_npl_get_current_task_id(void) return (void *)pthread_self(); } -bool ble_npl_os_started(void) +bool +ble_npl_os_started(void) { return true; } -void ble_npl_task_yield(void) +void +ble_npl_task_yield(void) { - pthread_yield(); + sched_yield(); } #ifdef __cplusplus diff --git a/porting/npl/linux/src/os_time.c b/porting/npl/linux/src/os_time.c index 4625159f2f..2af544e5f6 100644 --- a/porting/npl/linux/src/os_time.c +++ b/porting/npl/linux/src/os_time.c @@ -33,9 +33,11 @@ ble_npl_time_t ble_npl_time_get(void) { struct timespec now; + if (clock_gettime(CLOCK_MONOTONIC, &now)) { return 0; } + return now.tv_sec * 1000.0 + now.tv_nsec / 1000000.0; } diff --git a/porting/npl/linux/src/wqueue.h b/porting/npl/linux/src/wqueue.h index 1de779e7d3..61540562e1 100644 --- a/porting/npl/linux/src/wqueue.h +++ b/porting/npl/linux/src/wqueue.h @@ -25,11 +25,9 @@ #include #include -using namespace std; - template class wqueue { - list m_queue; + std::list m_queue; pthread_mutex_t m_mutex; pthread_mutexattr_t m_mutex_attr; pthread_cond_t m_condv; diff --git a/porting/npl/linux/test/Makefile b/porting/npl/linux/test/Makefile index c0be3d5f80..cab378d320 100644 --- a/porting/npl/linux/test/Makefile +++ b/porting/npl/linux/test/Makefile @@ -43,11 +43,12 @@ CFLAGS = \ $(INCLUDES) $(DEFINES) \ -g \ -D_GNU_SOURCE \ + -m32 \ $(NULL) LIBS = -lrt -lpthread -lstdc++ -LDFLAGS = +LDFLAGS = -m32 ### ===== Sources ===== @@ -99,7 +100,7 @@ show_objs: ### ===== Clean ===== clean: @echo "Cleaning artifacts." - rm *~ .depend $(OBJS) *.o *.exe + rm -f .depend $(OBJS) *.o *.exe ### ===== Dependencies ===== ### Rebuild if headers change diff --git a/porting/npl/mynewt/include/nimble/nimble_npl_os_log.h b/porting/npl/mynewt/include/nimble/nimble_npl_os_log.h new file mode 100644 index 0000000000..3ec47344ad --- /dev/null +++ b/porting/npl/mynewt/include/nimble/nimble_npl_os_log.h @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _NIMBLE_NPL_OS_LOG_H_ +#define _NIMBLE_NPL_OS_LOG_H_ + +#include +#include + +/* Only include the logcfg header if this version of newt can generate it. */ +#if MYNEWT_VAL(NEWT_FEATURE_LOGCFG) +#include +#endif + +#endif /* _NIMBLE_NPL_OS_LOG_H_ */ diff --git a/porting/npl/mynewt/pkg.yml b/porting/npl/mynewt/pkg.yml index b6a790f049..7bb94c6255 100644 --- a/porting/npl/mynewt/pkg.yml +++ b/porting/npl/mynewt/pkg.yml @@ -19,7 +19,7 @@ pkg.name: porting/npl/mynewt pkg.description: NimBLE porting layer for Apache Mynewt -pkg.author: "Apache Mynewt " +pkg.author: "Apache Mynewt " pkg.homepage: "http://mynewt.apache.org/" pkg.keywords: diff --git a/porting/npl/nuttx/include/modlog/modlog.h b/porting/npl/nuttx/include/modlog/modlog.h deleted file mode 100644 index 5e51b50102..0000000000 --- a/porting/npl/nuttx/include/modlog/modlog.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -#ifndef H_MODLOG_ -#define H_MODLOG_ - -#include -#include - -#include "log_common/log_common.h" - -#define MODLOG_MODULE_DFLT 255 - -#if MYNEWT_VAL(LOG_LEVEL) <= LOG_LEVEL_DEBUG || defined __DOXYGEN__ -#define MODLOG_DEBUG(ml_mod_, ml_msg_, ...) \ - printf((ml_msg_), ##__VA_ARGS__) -#else -#define MODLOG_DEBUG(ml_mod_, ...) IGNORE(__VA_ARGS__) -#endif - -#if MYNEWT_VAL(LOG_LEVEL) <= LOG_LEVEL_INFO || defined __DOXYGEN__ -#define MODLOG_INFO(ml_mod_, ml_msg_, ...) \ - printf((ml_msg_), ##__VA_ARGS__) -#else -#define MODLOG_INFO(ml_mod_, ...) IGNORE(__VA_ARGS__) -#endif - -#if MYNEWT_VAL(LOG_LEVEL) <= LOG_LEVEL_WARN || defined __DOXYGEN__ -#define MODLOG_WARN(ml_mod_, ml_msg_, ...) \ - printf((ml_msg_), ##__VA_ARGS__) -#else -#define MODLOG_WARN(ml_mod_, ...) IGNORE(__VA_ARGS__) -#endif - -#if MYNEWT_VAL(LOG_LEVEL) <= LOG_LEVEL_ERROR || defined __DOXYGEN__ -#define MODLOG_ERROR(ml_mod_, ml_msg_, ...) \ - printf((ml_msg_), ##__VA_ARGS__) -#else -#define MODLOG_ERROR(ml_mod_, ...) IGNORE(__VA_ARGS__) -#endif - -#if MYNEWT_VAL(LOG_LEVEL) <= LOG_LEVEL_CRITICAL || defined __DOXYGEN__ -#define MODLOG_CRITICAL(ml_mod_, ml_msg_, ...) \ - printf((ml_msg_), ##__VA_ARGS__) -#else -#define MODLOG_CRITICAL(ml_mod_, ...) IGNORE(__VA_ARGS__) -#endif - -#define MODLOG(ml_lvl_, ml_mod_, ...) \ - MODLOG_ ## ml_lvl_((ml_mod_), __VA_ARGS__) - -#endif diff --git a/porting/npl/nuttx/include/nimble/nimble_npl_os.h b/porting/npl/nuttx/include/nimble/nimble_npl_os.h index 0f765f5a3d..8a41d411db 100644 --- a/porting/npl/nuttx/include/nimble/nimble_npl_os.h +++ b/porting/npl/nuttx/include/nimble/nimble_npl_os.h @@ -35,15 +35,6 @@ extern "C" { #define BLE_NPL_TIME_FOREVER INT32_MAX -#define SYSINIT_PANIC_MSG(msg) { fprintf(stderr, "%s\n", msg); abort(); } - -#define SYSINIT_PANIC_ASSERT_MSG(rc, msg) do \ -{ \ - if (!(rc)) { \ - SYSINIT_PANIC_MSG(msg); \ - } \ -} while (0) - #ifdef __cplusplus } #endif diff --git a/porting/npl/nuttx/include/nimble/nimble_npl_os_log.h b/porting/npl/nuttx/include/nimble/nimble_npl_os_log.h new file mode 100644 index 0000000000..01220b805d --- /dev/null +++ b/porting/npl/nuttx/include/nimble/nimble_npl_os_log.h @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _NIMBLE_NPL_OS_LOG_H_ +#define _NIMBLE_NPL_OS_LOG_H_ + +#include +#include + +/* Debug log level configurable from Kconfig */ + +#ifdef CONFIG_NIMBLE_DEBUG_ERROR +#define nimble_err _err +#else +#define nimble_err _none +#endif + +#ifdef CONFIG_NIMBLE_DEBUG_WARN +#define nimble_warn _warn +#else +#define nimble_warn _none +#endif + +#ifdef CONFIG_NIMBLE_DEBUG_INFO +#define nimble_info _info +#else +#define nimble_info _none +#endif + +#define DFLT_LOG_DEBUG(msg, ...) nimble_info(msg, ##__VA_ARGS__) +#define DFLT_LOG_INFO(msg, ...) nimble_info(msg, ##__VA_ARGS__) +#define DFLT_LOG_WARN(msg, ...) nimble_warn(msg, ##__VA_ARGS__) +#define DFLT_LOG_ERROR(msg, ...) nimble_err(msg, ##__VA_ARGS__) +#define DFLT_LOG_CRITICAL(msg, ...) nimble_err(msg, ##__VA_ARGS__) + +#define BLE_HS_LOG_DEBUG(msg, ...) nimble_info(msg, ##__VA_ARGS__) +#define BLE_HS_LOG_INFO(msg, ...) nimble_info(msg, ##__VA_ARGS__) +#define BLE_HS_LOG_WARN(msg, ...) nimble_warn(msg, ##__VA_ARGS__) +#define BLE_HS_LOG_ERROR(msg, ...) nimble_err(msg, ##__VA_ARGS__) +#define BLE_HS_LOG_CRITICAL(msg, ...) nimble_err(msg, ##__VA_ARGS__) + +#define BLE_EATT_LOG_DEBUG(msg, ...) nimble_info(msg, ##__VA_ARGS__) +#define BLE_EATT_LOG_INFO(msg, ...) nimble_info(msg, ##__VA_ARGS__) +#define BLE_EATT_LOG_WARN(msg, ...) nimble_warn(msg, ##__VA_ARGS__) +#define BLE_EATT_LOG_ERROR(msg, ...) nimble_err(msg, ##__VA_ARGS__) +#define BLE_EATT_LOG_CRITICAL(msg, ...) nimble_err(msg, ##__VA_ARGS__) + +#endif /* _NIMBLE_NPL_OS_LOG_H_ */ diff --git a/porting/npl/nuttx/src/os_callout.c b/porting/npl/nuttx/src/os_callout.c index e4580da97a..5b384dc8f3 100644 --- a/porting/npl/nuttx/src/os_callout.c +++ b/porting/npl/nuttx/src/os_callout.c @@ -44,21 +44,23 @@ callout_handler(pthread_addr_t arg) { struct ble_npl_callout *c; - pthread_mutex_lock(&callout_mutex); - while (!pending_callout) { - pthread_cond_wait(&callout_cond, &callout_mutex); - } - - c = pending_callout; - pending_callout = NULL; - pthread_mutex_unlock(&callout_mutex); - - /* Invoke callback */ - - if (c->c_evq) { - ble_npl_eventq_put(c->c_evq, &c->c_ev); - } else { - c->c_ev.ev_cb(&c->c_ev); + while (true) { + pthread_mutex_lock(&callout_mutex); + while (!pending_callout) { + pthread_cond_wait(&callout_cond, &callout_mutex); + } + + c = pending_callout; + pending_callout = NULL; + pthread_mutex_unlock(&callout_mutex); + + /* Invoke callback */ + + if (c->c_evq) { + ble_npl_eventq_put(c->c_evq, &c->c_ev); + } else { + c->c_ev.ev_cb(&c->c_ev); + } } return NULL; @@ -89,6 +91,7 @@ ble_npl_callout_init(struct ble_npl_callout *c, pthread_attr_init(&attr); pthread_attr_setstacksize(&attr, CONFIG_NIMBLE_CALLOUT_THREAD_STACKSIZE); pthread_create(&callout_thread, &attr, callout_handler, NULL); + pthread_setname_np(callout_thread, "ble_npl_callout"); thread_started = true; } @@ -119,7 +122,7 @@ ble_npl_callout_is_active(struct ble_npl_callout *c) int ble_npl_callout_inited(struct ble_npl_callout *c) { - return (c->c_timer != NULL); + return (c->c_timer != 0); } ble_npl_error_t diff --git a/porting/npl/nuttx/src/os_task.c b/porting/npl/nuttx/src/os_task.c index 40f8c8c7ba..075928a784 100644 --- a/porting/npl/nuttx/src/os_task.c +++ b/porting/npl/nuttx/src/os_task.c @@ -77,6 +77,10 @@ ble_npl_task_init(struct ble_npl_task *t, const char *name, ble_npl_task_func_t { err = OS_ENOMEM; } + else + { + pthread_setname_np(t->handle, t->name); + } return err; } diff --git a/porting/npl/nuttx/src/wqueue.h b/porting/npl/nuttx/src/wqueue.h deleted file mode 100644 index 7821eacda6..0000000000 --- a/porting/npl/nuttx/src/wqueue.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - wqueue.h - Worker thread queue based on the Standard C++ library list - template class. - ------------------------------------------ - Copyright (c) 2013 Vic Hargrave - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -// https://vichargrave.github.io/articles/2013-01/multithreaded-work-queue-in-cpp -// https://github.com/vichargrave/wqueue/blob/master/wqueue.h - - -#ifndef __wqueue_h__ -#define __wqueue_h__ - -#include -#include -#include - -struct wqueue_s -{ - dq_queue_s m_queue; - pthread_mutex_t m_mutex; - pthread_mutexattr_t m_mutex_attr; - pthread_cond_t m_condv; -}; - -using namespace std; - -template class wqueue -{ - dq_queue_s m_queue; - pthread_mutex_t m_mutex; - pthread_mutexattr_t m_mutex_attr; - pthread_cond_t m_condv; - -public: - wqueue() - { - dq_init(m_queue); - pthread_mutexattr_init(&m_mutex_attr); - pthread_mutexattr_settype(&m_mutex_attr, PTHREAD_MUTEX_RECURSIVE); - pthread_mutex_init(&m_mutex, &m_mutex_attr); - pthread_cond_init(&m_condv, NULL); - } - - ~wqueue() { - pthread_mutex_destroy(&m_mutex); - pthread_cond_destroy(&m_condv); - } - - void put(T item) { - dq_entry_t* entry = malloc(sizeof(T)); - - pthread_mutex_lock(&m_mutex); - dq_addlast(entry, &m_queue); - m_queue.push_back(item); - pthread_cond_signal(&m_condv); - pthread_mutex_unlock(&m_mutex); - } - - T get(uint32_t tmo) { - pthread_mutex_lock(&m_mutex); - if (tmo) { - while (m_queue.size() == 0) { - pthread_cond_wait(&m_condv, &m_mutex); - } - } - - T item = NULL; - - if (m_queue.size() != 0) { - item = m_queue.front(); - m_queue.pop_front(); - } - - pthread_mutex_unlock(&m_mutex); - return item; - } - - void remove(T item) { - pthread_mutex_lock(&m_mutex); - m_queue.remove(item); - pthread_mutex_unlock(&m_mutex); - } - - int size() { - pthread_mutex_lock(&m_mutex); - int size = m_queue.size(); - pthread_mutex_unlock(&m_mutex); - return size; - } -}; - -#endif diff --git a/porting/npl/riot/include/logcfg/logcfg.h b/porting/npl/riot/include/logcfg/logcfg.h deleted file mode 100644 index 837cdeac1f..0000000000 --- a/porting/npl/riot/include/logcfg/logcfg.h +++ /dev/null @@ -1,32 +0,0 @@ -/** - * This file was generated by Apache newt version: 1.9.0-dev - */ - -#ifndef H_MYNEWT_LOGCFG_ -#define H_MYNEWT_LOGCFG_ - -#include "modlog/modlog.h" -#include "log_common/log_common.h" - -#define BLE_HS_LOG_DEBUG(...) IGNORE(__VA_ARGS__) -#define BLE_HS_LOG_INFO(...) MODLOG_INFO(4, __VA_ARGS__) -#define BLE_HS_LOG_WARN(...) MODLOG_WARN(4, __VA_ARGS__) -#define BLE_HS_LOG_ERROR(...) MODLOG_ERROR(4, __VA_ARGS__) -#define BLE_HS_LOG_CRITICAL(...) MODLOG_CRITICAL(4, __VA_ARGS__) -#define BLE_HS_LOG_DISABLED(...) MODLOG_DISABLED(4, __VA_ARGS__) - -#define DFLT_LOG_DEBUG(...) IGNORE(__VA_ARGS__) -#define DFLT_LOG_INFO(...) MODLOG_INFO(0, __VA_ARGS__) -#define DFLT_LOG_WARN(...) MODLOG_WARN(0, __VA_ARGS__) -#define DFLT_LOG_ERROR(...) MODLOG_ERROR(0, __VA_ARGS__) -#define DFLT_LOG_CRITICAL(...) MODLOG_CRITICAL(0, __VA_ARGS__) -#define DFLT_LOG_DISABLED(...) MODLOG_DISABLED(0, __VA_ARGS__) - -#define MFG_LOG_DEBUG(...) IGNORE(__VA_ARGS__) -#define MFG_LOG_INFO(...) IGNORE(__VA_ARGS__) -#define MFG_LOG_WARN(...) IGNORE(__VA_ARGS__) -#define MFG_LOG_ERROR(...) IGNORE(__VA_ARGS__) -#define MFG_LOG_CRITICAL(...) IGNORE(__VA_ARGS__) -#define MFG_LOG_DISABLED(...) MODLOG_DISABLED(128, __VA_ARGS__) - -#endif diff --git a/porting/npl/riot/include/nimble/nimble_npl_os.h b/porting/npl/riot/include/nimble/nimble_npl_os.h index ee0dfab340..4633cbd1a7 100644 --- a/porting/npl/riot/include/nimble/nimble_npl_os.h +++ b/porting/npl/riot/include/nimble/nimble_npl_os.h @@ -27,6 +27,10 @@ #include "sema.h" #include "ztimer.h" +#if defined(CPU_FAM_NRF51) || defined(CPU_FAM_NRF52) +#include "nrf_clock.h" +#endif + #ifdef __cplusplus extern "C" { #endif @@ -270,6 +274,22 @@ ble_npl_hw_is_in_critical(void) return (bool)!irq_is_enabled(); } +/* XXX: these functions are required to build hal_timer.c, however with the +* default configuration they are never used... */ +#if defined(CPU_FAM_NRF51) || defined(CPU_FAM_NRF52) +static inline void +nrf52_clock_hfxo_request(void) +{ + clock_hfxo_request(); +} + +static inline void +nrf52_clock_hfxo_release(void) +{ + clock_hfxo_release(); +} +#endif + #ifdef __cplusplus } #endif diff --git a/porting/npl/riot/include/nimble/nimble_npl_os_log.h b/porting/npl/riot/include/nimble/nimble_npl_os_log.h new file mode 100644 index 0000000000..f585070dad --- /dev/null +++ b/porting/npl/riot/include/nimble/nimble_npl_os_log.h @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef _NIMBLE_NPL_OS_LOG_H_ +#define _NIMBLE_NPL_OS_LOG_H_ + +#include +#include + +/* Example on how to use macro to generate module logging functions */ +#define BLE_NPL_LOG_IMPL(lvl) \ + __attribute__((__format__ (__printf__, 1, 0))) \ + static inline void _BLE_NPL_LOG_CAT(BLE_NPL_LOG_MODULE, \ + _BLE_NPL_LOG_CAT(_, lvl))(const char *fmt, ...)\ + { \ + va_list args; \ + va_start(args, fmt); \ + vprintf(fmt, args); \ + va_end(args); \ + } + +#endif /* _NIMBLE_NPL_OS_LOG_H_ */ diff --git a/porting/npl/riot/include/syscfg/syscfg.h b/porting/npl/riot/include/syscfg/syscfg.h index e3d282e1d8..30d0a44e05 100644 --- a/porting/npl/riot/include/syscfg/syscfg.h +++ b/porting/npl/riot/include/syscfg/syscfg.h @@ -1,65 +1,326 @@ -/** - * This file was generated by Apache newt version: 1.9.0-dev +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. */ #ifndef H_MYNEWT_SYSCFG_ #define H_MYNEWT_SYSCFG_ -/** - * This macro exists to ensure code includes this header when needed. If code - * checks the existence of a setting directly via ifdef without including this - * header, the setting macro will silently evaluate to 0. In contrast, an - * attempt to use these macros without including this header will result in a - * compiler error. - */ #define MYNEWT_VAL(_name) MYNEWT_VAL_ ## _name #define MYNEWT_VAL_CHOICE(_name, _val) MYNEWT_VAL_ ## _name ## __ ## _val +#ifndef MYNEWT_VAL_INCLUDE_IMAGE_HEADER +#define MYNEWT_VAL_INCLUDE_IMAGE_HEADER (1) +#endif + +#undef MYNEWT_VAL_LINK_TEMPLATE -/*** Repository @apache-mynewt-core info */ -#ifndef MYNEWT_VAL_REPO_HASH_APACHE_MYNEWT_CORE -#define MYNEWT_VAL_REPO_HASH_APACHE_MYNEWT_CORE ("6b205affd69a6f05787264fa2c70c621bbbdd325") +#ifndef MYNEWT_VAL_MAIN_STACK_FILL +#define MYNEWT_VAL_MAIN_STACK_FILL (0) #endif -#ifndef MYNEWT_VAL_REPO_VERSION_APACHE_MYNEWT_CORE -#define MYNEWT_VAL_REPO_VERSION_APACHE_MYNEWT_CORE ("0.0.0") +#ifndef MYNEWT_VAL_MAIN_STACK_SIZE +#define MYNEWT_VAL_MAIN_STACK_SIZE (768) #endif -/*** Repository @apache-mynewt-mcumgr info */ -#ifndef MYNEWT_VAL_REPO_HASH_APACHE_MYNEWT_MCUMGR -#define MYNEWT_VAL_REPO_HASH_APACHE_MYNEWT_MCUMGR ("64f5060bd8bb466367e0da94da8b425d5b9f6388") +#ifndef MYNEWT_VAL_MCU_RAM_SIZE +#define MYNEWT_VAL_MCU_RAM_SIZE (0x40000) #endif -#ifndef MYNEWT_VAL_REPO_VERSION_APACHE_MYNEWT_MCUMGR -#define MYNEWT_VAL_REPO_VERSION_APACHE_MYNEWT_MCUMGR ("0.0.0") +#ifndef MYNEWT_VAL_MCU_RAM_START +#define MYNEWT_VAL_MCU_RAM_START (0x20000000) #endif -/*** Repository @apache-mynewt-nimble info */ -#ifndef MYNEWT_VAL_REPO_HASH_APACHE_MYNEWT_NIMBLE -#define MYNEWT_VAL_REPO_HASH_APACHE_MYNEWT_NIMBLE ("3e5d7a994e117b2758906154433a1aac860cc845-dirty") +#ifndef MYNEWT_VAL_HARDFLOAT +#define MYNEWT_VAL_HARDFLOAT (0) #endif -#ifndef MYNEWT_VAL_REPO_VERSION_APACHE_MYNEWT_NIMBLE -#define MYNEWT_VAL_REPO_VERSION_APACHE_MYNEWT_NIMBLE ("0.0.0") +#ifndef MYNEWT_VAL_MBEDTLS_AES_ALT +#define MYNEWT_VAL_MBEDTLS_AES_ALT (0) #endif -/*** Repository @mcuboot info */ -#ifndef MYNEWT_VAL_REPO_HASH_MCUBOOT -#define MYNEWT_VAL_REPO_HASH_MCUBOOT ("579b30c29999860f9f7d843a25ff5453b6542cce") +#ifndef MYNEWT_VAL_MBEDTLS_AES_C +#define MYNEWT_VAL_MBEDTLS_AES_C (1) #endif -#ifndef MYNEWT_VAL_REPO_VERSION_MCUBOOT -#define MYNEWT_VAL_REPO_VERSION_MCUBOOT ("0.0.0") +#ifndef MYNEWT_VAL_MBEDTLS_AES_FEWER_TABLES +#define MYNEWT_VAL_MBEDTLS_AES_FEWER_TABLES (0) #endif +#ifndef MYNEWT_VAL_MBEDTLS_AES_ROM_TABLES +#define MYNEWT_VAL_MBEDTLS_AES_ROM_TABLES (0) +#endif +#ifndef MYNEWT_VAL_MBEDTLS_ARC4_C +#define MYNEWT_VAL_MBEDTLS_ARC4_C (0) +#endif -/*** @apache-mynewt-core/compiler/arm-none-eabi-m4 */ -#ifndef MYNEWT_VAL_HARDFLOAT -#define MYNEWT_VAL_HARDFLOAT (0) +#ifndef MYNEWT_VAL_MBEDTLS_ARIA_C +#define MYNEWT_VAL_MBEDTLS_ARIA_C (0) +#endif + +#ifndef MYNEWT_VAL_MBEDTLS_BASE64_C +#define MYNEWT_VAL_MBEDTLS_BASE64_C (1) +#endif + +#ifndef MYNEWT_VAL_MBEDTLS_BIGNUM_ALT +#define MYNEWT_VAL_MBEDTLS_BIGNUM_ALT (0) +#endif + +#ifndef MYNEWT_VAL_MBEDTLS_BLOWFISH_C +#define MYNEWT_VAL_MBEDTLS_BLOWFISH_C (0) +#endif + +#ifndef MYNEWT_VAL_MBEDTLS_CAMELLIA_C +#define MYNEWT_VAL_MBEDTLS_CAMELLIA_C (0) +#endif + +#ifndef MYNEWT_VAL_MBEDTLS_CCM_C +#define MYNEWT_VAL_MBEDTLS_CCM_C (0) +#endif + +#ifndef MYNEWT_VAL_MBEDTLS_CHACHA20_C +#define MYNEWT_VAL_MBEDTLS_CHACHA20_C (0) +#endif + +#ifndef MYNEWT_VAL_MBEDTLS_CHACHAPOLY_C +#define MYNEWT_VAL_MBEDTLS_CHACHAPOLY_C (0) +#endif + +#ifndef MYNEWT_VAL_MBEDTLS_CIPHER_MODE_CBC +#define MYNEWT_VAL_MBEDTLS_CIPHER_MODE_CBC (0) +#endif + +#ifndef MYNEWT_VAL_MBEDTLS_CIPHER_MODE_CFB +#define MYNEWT_VAL_MBEDTLS_CIPHER_MODE_CFB (0) +#endif + +#ifndef MYNEWT_VAL_MBEDTLS_CIPHER_MODE_CTR +#define MYNEWT_VAL_MBEDTLS_CIPHER_MODE_CTR (0) +#endif + +#ifndef MYNEWT_VAL_MBEDTLS_CIPHER_MODE_OFB +#define MYNEWT_VAL_MBEDTLS_CIPHER_MODE_OFB (0) +#endif + +#ifndef MYNEWT_VAL_MBEDTLS_CIPHER_MODE_XTS +#define MYNEWT_VAL_MBEDTLS_CIPHER_MODE_XTS (0) +#endif + +#ifndef MYNEWT_VAL_MBEDTLS_CMAC_C +#define MYNEWT_VAL_MBEDTLS_CMAC_C (0) +#endif + +#ifndef MYNEWT_VAL_MBEDTLS_CTR_DRBG_C +#define MYNEWT_VAL_MBEDTLS_CTR_DRBG_C (0) +#endif + +#ifndef MYNEWT_VAL_MBEDTLS_DES_C +#define MYNEWT_VAL_MBEDTLS_DES_C (0) +#endif + +#ifndef MYNEWT_VAL_MBEDTLS_ECDH_COMPUTE_SHARED_ALT +#define MYNEWT_VAL_MBEDTLS_ECDH_COMPUTE_SHARED_ALT (0) +#endif + +#ifndef MYNEWT_VAL_MBEDTLS_ECDH_GEN_PUBLIC_ALT +#define MYNEWT_VAL_MBEDTLS_ECDH_GEN_PUBLIC_ALT (0) +#endif + +#ifndef MYNEWT_VAL_MBEDTLS_ECDSA_GENKEY_ALT +#define MYNEWT_VAL_MBEDTLS_ECDSA_GENKEY_ALT (0) +#endif + +#ifndef MYNEWT_VAL_MBEDTLS_ECDSA_SIGN_ALT +#define MYNEWT_VAL_MBEDTLS_ECDSA_SIGN_ALT (0) +#endif + +#ifndef MYNEWT_VAL_MBEDTLS_ECDSA_VERIFY_ALT +#define MYNEWT_VAL_MBEDTLS_ECDSA_VERIFY_ALT (0) +#endif + +#ifndef MYNEWT_VAL_MBEDTLS_ECJPAKE_C +#define MYNEWT_VAL_MBEDTLS_ECJPAKE_C (0) +#endif + +#ifndef MYNEWT_VAL_MBEDTLS_ECP_ALT +#define MYNEWT_VAL_MBEDTLS_ECP_ALT (0) +#endif + +#ifndef MYNEWT_VAL_MBEDTLS_ECP_DP_BP256R1 +#define MYNEWT_VAL_MBEDTLS_ECP_DP_BP256R1 (0) +#endif + +#ifndef MYNEWT_VAL_MBEDTLS_ECP_DP_BP384R1 +#define MYNEWT_VAL_MBEDTLS_ECP_DP_BP384R1 (0) +#endif + +#ifndef MYNEWT_VAL_MBEDTLS_ECP_DP_BP512R1 +#define MYNEWT_VAL_MBEDTLS_ECP_DP_BP512R1 (0) +#endif + +#ifndef MYNEWT_VAL_MBEDTLS_ECP_DP_CURVE25519 +#define MYNEWT_VAL_MBEDTLS_ECP_DP_CURVE25519 (0) +#endif + +#ifndef MYNEWT_VAL_MBEDTLS_ECP_DP_CURVE448 +#define MYNEWT_VAL_MBEDTLS_ECP_DP_CURVE448 (0) +#endif + +#ifndef MYNEWT_VAL_MBEDTLS_ECP_DP_SECP192K1 +#define MYNEWT_VAL_MBEDTLS_ECP_DP_SECP192K1 (0) +#endif + +#ifndef MYNEWT_VAL_MBEDTLS_ECP_DP_SECP192R1 +#define MYNEWT_VAL_MBEDTLS_ECP_DP_SECP192R1 (0) +#endif + +#ifndef MYNEWT_VAL_MBEDTLS_ECP_DP_SECP224K1 +#define MYNEWT_VAL_MBEDTLS_ECP_DP_SECP224K1 (0) +#endif + +#ifndef MYNEWT_VAL_MBEDTLS_ECP_DP_SECP224R1 +#define MYNEWT_VAL_MBEDTLS_ECP_DP_SECP224R1 (0) +#endif + +#ifndef MYNEWT_VAL_MBEDTLS_ECP_DP_SECP256K1 +#define MYNEWT_VAL_MBEDTLS_ECP_DP_SECP256K1 (0) +#endif + +#ifndef MYNEWT_VAL_MBEDTLS_ECP_DP_SECP256R1 +#define MYNEWT_VAL_MBEDTLS_ECP_DP_SECP256R1 (1) +#endif + +#ifndef MYNEWT_VAL_MBEDTLS_ECP_DP_SECP384R1 +#define MYNEWT_VAL_MBEDTLS_ECP_DP_SECP384R1 (0) +#endif + +#ifndef MYNEWT_VAL_MBEDTLS_ECP_DP_SECP521R1 +#define MYNEWT_VAL_MBEDTLS_ECP_DP_SECP521R1 (0) +#endif + +#ifndef MYNEWT_VAL_MBEDTLS_ECP_RESTARTABLE +#define MYNEWT_VAL_MBEDTLS_ECP_RESTARTABLE (0) +#endif + +#ifndef MYNEWT_VAL_MBEDTLS_ENTROPY_C +#define MYNEWT_VAL_MBEDTLS_ENTROPY_C (1) +#endif + +#ifndef MYNEWT_VAL_MBEDTLS_ENTROPY_HARDWARE_ALT +#define MYNEWT_VAL_MBEDTLS_ENTROPY_HARDWARE_ALT (0) +#endif + +#ifndef MYNEWT_VAL_MBEDTLS_GENPRIME +#define MYNEWT_VAL_MBEDTLS_GENPRIME (0) +#endif + +#ifndef MYNEWT_VAL_MBEDTLS_HKDF_C +#define MYNEWT_VAL_MBEDTLS_HKDF_C (0) +#endif + +#ifndef MYNEWT_VAL_MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED +#define MYNEWT_VAL_MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED (0) +#endif + +#ifndef MYNEWT_VAL_MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED +#define MYNEWT_VAL_MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED (0) +#endif + +#ifndef MYNEWT_VAL_MBEDTLS_KEY_EXCHANGE_RSA_ENABLED +#define MYNEWT_VAL_MBEDTLS_KEY_EXCHANGE_RSA_ENABLED (0) +#endif + +#ifndef MYNEWT_VAL_MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED +#define MYNEWT_VAL_MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED (0) +#endif + +#ifndef MYNEWT_VAL_MBEDTLS_MD2_C +#define MYNEWT_VAL_MBEDTLS_MD2_C (0) +#endif + +#ifndef MYNEWT_VAL_MBEDTLS_MD4_C +#define MYNEWT_VAL_MBEDTLS_MD4_C (0) +#endif + +#ifndef MYNEWT_VAL_MBEDTLS_MD5_C +#define MYNEWT_VAL_MBEDTLS_MD5_C (0) +#endif + +#ifndef MYNEWT_VAL_MBEDTLS_MPI_MAX_SIZE +#define MYNEWT_VAL_MBEDTLS_MPI_MAX_SIZE (1024) +#endif + +#ifndef MYNEWT_VAL_MBEDTLS_NIST_KW_C +#define MYNEWT_VAL_MBEDTLS_NIST_KW_C (0) +#endif + +#ifndef MYNEWT_VAL_MBEDTLS_PKCS1_V15 +#define MYNEWT_VAL_MBEDTLS_PKCS1_V15 (1) +#endif + +#ifndef MYNEWT_VAL_MBEDTLS_PKCS1_V21 +#define MYNEWT_VAL_MBEDTLS_PKCS1_V21 (1) +#endif + +#ifndef MYNEWT_VAL_MBEDTLS_POLY1305_C +#define MYNEWT_VAL_MBEDTLS_POLY1305_C (0) +#endif + +#ifndef MYNEWT_VAL_MBEDTLS_RIPEMD160_C +#define MYNEWT_VAL_MBEDTLS_RIPEMD160_C (0) +#endif + +#ifndef MYNEWT_VAL_MBEDTLS_SHA1_C +#define MYNEWT_VAL_MBEDTLS_SHA1_C (0) +#endif + +#ifndef MYNEWT_VAL_MBEDTLS_SHA256_ALT +#define MYNEWT_VAL_MBEDTLS_SHA256_ALT (0) +#endif + +#ifndef MYNEWT_VAL_MBEDTLS_SHA256_C +#define MYNEWT_VAL_MBEDTLS_SHA256_C (1) +#endif + +#ifndef MYNEWT_VAL_MBEDTLS_SHA512_C +#define MYNEWT_VAL_MBEDTLS_SHA512_C (0) +#endif + +#ifndef MYNEWT_VAL_MBEDTLS_SSL_TLS_C +#define MYNEWT_VAL_MBEDTLS_SSL_TLS_C (0) +#endif + +#ifndef MYNEWT_VAL_MBEDTLS_TIMING_C +#define MYNEWT_VAL_MBEDTLS_TIMING_C (0) +#endif + +#ifndef MYNEWT_VAL_TINYCRYPT_SYSINIT_STAGE +#define MYNEWT_VAL_TINYCRYPT_SYSINIT_STAGE (200) +#endif + +#ifndef MYNEWT_VAL_TINYCRYPT_UECC_RNG_TRNG_DEV_NAME +#define MYNEWT_VAL_TINYCRYPT_UECC_RNG_TRNG_DEV_NAME "trng" +#endif + +#ifndef MYNEWT_VAL_TINYCRYPT_UECC_RNG_USE_TRNG +#define MYNEWT_VAL_TINYCRYPT_UECC_RNG_USE_TRNG (0) #endif -/*** @apache-mynewt-core/hw/bsp/nordic_pca10056 */ #ifndef MYNEWT_VAL_BSP_NRF52840 #define MYNEWT_VAL_BSP_NRF52840 (1) #endif @@ -68,11 +329,14 @@ #define MYNEWT_VAL_SOFT_PWM (0) #endif -/*** @apache-mynewt-core/hw/hal */ #ifndef MYNEWT_VAL_HAL_ENABLE_SOFTWARE_BREAKPOINTS #define MYNEWT_VAL_HAL_ENABLE_SOFTWARE_BREAKPOINTS (1) #endif +#ifndef MYNEWT_VAL_HAL_FLASH_MAX_DEVICE_COUNT +#define MYNEWT_VAL_HAL_FLASH_MAX_DEVICE_COUNT (0) +#endif + #ifndef MYNEWT_VAL_HAL_FLASH_VERIFY_BUF_SZ #define MYNEWT_VAL_HAL_FLASH_VERIFY_BUF_SZ (16) #endif @@ -85,11 +349,14 @@ #define MYNEWT_VAL_HAL_FLASH_VERIFY_WRITES (0) #endif +#ifndef MYNEWT_VAL_HAL_SBRK +#define MYNEWT_VAL_HAL_SBRK (1) +#endif + #ifndef MYNEWT_VAL_HAL_SYSTEM_RESET_CB #define MYNEWT_VAL_HAL_SYSTEM_RESET_CB (0) #endif -/*** @apache-mynewt-core/hw/mcu/nordic/nrf52xxx */ #ifndef MYNEWT_VAL_ADC_0 #define MYNEWT_VAL_ADC_0 (0) #endif @@ -103,7 +370,7 @@ #endif #ifndef MYNEWT_VAL_GPIO_AS_PIN_RESET -#define MYNEWT_VAL_GPIO_AS_PIN_RESET (0) +#define MYNEWT_VAL_GPIO_AS_PIN_RESET (1) #endif #ifndef MYNEWT_VAL_I2C_0 @@ -114,12 +381,10 @@ #define MYNEWT_VAL_I2C_0_FREQ_KHZ (100) #endif -/* Overridden by @apache-mynewt-core/hw/bsp/nordic_pca10056 (defined by @apache-mynewt-core/hw/mcu/nordic/nrf52xxx) */ #ifndef MYNEWT_VAL_I2C_0_PIN_SCL #define MYNEWT_VAL_I2C_0_PIN_SCL (27) #endif -/* Overridden by @apache-mynewt-core/hw/bsp/nordic_pca10056 (defined by @apache-mynewt-core/hw/mcu/nordic/nrf52xxx) */ #ifndef MYNEWT_VAL_I2C_0_PIN_SDA #define MYNEWT_VAL_I2C_0_PIN_SDA (26) #endif @@ -136,11 +401,27 @@ #undef MYNEWT_VAL_I2C_1_PIN_SDA +#ifndef MYNEWT_VAL_MCU_ACCESS_PORT_PROTECTION__default +#define MYNEWT_VAL_MCU_ACCESS_PORT_PROTECTION__default (0) +#endif +#ifndef MYNEWT_VAL_MCU_ACCESS_PORT_PROTECTION__disable +#define MYNEWT_VAL_MCU_ACCESS_PORT_PROTECTION__disable (1) +#endif +#ifndef MYNEWT_VAL_MCU_ACCESS_PORT_PROTECTION__enable +#define MYNEWT_VAL_MCU_ACCESS_PORT_PROTECTION__enable (0) +#endif +#ifndef MYNEWT_VAL_MCU_ACCESS_PORT_PROTECTION +#define MYNEWT_VAL_MCU_ACCESS_PORT_PROTECTION (1) +#endif + #ifndef MYNEWT_VAL_MCU_BUS_DRIVER_I2C_USE_TWIM #define MYNEWT_VAL_MCU_BUS_DRIVER_I2C_USE_TWIM (0) #endif -/* Overridden by @apache-mynewt-core/hw/bsp/nordic_pca10056 (defined by @apache-mynewt-core/hw/mcu/nordic/nrf52xxx) */ +#ifndef MYNEWT_VAL_MCU_COMMON_STARTUP +#define MYNEWT_VAL_MCU_COMMON_STARTUP (1) +#endif + #ifndef MYNEWT_VAL_MCU_DCDC_ENABLED #define MYNEWT_VAL_MCU_DCDC_ENABLED (1) #endif @@ -157,11 +438,24 @@ #define MYNEWT_VAL_MCU_GPIO_USE_PORT_EVENT (0) #endif +#ifndef MYNEWT_VAL_MCU_HFCLK_SOURCE__HFINT +#define MYNEWT_VAL_MCU_HFCLK_SOURCE__HFINT (0) +#endif +#ifndef MYNEWT_VAL_MCU_HFCLK_SOURCE__HFXO +#define MYNEWT_VAL_MCU_HFCLK_SOURCE__HFXO (1) +#endif +#ifndef MYNEWT_VAL_MCU_HFCLK_SOURCE +#define MYNEWT_VAL_MCU_HFCLK_SOURCE (1) +#endif + #ifndef MYNEWT_VAL_MCU_I2C_RECOVERY_DELAY_USEC #define MYNEWT_VAL_MCU_I2C_RECOVERY_DELAY_USEC (100) #endif -/* Overridden by @apache-mynewt-core/hw/bsp/nordic_pca10056 (defined by @apache-mynewt-core/hw/mcu/nordic/nrf52xxx) */ +#ifndef MYNEWT_VAL_MCU_ICACHE_ENABLED +#define MYNEWT_VAL_MCU_ICACHE_ENABLED (1) +#endif + #ifndef MYNEWT_VAL_MCU_LFCLK_SOURCE__LFRC #define MYNEWT_VAL_MCU_LFCLK_SOURCE__LFRC (0) #endif @@ -183,7 +477,6 @@ #define MYNEWT_VAL_MCU_NRF52840 (0) #endif -/* Overridden by @apache-mynewt-core/hw/bsp/nordic_pca10056 (defined by @apache-mynewt-core/hw/mcu/nordic/nrf52xxx) */ #ifndef MYNEWT_VAL_MCU_TARGET__nRF52810 #define MYNEWT_VAL_MCU_TARGET__nRF52810 (0) #endif @@ -204,10 +497,6 @@ #define MYNEWT_VAL_NFC_PINS_AS_GPIO (1) #endif -#ifndef MYNEWT_VAL_OS_TICKS_PER_SEC -#define MYNEWT_VAL_OS_TICKS_PER_SEC (128) -#endif - #ifndef MYNEWT_VAL_PWM_0 #define MYNEWT_VAL_PWM_0 (0) #endif @@ -236,47 +525,38 @@ #define MYNEWT_VAL_QSPI_ENABLE (0) #endif -/* Overridden by @apache-mynewt-core/hw/bsp/nordic_pca10056 (defined by @apache-mynewt-core/hw/mcu/nordic/nrf52xxx) */ #ifndef MYNEWT_VAL_QSPI_FLASH_PAGE_SIZE #define MYNEWT_VAL_QSPI_FLASH_PAGE_SIZE (256) #endif -/* Overridden by @apache-mynewt-core/hw/bsp/nordic_pca10056 (defined by @apache-mynewt-core/hw/mcu/nordic/nrf52xxx) */ #ifndef MYNEWT_VAL_QSPI_FLASH_SECTOR_COUNT #define MYNEWT_VAL_QSPI_FLASH_SECTOR_COUNT (4096) #endif -/* Overridden by @apache-mynewt-core/hw/bsp/nordic_pca10056 (defined by @apache-mynewt-core/hw/mcu/nordic/nrf52xxx) */ #ifndef MYNEWT_VAL_QSPI_FLASH_SECTOR_SIZE #define MYNEWT_VAL_QSPI_FLASH_SECTOR_SIZE (4096) #endif -/* Overridden by @apache-mynewt-core/hw/bsp/nordic_pca10056 (defined by @apache-mynewt-core/hw/mcu/nordic/nrf52xxx) */ #ifndef MYNEWT_VAL_QSPI_PIN_CS #define MYNEWT_VAL_QSPI_PIN_CS (17) #endif -/* Overridden by @apache-mynewt-core/hw/bsp/nordic_pca10056 (defined by @apache-mynewt-core/hw/mcu/nordic/nrf52xxx) */ #ifndef MYNEWT_VAL_QSPI_PIN_DIO0 #define MYNEWT_VAL_QSPI_PIN_DIO0 (20) #endif -/* Overridden by @apache-mynewt-core/hw/bsp/nordic_pca10056 (defined by @apache-mynewt-core/hw/mcu/nordic/nrf52xxx) */ #ifndef MYNEWT_VAL_QSPI_PIN_DIO1 #define MYNEWT_VAL_QSPI_PIN_DIO1 (21) #endif -/* Overridden by @apache-mynewt-core/hw/bsp/nordic_pca10056 (defined by @apache-mynewt-core/hw/mcu/nordic/nrf52xxx) */ #ifndef MYNEWT_VAL_QSPI_PIN_DIO2 #define MYNEWT_VAL_QSPI_PIN_DIO2 (22) #endif -/* Overridden by @apache-mynewt-core/hw/bsp/nordic_pca10056 (defined by @apache-mynewt-core/hw/mcu/nordic/nrf52xxx) */ #ifndef MYNEWT_VAL_QSPI_PIN_DIO3 #define MYNEWT_VAL_QSPI_PIN_DIO3 (23) #endif -/* Overridden by @apache-mynewt-core/hw/bsp/nordic_pca10056 (defined by @apache-mynewt-core/hw/mcu/nordic/nrf52xxx) */ #ifndef MYNEWT_VAL_QSPI_PIN_SCK #define MYNEWT_VAL_QSPI_PIN_SCK (19) #endif @@ -301,45 +581,42 @@ #define MYNEWT_VAL_QSPI_WRITEOC (0) #endif +#ifndef MYNEWT_VAL_QSPI_XIP_OFFSET +#define MYNEWT_VAL_QSPI_XIP_OFFSET (0x10000000) +#endif + #ifndef MYNEWT_VAL_SPI_0_MASTER #define MYNEWT_VAL_SPI_0_MASTER (0) #endif -/* Overridden by @apache-mynewt-core/hw/bsp/nordic_pca10056 (defined by @apache-mynewt-core/hw/mcu/nordic/nrf52xxx) */ #ifndef MYNEWT_VAL_SPI_0_MASTER_PIN_MISO -#define MYNEWT_VAL_SPI_0_MASTER_PIN_MISO (47) +#define MYNEWT_VAL_SPI_0_MASTER_PIN_MISO (46) #endif -/* Overridden by @apache-mynewt-core/hw/bsp/nordic_pca10056 (defined by @apache-mynewt-core/hw/mcu/nordic/nrf52xxx) */ #ifndef MYNEWT_VAL_SPI_0_MASTER_PIN_MOSI -#define MYNEWT_VAL_SPI_0_MASTER_PIN_MOSI (46) +#define MYNEWT_VAL_SPI_0_MASTER_PIN_MOSI (45) #endif -/* Overridden by @apache-mynewt-core/hw/bsp/nordic_pca10056 (defined by @apache-mynewt-core/hw/mcu/nordic/nrf52xxx) */ #ifndef MYNEWT_VAL_SPI_0_MASTER_PIN_SCK -#define MYNEWT_VAL_SPI_0_MASTER_PIN_SCK (45) +#define MYNEWT_VAL_SPI_0_MASTER_PIN_SCK (47) #endif #ifndef MYNEWT_VAL_SPI_0_SLAVE #define MYNEWT_VAL_SPI_0_SLAVE (0) #endif -/* Overridden by @apache-mynewt-core/hw/bsp/nordic_pca10056 (defined by @apache-mynewt-core/hw/mcu/nordic/nrf52xxx) */ #ifndef MYNEWT_VAL_SPI_0_SLAVE_PIN_MISO -#define MYNEWT_VAL_SPI_0_SLAVE_PIN_MISO (47) +#define MYNEWT_VAL_SPI_0_SLAVE_PIN_MISO (46) #endif -/* Overridden by @apache-mynewt-core/hw/bsp/nordic_pca10056 (defined by @apache-mynewt-core/hw/mcu/nordic/nrf52xxx) */ #ifndef MYNEWT_VAL_SPI_0_SLAVE_PIN_MOSI -#define MYNEWT_VAL_SPI_0_SLAVE_PIN_MOSI (46) +#define MYNEWT_VAL_SPI_0_SLAVE_PIN_MOSI (45) #endif -/* Overridden by @apache-mynewt-core/hw/bsp/nordic_pca10056 (defined by @apache-mynewt-core/hw/mcu/nordic/nrf52xxx) */ #ifndef MYNEWT_VAL_SPI_0_SLAVE_PIN_SCK -#define MYNEWT_VAL_SPI_0_SLAVE_PIN_SCK (45) +#define MYNEWT_VAL_SPI_0_SLAVE_PIN_SCK (47) #endif -/* Overridden by @apache-mynewt-core/hw/bsp/nordic_pca10056 (defined by @apache-mynewt-core/hw/mcu/nordic/nrf52xxx) */ #ifndef MYNEWT_VAL_SPI_0_SLAVE_PIN_SS #define MYNEWT_VAL_SPI_0_SLAVE_PIN_SS (44) #endif @@ -402,7 +679,6 @@ #define MYNEWT_VAL_TEMP (0) #endif -/* Overridden by @apache-mynewt-core/hw/bsp/nordic_pca10056 (defined by @apache-mynewt-core/hw/mcu/nordic/nrf52xxx) */ #ifndef MYNEWT_VAL_TIMER_0 #define MYNEWT_VAL_TIMER_0 (0) #endif @@ -423,7 +699,6 @@ #define MYNEWT_VAL_TIMER_4 (0) #endif -/* Overridden by @apache-mynewt-core/hw/bsp/nordic_pca10056 (defined by @apache-mynewt-core/hw/mcu/nordic/nrf52xxx) */ #ifndef MYNEWT_VAL_TIMER_5 #define MYNEWT_VAL_TIMER_5 (1) #endif @@ -436,22 +711,18 @@ #define MYNEWT_VAL_UART_0 (1) #endif -/* Overridden by @apache-mynewt-core/hw/bsp/nordic_pca10056 (defined by @apache-mynewt-core/hw/mcu/nordic/nrf52xxx) */ #ifndef MYNEWT_VAL_UART_0_PIN_CTS #define MYNEWT_VAL_UART_0_PIN_CTS (7) #endif -/* Overridden by @apache-mynewt-core/hw/bsp/nordic_pca10056 (defined by @apache-mynewt-core/hw/mcu/nordic/nrf52xxx) */ #ifndef MYNEWT_VAL_UART_0_PIN_RTS #define MYNEWT_VAL_UART_0_PIN_RTS (5) #endif -/* Overridden by @apache-mynewt-core/hw/bsp/nordic_pca10056 (defined by @apache-mynewt-core/hw/mcu/nordic/nrf52xxx) */ #ifndef MYNEWT_VAL_UART_0_PIN_RX #define MYNEWT_VAL_UART_0_PIN_RX (8) #endif -/* Overridden by @apache-mynewt-core/hw/bsp/nordic_pca10056 (defined by @apache-mynewt-core/hw/mcu/nordic/nrf52xxx) */ #ifndef MYNEWT_VAL_UART_0_PIN_TX #define MYNEWT_VAL_UART_0_PIN_TX (6) #endif @@ -472,9 +743,8 @@ #undef MYNEWT_VAL_UART_1_PIN_TX -/* Overridden by @apache-mynewt-nimble/porting/targets/riot (defined by @apache-mynewt-core/hw/mcu/nordic/nrf52xxx) */ #ifndef MYNEWT_VAL_XTAL_32768 -#define MYNEWT_VAL_XTAL_32768 (1) +#define MYNEWT_VAL_XTAL_32768 (0) #endif #ifndef MYNEWT_VAL_XTAL_32768_SYNTH @@ -485,17 +755,88 @@ #define MYNEWT_VAL_XTAL_RC (0) #endif -/*** @apache-mynewt-core/kernel/os */ +#ifndef MYNEWT_VAL_JLINK_TARGET +#define MYNEWT_VAL_JLINK_TARGET (NRF52) +#endif + +#ifndef MYNEWT_VAL_MYNEWT_DEBUGGER__jlink +#define MYNEWT_VAL_MYNEWT_DEBUGGER__jlink (0) +#endif +#ifndef MYNEWT_VAL_MYNEWT_DEBUGGER__openocd +#define MYNEWT_VAL_MYNEWT_DEBUGGER__openocd (0) +#endif +#ifndef MYNEWT_VAL_MYNEWT_DEBUGGER__pyocd +#define MYNEWT_VAL_MYNEWT_DEBUGGER__pyocd (0) +#endif +#ifndef MYNEWT_VAL_MYNEWT_DEBUGGER__st_link_gdbserver +#define MYNEWT_VAL_MYNEWT_DEBUGGER__st_link_gdbserver (0) +#endif +#ifndef MYNEWT_VAL_MYNEWT_DEBUGGER__stutil +#define MYNEWT_VAL_MYNEWT_DEBUGGER__stutil (0) +#endif +#undef MYNEWT_VAL_MYNEWT_DEBUGGER + +#undef MYNEWT_VAL_MYNEWT_DEBUGGER_SN + +#ifndef MYNEWT_VAL_MYNEWT_DOWNLOADER__bsp_downloader +#define MYNEWT_VAL_MYNEWT_DOWNLOADER__bsp_downloader (0) +#endif +#ifndef MYNEWT_VAL_MYNEWT_DOWNLOADER__ezflashcli +#define MYNEWT_VAL_MYNEWT_DOWNLOADER__ezflashcli (0) +#endif +#ifndef MYNEWT_VAL_MYNEWT_DOWNLOADER__jlink +#define MYNEWT_VAL_MYNEWT_DOWNLOADER__jlink (0) +#endif +#ifndef MYNEWT_VAL_MYNEWT_DOWNLOADER__nrfjprog +#define MYNEWT_VAL_MYNEWT_DOWNLOADER__nrfjprog (0) +#endif +#ifndef MYNEWT_VAL_MYNEWT_DOWNLOADER__nrfutil +#define MYNEWT_VAL_MYNEWT_DOWNLOADER__nrfutil (1) +#endif +#ifndef MYNEWT_VAL_MYNEWT_DOWNLOADER__openocd +#define MYNEWT_VAL_MYNEWT_DOWNLOADER__openocd (0) +#endif +#ifndef MYNEWT_VAL_MYNEWT_DOWNLOADER__pyocd +#define MYNEWT_VAL_MYNEWT_DOWNLOADER__pyocd (0) +#endif +#ifndef MYNEWT_VAL_MYNEWT_DOWNLOADER__stflash +#define MYNEWT_VAL_MYNEWT_DOWNLOADER__stflash (0) +#endif +#ifndef MYNEWT_VAL_MYNEWT_DOWNLOADER__stm32_programmer_cli +#define MYNEWT_VAL_MYNEWT_DOWNLOADER__stm32_programmer_cli (0) +#endif +#ifndef MYNEWT_VAL_MYNEWT_DOWNLOADER +#define MYNEWT_VAL_MYNEWT_DOWNLOADER (1) +#endif + +#ifndef MYNEWT_VAL_MYNEWT_DOWNLOADER_MFG_IMAGE_FLASH_OFFSET +#define MYNEWT_VAL_MYNEWT_DOWNLOADER_MFG_IMAGE_FLASH_OFFSET (0x0) +#endif + +#undef MYNEWT_VAL_MYNEWT_DOWNLOADER_OPENOCD_BOARD + +#undef MYNEWT_VAL_MYNEWT_DOWNLOADER_OPENOCD_CFG + +#undef MYNEWT_VAL_MYNEWT_DOWNLOADER_OPENOCD_INTERFACE + +#undef MYNEWT_VAL_MYNEWT_DOWNLOADER_SCRIPT + +#undef MYNEWT_VAL_NRFJPROG_COPROCESSOR + +#undef MYNEWT_VAL_NRFUTIL_TRAITS + +#ifndef MYNEWT_VAL_PYOCD_TARGET +#define MYNEWT_VAL_PYOCD_TARGET (nrf52840) +#endif + #ifndef MYNEWT_VAL_FLOAT_USER #define MYNEWT_VAL_FLOAT_USER (0) #endif -/* Overridden by @apache-mynewt-nimble/porting/targets/riot (defined by @apache-mynewt-core/kernel/os) */ #ifndef MYNEWT_VAL_MSYS_1_BLOCK_COUNT #define MYNEWT_VAL_MSYS_1_BLOCK_COUNT (5) #endif -/* Overridden by @apache-mynewt-nimble/porting/targets/riot (defined by @apache-mynewt-core/kernel/os) */ #ifndef MYNEWT_VAL_MSYS_1_BLOCK_SIZE #define MYNEWT_VAL_MSYS_1_BLOCK_SIZE (88) #endif @@ -532,12 +873,14 @@ #define MYNEWT_VAL_OS_COREDUMP (0) #endif -/* Overridden by @apache-mynewt-core/hw/bsp/nordic_pca10056 (defined by @apache-mynewt-core/kernel/os) */ +#ifndef MYNEWT_VAL_OS_COREDUMP_CB +#define MYNEWT_VAL_OS_COREDUMP_CB (0) +#endif + #ifndef MYNEWT_VAL_OS_CPUTIME_FREQ #define MYNEWT_VAL_OS_CPUTIME_FREQ (32768) #endif -/* Overridden by @apache-mynewt-core/hw/bsp/nordic_pca10056 (defined by @apache-mynewt-core/kernel/os) */ #ifndef MYNEWT_VAL_OS_CPUTIME_TIMER_NUM #define MYNEWT_VAL_OS_CPUTIME_TIMER_NUM (5) #endif @@ -570,6 +913,10 @@ #define MYNEWT_VAL_OS_DEBUG_MODE (0) #endif +#ifndef MYNEWT_VAL_OS_DEFAULT_IRQ_CB +#define MYNEWT_VAL_OS_DEFAULT_IRQ_CB (0) +#endif + #ifndef MYNEWT_VAL_OS_EVENTQ_DEBUG #define MYNEWT_VAL_OS_EVENTQ_DEBUG (0) #endif @@ -650,6 +997,10 @@ #define MYNEWT_VAL_OS_TASK_RUN_TIME_CPUTIME (0) #endif +#ifndef MYNEWT_VAL_OS_TICKS_PER_SEC +#define MYNEWT_VAL_OS_TICKS_PER_SEC (128) +#endif + #ifndef MYNEWT_VAL_OS_TIME_DEBUG #define MYNEWT_VAL_OS_TIME_DEBUG (0) #endif @@ -666,38 +1017,60 @@ #define MYNEWT_VAL_WATCHDOG_INTERVAL (30000) #endif -/*** @apache-mynewt-core/libc/baselibc */ +#ifndef MYNEWT_VAL_LIBC__baselibc +#define MYNEWT_VAL_LIBC__baselibc (1) +#endif +#ifndef MYNEWT_VAL_LIBC__nano +#define MYNEWT_VAL_LIBC__nano (0) +#endif +#ifndef MYNEWT_VAL_LIBC +#define MYNEWT_VAL_LIBC (1) +#endif + #ifndef MYNEWT_VAL_BASELIBC_ASSERT_FILE_LINE #define MYNEWT_VAL_BASELIBC_ASSERT_FILE_LINE (0) #endif +#ifndef MYNEWT_VAL_BASELIBC_DEBUG_MALLOC +#define MYNEWT_VAL_BASELIBC_DEBUG_MALLOC (0) +#endif + +#ifndef MYNEWT_VAL_BASELIBC_EXECUTE_GLOBAL_CONSTRUCTORS +#define MYNEWT_VAL_BASELIBC_EXECUTE_GLOBAL_CONSTRUCTORS (1) +#endif + #ifndef MYNEWT_VAL_BASELIBC_PRESENT #define MYNEWT_VAL_BASELIBC_PRESENT (1) #endif -/*** @apache-mynewt-core/sys/console/stub */ +#ifndef MYNEWT_VAL_BASELIBC_THREAD_SAFE_HEAP_ALLOCATION +#define MYNEWT_VAL_BASELIBC_THREAD_SAFE_HEAP_ALLOCATION (0) +#endif + #ifndef MYNEWT_VAL_CONSOLE_UART_BAUD #define MYNEWT_VAL_CONSOLE_UART_BAUD (115200) #endif #ifndef MYNEWT_VAL_CONSOLE_UART_DEV -#define MYNEWT_VAL_CONSOLE_UART_DEV ("uart0") +#define MYNEWT_VAL_CONSOLE_UART_DEV "uart0" #endif #ifndef MYNEWT_VAL_CONSOLE_UART_FLOW_CONTROL #define MYNEWT_VAL_CONSOLE_UART_FLOW_CONTROL (UART_FLOW_CTL_NONE) #endif -/*** @apache-mynewt-core/sys/flash_map */ #ifndef MYNEWT_VAL_FLASH_MAP_MAX_AREAS #define MYNEWT_VAL_FLASH_MAP_MAX_AREAS (10) #endif +#ifndef MYNEWT_VAL_FLASH_MAP_SUPPORT_MFG +#define MYNEWT_VAL_FLASH_MAP_SUPPORT_MFG (0) +#endif + #ifndef MYNEWT_VAL_FLASH_MAP_SYSINIT_STAGE -#define MYNEWT_VAL_FLASH_MAP_SYSINIT_STAGE (2) +#define MYNEWT_VAL_FLASH_MAP_SYSINIT_STAGE (9) #endif -/*** @apache-mynewt-core/sys/log/common */ #ifndef MYNEWT_VAL_DFLT_LOG_LVL #define MYNEWT_VAL_DFLT_LOG_LVL (1) #endif @@ -710,7 +1083,6 @@ #define MYNEWT_VAL_LOG_GLOBAL_IDX (1) #endif -/*** @apache-mynewt-core/sys/log/modlog */ #ifndef MYNEWT_VAL_MODLOG_CONSOLE_DFLT #define MYNEWT_VAL_MODLOG_CONSOLE_DFLT (1) #endif @@ -731,7 +1103,6 @@ #define MYNEWT_VAL_MODLOG_SYSINIT_STAGE (100) #endif -/*** @apache-mynewt-core/sys/log/stub */ #ifndef MYNEWT_VAL_LOG_CONSOLE #define MYNEWT_VAL_LOG_CONSOLE (1) #endif @@ -748,29 +1119,10 @@ #define MYNEWT_VAL_LOG_LEVEL (255) #endif -/*** @apache-mynewt-core/sys/mfg */ -#ifndef MYNEWT_VAL_MFG_LOG_LVL -#define MYNEWT_VAL_MFG_LOG_LVL (15) -#endif - -#ifndef MYNEWT_VAL_MFG_LOG_MODULE -#define MYNEWT_VAL_MFG_LOG_MODULE (128) -#endif - -#ifndef MYNEWT_VAL_MFG_MAX_MMRS -#define MYNEWT_VAL_MFG_MAX_MMRS (2) -#endif - -#ifndef MYNEWT_VAL_MFG_SYSINIT_STAGE -#define MYNEWT_VAL_MFG_SYSINIT_STAGE (100) -#endif - -/*** @apache-mynewt-core/sys/sys */ #ifndef MYNEWT_VAL_DEBUG_PANIC_ENABLED #define MYNEWT_VAL_DEBUG_PANIC_ENABLED (1) #endif -/*** @apache-mynewt-core/sys/sysdown */ #ifndef MYNEWT_VAL_SYSDOWN_CONSTRAIN_DOWN #define MYNEWT_VAL_SYSDOWN_CONSTRAIN_DOWN (1) #endif @@ -787,7 +1139,6 @@ #define MYNEWT_VAL_SYSDOWN_TIMEOUT_MS (10000) #endif -/*** @apache-mynewt-core/sys/sysinit */ #ifndef MYNEWT_VAL_SYSINIT_CONSTRAIN_INIT #define MYNEWT_VAL_SYSINIT_CONSTRAIN_INIT (1) #endif @@ -800,12 +1151,18 @@ #define MYNEWT_VAL_SYSINIT_PANIC_MESSAGE (0) #endif -/*** @apache-mynewt-core/util/rwlock */ #ifndef MYNEWT_VAL_RWLOCK_DEBUG #define MYNEWT_VAL_RWLOCK_DEBUG (0) #endif -/*** @apache-mynewt-nimble/nimble */ +#ifndef MYNEWT_VAL_BLE_CHANNEL_SOUNDING +#define MYNEWT_VAL_BLE_CHANNEL_SOUNDING (0) +#endif + +#ifndef MYNEWT_VAL_BLE_CONN_SUBRATING +#define MYNEWT_VAL_BLE_CONN_SUBRATING (0) +#endif + #ifndef MYNEWT_VAL_BLE_EXT_ADV #define MYNEWT_VAL_BLE_EXT_ADV (0) #endif @@ -814,15 +1171,26 @@ #define MYNEWT_VAL_BLE_EXT_ADV_MAX_SIZE (31) #endif -/* Overridden by @apache-mynewt-nimble/porting/targets/riot (defined by @apache-mynewt-nimble/nimble) */ #ifndef MYNEWT_VAL_BLE_HCI_VS #define MYNEWT_VAL_BLE_HCI_VS (1) #endif +#ifndef MYNEWT_VAL_BLE_HCI_VS_OCF_OFFSET +#define MYNEWT_VAL_BLE_HCI_VS_OCF_OFFSET (0) +#endif + #ifndef MYNEWT_VAL_BLE_ISO #define MYNEWT_VAL_BLE_ISO (0) #endif +#ifndef MYNEWT_VAL_BLE_ISO_BROADCAST_SINK +#define MYNEWT_VAL_BLE_ISO_BROADCAST_SINK (0) +#endif + +#ifndef MYNEWT_VAL_BLE_ISO_BROADCAST_SOURCE +#define MYNEWT_VAL_BLE_ISO_BROADCAST_SOURCE (0) +#endif + #ifndef MYNEWT_VAL_BLE_ISO_TEST #define MYNEWT_VAL_BLE_ISO_TEST (0) #endif @@ -831,7 +1199,6 @@ #define MYNEWT_VAL_BLE_MAX_CONNECTIONS (1) #endif -/* Overridden by @apache-mynewt-nimble/porting/targets/riot (defined by @apache-mynewt-nimble/nimble) */ #ifndef MYNEWT_VAL_BLE_MAX_PERIODIC_SYNCS #define MYNEWT_VAL_BLE_MAX_PERIODIC_SYNCS (0) #endif @@ -844,10 +1211,26 @@ #define MYNEWT_VAL_BLE_PERIODIC_ADV (0) #endif +#ifndef MYNEWT_VAL_BLE_PERIODIC_ADV_SYNC_BIGINFO_REPORTS +#define MYNEWT_VAL_BLE_PERIODIC_ADV_SYNC_BIGINFO_REPORTS (0) +#endif + #ifndef MYNEWT_VAL_BLE_PERIODIC_ADV_SYNC_TRANSFER #define MYNEWT_VAL_BLE_PERIODIC_ADV_SYNC_TRANSFER (0) #endif +#ifndef MYNEWT_VAL_BLE_PHY_2M +#define MYNEWT_VAL_BLE_PHY_2M (0) +#endif + +#ifndef MYNEWT_VAL_BLE_PHY_CODED +#define MYNEWT_VAL_BLE_PHY_CODED (0) +#endif + +#ifndef MYNEWT_VAL_BLE_POWER_CONTROL +#define MYNEWT_VAL_BLE_POWER_CONTROL (0) +#endif + #ifndef MYNEWT_VAL_BLE_ROLE_BROADCASTER #define MYNEWT_VAL_BLE_ROLE_BROADCASTER (1) #endif @@ -872,7 +1255,6 @@ #define MYNEWT_VAL_BLE_WHITELIST (1) #endif -/*** @apache-mynewt-nimble/nimble/controller */ #ifndef MYNEWT_VAL_BLE_CONTROLLER #define MYNEWT_VAL_BLE_CONTROLLER (1) #endif @@ -881,7 +1263,50 @@ #define MYNEWT_VAL_BLE_DEVICE (1) #endif -/* Overridden by @apache-mynewt-nimble/porting/targets/riot (defined by @apache-mynewt-nimble/nimble/controller) */ +#ifndef MYNEWT_VAL_BLE_FEM_ANTENNA +#define MYNEWT_VAL_BLE_FEM_ANTENNA (0) +#endif + +#ifndef MYNEWT_VAL_BLE_FEM_LNA +#define MYNEWT_VAL_BLE_FEM_LNA (0) +#endif + +#ifndef MYNEWT_VAL_BLE_FEM_LNA_GAIN +#define MYNEWT_VAL_BLE_FEM_LNA_GAIN (0) +#endif + +#ifndef MYNEWT_VAL_BLE_FEM_LNA_GAIN_TUNABLE +#define MYNEWT_VAL_BLE_FEM_LNA_GAIN_TUNABLE (0) +#endif + +#ifndef MYNEWT_VAL_BLE_FEM_LNA_GPIO +#define MYNEWT_VAL_BLE_FEM_LNA_GPIO (-1) +#endif + +#ifndef MYNEWT_VAL_BLE_FEM_LNA_TURN_ON_US +#define MYNEWT_VAL_BLE_FEM_LNA_TURN_ON_US (1) +#endif + +#ifndef MYNEWT_VAL_BLE_FEM_PA +#define MYNEWT_VAL_BLE_FEM_PA (0) +#endif + +#ifndef MYNEWT_VAL_BLE_FEM_PA_GAIN +#define MYNEWT_VAL_BLE_FEM_PA_GAIN (0) +#endif + +#ifndef MYNEWT_VAL_BLE_FEM_PA_GAIN_TUNABLE +#define MYNEWT_VAL_BLE_FEM_PA_GAIN_TUNABLE (0) +#endif + +#ifndef MYNEWT_VAL_BLE_FEM_PA_GPIO +#define MYNEWT_VAL_BLE_FEM_PA_GPIO (-1) +#endif + +#ifndef MYNEWT_VAL_BLE_FEM_PA_TURN_ON_US +#define MYNEWT_VAL_BLE_FEM_PA_TURN_ON_US (1) +#endif + #ifndef MYNEWT_VAL_BLE_HW_WHITELIST_ENABLE #define MYNEWT_VAL_BLE_HW_WHITELIST_ENABLE (0) #endif @@ -890,15 +1315,18 @@ #define MYNEWT_VAL_BLE_LL_ADD_STRICT_SCHED_PERIODS (0) #endif +#ifndef MYNEWT_VAL_BLE_LL_ADV_CODING_SELECTION +#define MYNEWT_VAL_BLE_LL_ADV_CODING_SELECTION (0) +#endif + #ifndef MYNEWT_VAL_BLE_LL_CFG_FEAT_CONN_PARAM_REQ -#define MYNEWT_VAL_BLE_LL_CFG_FEAT_CONN_PARAM_REQ (1) +#define MYNEWT_VAL_BLE_LL_CFG_FEAT_CONN_PARAM_REQ (MYNEWT_VAL_BLE_LL_ROLE_CENTRAL || MYNEWT_VAL_BLE_LL_ROLE_PERIPHERAL) #endif #ifndef MYNEWT_VAL_BLE_LL_CFG_FEAT_CTRL_TO_HOST_FLOW_CONTROL #define MYNEWT_VAL_BLE_LL_CFG_FEAT_CTRL_TO_HOST_FLOW_CONTROL (0) #endif -/* Overridden by @apache-mynewt-nimble/porting/targets/riot (defined by @apache-mynewt-nimble/nimble/controller) */ #ifndef MYNEWT_VAL_BLE_LL_CFG_FEAT_DATA_LEN_EXT #define MYNEWT_VAL_BLE_LL_CFG_FEAT_DATA_LEN_EXT (0) #endif @@ -911,12 +1339,10 @@ #define MYNEWT_VAL_BLE_LL_CFG_FEAT_LE_CODED_PHY (0) #endif -/* Overridden by @apache-mynewt-nimble/porting/targets/riot (defined by @apache-mynewt-nimble/nimble/controller) */ #ifndef MYNEWT_VAL_BLE_LL_CFG_FEAT_LE_CSA2 #define MYNEWT_VAL_BLE_LL_CFG_FEAT_LE_CSA2 (1) #endif -/* Overridden by @apache-mynewt-nimble/porting/targets/riot (defined by @apache-mynewt-nimble/nimble/controller) */ #ifndef MYNEWT_VAL_BLE_LL_CFG_FEAT_LE_ENCRYPTION #define MYNEWT_VAL_BLE_LL_CFG_FEAT_LE_ENCRYPTION (0) #endif @@ -925,42 +1351,34 @@ #define MYNEWT_VAL_BLE_LL_CFG_FEAT_LE_PING (MYNEWT_VAL_BLE_LL_CFG_FEAT_LE_ENCRYPTION) #endif -/* Value copied from BLE_EXT_ADV */ -#ifndef MYNEWT_VAL_BLE_LL_CFG_FEAT_LL_EXT_ADV -#define MYNEWT_VAL_BLE_LL_CFG_FEAT_LL_EXT_ADV (0) +#ifndef MYNEWT_VAL_BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE +#define MYNEWT_VAL_BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE (0) #endif -/* Value copied from BLE_ISO */ -#ifndef MYNEWT_VAL_BLE_LL_CFG_FEAT_LL_ISO -#define MYNEWT_VAL_BLE_LL_CFG_FEAT_LL_ISO (0) -#endif - -/* Value copied from BLE_ISO_TEST */ -#ifndef MYNEWT_VAL_BLE_LL_CFG_FEAT_LL_ISO_TEST -#define MYNEWT_VAL_BLE_LL_CFG_FEAT_LL_ISO_TEST (0) +#ifndef MYNEWT_VAL_BLE_LL_CFG_FEAT_LL_EXT_ADV +#define MYNEWT_VAL_BLE_LL_CFG_FEAT_LL_EXT_ADV (0) #endif -/* Value copied from BLE_PERIODIC_ADV */ #ifndef MYNEWT_VAL_BLE_LL_CFG_FEAT_LL_PERIODIC_ADV #define MYNEWT_VAL_BLE_LL_CFG_FEAT_LL_PERIODIC_ADV (0) #endif -/* Value copied from BLE_MAX_PERIODIC_SYNCS */ +#ifndef MYNEWT_VAL_BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_ADI_SUPPORT +#define MYNEWT_VAL_BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_ADI_SUPPORT (0) +#endif + #ifndef MYNEWT_VAL_BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_CNT #define MYNEWT_VAL_BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_CNT (0) #endif -/* Value copied from BLE_MAX_PERIODIC_SYNCS */ #ifndef MYNEWT_VAL_BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_LIST_CNT #define MYNEWT_VAL_BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_LIST_CNT (0) #endif -/* Value copied from BLE_PERIODIC_ADV_SYNC_TRANSFER */ #ifndef MYNEWT_VAL_BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER #define MYNEWT_VAL_BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER (0) #endif -/* Overridden by @apache-mynewt-nimble/porting/targets/riot (defined by @apache-mynewt-nimble/nimble/controller) */ #ifndef MYNEWT_VAL_BLE_LL_CFG_FEAT_LL_PRIVACY #define MYNEWT_VAL_BLE_LL_CFG_FEAT_LL_PRIVACY (0) #endif @@ -969,11 +1387,26 @@ #define MYNEWT_VAL_BLE_LL_CFG_FEAT_LL_SCA_UPDATE (0) #endif +#ifndef MYNEWT_VAL_BLE_LL_CFG_FEAT_PERIPH_INIT_FEAT_XCHG +#define MYNEWT_VAL_BLE_LL_CFG_FEAT_PERIPH_INIT_FEAT_XCHG (MYNEWT_VAL_BLE_LL_ROLE_CENTRAL || MYNEWT_VAL_BLE_LL_ROLE_PERIPHERAL) +#endif + #ifndef MYNEWT_VAL_BLE_LL_CFG_FEAT_SLAVE_INIT_FEAT_XCHG -#define MYNEWT_VAL_BLE_LL_CFG_FEAT_SLAVE_INIT_FEAT_XCHG (1) +#define MYNEWT_VAL_BLE_LL_CFG_FEAT_SLAVE_INIT_FEAT_XCHG (0) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_CHANNEL_SOUNDING +#define MYNEWT_VAL_BLE_LL_CHANNEL_SOUNDING (0) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_CONN_EVENT_END_MARGIN +#define MYNEWT_VAL_BLE_LL_CONN_EVENT_END_MARGIN (0) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_CONN_INIT_AUTO_DLE +#define MYNEWT_VAL_BLE_LL_CONN_INIT_AUTO_DLE (1) #endif -/* Overridden by @apache-mynewt-nimble/porting/targets/riot (defined by @apache-mynewt-nimble/nimble/controller) */ #ifndef MYNEWT_VAL_BLE_LL_CONN_INIT_MAX_TX_BYTES #define MYNEWT_VAL_BLE_LL_CONN_INIT_MAX_TX_BYTES (MYNEWT_VAL_BLE_LL_MAX_PKT_SIZE) #endif @@ -986,6 +1419,34 @@ #define MYNEWT_VAL_BLE_LL_CONN_INIT_SLOTS (4) #endif +#ifndef MYNEWT_VAL_BLE_LL_CONN_PHY_DEFAULT_PREF_MASK +#define MYNEWT_VAL_BLE_LL_CONN_PHY_DEFAULT_PREF_MASK (0x07) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_CONN_PHY_INIT_UPDATE +#define MYNEWT_VAL_BLE_LL_CONN_PHY_INIT_UPDATE (0) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_CONN_PHY_PREFER_2M +#define MYNEWT_VAL_BLE_LL_CONN_PHY_PREFER_2M (0) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_CONN_STRICT_SCHED +#define MYNEWT_VAL_BLE_LL_CONN_STRICT_SCHED (0) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_CONN_STRICT_SCHED_FIXED +#define MYNEWT_VAL_BLE_LL_CONN_STRICT_SCHED_FIXED (0) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_CONN_STRICT_SCHED_PERIOD_SLOTS +#define MYNEWT_VAL_BLE_LL_CONN_STRICT_SCHED_PERIOD_SLOTS (8) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_CONN_STRICT_SCHED_SLOT_US +#define MYNEWT_VAL_BLE_LL_CONN_STRICT_SCHED_SLOT_US (3750) +#endif + #ifndef MYNEWT_VAL_BLE_LL_DEBUG_GPIO_HCI_CMD #define MYNEWT_VAL_BLE_LL_DEBUG_GPIO_HCI_CMD (-1) #endif @@ -994,8 +1455,12 @@ #define MYNEWT_VAL_BLE_LL_DEBUG_GPIO_HCI_EV (-1) #endif -#ifndef MYNEWT_VAL_BLE_LL_DEBUG_GPIO_SCHED_ITEM_CB -#define MYNEWT_VAL_BLE_LL_DEBUG_GPIO_SCHED_ITEM_CB (-1) +#ifndef MYNEWT_VAL_BLE_LL_DEBUG_GPIO_RFMGMT +#define MYNEWT_VAL_BLE_LL_DEBUG_GPIO_RFMGMT (-1) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_DEBUG_GPIO_SCHED_ITEM +#define MYNEWT_VAL_BLE_LL_DEBUG_GPIO_SCHED_ITEM (-1) #endif #ifndef MYNEWT_VAL_BLE_LL_DEBUG_GPIO_SCHED_RUN @@ -1006,7 +1471,6 @@ #define MYNEWT_VAL_BLE_LL_DIRECT_TEST_MODE (0) #endif -/* Value copied from BLE_LL_DIRECT_TEST_MODE */ #ifndef MYNEWT_VAL_BLE_LL_DTM #define MYNEWT_VAL_BLE_LL_DTM (0) #endif @@ -1015,10 +1479,82 @@ #define MYNEWT_VAL_BLE_LL_DTM_EXTENSIONS (0) #endif +#ifndef MYNEWT_VAL_BLE_LL_EXT +#define MYNEWT_VAL_BLE_LL_EXT (0) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_EXT_ADV_ADVA_IN_AUX +#define MYNEWT_VAL_BLE_LL_EXT_ADV_ADVA_IN_AUX (1) +#endif + #ifndef MYNEWT_VAL_BLE_LL_EXT_ADV_AUX_PTR_CNT #define MYNEWT_VAL_BLE_LL_EXT_ADV_AUX_PTR_CNT (0) #endif +#ifndef MYNEWT_VAL_BLE_LL_HBD_FAKE_DUAL_MODE +#define MYNEWT_VAL_BLE_LL_HBD_FAKE_DUAL_MODE (0) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_HCI_LLCP_TRACE +#define MYNEWT_VAL_BLE_LL_HCI_LLCP_TRACE (0) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_HCI_VS +#define MYNEWT_VAL_BLE_LL_HCI_VS (1) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_HCI_VS_CONN_STRICT_SCHED +#define MYNEWT_VAL_BLE_LL_HCI_VS_CONN_STRICT_SCHED (0) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_HCI_VS_EVENT_ON_ASSERT +#define MYNEWT_VAL_BLE_LL_HCI_VS_EVENT_ON_ASSERT (0) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_HCI_VS_LOCAL_IRK +#define MYNEWT_VAL_BLE_LL_HCI_VS_LOCAL_IRK (0) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_HCI_VS_SET_SCAN_CFG +#define MYNEWT_VAL_BLE_LL_HCI_VS_SET_SCAN_CFG (0) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_ISO +#define MYNEWT_VAL_BLE_LL_ISO (0) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_ISOAL_MUX_PREFILL +#define MYNEWT_VAL_BLE_LL_ISOAL_MUX_PREFILL (0) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_ISO_BROADCASTER +#define MYNEWT_VAL_BLE_LL_ISO_BROADCASTER (0) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_ISO_HCI_DISCARD_THRESHOLD +#define MYNEWT_VAL_BLE_LL_ISO_HCI_DISCARD_THRESHOLD (0) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_ISO_HCI_FEEDBACK_INTERVAL_MS +#define MYNEWT_VAL_BLE_LL_ISO_HCI_FEEDBACK_INTERVAL_MS (0) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_LNA +#define MYNEWT_VAL_BLE_LL_LNA (0) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_LNA_GPIO +#define MYNEWT_VAL_BLE_LL_LNA_GPIO (-1) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_LNA_TURN_ON_US +#define MYNEWT_VAL_BLE_LL_LNA_TURN_ON_US (1) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_MANUFACTURER_ID +#define MYNEWT_VAL_BLE_LL_MANUFACTURER_ID (0x0B65) +#endif + #ifndef MYNEWT_VAL_BLE_LL_MASTER_SCA #define MYNEWT_VAL_BLE_LL_MASTER_SCA (4) #endif @@ -1028,7 +1564,7 @@ #endif #ifndef MYNEWT_VAL_BLE_LL_MFRG_ID -#define MYNEWT_VAL_BLE_LL_MFRG_ID (0xFFFF) +#define MYNEWT_VAL_BLE_LL_MFRG_ID (0x0B65) #endif #ifndef MYNEWT_VAL_BLE_LL_NUM_COMP_PKT_ITVL_MS @@ -1047,15 +1583,34 @@ #define MYNEWT_VAL_BLE_LL_OUR_SCA (60) #endif +#ifndef MYNEWT_VAL_BLE_LL_PA +#define MYNEWT_VAL_BLE_LL_PA (0) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_PA_GPIO +#define MYNEWT_VAL_BLE_LL_PA_GPIO (-1) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_PA_TURN_ON_US +#define MYNEWT_VAL_BLE_LL_PA_TURN_ON_US (1) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_PERIODIC_ADV_SYNC_BIGINFO_REPORTS +#define MYNEWT_VAL_BLE_LL_PERIODIC_ADV_SYNC_BIGINFO_REPORTS (0) +#endif + #ifndef MYNEWT_VAL_BLE_LL_PRIO #define MYNEWT_VAL_BLE_LL_PRIO (0) #endif +#ifndef MYNEWT_VAL_BLE_LL_PUBLIC_DEV_ADDR +#define MYNEWT_VAL_BLE_LL_PUBLIC_DEV_ADDR (0x000000000000) +#endif + #ifndef MYNEWT_VAL_BLE_LL_RESOLV_LIST_SIZE #define MYNEWT_VAL_BLE_LL_RESOLV_LIST_SIZE (4) #endif -/* Overridden by @apache-mynewt-core/hw/bsp/nordic_pca10056 (defined by @apache-mynewt-nimble/nimble/controller) */ #ifndef MYNEWT_VAL_BLE_LL_RFMGMT_ENABLE_TIME #define MYNEWT_VAL_BLE_LL_RFMGMT_ENABLE_TIME (1500) #endif @@ -1064,11 +1619,34 @@ #define MYNEWT_VAL_BLE_LL_RNG_BUFSIZE (32) #endif -/* Value copied from BLE_LL_OUR_SCA */ +#ifndef MYNEWT_VAL_BLE_LL_ROLE_BROADCASTER +#define MYNEWT_VAL_BLE_LL_ROLE_BROADCASTER (1) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_ROLE_CENTRAL +#define MYNEWT_VAL_BLE_LL_ROLE_CENTRAL (1) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_ROLE_OBSERVER +#define MYNEWT_VAL_BLE_LL_ROLE_OBSERVER (1) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_ROLE_PERIPHERAL +#define MYNEWT_VAL_BLE_LL_ROLE_PERIPHERAL (1) +#endif + #ifndef MYNEWT_VAL_BLE_LL_SCA #define MYNEWT_VAL_BLE_LL_SCA (60) #endif +#ifndef MYNEWT_VAL_BLE_LL_SCAN_ACTIVE_SCAN_NRPA +#define MYNEWT_VAL_BLE_LL_SCAN_ACTIVE_SCAN_NRPA (0) +#endif + +#ifndef MYNEWT_VAL_BLE_LL_SCAN_AUX_SEGMENT_CNT +#define MYNEWT_VAL_BLE_LL_SCAN_AUX_SEGMENT_CNT (0) +#endif + #ifndef MYNEWT_VAL_BLE_LL_SCHED_AUX_CHAIN_MAFS_DELAY #define MYNEWT_VAL_BLE_LL_SCHED_AUX_CHAIN_MAFS_DELAY (0) #endif @@ -1085,16 +1663,18 @@ #define MYNEWT_VAL_BLE_LL_SCHED_SCAN_SYNC_PDU_LEN (32) #endif +#ifndef MYNEWT_VAL_BLE_LL_STACK_SIZE +#define MYNEWT_VAL_BLE_LL_STACK_SIZE (120) +#endif + #ifndef MYNEWT_VAL_BLE_LL_STRICT_CONN_SCHEDULING #define MYNEWT_VAL_BLE_LL_STRICT_CONN_SCHEDULING (0) #endif -/* Overridden by @apache-mynewt-nimble/porting/targets/riot (defined by @apache-mynewt-nimble/nimble/controller) */ #ifndef MYNEWT_VAL_BLE_LL_SUPP_MAX_RX_BYTES #define MYNEWT_VAL_BLE_LL_SUPP_MAX_RX_BYTES (MYNEWT_VAL_BLE_LL_MAX_PKT_SIZE) #endif -/* Overridden by @apache-mynewt-nimble/porting/targets/riot (defined by @apache-mynewt-nimble/nimble/controller) */ #ifndef MYNEWT_VAL_BLE_LL_SUPP_MAX_TX_BYTES #define MYNEWT_VAL_BLE_LL_SUPP_MAX_TX_BYTES (MYNEWT_VAL_BLE_LL_MAX_PKT_SIZE) #endif @@ -1111,8 +1691,12 @@ #define MYNEWT_VAL_BLE_LL_TX_PWR_DBM (0) #endif +#ifndef MYNEWT_VAL_BLE_LL_TX_PWR_MAX_DBM +#define MYNEWT_VAL_BLE_LL_TX_PWR_MAX_DBM (20) +#endif + #ifndef MYNEWT_VAL_BLE_LL_USECS_PER_PERIOD -#define MYNEWT_VAL_BLE_LL_USECS_PER_PERIOD (3250) +#define MYNEWT_VAL_BLE_LL_USECS_PER_PERIOD (0) #endif #ifndef MYNEWT_VAL_BLE_LL_VND_EVENT_ON_ASSERT @@ -1139,11 +1723,6 @@ #define MYNEWT_VAL_BLE_XTAL_SETTLE_TIME (0) #endif -/*** @apache-mynewt-nimble/nimble/drivers/nrf52 */ -#ifndef MYNEWT_VAL_BLE_PHY_CODED_RX_IFS_EXTRA_MARGIN -#define MYNEWT_VAL_BLE_PHY_CODED_RX_IFS_EXTRA_MARGIN (0) -#endif - #ifndef MYNEWT_VAL_BLE_PHY_DBG_TIME_ADDRESS_END_PIN #define MYNEWT_VAL_BLE_PHY_DBG_TIME_ADDRESS_END_PIN (-1) #endif @@ -1156,19 +1735,30 @@ #define MYNEWT_VAL_BLE_PHY_DBG_TIME_WFR_PIN (-1) #endif -#ifndef MYNEWT_VAL_BLE_PHY_NRF52840_ERRATA_164 -#define MYNEWT_VAL_BLE_PHY_NRF52840_ERRATA_164 (0) +#ifndef MYNEWT_VAL_BLE_PHY_EXTENDED_TIFS +#define MYNEWT_VAL_BLE_PHY_EXTENDED_TIFS (2) +#endif + +#ifndef MYNEWT_VAL_BLE_PHY_NRF52_HEADERMASK_WORKAROUND +#define MYNEWT_VAL_BLE_PHY_NRF52_HEADERMASK_WORKAROUND (0) #endif -#ifndef MYNEWT_VAL_BLE_PHY_NRF52840_ERRATA_191 -#define MYNEWT_VAL_BLE_PHY_NRF52840_ERRATA_191 (1) +#ifndef MYNEWT_VAL_BLE_PHY_NRF5340_VDDH +#define MYNEWT_VAL_BLE_PHY_NRF5340_VDDH (0) #endif #ifndef MYNEWT_VAL_BLE_PHY_SYSVIEW #define MYNEWT_VAL_BLE_PHY_SYSVIEW (0) #endif -/*** @apache-mynewt-nimble/nimble/host */ +#ifndef MYNEWT_VAL_BLE_PHY_UBLOX_BMD345_PUBLIC_ADDR +#define MYNEWT_VAL_BLE_PHY_UBLOX_BMD345_PUBLIC_ADDR (0) +#endif + +#ifndef MYNEWT_VAL_BLE_PHY_VARIABLE_TIFS +#define MYNEWT_VAL_BLE_PHY_VARIABLE_TIFS (0) +#endif + #ifndef MYNEWT_VAL_BLE_ATT_PREFERRED_MTU #define MYNEWT_VAL_BLE_ATT_PREFERRED_MTU (256) #endif @@ -1193,6 +1783,10 @@ #define MYNEWT_VAL_BLE_ATT_SVR_NOTIFY (1) #endif +#ifndef MYNEWT_VAL_BLE_ATT_SVR_NOTIFY_MULTI +#define MYNEWT_VAL_BLE_ATT_SVR_NOTIFY_MULTI (MYNEWT_VAL_BLE_ATT_SVR_NOTIFY && (MYNEWT_VAL_BLE_VERSION >= 52)) +#endif + #ifndef MYNEWT_VAL_BLE_ATT_SVR_QUEUED_WRITE #define MYNEWT_VAL_BLE_ATT_SVR_QUEUED_WRITE (1) #endif @@ -1233,6 +1827,26 @@ #define MYNEWT_VAL_BLE_ATT_SVR_WRITE_NO_RSP (1) #endif +#ifndef MYNEWT_VAL_BLE_AUDIO +#define MYNEWT_VAL_BLE_AUDIO (0) +#endif + +#ifndef MYNEWT_VAL_BLE_EATT_CHAN_NUM +#define MYNEWT_VAL_BLE_EATT_CHAN_NUM (0) +#endif + +#ifndef MYNEWT_VAL_BLE_EATT_LOG_LVL +#define MYNEWT_VAL_BLE_EATT_LOG_LVL (1) +#endif + +#ifndef MYNEWT_VAL_BLE_EATT_LOG_MOD +#define MYNEWT_VAL_BLE_EATT_LOG_MOD (27) +#endif + +#ifndef MYNEWT_VAL_BLE_EATT_MTU +#define MYNEWT_VAL_BLE_EATT_MTU (128) +#endif + #ifndef MYNEWT_VAL_BLE_GAP_MAX_PENDING_CONN_PARAM_UPDATE #define MYNEWT_VAL_BLE_GAP_MAX_PENDING_CONN_PARAM_UPDATE (1) #endif @@ -1273,6 +1887,10 @@ #define MYNEWT_VAL_BLE_GATT_NOTIFY (1) #endif +#ifndef MYNEWT_VAL_BLE_GATT_NOTIFY_MULTIPLE +#define MYNEWT_VAL_BLE_GATT_NOTIFY_MULTIPLE ((MYNEWT_VAL_BLE_VERSION >= 52)) +#endif + #ifndef MYNEWT_VAL_BLE_GATT_READ #define MYNEWT_VAL_BLE_GATT_READ (MYNEWT_VAL_BLE_ROLE_CENTRAL) #endif @@ -1289,6 +1907,10 @@ #define MYNEWT_VAL_BLE_GATT_READ_MULT (MYNEWT_VAL_BLE_ROLE_CENTRAL) #endif +#ifndef MYNEWT_VAL_BLE_GATT_READ_MULT_VAR +#define MYNEWT_VAL_BLE_GATT_READ_MULT_VAR (MYNEWT_VAL_BLE_ROLE_CENTRAL && (MYNEWT_VAL_BLE_VERSION >= 52)) +#endif + #ifndef MYNEWT_VAL_BLE_GATT_READ_UUID #define MYNEWT_VAL_BLE_GATT_READ_UUID (MYNEWT_VAL_BLE_ROLE_CENTRAL) #endif @@ -1333,6 +1955,10 @@ #define MYNEWT_VAL_BLE_HS_DEBUG (0) #endif +#ifndef MYNEWT_VAL_BLE_HS_EXT_ADV_LEGACY_INSTANCE +#define MYNEWT_VAL_BLE_HS_EXT_ADV_LEGACY_INSTANCE (0) +#endif + #ifndef MYNEWT_VAL_BLE_HS_FLOW_CTRL #define MYNEWT_VAL_BLE_HS_FLOW_CTRL (0) #endif @@ -1349,6 +1975,10 @@ #define MYNEWT_VAL_BLE_HS_FLOW_CTRL_TX_ON_DISCONNECT (0) #endif +#ifndef MYNEWT_VAL_BLE_HS_GAP_UNHANDLED_HCI_EVENT +#define MYNEWT_VAL_BLE_HS_GAP_UNHANDLED_HCI_EVENT (0) +#endif + #ifndef MYNEWT_VAL_BLE_HS_LOG_LVL #define MYNEWT_VAL_BLE_HS_LOG_LVL (1) #endif @@ -1377,6 +2007,14 @@ #define MYNEWT_VAL_BLE_HS_SYSINIT_STAGE (200) #endif +#ifndef MYNEWT_VAL_BLE_ISO_MAX_BIGS +#define MYNEWT_VAL_BLE_ISO_MAX_BIGS (MYNEWT_VAL_BLE_MULTI_ADV_INSTANCES) +#endif + +#ifndef MYNEWT_VAL_BLE_ISO_MAX_BISES +#define MYNEWT_VAL_BLE_ISO_MAX_BISES (4) +#endif + #ifndef MYNEWT_VAL_BLE_L2CAP_COC_MAX_NUM #define MYNEWT_VAL_BLE_L2CAP_COC_MAX_NUM (0) #endif @@ -1385,6 +2023,10 @@ #define MYNEWT_VAL_BLE_L2CAP_COC_MPS (MYNEWT_VAL_MSYS_1_BLOCK_SIZE-8) #endif +#ifndef MYNEWT_VAL_BLE_L2CAP_COC_SDU_BUFF_COUNT +#define MYNEWT_VAL_BLE_L2CAP_COC_SDU_BUFF_COUNT (1) +#endif + #ifndef MYNEWT_VAL_BLE_L2CAP_ENHANCED_COC #define MYNEWT_VAL_BLE_L2CAP_ENHANCED_COC (0) #endif @@ -1409,42 +2051,6 @@ #define MYNEWT_VAL_BLE_MESH (0) #endif -#ifndef MYNEWT_VAL_BLE_MONITOR_CONSOLE_BUFFER_SIZE -#define MYNEWT_VAL_BLE_MONITOR_CONSOLE_BUFFER_SIZE (128) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_RTT -#define MYNEWT_VAL_BLE_MONITOR_RTT (0) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFERED -#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFERED (1) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_NAME -#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_NAME ("btmonitor") -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_SIZE -#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_SIZE (256) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_UART -#define MYNEWT_VAL_BLE_MONITOR_UART (0) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_UART_BAUDRATE -#define MYNEWT_VAL_BLE_MONITOR_UART_BAUDRATE (1000000) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_UART_BUFFER_SIZE -#define MYNEWT_VAL_BLE_MONITOR_UART_BUFFER_SIZE (64) -#endif - -#ifndef MYNEWT_VAL_BLE_MONITOR_UART_DEV -#define MYNEWT_VAL_BLE_MONITOR_UART_DEV ("uart0") -#endif - #ifndef MYNEWT_VAL_BLE_RPA_TIMEOUT #define MYNEWT_VAL_BLE_RPA_TIMEOUT (300) #endif @@ -1453,6 +2059,10 @@ #define MYNEWT_VAL_BLE_SM_BONDING (0) #endif +#ifndef MYNEWT_VAL_BLE_SM_CSIS_SIRK +#define MYNEWT_VAL_BLE_SM_CSIS_SIRK (0) +#endif + #ifndef MYNEWT_VAL_BLE_SM_IO_CAP #define MYNEWT_VAL_BLE_SM_IO_CAP (BLE_HS_IO_NO_INPUT_OUTPUT) #endif @@ -1461,11 +2071,14 @@ #define MYNEWT_VAL_BLE_SM_KEYPRESS (0) #endif -/* Overridden by @apache-mynewt-nimble/porting/targets/riot (defined by @apache-mynewt-nimble/nimble/host) */ #ifndef MYNEWT_VAL_BLE_SM_LEGACY #define MYNEWT_VAL_BLE_SM_LEGACY (0) #endif +#ifndef MYNEWT_VAL_BLE_SM_LVL +#define MYNEWT_VAL_BLE_SM_LVL (0) +#endif + #ifndef MYNEWT_VAL_BLE_SM_MAX_PROCS #define MYNEWT_VAL_BLE_SM_MAX_PROCS (1) #endif @@ -1482,23 +2095,18 @@ #define MYNEWT_VAL_BLE_SM_OUR_KEY_DIST (0) #endif -/* Overridden by @apache-mynewt-nimble/porting/targets/riot (defined by @apache-mynewt-nimble/nimble/host) */ #ifndef MYNEWT_VAL_BLE_SM_SC #define MYNEWT_VAL_BLE_SM_SC (0) #endif -#ifndef MYNEWT_VAL_BLE_SM_SC_ONLY -#define MYNEWT_VAL_BLE_SM_SC_ONLY (0) -#endif - -#ifndef MYNEWT_VAL_BLE_SM_SC_LVL -#define MYNEWT_VAL_BLE_SM_SC_LVL (0) -#endif - #ifndef MYNEWT_VAL_BLE_SM_SC_DEBUG_KEYS #define MYNEWT_VAL_BLE_SM_SC_DEBUG_KEYS (0) #endif +#ifndef MYNEWT_VAL_BLE_SM_SC_ONLY +#define MYNEWT_VAL_BLE_SM_SC_ONLY (0) +#endif + #ifndef MYNEWT_VAL_BLE_SM_THEIR_KEY_DIST #define MYNEWT_VAL_BLE_SM_THEIR_KEY_DIST (0) #endif @@ -1511,7 +2119,6 @@ #define MYNEWT_VAL_BLE_STORE_MAX_CCCDS (8) #endif -/*** @apache-mynewt-nimble/nimble/host/services/gap */ #ifndef MYNEWT_VAL_BLE_SVC_GAP_APPEARANCE #define MYNEWT_VAL_BLE_SVC_GAP_APPEARANCE (0) #endif @@ -1525,7 +2132,7 @@ #endif #ifndef MYNEWT_VAL_BLE_SVC_GAP_DEVICE_NAME -#define MYNEWT_VAL_BLE_SVC_GAP_DEVICE_NAME ("nimble") +#define MYNEWT_VAL_BLE_SVC_GAP_DEVICE_NAME "nimble" #endif #ifndef MYNEWT_VAL_BLE_SVC_GAP_DEVICE_NAME_MAX_LENGTH @@ -1556,41 +2163,292 @@ #define MYNEWT_VAL_BLE_SVC_GAP_SYSINIT_STAGE (301) #endif -/*** @apache-mynewt-nimble/nimble/host/services/gatt */ #ifndef MYNEWT_VAL_BLE_SVC_GATT_SYSINIT_STAGE #define MYNEWT_VAL_BLE_SVC_GATT_SYSINIT_STAGE (302) #endif -/*** @apache-mynewt-nimble/nimble/transport/ram */ -/* Overridden by @apache-mynewt-nimble/porting/targets/riot (defined by @apache-mynewt-nimble/nimble/transport/ram) */ -#ifndef MYNEWT_VAL_BLE_ACL_BUF_COUNT -#define MYNEWT_VAL_BLE_ACL_BUF_COUNT (24) +#undef MYNEWT_VAL_BLE_ACL_BUF_COUNT + +#undef MYNEWT_VAL_BLE_ACL_BUF_SIZE + +#undef MYNEWT_VAL_BLE_HCI_BRIDGE + +#undef MYNEWT_VAL_BLE_HCI_EVT_BUF_SIZE + +#undef MYNEWT_VAL_BLE_HCI_EVT_HI_BUF_COUNT + +#undef MYNEWT_VAL_BLE_HCI_EVT_LO_BUF_COUNT + +#undef MYNEWT_VAL_BLE_HCI_TRANSPORT + +#ifndef MYNEWT_VAL_BLE_MONITOR_CONSOLE_BUFFER_SIZE +#define MYNEWT_VAL_BLE_MONITOR_CONSOLE_BUFFER_SIZE (128) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_RTT +#define MYNEWT_VAL_BLE_MONITOR_RTT (0) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFERED +#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFERED (1) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_NAME +#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_NAME "btmonitor" +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_SIZE +#define MYNEWT_VAL_BLE_MONITOR_RTT_BUFFER_SIZE (256) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_UART +#define MYNEWT_VAL_BLE_MONITOR_UART (0) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_UART_BAUDRATE +#define MYNEWT_VAL_BLE_MONITOR_UART_BAUDRATE (1000000) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_UART_BUFFER_SIZE +#define MYNEWT_VAL_BLE_MONITOR_UART_BUFFER_SIZE (64) +#endif + +#ifndef MYNEWT_VAL_BLE_MONITOR_UART_DEV +#define MYNEWT_VAL_BLE_MONITOR_UART_DEV "uart0" +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT +#define MYNEWT_VAL_BLE_TRANSPORT (1) +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT_ACL_COUNT +#define MYNEWT_VAL_BLE_TRANSPORT_ACL_COUNT (24) +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT_ACL_FROM_HS_COUNT +#define MYNEWT_VAL_BLE_TRANSPORT_ACL_FROM_HS_COUNT (24) +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT_ACL_FROM_LL_COUNT +#define MYNEWT_VAL_BLE_TRANSPORT_ACL_FROM_LL_COUNT (24) +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT_ACL_SIZE +#define MYNEWT_VAL_BLE_TRANSPORT_ACL_SIZE (251) +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT_EVT_COUNT +#define MYNEWT_VAL_BLE_TRANSPORT_EVT_COUNT (2) +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT_EVT_DISCARDABLE_COUNT +#define MYNEWT_VAL_BLE_TRANSPORT_EVT_DISCARDABLE_COUNT (16) +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT_EVT_SIZE +#define MYNEWT_VAL_BLE_TRANSPORT_EVT_SIZE (70) +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT_HS__cdc +#define MYNEWT_VAL_BLE_TRANSPORT_HS__cdc (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_HS__custom +#define MYNEWT_VAL_BLE_TRANSPORT_HS__custom (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_HS__dialog_cmac +#define MYNEWT_VAL_BLE_TRANSPORT_HS__dialog_cmac (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_HS__native +#define MYNEWT_VAL_BLE_TRANSPORT_HS__native (1) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_HS__nrf5340 +#define MYNEWT_VAL_BLE_TRANSPORT_HS__nrf5340 (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_HS__uart +#define MYNEWT_VAL_BLE_TRANSPORT_HS__uart (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_HS__usb +#define MYNEWT_VAL_BLE_TRANSPORT_HS__usb (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_HS +#define MYNEWT_VAL_BLE_TRANSPORT_HS (1) +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT_ISO_COUNT +#define MYNEWT_VAL_BLE_TRANSPORT_ISO_COUNT (10) +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT_ISO_FROM_HS_COUNT +#define MYNEWT_VAL_BLE_TRANSPORT_ISO_FROM_HS_COUNT (10) +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT_ISO_FROM_LL_COUNT +#define MYNEWT_VAL_BLE_TRANSPORT_ISO_FROM_LL_COUNT (10) +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT_ISO_SIZE +#define MYNEWT_VAL_BLE_TRANSPORT_ISO_SIZE (300) +#endif + +#ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__apollo3 +#define MYNEWT_VAL_BLE_TRANSPORT_LL__apollo3 (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__custom +#define MYNEWT_VAL_BLE_TRANSPORT_LL__custom (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__dialog_cmac +#define MYNEWT_VAL_BLE_TRANSPORT_LL__dialog_cmac (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__emspi +#define MYNEWT_VAL_BLE_TRANSPORT_LL__emspi (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__native +#define MYNEWT_VAL_BLE_TRANSPORT_LL__native (1) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__nrf5340 +#define MYNEWT_VAL_BLE_TRANSPORT_LL__nrf5340 (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__socket +#define MYNEWT_VAL_BLE_TRANSPORT_LL__socket (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_LL__uart_ll +#define MYNEWT_VAL_BLE_TRANSPORT_LL__uart_ll (0) +#endif +#ifndef MYNEWT_VAL_BLE_TRANSPORT_LL +#define MYNEWT_VAL_BLE_TRANSPORT_LL (1) +#endif + +#undef MYNEWT_VAL_BLE_TRANSPORT_RX_TASK_STACK_SIZE + +#ifndef MYNEWT_VAL_BOOTUTIL_BOOTSTRAP +#define MYNEWT_VAL_BOOTUTIL_BOOTSTRAP (0) +#endif + +#ifndef MYNEWT_VAL_BOOTUTIL_DOWNGRADE_PREVENTION__none +#define MYNEWT_VAL_BOOTUTIL_DOWNGRADE_PREVENTION__none (1) +#endif +#ifndef MYNEWT_VAL_BOOTUTIL_DOWNGRADE_PREVENTION__security_counter +#define MYNEWT_VAL_BOOTUTIL_DOWNGRADE_PREVENTION__security_counter (0) +#endif +#ifndef MYNEWT_VAL_BOOTUTIL_DOWNGRADE_PREVENTION__version +#define MYNEWT_VAL_BOOTUTIL_DOWNGRADE_PREVENTION__version (0) +#endif +#ifndef MYNEWT_VAL_BOOTUTIL_DOWNGRADE_PREVENTION +#define MYNEWT_VAL_BOOTUTIL_DOWNGRADE_PREVENTION (1) +#endif + +#ifndef MYNEWT_VAL_BOOTUTIL_ENCRYPT_EC256 +#define MYNEWT_VAL_BOOTUTIL_ENCRYPT_EC256 (0) +#endif + +#ifndef MYNEWT_VAL_BOOTUTIL_ENCRYPT_KW +#define MYNEWT_VAL_BOOTUTIL_ENCRYPT_KW (0) +#endif + +#ifndef MYNEWT_VAL_BOOTUTIL_ENCRYPT_RSA +#define MYNEWT_VAL_BOOTUTIL_ENCRYPT_RSA (0) +#endif + +#ifndef MYNEWT_VAL_BOOTUTIL_ENCRYPT_X25519 +#define MYNEWT_VAL_BOOTUTIL_ENCRYPT_X25519 (0) +#endif + +#ifndef MYNEWT_VAL_BOOTUTIL_FEED_WATCHDOG +#define MYNEWT_VAL_BOOTUTIL_FEED_WATCHDOG (0) +#endif + +#ifndef MYNEWT_VAL_BOOTUTIL_HAVE_LOGGING +#define MYNEWT_VAL_BOOTUTIL_HAVE_LOGGING (0) +#endif + +#ifndef MYNEWT_VAL_BOOTUTIL_HW_ROLLBACK_PROT +#define MYNEWT_VAL_BOOTUTIL_HW_ROLLBACK_PROT (0) +#endif + +#ifndef MYNEWT_VAL_BOOTUTIL_IMAGE_FORMAT_V2 +#define MYNEWT_VAL_BOOTUTIL_IMAGE_FORMAT_V2 (1) +#endif + +#ifndef MYNEWT_VAL_BOOTUTIL_IMAGE_NUMBER +#define MYNEWT_VAL_BOOTUTIL_IMAGE_NUMBER (0) +#endif + +#ifndef MYNEWT_VAL_BOOTUTIL_LOG_LEVEL +#define MYNEWT_VAL_BOOTUTIL_LOG_LEVEL (BOOTUTIL_LOG_LEVEL_INFO) +#endif + +#ifndef MYNEWT_VAL_BOOTUTIL_MAX_IMG_SECTORS +#define MYNEWT_VAL_BOOTUTIL_MAX_IMG_SECTORS (128) #endif -#ifndef MYNEWT_VAL_BLE_ACL_BUF_SIZE -#define MYNEWT_VAL_BLE_ACL_BUF_SIZE (255) +#ifndef MYNEWT_VAL_BOOTUTIL_NO_LOGGING +#define MYNEWT_VAL_BOOTUTIL_NO_LOGGING (1) #endif -#ifndef MYNEWT_VAL_BLE_HCI_EVT_BUF_SIZE -#define MYNEWT_VAL_BLE_HCI_EVT_BUF_SIZE (70) +#ifndef MYNEWT_VAL_BOOTUTIL_OVERWRITE_ONLY +#define MYNEWT_VAL_BOOTUTIL_OVERWRITE_ONLY (0) #endif -/* Overridden by @apache-mynewt-nimble/porting/targets/riot (defined by @apache-mynewt-nimble/nimble/transport/ram) */ -#ifndef MYNEWT_VAL_BLE_HCI_EVT_HI_BUF_COUNT -#define MYNEWT_VAL_BLE_HCI_EVT_HI_BUF_COUNT (2) +#ifndef MYNEWT_VAL_BOOTUTIL_OVERWRITE_ONLY_FAST +#define MYNEWT_VAL_BOOTUTIL_OVERWRITE_ONLY_FAST (1) #endif -#ifndef MYNEWT_VAL_BLE_HCI_EVT_LO_BUF_COUNT -#define MYNEWT_VAL_BLE_HCI_EVT_LO_BUF_COUNT (8) +#ifndef MYNEWT_VAL_BOOTUTIL_SIGN_EC256 +#define MYNEWT_VAL_BOOTUTIL_SIGN_EC256 (0) #endif -#ifndef MYNEWT_VAL_BLE_TRANS_RAM_SYSINIT_STAGE -#define MYNEWT_VAL_BLE_TRANS_RAM_SYSINIT_STAGE (100) +#ifndef MYNEWT_VAL_BOOTUTIL_SIGN_ED25519 +#define MYNEWT_VAL_BOOTUTIL_SIGN_ED25519 (0) #endif -/*** newt */ +#ifndef MYNEWT_VAL_BOOTUTIL_SIGN_RSA +#define MYNEWT_VAL_BOOTUTIL_SIGN_RSA (0) +#endif + +#ifndef MYNEWT_VAL_BOOTUTIL_SIGN_RSA_LEN +#define MYNEWT_VAL_BOOTUTIL_SIGN_RSA_LEN (2048) +#endif + +#ifndef MYNEWT_VAL_BOOTUTIL_SINGLE_APPLICATION_SLOT +#define MYNEWT_VAL_BOOTUTIL_SINGLE_APPLICATION_SLOT (0) +#endif + +#ifndef MYNEWT_VAL_BOOTUTIL_SWAP_SAVE_ENCTLV +#define MYNEWT_VAL_BOOTUTIL_SWAP_SAVE_ENCTLV (0) +#endif + +#ifndef MYNEWT_VAL_BOOTUTIL_SWAP_USING_MOVE +#define MYNEWT_VAL_BOOTUTIL_SWAP_USING_MOVE (0) +#endif + +#ifndef MYNEWT_VAL_BOOTUTIL_USE_MBED_TLS +#define MYNEWT_VAL_BOOTUTIL_USE_MBED_TLS (1) +#endif + +#ifndef MYNEWT_VAL_BOOTUTIL_USE_TINYCRYPT +#define MYNEWT_VAL_BOOTUTIL_USE_TINYCRYPT (0) +#endif + +#ifndef MYNEWT_VAL_BOOTUTIL_VALIDATE_SLOT0 +#define MYNEWT_VAL_BOOTUTIL_VALIDATE_SLOT0 (0) +#endif + +#ifndef MYNEWT_VAL_BOOTUTIL_VERSION_CMP_USE_BUILD_NUMBER +#define MYNEWT_VAL_BOOTUTIL_VERSION_CMP_USE_BUILD_NUMBER (0) +#endif + +#undef MYNEWT_VAL_MCUBOOT_DATA_SHARING + +#undef MYNEWT_VAL_MCUBOOT_MEASURED_BOOT + +#undef MYNEWT_VAL_MCUBOOT_MEASURED_BOOT_MAX_RECORD_SZ + +#undef MYNEWT_VAL_MCUBOOT_SHARED_DATA_BASE + +#undef MYNEWT_VAL_MCUBOOT_SHARED_DATA_SIZE + #ifndef MYNEWT_VAL_APP_NAME -#define MYNEWT_VAL_APP_NAME ("dummy_app") +#define MYNEWT_VAL_APP_NAME "dummy_app" #endif #ifndef MYNEWT_VAL_APP_dummy_app @@ -1598,7 +2456,7 @@ #endif #ifndef MYNEWT_VAL_ARCH_NAME -#define MYNEWT_VAL_ARCH_NAME ("cortex_m4") +#define MYNEWT_VAL_ARCH_NAME "cortex_m4" #endif #ifndef MYNEWT_VAL_ARCH_cortex_m4 @@ -1606,7 +2464,7 @@ #endif #ifndef MYNEWT_VAL_BSP_NAME -#define MYNEWT_VAL_BSP_NAME ("nordic_pca10056") +#define MYNEWT_VAL_BSP_NAME "nordic_pca10056" #endif #ifndef MYNEWT_VAL_BSP_nordic_pca10056 @@ -1622,11 +2480,61 @@ #endif #ifndef MYNEWT_VAL_TARGET_NAME -#define MYNEWT_VAL_TARGET_NAME ("riot") +#define MYNEWT_VAL_TARGET_NAME "riot" #endif #ifndef MYNEWT_VAL_TARGET_riot #define MYNEWT_VAL_TARGET_riot (1) #endif +#define MYNEWT_PKG_apache_mynewt_core__boot_startup 1 +#define MYNEWT_PKG_apache_mynewt_core__compiler_arm_none_eabi_m4 1 +#define MYNEWT_PKG_apache_mynewt_core__crypto_mbedtls 1 +#define MYNEWT_PKG_apache_mynewt_core__crypto_tinycrypt 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_bsp_nordic_pca10056 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_cmsis_core 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_drivers_uart 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_drivers_uart_uart_hal 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_hal 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_mcu_nordic 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_mcu_nordic_nrf52xxx 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_mcu_nordic_nrf_common 1 +#define MYNEWT_PKG_apache_mynewt_core__hw_scripts 1 +#define MYNEWT_PKG_apache_mynewt_core__kernel_os 1 +#define MYNEWT_PKG_apache_mynewt_core__libc 1 +#define MYNEWT_PKG_apache_mynewt_core__libc_baselibc 1 +#define MYNEWT_PKG_apache_mynewt_core__mgmt_image_header 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_console_stub 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_defs 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_flash_map 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_log_common 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_log_modlog 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_log_stub 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_stats_stub 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_sys 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_sysdown 1 +#define MYNEWT_PKG_apache_mynewt_core__sys_sysinit 1 +#define MYNEWT_PKG_apache_mynewt_core__util_mem 1 +#define MYNEWT_PKG_apache_mynewt_core__util_rwlock 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_controller 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_drivers_nrf5x 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_gap 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_host_services_gatt 1 +#define MYNEWT_PKG_apache_mynewt_nimble__nimble_transport 1 +#define MYNEWT_PKG_apache_mynewt_nimble__porting_npl_mynewt 1 +#define MYNEWT_PKG_apache_mynewt_nimble__porting_targets_dummy_app 1 +#define MYNEWT_PKG_apache_mynewt_nimble__porting_targets_riot 1 +#define MYNEWT_PKG_mcuboot__boot_bootutil 1 +#define MYNEWT_PKG_mcuboot__boot_mynewt_flash_map_backend 1 +#define MYNEWT_PKG_mcuboot__boot_mynewt_mcuboot_config 1 + +#define MYNEWT_API_ble_driver 1 +#define MYNEWT_API_ble_transport 1 +#define MYNEWT_API_bootloader 1 +#define MYNEWT_API_console 1 +#define MYNEWT_API_log 1 +#define MYNEWT_API_stats 1 + #endif diff --git a/porting/npl/riot/include/sysflash/sysflash.h b/porting/npl/riot/include/sysflash/sysflash.h deleted file mode 100644 index ab1341b25d..0000000000 --- a/porting/npl/riot/include/sysflash/sysflash.h +++ /dev/null @@ -1,24 +0,0 @@ -/** - * This file was generated by Apache newt version: 1.9.0-dev - */ - -#ifndef H_MYNEWT_SYSFLASH_ -#define H_MYNEWT_SYSFLASH_ - -#include "flash_map/flash_map.h" - -/** - * This flash map definition is used for two purposes: - * 1. To locate the meta area, which contains the true flash map definition. - * 2. As a fallback in case the meta area cannot be read from flash. - */ -extern const struct flash_area sysflash_map_dflt[6]; - -#define FLASH_AREA_BOOTLOADER 0 -#define FLASH_AREA_IMAGE_0 1 -#define FLASH_AREA_IMAGE_1 2 -#define FLASH_AREA_IMAGE_SCRATCH 3 -#define FLASH_AREA_REBOOT_LOG 16 -#define FLASH_AREA_NFFS 17 - -#endif diff --git a/porting/targets/dummy_app/src/dummy.c b/porting/targets/dummy_app/src/dummy.c index 0bd431fd99..a54c7fc94c 100644 --- a/porting/targets/dummy_app/src/dummy.c +++ b/porting/targets/dummy_app/src/dummy.c @@ -20,7 +20,7 @@ #pragma message ( "This will probably not compile. Used to generate syscfg.h file and other artifacts." ) int -main(void) +mynewt_main(void) { return 0; } diff --git a/porting/targets/linux/pkg.yml b/porting/targets/linux/pkg.yml index c819a83c1c..72018c87e7 100644 --- a/porting/targets/linux/pkg.yml +++ b/porting/targets/linux/pkg.yml @@ -28,7 +28,7 @@ pkg.deps: - "@apache-mynewt-core/sys/log/stub" - "@apache-mynewt-core/sys/stats/stub" - "@apache-mynewt-nimble/nimble/host" - - "@apache-mynewt-nimble/nimble/transport/socket" + - "@apache-mynewt-nimble/nimble/transport" - "@apache-mynewt-nimble/nimble/host/services/ans" - "@apache-mynewt-nimble/nimble/host/services/bas" - "@apache-mynewt-nimble/nimble/host/services/dis" diff --git a/porting/targets/linux/syscfg.yml b/porting/targets/linux/syscfg.yml index 603e586c87..e5faa62775 100644 --- a/porting/targets/linux/syscfg.yml +++ b/porting/targets/linux/syscfg.yml @@ -17,6 +17,7 @@ # syscfg.vals: + BLE_TRANSPORT_LL: socket BLE_SOCK_USE_TCP: 0 BLE_SOCK_USE_LINUX_BLUE: 1 BLE_SOCK_TASK_PRIO: 3 diff --git a/porting/targets/linux/target.yml b/porting/targets/linux/target.yml index 9ab4152c9d..7145d70386 100644 --- a/porting/targets/linux/target.yml +++ b/porting/targets/linux/target.yml @@ -16,5 +16,5 @@ # under the License. # target.app: "porting/targets/dummy_app" -target.bsp: "porting/targets/dummy_bsp" +target.bsp: "@apache-mynewt-core/hw/bsp/native" target.build_profile: "debug" diff --git a/porting/targets/linux_blemesh/pkg.yml b/porting/targets/linux_blemesh/pkg.yml index 3cbe09a4b6..14cb2d916c 100644 --- a/porting/targets/linux_blemesh/pkg.yml +++ b/porting/targets/linux_blemesh/pkg.yml @@ -28,7 +28,7 @@ pkg.deps: - "@apache-mynewt-core/sys/log/stub" - "@apache-mynewt-core/sys/stats/stub" - "@apache-mynewt-nimble/nimble/host" - - "@apache-mynewt-nimble/nimble/transport/socket" + - "@apache-mynewt-nimble/nimble/transport" - "@apache-mynewt-nimble/nimble/host/services/ans" - "@apache-mynewt-nimble/nimble/host/services/bas" - "@apache-mynewt-nimble/nimble/host/services/dis" diff --git a/porting/targets/linux_blemesh/syscfg.yml b/porting/targets/linux_blemesh/syscfg.yml index efc4150b4c..b5e48f4400 100644 --- a/porting/targets/linux_blemesh/syscfg.yml +++ b/porting/targets/linux_blemesh/syscfg.yml @@ -34,6 +34,7 @@ syscfg.vals: BLE_MESH_LABEL_COUNT: 2 BLE_MESH_SUBNET_COUNT: 2 BLE_MESH_MODEL_GROUP_COUNT: 2 + BLE_MESH_MODEL_VND_MSG_CID_FORCE: 1 BLE_MESH_APP_KEY_COUNT: 4 BLE_MESH_IV_UPDATE_TEST: 1 BLE_MESH_TESTING: 1 @@ -42,6 +43,7 @@ syscfg.vals: BLE_MESH_SETTINGS: 0 CONFIG_NFFS: 0 + BLE_TRANSPORT_LL: socket BLE_SOCK_USE_TCP: 0 BLE_SOCK_USE_LINUX_BLUE: 1 BLE_SOCK_TASK_PRIO: 3 diff --git a/porting/targets/linux_blemesh/target.yml b/porting/targets/linux_blemesh/target.yml index 83eb415886..4b9a4dab8b 100644 --- a/porting/targets/linux_blemesh/target.yml +++ b/porting/targets/linux_blemesh/target.yml @@ -17,5 +17,5 @@ # target.app: "porting/targets/dummy_app" -target.bsp: "porting/targets/dummy_bsp" +target.bsp: "@apache-mynewt-core/hw/bsp/native" target.build_profile: "debug" diff --git a/porting/targets/nuttx/pkg.yml b/porting/targets/nuttx/pkg.yml index e105cd6308..fb6c01451b 100644 --- a/porting/targets/nuttx/pkg.yml +++ b/porting/targets/nuttx/pkg.yml @@ -28,7 +28,7 @@ pkg.deps: - "@apache-mynewt-core/sys/log/stub" - "@apache-mynewt-core/sys/stats/stub" - "@apache-mynewt-nimble/nimble/host" -- "@apache-mynewt-nimble/nimble/transport/socket" +- "@apache-mynewt-nimble/nimble/transport" - "@apache-mynewt-nimble/nimble/host/services/ans" - "@apache-mynewt-nimble/nimble/host/services/bas" - "@apache-mynewt-nimble/nimble/host/services/dis" diff --git a/porting/targets/nuttx/syscfg.yml b/porting/targets/nuttx/syscfg.yml index fdfa7b5924..98ec29bf34 100644 --- a/porting/targets/nuttx/syscfg.yml +++ b/porting/targets/nuttx/syscfg.yml @@ -17,6 +17,7 @@ # syscfg.vals: + BLE_TRANSPORT_LL: socket BLE_SOCK_USE_TCP: 0 BLE_SOCK_USE_NUTTX: 1 BLE_SOCK_TASK_PRIO: 3 @@ -25,4 +26,3 @@ syscfg.vals: LOG_LEVEL: 2 BLE_SM_LEGACY: 1 BLE_SM_SC: 1 - diff --git a/porting/targets/nuttx/target.yml b/porting/targets/nuttx/target.yml index 9ab4152c9d..7145d70386 100644 --- a/porting/targets/nuttx/target.yml +++ b/porting/targets/nuttx/target.yml @@ -16,5 +16,5 @@ # under the License. # target.app: "porting/targets/dummy_app" -target.bsp: "porting/targets/dummy_bsp" +target.bsp: "@apache-mynewt-core/hw/bsp/native" target.build_profile: "debug" diff --git a/porting/targets/porting_default/pkg.yml b/porting/targets/porting_default/pkg.yml index 44a34ba097..8b7aab0e34 100644 --- a/porting/targets/porting_default/pkg.yml +++ b/porting/targets/porting_default/pkg.yml @@ -28,7 +28,7 @@ pkg.deps: - "@apache-mynewt-core/sys/log/stub" - "@apache-mynewt-core/sys/stats/stub" - "@apache-mynewt-nimble/nimble/host" - - "@apache-mynewt-nimble/nimble/transport/socket" + - "@apache-mynewt-nimble/nimble/transport" - "@apache-mynewt-nimble/nimble/host/services/ans" - "@apache-mynewt-nimble/nimble/host/services/bas" - "@apache-mynewt-nimble/nimble/host/services/dis" diff --git a/porting/targets/porting_default/syscfg.yml b/porting/targets/porting_default/syscfg.yml new file mode 100644 index 0000000000..cb6cda18ef --- /dev/null +++ b/porting/targets/porting_default/syscfg.yml @@ -0,0 +1,22 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +syscfg.vals: + BLE_TRANSPORT_LL: socket + BLE_SOCK_USE_TCP: 0 + BLE_SOCK_USE_LINUX_BLUE: 1 diff --git a/porting/targets/porting_default/target.yml b/porting/targets/porting_default/target.yml index 83eb415886..4b9a4dab8b 100644 --- a/porting/targets/porting_default/target.yml +++ b/porting/targets/porting_default/target.yml @@ -17,5 +17,5 @@ # target.app: "porting/targets/dummy_app" -target.bsp: "porting/targets/dummy_bsp" +target.bsp: "@apache-mynewt-core/hw/bsp/native" target.build_profile: "debug" diff --git a/porting/targets/riot/pkg.yml b/porting/targets/riot/pkg.yml index 7d1a3243bd..e57c47c293 100644 --- a/porting/targets/riot/pkg.yml +++ b/porting/targets/riot/pkg.yml @@ -28,7 +28,7 @@ pkg.deps: - "@apache-mynewt-core/sys/log/stub" - "@apache-mynewt-core/sys/stats/stub" - "@apache-mynewt-nimble/nimble/host" + - "@apache-mynewt-nimble/nimble/transport" - "@apache-mynewt-nimble/nimble/controller" - - "@apache-mynewt-nimble/nimble/transport/ram" - "@apache-mynewt-nimble/nimble/host/services/gap" - "@apache-mynewt-nimble/nimble/host/services/gatt" diff --git a/porting/targets/riot/syscfg.yml b/porting/targets/riot/syscfg.yml index 8359eaa7c9..380c219e1b 100644 --- a/porting/targets/riot/syscfg.yml +++ b/porting/targets/riot/syscfg.yml @@ -17,9 +17,9 @@ # syscfg.vals: - BLE_ACL_BUF_COUNT: 24 BLE_HCI_VS: 1 - BLE_HCI_EVT_HI_BUF_COUNT: 2 + BLE_TRANSPORT_ACL_COUNT: 24 + BLE_TRANSPORT_EVT_COUNT: 2 BLE_HW_WHITELIST_ENABLE: 0 BLE_LL_CFG_FEAT_DATA_LEN_EXT: 0 BLE_LL_CFG_FEAT_LE_CSA2: 1 @@ -33,4 +33,4 @@ syscfg.vals: BLE_MAX_PERIODIC_SYNCS: 0 MSYS_1_BLOCK_COUNT: 5 MSYS_1_BLOCK_SIZE: 88 - XTAL_32768: 1 + MCU_LFCLK_SOURCE: LFXO diff --git a/porting/update_generated_files.sh b/porting/update_generated_files.sh index 6309ed2b2e..e5104b63f8 100755 --- a/porting/update_generated_files.sh +++ b/porting/update_generated_files.sh @@ -33,10 +33,14 @@ declare -A targets=( for target in "${!targets[@]}"; do echo "Updating target $target" newt build "@apache-mynewt-nimble/porting/targets/$target" > /dev/null 2>&1 + # logcfg and sysflash is not used in ports + rm -rf "bin/@apache-mynewt-nimble/porting/targets/${target}/generated/include/logcfg" + rm -rf "bin/@apache-mynewt-nimble/porting/targets/${target}/generated/include/sysflash" cp "bin/@apache-mynewt-nimble/porting/targets/${target}/generated/include" "${targets[$target]}" -r - # Remove repo version and hash MYNEWT_VALS as it doesn't make much sense to commit them and they - # defeat the purpose of this script. + # Remove all comments and hash MYNEWT_VALS as it doesn't make much sense to commit them and they + # defeat the purpose of this script. Prepend the license header. find "${targets[$target]}/include" -type f -name 'syscfg.h' -exec sed -i '/MYNEWT_VAL_REPO_*/,/#endif/d' {} \; - find "${targets[$target]}/include" -type f -name 'syscfg.h' -exec sed -i '/\/\*\*\* Repository/,/\*\//d' {} \; + find "${targets[$target]}/include" -type f -name 'syscfg.h' -exec sed -i -E ':a;N;$!ba;s:/\*([^*]|(\*+([^*/])))*\*+/::g' {} \; find "${targets[$target]}/include" -type f -name 'syscfg.h' -exec sed -i '$!N;/^\n$/{$q;D;};P;D;' {} \; + find "${targets[$target]}/include" -type f -name 'syscfg.h' -exec sh -c 'cat "$0" "$1" > "$1.tmp" && mv "$1.tmp" "$1"' "repos/apache-mynewt-nimble/.github/LICENSE_TEMPLATE" {} \; done diff --git a/nimble/transport/dialog_cmac/cmac_driver/scripts/create_cmac_bin.sh b/qualification/README.txt old mode 100755 new mode 100644 similarity index 56% rename from nimble/transport/dialog_cmac/cmac_driver/scripts/create_cmac_bin.sh rename to qualification/README.txt index 954d086048..f4f76ae39c --- a/nimble/transport/dialog_cmac/cmac_driver/scripts/create_cmac_bin.sh +++ b/qualification/README.txt @@ -1,5 +1,4 @@ -#!/bin/bash - +# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information @@ -8,24 +7,27 @@ # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # -# http://www.apache.org/licenses/LICENSE-2.0 +# http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the +# KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. +# + +This folder contains informations related to NimBLE qualification. + + +NimBLE Host: -OBJCOPY=${MYNEWT_OBJCOPY_PATH} -ELF=${MYNEWT_APP_BIN_DIR}/blehci.elf +Currently PTS tests are done with AutoPTS [1] environment and qualification +related files (Qualification Workspace draft and PTS workspace) are stored +within NimBLE's AutoPTS workspace [2]. -cd ${WORK_DIR} +[1] https://github.com/auto-pts/auto-pts +[2] https://github.com/auto-pts/auto-pts/tree/master/autopts/workspaces/nimble-master -# Strip .ram section from ROM image -${OBJCOPY} -R .ram -O binary ${ELF} ${BASENAME_ROM}.bin -# RAM image is the same as binary created by newt -cp ${ELF}.bin ${BASENAME_RAM}.bin -# Create a copy of ROM image to flash to partition, if required -cp ${BASENAME_ROM}.bin ${ELF}.rom.bin +NimBLE Controller: TBD diff --git a/repository.yml b/repository.yml index 9f112a825e..8261ae866a 100644 --- a/repository.yml +++ b/repository.yml @@ -22,20 +22,28 @@ repo.versions: "0.0.0": "master" "0-dev": "0.0.0" - "0-latest": "1.4.0" - "1-latest": "1.4.0" + "0-latest": "1.8.0" + "1-latest": "1.8.0" "1.0.0": "nimble_1_0_0_tag" "1.1.0": "nimble_1_1_0_tag" "1.2.0": "nimble_1_2_0_tag" "1.3.0": "nimble_1_3_0_tag" "1.4.0": "nimble_1_4_0_tag" + "1.5.0": "nimble_1_5_0_tag" + "1.6.0": "nimble_1_6_0_tag" + "1.7.0": "nimble_1_7_0_tag" + "1.8.0": "nimble_1_8_0_tag" "1.0-latest": "1.0.0" "1.1-latest": "1.1.0" "1.2-latest": "1.2.0" "1.3-latest": "1.3.0" "1.4-latest": "1.4.0" + "1.5-latest": "1.5.0" + "1.6-latest": "1.6.0" + "1.7-latest": "1.7.0" + "1.8-latest": "1.8.0" repo.newt_compatibility: 0.0.0: @@ -50,3 +58,11 @@ repo.newt_compatibility: 1.8.0: good 1.4.0: 1.9.0: good + 1.5.0: + 1.10.0: good + 1.6.0: + 1.11.0: good + 1.7.0: + 1.12.0: good + 1.8.0: + 1.13.0: good diff --git a/targets/auracast_usb/nrf5340-mcu.ld b/targets/auracast_usb/nrf5340-mcu.ld new file mode 100644 index 0000000000..2e2e4f1679 --- /dev/null +++ b/targets/auracast_usb/nrf5340-mcu.ld @@ -0,0 +1,220 @@ +/* Linker script for Nordic Semiconductor nRF5 devices + * + * Version: Sourcery G++ 4.5-1 + * Support: https://support.codesourcery.com/GNUToolchain/ + * + * Copyright (c) 2007, 2008, 2009, 2010 CodeSourcery, Inc. + * + * The authors hereby grant permission to use, copy, modify, distribute, + * and license this software and its documentation for any purpose, provided + * that existing copyright notices are retained in all copies and that this + * notice is included verbatim in any distributions. No written agreement, + * license, or royalty fee is required for any of the authorized uses. + * Modifications to this software may be copyrighted by their authors + * and need not follow the licensing terms described here, provided that + * the new terms are clearly indicated on the first page of each file where + * they apply. + */ +OUTPUT_FORMAT ("elf32-littlearm", "elf32-bigarm", "elf32-littlearm") + +/* Linker script to place sections and symbol values. Should be used together + * with other linker script that defines memory regions FLASH and RAM. + * It references following symbols, which must be defined in code: + * Reset_Handler : Entry of reset handler + * + * It defines following symbols, which code can use without definition: + * __exidx_start + * __exidx_end + * __etext + * __data_start__ + * __preinit_array_start + * __preinit_array_end + * __init_array_start + * __init_array_end + * __fini_array_start + * __fini_array_end + * __data_end__ + * __bss_start__ + * __bss_end__ + * __HeapBase + * __HeapLimit + * __StackLimit + * __StackTop + * __stack + * __bssnz_start__ + * __bssnz_end__ + */ +ENTRY(Reset_Handler) + +SECTIONS +{ + .imghdr (NOLOAD): + { + . = . + _imghdr_size; + } > FLASH + + __text = .; + + .text : + { + __isr_vector_start = .; + KEEP(*(.isr_vector)) + __isr_vector_end = .; + EXCLUDE_FILE(*liblc3.a: *libm.a: *libsamplerate.a: *audio_usb.o) *(.text*) + + KEEP(*(.init)) + KEEP(*(.fini)) + + . = ALIGN(4); + /* preinit data */ + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP(*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + + . = ALIGN(4); + /* init data */ + PROVIDE_HIDDEN (__init_array_start = .); + KEEP(*(SORT(.init_array.*))) + KEEP(*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + + . = ALIGN(4); + /* finit data */ + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP(*(SORT(.fini_array.*))) + KEEP(*(.fini_array)) + PROVIDE_HIDDEN (__fini_array_end = .); + + /* .ctors */ + *crtbegin.o(.ctors) + *crtbegin?.o(.ctors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) + *(SORT(.ctors.*)) + *(.ctors) + + /* .dtors */ + *crtbegin.o(.dtors) + *crtbegin?.o(.dtors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) + *(SORT(.dtors.*)) + *(.dtors) + + EXCLUDE_FILE(*liblc3.a: *libsamplerate.a:) *(.rodata*) + + *(.eh_frame*) + PROVIDE(mynewt_main = main); + . = ALIGN(4); + } > FLASH + + + .net_core_img : + { + PROVIDE(net_core_img_start = .); + KEEP(*(.net_core_img)); + PROVIDE(net_core_img_end = .); + } > FLASH + + .ARM.extab : + { + *(.ARM.extab* .gnu.linkonce.armextab.*) + . = ALIGN(4); + } > FLASH + + __exidx_start = .; + .ARM.exidx : + { + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + . = ALIGN(4); + } > FLASH + __exidx_end = .; + + __etext = .; + + .vector_relocation : + { + . = ALIGN(4); + __vector_tbl_reloc__ = .; + . = . + (__isr_vector_end - __isr_vector_start); + . = ALIGN(4); + } > RAM + + /* Section for app-net cores IPC */ + .ipc 0x20000400 (NOLOAD): + { + . = ALIGN(4); + *(.ipc) + . = ALIGN(4); + } > RAM + + /* This section will be zeroed by RTT package init */ + .rtt (NOLOAD): + { + . = ALIGN(4); + *(.rtt) + . = ALIGN(4); + } > RAM + + .data : + { + __data_start__ = .; + *(vtable) + *(.data*) + + *(.jcr) + *liblc3.a:(.text* .rodata*) + *libsamplerate.a:(.text* .rodata*) + *audio_usb.o(.text*) + *libm.a:(.text*) + . = ALIGN(4); + /* All data end */ + __data_end__ = .; + } > RAM AT > FLASH + + /* Non-zeroed BSS. This section is similar to BSS, but does not get zeroed at init-time. + */ + .bssnz : + { + . = ALIGN(4); + __bssnz_start__ = .; + *(.bss.core.nz*) + . = ALIGN(4); + __bssnz_end__ = .; + } > RAM + + .bss : + { + . = ALIGN(4); + __bss_start__ = .; + *(.bss*) + *(COMMON) + . = ALIGN(4); + __bss_end__ = .; + } > RAM + + /* Heap starts after BSS */ + . = ALIGN(8); + __HeapBase = .; + + /* .stack_dummy section doesn't contains any symbols. It is only + * used for linker to calculate size of stack sections, and assign + * values to stack symbols later */ + .stack_dummy (COPY): + { + *(.stack*) + } > RAM + + _ram_start = ORIGIN(RAM); + + /* Set stack top to end of RAM, and stack limit move down by + * size of stack_dummy section */ + __StackTop = ORIGIN(RAM) + LENGTH(RAM); + __StackLimit = __StackTop - SIZEOF(.stack_dummy); + PROVIDE(__stack = __StackTop); + + /* Top of head is the bottom of the stack */ + __HeapLimit = __StackLimit; + + /* Check if data + heap + stack exceeds RAM limit */ + ASSERT(__HeapBase <= __HeapLimit, "region RAM overflowed with stack") +} + diff --git a/targets/auracast_usb/nrf5340.ld b/targets/auracast_usb/nrf5340.ld new file mode 100644 index 0000000000..6ee5122a54 --- /dev/null +++ b/targets/auracast_usb/nrf5340.ld @@ -0,0 +1,26 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x0000c000, LENGTH = 0x76000 + RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x80000 +} + +/* This linker script is used for images and thus contains an image header */ +_imghdr_size = 0x20; diff --git a/targets/auracast_usb/pkg.yml b/targets/auracast_usb/pkg.yml new file mode 100755 index 0000000000..379a8ac882 --- /dev/null +++ b/targets/auracast_usb/pkg.yml @@ -0,0 +1,24 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +pkg.name: targets/auracast_usb +pkg.type: target +pkg.description: +pkg.author: +pkg.homepage: diff --git a/targets/auracast_usb/syscfg.yml b/targets/auracast_usb/syscfg.yml new file mode 100755 index 0000000000..2e58b5cbac --- /dev/null +++ b/targets/auracast_usb/syscfg.yml @@ -0,0 +1,25 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +syscfg.vals.BSP_NRF5340: + MCU_MPU_ENABLE: 0 + MCU_CACHE_ENABLED: 1 + BSP_NRF5340_NET_ENABLE: 1 + NRF5340_EMBED_NET_CORE: 1 + NET_CORE_IMAGE_TARGET_NAME: "@apache-mynewt-nimble/targets/nordic_pca10095_net-blehci_broadcaster" diff --git a/targets/auracast_usb/target.yml b/targets/auracast_usb/target.yml new file mode 100755 index 0000000000..3aa75b5248 --- /dev/null +++ b/targets/auracast_usb/target.yml @@ -0,0 +1,27 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +target.app: "@apache-mynewt-nimble/apps/auracast_usb" +target.bsp: "@apache-mynewt-core/hw/bsp/nordic_pca10121" +target.build_profile: speed + +# linkerscrupt that moves audio processing to RAM, for better performance +bsp.linkerscript: + - "@apache-mynewt-nimble/targets/auracast_usb/nrf5340.ld" + - "@apache-mynewt-nimble/targets/auracast_usb/nrf5340-mcu.ld" diff --git a/targets/dialog_cmac/syscfg.yml b/targets/dialog_cmac/syscfg.yml index b94427ac22..daf84a4ca9 100644 --- a/targets/dialog_cmac/syscfg.yml +++ b/targets/dialog_cmac/syscfg.yml @@ -21,10 +21,18 @@ syscfg.vals: MCU_DEEP_SLEEP: 1 MCU_SLP_TIMER: 1 MCU_SLP_TIMER_32K_ONLY: 1 + MCU_DEBUG_HCI_EVENT_ON_FAULT: 1 + MCU_DEBUG_HCI_EVENT_ON_ASSERT: 1 + MSYS_1_BLOCK_SIZE: 308 - BLE_HCI_TRANSPORT: dialog_cmac + BLE_TRANSPORT_HS: dialog_cmac + BLE_TRANSPORT_ACL_COUNT: 16 + BLE_TRANSPORT_ACL_SIZE: 255 + BLE_TRANSPORT_EVT_COUNT: 4 + BLE_TRANSPORT_EVT_DISCARDABLE_COUNT: 16 # LL recommended settings (decreasing timing values is not recommended) + BLE_LL_STACK_SIZE: 200 BLE_LL_CFG_FEAT_CTRL_TO_HOST_FLOW_CONTROL: 1 BLE_LL_CONN_INIT_MIN_WIN_OFFSET: 2 BLE_LL_RFMGMT_ENABLE_TIME: 20 @@ -32,4 +40,22 @@ syscfg.vals: BLE_LL_SCHED_AUX_CHAIN_MAFS_DELAY: 150 # NOTE: set public address in target settings - # BLE_PUBLIC_DEV_ADDR: "(uint8_t[6]){0xff, 0xff, 0xff, 0xff, 0xff, 0xff}" + # BLE_LL_PUBLIC_DEV_ADDR: 0xffffffffffff + + # LL features + BLE_VERSION: 53 + BLE_EXT_ADV: 1 + BLE_EXT_ADV_MAX_SIZE: 1650 + BLE_PERIODIC_ADV: 1 + BLE_PERIODIC_ADV_SYNC_TRANSFER: 1 + BLE_MULTI_ADV_INSTANCES: 4 + BLE_MAX_PERIODIC_SYNCS: 4 + BLE_MAX_CONNECTIONS: 4 + BLE_PHY_2M: 1 + BLE_LL_CFG_FEAT_DATA_LEN_EXT: 1 + BLE_LL_CFG_FEAT_LL_PRIVACY: 1 + BLE_LL_CFG_FEAT_LL_SCA_UPDATE: 1 + BLE_LL_CFG_FEAT_LL_ENHANCED_CONN_UPDATE: 1 + BLE_LL_CONN_INIT_SLOTS: 1 + BLE_LL_SCAN_AUX_SEGMENT_CNT: 16 + BLE_LL_NUM_SCAN_DUP_ADVS: 64 diff --git a/targets/nordic_pca10056-blehci-usb/pkg.yml b/targets/nordic_pca10056-blehci-usb/pkg.yml new file mode 100644 index 0000000000..2c8307d3df --- /dev/null +++ b/targets/nordic_pca10056-blehci-usb/pkg.yml @@ -0,0 +1,27 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +pkg.name: "targets/nordic_pca10056-blehci-usb" +pkg.type: target +pkg.description: +pkg.author: +pkg.homepage: + +pkg.deps: + - "@apache-mynewt-core/hw/usb/tinyusb" + - "@apache-mynewt-core/hw/usb/tinyusb/std_descriptors" diff --git a/targets/nordic_pca10056-blehci-usb/syscfg.yml b/targets/nordic_pca10056-blehci-usb/syscfg.yml new file mode 100644 index 0000000000..0c5701a98b --- /dev/null +++ b/targets/nordic_pca10056-blehci-usb/syscfg.yml @@ -0,0 +1,24 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +syscfg.vals: + BLE_TRANSPORT_HS: usb + USBD_BTH: 1 + + USBD_PID: 0xC01A + USBD_VID: 0xC0CA diff --git a/targets/nordic_pca10056-blehci-usb/target.yml b/targets/nordic_pca10056-blehci-usb/target.yml new file mode 100644 index 0000000000..ce455d45c9 --- /dev/null +++ b/targets/nordic_pca10056-blehci-usb/target.yml @@ -0,0 +1,21 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +target.app: "@apache-mynewt-nimble/apps/blehci" +target.bsp: "@apache-mynewt-core/hw/bsp/nordic_pca10056" +target.build_profile: debug diff --git a/targets/nordic_pca10095-blehci/pkg.yml b/targets/nordic_pca10095_net-blehci/pkg.yml similarity index 95% rename from targets/nordic_pca10095-blehci/pkg.yml rename to targets/nordic_pca10095_net-blehci/pkg.yml index 3b72abe1bc..af24376a83 100644 --- a/targets/nordic_pca10095-blehci/pkg.yml +++ b/targets/nordic_pca10095_net-blehci/pkg.yml @@ -17,7 +17,7 @@ # under the License. # -pkg.name: targets/nordic_pca10095-blehci +pkg.name: targets/nordic_pca10095_net-blehci pkg.type: target pkg.description: Sample target for BLE controller on NRF5340 pkg.author: "Apache Mynewt " diff --git a/targets/nordic_pca10095-blehci/syscfg.yml b/targets/nordic_pca10095_net-blehci/syscfg.yml similarity index 90% rename from targets/nordic_pca10095-blehci/syscfg.yml rename to targets/nordic_pca10095_net-blehci/syscfg.yml index 4a4a1ba069..30f9bcc985 100644 --- a/targets/nordic_pca10095-blehci/syscfg.yml +++ b/targets/nordic_pca10095_net-blehci/syscfg.yml @@ -18,20 +18,20 @@ # syscfg.vals: - BLE_HCI_TRANSPORT: nrf5340 + BLE_TRANSPORT_HS: nrf5340 MSYS_1_BLOCK_COUNT: 12 MSYS_1_BLOCK_SIZE: 292 BLE_LL_CFG_FEAT_DATA_LEN_EXT: 1 - BLE_LL_CFG_FEAT_LE_2M_PHY: 1 - BLE_LL_CFG_FEAT_LE_CODED_PHY: 1 + BLE_PHY_2M: 1 + BLE_PHY_CODED: 1 BLE_LL_CFG_FEAT_LL_PRIVACY: 1 BLE_LL_CFG_FEAT_CTRL_TO_HOST_FLOW_CONTROL: 1 BLE_LL_CONN_INIT_MAX_TX_BYTES: 251 BLE_LL_CONN_INIT_SLOTS: 4 BLE_LL_DTM: 1 BLE_LL_DTM_EXTENSIONS: 1 - BLE_LL_VND_EVENT_ON_ASSERT: 1 + BLE_LL_HCI_VS_EVENT_ON_ASSERT: 1 BLE_MAX_CONNECTIONS: 5 BLE_EXT_ADV: 1 BLE_EXT_ADV_MAX_SIZE: 1650 diff --git a/targets/nordic_pca10095-blehci/target.yml b/targets/nordic_pca10095_net-blehci/target.yml similarity index 100% rename from targets/nordic_pca10095-blehci/target.yml rename to targets/nordic_pca10095_net-blehci/target.yml diff --git a/targets/nordic_pca10095_net-blehci_broadcaster/pkg.yml b/targets/nordic_pca10095_net-blehci_broadcaster/pkg.yml new file mode 100644 index 0000000000..b8548dbb37 --- /dev/null +++ b/targets/nordic_pca10095_net-blehci_broadcaster/pkg.yml @@ -0,0 +1,24 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +pkg.name: targets/nordic_pca10095_net-blehci_broadcaster +pkg.type: target +pkg.description: Sample target for BLE controller on NRF5340 with enable LE Audio broadcaster +pkg.author: "Apache Mynewt " +pkg.homepage: "http://mynewt.apache.org/" diff --git a/targets/nordic_pca10095_net-blehci_broadcaster/syscfg.yml b/targets/nordic_pca10095_net-blehci_broadcaster/syscfg.yml new file mode 100644 index 0000000000..ba780d33cd --- /dev/null +++ b/targets/nordic_pca10095_net-blehci_broadcaster/syscfg.yml @@ -0,0 +1,47 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +syscfg.vals: + BLE_TRANSPORT_HS: nrf5340 + + MSYS_1_BLOCK_COUNT: 12 + MSYS_1_BLOCK_SIZE: 292 + BLE_LL_CFG_FEAT_DATA_LEN_EXT: 1 + BLE_PHY_2M: 1 + BLE_PHY_CODED: 1 + BLE_LL_CFG_FEAT_LL_PRIVACY: 1 + BLE_LL_CFG_FEAT_CTRL_TO_HOST_FLOW_CONTROL: 1 + BLE_LL_CONN_INIT_MAX_TX_BYTES: 251 + BLE_LL_CONN_INIT_SLOTS: 4 + BLE_LL_DTM: 1 + BLE_LL_DTM_EXTENSIONS: 1 + BLE_LL_HCI_VS_EVENT_ON_ASSERT: 1 + BLE_MAX_CONNECTIONS: 5 + BLE_EXT_ADV: 1 + BLE_EXT_ADV_MAX_SIZE: 1650 + BLE_MAX_PERIODIC_SYNCS: 5 + BLE_MULTI_ADV_INSTANCES: 5 + BLE_PERIODIC_ADV: 1 + BLE_PERIODIC_ADV_SYNC_TRANSFER: 1 + + BLE_VERSION: 54 + BLE_ISO: 1 + BLE_ISO_BROADCAST_SOURCE: 1 + BLE_ISO_MAX_BIGS: 1 + BLE_ISO_MAX_BISES: 2 diff --git a/targets/nordic_pca10095_net-blehci_broadcaster/target.yml b/targets/nordic_pca10095_net-blehci_broadcaster/target.yml new file mode 100644 index 0000000000..4d2641b77c --- /dev/null +++ b/targets/nordic_pca10095_net-blehci_broadcaster/target.yml @@ -0,0 +1,22 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +target.app: "@apache-mynewt-nimble/apps/blehci" +target.bsp: "@apache-mynewt-core/hw/bsp/nordic_pca10095_net" +target.build_profile: debug diff --git a/tools/README.md b/tools/README.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tools/hci_throughput/README.md b/tools/hci_throughput/README.md new file mode 100644 index 0000000000..1e153928a9 --- /dev/null +++ b/tools/hci_throughput/README.md @@ -0,0 +1,110 @@ +# HCI Throughput + +Tool for measuring BLE throughput. + +## Packages versions +Python 3.8.10 \ +Matplotlib 3.5.1 + +Install all required packages with: +``` +sudo pip install -r requirements.txt +``` + +## Usage +### Prepare devices +This tool may be used with the existing controller or with any board with ```blehci``` app. + + - If you want to use the builtin PC controller, provide HCI index of the controller. Turn the Bluetooth ON on your device, run ```hciconfig``` in the terminal and get the HCI index. In the case below HCI index is equal to 0: + +``` +user@user:~$ hciconfig +hci0: Type: Primary Bus: USB + BD Address: 64:BC:58:E2:9C:52 ACL MTU: 1021:4 SCO MTU: 96:6 + UP RUNNING + RX bytes:20003 acl:0 sco:0 events:3176 errors:0 + TX bytes:771246 acl:0 sco:0 commands:3174 errors:0 +``` + + - If you want to use the nimble controller, create the image and load the provided target (can be found under ```/targets``` for NRF52840 and NRF52832). + - NRF52840 may use USB or UART as HCI transport. The target is configured for USB by default. + - NRF52832 uses UART as HCI transport. This requires some additional configuration. Get the tty path and run in the terminal: + ``` + sudo btattach -B /dev/ttyACM0 -S 1000000 + ``` + Then proceed with ```hciconfig``` as shown above. + +### Run tests + + +This tool opens a raw socket which requires running all scripts as ```sudo```. Copy the ```config.yaml.sample``` file, change the name to ```config.yaml``` and fill the parameters. +Optionally pass the path to the custom transport directory if used. Run ```main.py``` as shown below: +``` +sudo python main.py -i -m rx tx -t -cf config.yaml +``` +Switch `````` and `````` to corresponding hci indexes present in your computer. ```-m```, ```-t``` and ```-cf``` may be omitted if the defaults are correct. \ +The output provides the plots of measured throughput in ```kb``` or ```kB``` as predefined in ```config.yaml```. In addition to the throughput plots, when the ```flag_plot_packets``` is turned on, the number of packets transmitted/received in time is visualized. + +**_When encountering issues with running tests, try to investigate the files in the log folder._** + +#### Set ```config.yaml``` file +To run **once** the throughput measurement with given parameters, set the ```flag_testing``` to false. +``` +flag_testing: false +``` + +To run the throughput measurements **more than once** with the same parameters and to generate the plot of average throughputs, set ```config.yaml``` as shown below: +``` +show_tp_plots: false +flag_testing: true +test: + change_param_group: null + change_param_variable: null + start_value: 0 + stop_value: 5 + step: 1 +``` +This configuration provides 5 measurements. The ```show_tp_plots``` flag is optionally set as ```false``` for speed, changing it to ```true``` will trigger rx and tx throughput plots at the end of every iteration. + +To run the throughput measurement with some parameters changing within tests, fill config as below: +``` +flag_testing: true +test: + change_param_group: + - conn + - conn + change_param_variable: + - connection_interval_min + - connection_interval_max + start_value: 0x000A + stop_value: 0x0320 + step: 20 +``` +This will run each test incrementing ```connection_interval_min``` and ```connection_interval_max``` by 20. the final plot will show the influence of the parameters change on the average throughput. + +## Tools +The ```main.py``` script usees all tools mentioned below and it is advised to use it above all. Nevertheless, the sub-tools may be used separately as shown below. + +### HCI device sub-tool +```hci_device.py``` is a tool that manages one hci device. User can provide parameters and run it as receiver or transmitter as shown below: +``` +sudo python hci_device.py -m rx -oa 00:00:00:00:00:00 -oat 0 -di 0 -pa 00:00:00:00:00:00 -pat 0 -pdi 0 -cf config.yaml +``` +Run ```python hci_device.py --help``` for parameters description. \ +If properly configured ```init.yaml``` is present (it is created automatically while running ```main.py```), the script can be run like this: + +``` +sudo python hci_device.py -m tx -if init.yaml +``` + +### Check addr sub-tool +When given hci indexes, ```check_addr.py``` returns devices' address types and addresses. Optionally pass the path to the custom transport directory if used. +``` +sudo python check_addr.py -i ... -t +``` + +### Throughput sub-tool +The timestamps of the received packets are stored in csv files (```tp_receiver.csv``` and ```tp_transmitter.csv``` by default). If the program stopped in the middle of the measurements, you can still plot the values and get the average througput. Provide the filename, sample time and run the tool as shown below: +``` +python throughput.py -f tp_receiver -s 0.1 +``` diff --git a/tools/hci_throughput/check_addr.py b/tools/hci_throughput/check_addr.py new file mode 100644 index 0000000000..ce2a944651 --- /dev/null +++ b/tools/hci_throughput/check_addr.py @@ -0,0 +1,124 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +import argparse +import asyncio +import hci_commands +import sys +import logging +import hci +import traceback +import util +import transport_factory + + +def parse_arguments(): + parser = argparse.ArgumentParser( + description='Check HCI device address type and address', + epilog='How to run script: \ + sudo python check_addr.py -i 0 1 2 \ + -t path/to/custom_transport_dir') + parser.add_argument('-i', '--indexes', type=str, nargs='*', + help='specify hci adapters indexes', default=0) + parser.add_argument('-t', '--transport_directory', type=str, nargs='*', + help='specify hci transport directory path. \ + Use for transport other than the default linux socket.', + default=["default"]) + try: + args = parser.parse_args() + if (isinstance(args.transport_directory, list)): + args.transport_directory = args.transport_directory.pop() + else: + args.transport_directory = args.transport_directory + + except Exception as e: + print(traceback.format_exc()) + return args + + +async def main(dev: hci_commands.HCI_Commands): + result = tuple() + task = asyncio.create_task(dev.rx_buffer_q_wait()) + await dev.cmd_reset() + await dev.cmd_read_bd_addr() + + if hci.bdaddr != '00:00:00:00:00:00': + logging.info("Type public: %s, address: %s", + hci.PUBLIC_ADDRESS_TYPE, hci.bdaddr) + result = (0, hci.bdaddr) + print("Public address: ", result) + else: + await dev.cmd_vs_read_static_addr() + if hci.static_addr != '00:00:00:00:00:00': + logging.info("Type static random: %s, address: %s", + hci.STATIC_RANDOM_ADDRESS_TYPE, hci.static_addr) + result = (1, hci.static_addr) + print("Static random address: ", result) + else: + addr = hci.gen_static_rand_addr() + logging.info("Type static random: %s, generated address: %s", + hci.STATIC_RANDOM_ADDRESS_TYPE, addr) + result = (1, addr) + print("Generated static random address: ", result) + task.cancel() + return result + + +def check_addr( + device_indexes: list, + addresses: list, + transport_directory: str) -> list: + util.configure_logging(f"log/check_addr.log", clear_log_file=True) + + logging.info(f"Devices indexes: {device_indexes}") + for index in device_indexes: + loop = asyncio.new_event_loop() + asyncio.set_event_loop(loop) + loop.set_debug(True) + + transport = transport_factory.TransportFactory(device_index=str( + index), asyncio_loop=loop, transport_directory=transport_directory) + + bt_dev = hci_commands.HCI_Commands(send=transport.send, + rx_buffer_q=transport.rx_buffer_q, + asyncio_loop=loop) + + transport.start() + + addresses.append(loop.run_until_complete(main(bt_dev))) + + transport.stop() + loop.close() + + logging.info(f"Finished: {addresses}") + return addresses + + +if __name__ == '__main__': + try: + args = parse_arguments() + print(args) + addresses = [] + addresses = check_addr(args.indexes, addresses, + args.transport_directory) + print(addresses) + except Exception as e: + print(traceback.format_exc()) + finally: + sys.exit() diff --git a/tools/hci_throughput/config.yaml.sample b/tools/hci_throughput/config.yaml.sample new file mode 100644 index 0000000000..6d5dcbcf8a --- /dev/null +++ b/tools/hci_throughput/config.yaml.sample @@ -0,0 +1,56 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +num_of_bytes_to_send: 247 +num_of_packets_to_send: 2000 +show_tp_plots: true +flag_testing: false +test: + change_param_group: + - conn + - conn + change_param_variable: + - connection_interval_min + - connection_interval_max + start_value: 16 + stop_value: 160 + step: 8 +tp: + data_type: kb + sample_time: 0.1 + flag_plot_packets: true +phy: 2M +adv: + advertising_interval_min: 2048 + advertising_interval_max: 2048 + advertising_type: 0 + peer_address: 00:00:00:00:00:00 + advertising_channel_map: 7 + advertising_filter_policy: 0 +enable_encryption: false +conn: + le_scan_interval: 2400 + le_scan_window: 2400 + initiator_filter_policy: 0 + connection_interval_min: 0x0080 + connection_interval_max: 0x0080 + max_latency: 0 + supervision_timeout: 3200 + min_ce_length: 0 + max_ce_length: 0 \ No newline at end of file diff --git a/tools/hci_throughput/hci.py b/tools/hci_throughput/hci.py new file mode 100644 index 0000000000..e5eb1179c9 --- /dev/null +++ b/tools/hci_throughput/hci.py @@ -0,0 +1,742 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +from dataclasses import dataclass +import struct +from binascii import unhexlify +import random +import ctypes + +############ +# DEFINES +############ +AF_BLUETOOTH = 31 +HCI_CHANNEL_USER = 1 +HCI_COMMAND_PACKET = 0x01 +HCI_ACL_DATA_PACKET = 0x02 +HCI_EVENT_PACKET = 0x04 + +L2CAP_HDR_BYTES = 4 + +HCI_EV_CODE_DISCONN_CMP = 0x05 +HCI_EV_CODE_ENCRYPTION_CHANGE = 0x08 +HCI_EV_CODE_CMD_CMP = 0x0e +HCI_EV_CODE_CMD_STATUS = 0x0f +HCI_EV_CODE_LE_META_EVENT = 0x3e +HCI_SUBEV_CODE_LE_ENHANCED_CONN_CMP = 0x0a +HCI_SUBEV_CODE_LE_DATA_LEN_CHANGE = 0x07 +HCI_SUBEV_CODE_LE_PHY_UPDATE_CMP = 0x0c +HCI_SUBEV_CODE_LE_CHAN_SEL_ALG = 0x14 +HCI_SUBEV_CODE_LE_LONG_TERM_KEY_REQUEST = 0x05 +HCI_EV_NUM_COMP_PKTS = 0x13 + +CONN_FAILED_TO_BE_ESTABLISHED = 0x3e +CONN_TIMEOUT = 0x08 + +OGF_HOST_CTL = 0x03 +OCF_SET_EVENT_MASK = 0x0001 +OCF_RESET = 0X0003 + +OGF_INFO_PARAM = 0x04 +OCF_READ_LOCAL_COMMANDS = 0x0002 +OCF_READ_BD_ADDR = 0x0009 + +OGF_LE_CTL = 0x08 +OCF_LE_SET_EVENT_MASK = 0x0001 +OCF_LE_READ_BUFFER_SIZE_V1 = 0x0002 +OCF_LE_READ_LOCAL_SUPPORTED_FEATURES = 0x0003 +OCF_LE_READ_BUFFER_SIZE_V2 = 0x0060 +OCF_LE_SET_RANDOM_ADDRESS = 0x0005 +OCF_LE_SET_ADVERTISING_PARAMETERS = 0x0006 +OCF_LE_SET_ADVERTISE_ENABLE = 0x000a +OCF_LE_SET_SCAN_PARAMETERS = 0x000b +OCF_LE_SET_SCAN_ENABLE = 0x000c +OCF_LE_CREATE_CONN = 0x000d +OCF_LE_ENABLE_ENCRYPTION = 0x0019 +OCF_LE_LONG_TERM_KEY_REQUEST_REPLY = 0x001A +OCF_LE_SET_DATA_LEN = 0x0022 +OCF_LE_READ_SUGGESTED_DFLT_DATA_LEN = 0x0023 +OCF_LE_READ_MAX_DATA_LEN = 0x002f +OCF_LE_READ_PHY = 0x0030 +OCF_LE_SET_DFLT_PHY = 0x0031 +OCF_LE_SET_PHY = 0x0032 + +OGF_VENDOR_SPECIFIC = 0x003f +BLE_HCI_OCF_VS_RD_STATIC_ADDR = 0x0001 + +PUBLIC_ADDRESS_TYPE = 0 +STATIC_RANDOM_ADDRESS_TYPE = 1 + +WAIT_FOR_EVENT_TIMEOUT = 5 +WAIT_FOR_EVENT_CONN_TIMEOUT = 25 + +LE_FEATURE_2M_PHY = ctypes.c_uint64(0x0100).value +LE_FEATURE_CODED_PHY = ctypes.c_uint64(0x0800).value + +############ +# GLOBAL VAR +############ +num_of_bytes_to_send = None # based on supported_max_tx_octets +num_of_packets_to_send = None + +events_list = [] +bdaddr = '00:00:00:00:00:00' +static_addr = '00:00:00:00:00:00' +le_read_buffer_size = None +conn_handle = 0 +requested_tx_octets = 1 +requested_tx_time = 1 +suggested_dflt_data_len = None +max_data_len = None +phy = None +ev_num_comp_pkts = None +num_of_completed_packets_cnt = 0 +num_of_completed_packets_time = 0 +read_local_commands = None +le_read_local_supported_features = None +ltk = None + +############ +# FUNCTIONS +############ + + +def get_opcode(ogf: int, ocf: int): + return ((ocf & 0x03ff) | (ogf << 10)) + + +def get_ogf_ocf(opcode: int): + ogf = opcode >> 10 + ocf = opcode & 0x03ff + return ogf, ocf + + +def cmd_addr_to_ba(addr_str: str): + return unhexlify("".join(addr_str.split(':')))[::-1] + + +def ba_addr_to_str(addr_ba: bytearray): + addr_str = addr_ba.hex().upper() + return ':'.join(addr_str[i:i + 2] + for i in range(len(addr_str), -2, -2))[1:] + + +def gen_static_rand_addr(): + while True: + x = [random.randint(0, 1) for _ in range(0, 48)] + + if 0 in x[:-2] and 1 in x[:-2]: + x[0] = 1 + x[1] = 1 + break + addr_int = int("".join([str(x[i]) for i in range(0, len(x))]), 2) + addr_hex = "{0:0{1}x}".format(addr_int, 12) + addr = ":".join(addr_hex[i:i + 2] for i in range(0, len(addr_hex), 2)) + return addr.upper() + +############ +# GLOBAL VAR CLASSES +############ + + +@dataclass +class Suggested_Dflt_Data_Length(): + status: int + suggested_max_tx_octets: int + suggested_max_tx_time: int + + def __init__(self): + self.set() + + def set( + self, + status=0, + suggested_max_tx_octets=0, + suggested_max_tx_time=0): + self.status = status + self.suggested_max_tx_octets = suggested_max_tx_octets + self.suggested_max_tx_time = suggested_max_tx_time + + +@dataclass +class Max_Data_Length(): + status: int + supported_max_tx_octets: int + supported_max_tx_time: int + supported_max_rx_octets: int + supported_max_rx_time: int + + def __init__(self): + self.set() + + def set(self, status=0, supported_max_tx_octets=0, supported_max_tx_time=0, + supported_max_rx_octets=0, supported_max_rx_time=0): + self.status = status + self.supported_max_tx_octets = supported_max_tx_octets + self.supported_max_tx_time = supported_max_tx_time + self.supported_max_rx_octets = supported_max_rx_octets + self.supported_max_rx_time = supported_max_rx_time + + +@dataclass +class LE_Read_Buffer_Size: + status: int + le_acl_data_packet_length: int + total_num_le_acl_data_packets: int + iso_data_packet_len: int + total_num_iso_data_packets: int + + def __init__(self): + self.set() + + def set(self, status=0, le_acl_data_packet_length=0, + total_num_le_acl_data_packets=0, iso_data_packet_len=0, + total_num_iso_data_packets=0): + self.status = status + self.le_acl_data_packet_length = le_acl_data_packet_length + self.total_num_le_acl_data_packets = total_num_le_acl_data_packets + self.iso_data_packet_len = iso_data_packet_len + self.total_num_iso_data_packets = total_num_iso_data_packets + + +@dataclass +class LE_Read_PHY: + status: int + connection_handle: int + tx_phy: int + rx_phy: int + + def __init__(self): + self.set() + + def set(self, status=0, connection_handle=0, tx_phy=0, rx_phy=0): + self.status = status + self.connection_handle = connection_handle + self.tx_phy = tx_phy + self.rx_phy = rx_phy + + +@dataclass +class Read_Local_Commands: + status: int + supported_commands: bytes + + def __init__(self): + self.set() + + def set(self, rcv_bytes=bytes(65)): + self.status = int(rcv_bytes[0]) + self.supported_commands = rcv_bytes[1:] + + +@dataclass +class LE_Read_Local_Supported_Features: + status: int + le_features: bytes + + def __init__(self): + self.set() + + def set(self, rcv_bytes=bytes(9)): + self.status = int(rcv_bytes[0]) + self.le_features = ctypes.c_uint64.from_buffer_copy( + rcv_bytes[1:]).value + +############ +# EVENTS +############ + + +@dataclass +class HCI_Ev_Disconn_Complete: + status: int + connection_handle: int + reason: int + + def __init__(self): + self.set() + + def set(self, status=0, connection_handle=0, reason=0): + self.status = status + self.connection_handle = connection_handle + self.reason = reason + + +@dataclass +class HCI_Ev_Cmd_Complete: + num_hci_command_packets: int + opcode: int + return_parameters: int + + def __init__(self): + self.set() + + def set(self, num_hci_cmd_packets=0, opcode=0, return_parameters=b''): + self.num_hci_command_packets = num_hci_cmd_packets + self.opcode = opcode + self.return_parameters = return_parameters + + +@dataclass +class HCI_Ev_Cmd_Status: + status: int + num_hci_command_packets: int + opcode: int + + def __init__(self): + self.set() + + def set(self, status=0, num_hci_cmd_packets=0, opcode=0): + self.status = status + self.num_hci_command_packets = num_hci_cmd_packets + self.opcode = opcode + + +@dataclass +class HCI_Ev_LE_Encryption_Change(): + status: int + connection_handle: int + encryption_enabled: int + + def __init__(self): + self.set() + + def set(self, status=0, connection_handle=0, encryption_enabled=0): + self.status = status + self.connection_handle = connection_handle + self.encryption_enabled = encryption_enabled + + +@dataclass +class HCI_Ev_LE_Meta: + subevent_code: int + + def __init__(self): + self.set() + + def set(self, subevent_code=0): + self.subevent_code = subevent_code + + +@dataclass +class HCI_Ev_LE_Enhanced_Connection_Complete(HCI_Ev_LE_Meta): + status: int + connection_handle: int + role: int + peer_address_type: int + peer_address: str + local_resolvable_private_address: int + peer_resolvable_private_address: int + connection_interval: int + peripheral_latency: int + supervision_timeout: int + central_clock_accuracy: int + + def __init__(self): + self.set() + + def set(self, subevent_code=0, status=0, connection_handle=0, role=0, + peer_address_type=0, peer_address='00:00:00:00:00:00', + local_resolvable_private_address='00:00:00:00:00:00', + peer_resolvable_private_address='00:00:00:00:00:00', + connection_interval=0, peripheral_latency=0, supervision_timeout=0, + central_clock_accuracy=0): + super().set(subevent_code) + self.status = status + self.connection_handle = connection_handle + self.role = role + self.peer_address_type = peer_address_type + self.peer_address = peer_address + self.local_resolvable_private_address = local_resolvable_private_address + self.peer_resolvable_private_address = peer_resolvable_private_address + self.connection_interval = connection_interval + self.peripheral_latency = peripheral_latency + self.supervision_timeout = supervision_timeout + self.central_clock_accuracy = central_clock_accuracy + + +@dataclass +class HCI_Ev_LE_Data_Length_Change(HCI_Ev_LE_Meta): + conn_handle: int + max_tx_octets: int + max_tx_time: int + max_rx_octets: int + max_rx_time: int + triggered: int + + def __init__(self): + self.set() + + def set(self, subevent_code=0, conn_handle=0, max_tx_octets=0, + max_tx_time=0, max_rx_octets=0, max_rx_time=0, triggered=0): + super().set(subevent_code) + self.conn_handle = conn_handle + self.max_tx_octets = max_tx_octets + self.max_tx_time = max_tx_time + self.max_rx_octets = max_rx_octets + self.max_rx_time = max_rx_time + self.triggered = triggered + + +@dataclass +class HCI_Ev_LE_Long_Term_Key_Request(HCI_Ev_LE_Meta): + conn_handle: int + random_number: int + encrypted_diversifier: int + + def __init__(self): + self.set() + + def set(self, subevent_code=0, conn_handle=0, random_number=0, + encrypted_diversifier=0): + super().set(subevent_code) + self.conn_handle = conn_handle + self.random_number = random_number + self.encrypted_diversifier = encrypted_diversifier + + +@dataclass +class HCI_Ev_LE_PHY_Update_Complete(HCI_Ev_LE_Meta): + status: int + connection_handle: int + tx_phy: int + rx_phy: int + + def __init__(self): + self.set() + + def set(self, subevent_code=0, status=0, connection_handle=0, + tx_phy=0, rx_phy=0): + super().set(subevent_code) + self.status = status + self.connection_handle = connection_handle + self.tx_phy = tx_phy + self.rx_phy = rx_phy + + +@dataclass +class HCI_Number_Of_Completed_Packets: + num_handles: int + connection_handle: int + num_completed_packets: int + + def __init__(self): + self.set() + + def set(self, num_handles=0, connection_handle=0, num_completed_packets=0): + self.num_handles = num_handles + self.connection_handle = connection_handle + self.num_completed_packets = num_completed_packets + + +class HCI_Ev_LE_Chan_Sel_Alg(HCI_Ev_LE_Meta): + connection_handle: int + algorithm: int + + def __init__(self): + self.set() + + def set(self, subevent_code=0, connection_handle=0, algorithm=0): + super().set(subevent_code) + self.connection_handle = connection_handle + self.algorithm = algorithm + +############ +# PARAMETERS +############ + + +@dataclass +class HCI_Advertising: + advertising_interval_min: int + advertising_interval_max: int + advertising_type: int + own_address_type: int + peer_address_type: int + peer_address: str + advertising_channel_map: int + advertising_filter_policy: int + ba_full_message: bytearray + + def __init__(self): + self.set() + + def set(self, advertising_interval_min=0, advertising_interval_max=0, + advertising_type=0, own_address_type=0, peer_address_type=0, + peer_address='00:00:00:00:00:00', advertising_channel_map=0, + advertising_filter_policy=0): + self.advertising_interval_min = advertising_interval_min + self.advertising_interval_max = advertising_interval_max + self.advertising_type = advertising_type + self.own_address_type = own_address_type + self.peer_address_type = peer_address_type + self.peer_address = peer_address + self.advertising_channel_map = advertising_channel_map + self.advertising_filter_policy = advertising_filter_policy + self.ba_full_message = bytearray( + struct.pack( + ' int: + current_ev_name = type( + self.hci_recv_ev_packet.current_event).__name__ + if current_ev_name == type(hci.HCI_Ev_Cmd_Complete()).__name__: + return struct.unpack_from( + " + hci.max_data_len.supported_max_tx_octets - hci.L2CAP_HDR_BYTES): + logging.critical( + f"Number of data bytes to send + 4 bytes of L2CAP header: {hci.num_of_bytes_to_send + 4} " + f"exceeds allowed value of: {hci.max_data_len.supported_max_tx_octets}. Closing.") + raise SystemExit( + f"Number of data bytes to send + 4 bytes of L2CAP header: {hci.num_of_bytes_to_send + 4} " + f"exceeds allowed value of: {hci.max_data_len.supported_max_tx_octets}. Closing.") + + return status() + elif ocf == hci.OCF_LE_READ_PHY: + hci.phy = hci.LE_Read_PHY() + hci.phy.set(*struct.unpack('> 12 + bc_flag = (handle_pb_bc_flags & 0xC000) >> 14 + + hci_recv_acl_data_packet = hci.HCI_Recv_ACL_Data_Packet() + + if pb_flag == 0b10: + l2cap_data = hci.HCI_Recv_L2CAP_Data() + data = buffer[5:] + l2cap_data.set(*struct.unpack(" self.tp.sample_time \ + # or packet_number == 0 \ + # or packet_number == self.tp.total_packets_number-1: + # self.tp.record_throughput(packet_number, timestamp) + # self.last_timestamp = timestamp + + if packet_number >= self.tp.total_packets_number - 1: + self.async_ev_recv_data_finish.set() + + def handle_acl_data(self, buffer: bytes, timestamp: int): + hci_recv_acl_data_packet = self.parse_acl_data(buffer) + logging.debug("%s", hci_recv_acl_data_packet) + recv_data_type = type(hci_recv_acl_data_packet.data).__name__ + if recv_data_type == 'HCI_Recv_L2CAP_Data': + self.match_recv_l2cap_data(buffer, timestamp) + + async def recv_handler(self): + while not self.rx_buffer_q.empty(): + q_buffer_item, q_timestamp = self.rx_buffer_q.get() + packet_type = struct.unpack(' 0 and packets_to_send > 0: + data, last_value = tp.gen_data( + hci.num_of_bytes_to_send, last_value) + l2cap_data.set(channel_id=0x0044, data=data) + acl_data.set(connection_handle=hci.conn_handle, pb_flag=0b00, + bc_flag=0b00, data=l2cap_data.ba_full_message) + await bt_dev.acl_data_send(acl_data) + async with bt_dev.async_lock_packets_cnt: + packets_to_send -= 1 + packet_credits -= 1 + else: + logging.info(f"Waiting for num_of_cmp_packets event") + await bt_dev.async_ev_num_cmp_pckts.wait() + bt_dev.async_ev_num_cmp_pckts.clear() + + if hci.num_of_completed_packets_cnt > 0: + async with bt_dev.async_lock_packets_cnt: + sent_packets += hci.num_of_completed_packets_cnt + tx_sent_timestamps.append((hci.num_of_completed_packets_time, + sent_packets)) + logging.info(f"Sent : {sent_packets}") + + packet_credits += hci.num_of_completed_packets_cnt + hci.num_of_completed_packets_cnt = 0 + + for timestamp in tx_sent_timestamps: + bt_dev.tp.append_to_csv_file(*timestamp) + + await finish(bt_dev, cfg) + + +def parse_cfg_files(args) -> dict: + if args.init_file is None: + ini = { + "own_address": args.own_addr, + "own_address_type": args.own_addr_type, + "dev_index": args.dev_idx, + "peer_address": args.peer_addr, + "peer_address_type": args.peer_addr_type, + "peer_dev_index": args.peer_dev_idx + } + else: + with open(args.init_file, "r") as file: + init_file = yaml.safe_load(file) + ini = init_file[args.mode] + global test_dir, transport_directory, ltk + test_dir = init_file["test_dir"] + transport_directory = init_file["transport_directory"] + hci.ltk = int(init_file["ltk"], 16) + + with open(args.config_file) as f: + cfg = yaml.safe_load(f) + + global show_tp_plots + + hci.num_of_bytes_to_send = cfg["num_of_bytes_to_send"] + hci.num_of_packets_to_send = cfg["num_of_packets_to_send"] + show_tp_plots = cfg["show_tp_plots"] + + return ini, cfg + + +def signal_handler(signum, frame): + logging.critical(f"Received signal: {signal.Signals(signum).name}") + raise ParentCalledException( + f"Received signal: {signal.Signals(signum).name}") + + +def main(): + args = parse_arguments() + ini, cfg = parse_cfg_files(args) + log_path = f"log/log_{args.mode}.log" + transport = None + + try: + util.configure_logging(log_path, clear_log_file=True) + + loop = asyncio.get_event_loop() + loop.set_debug(True) + + transport = transport_factory.TransportFactory( + device_index=ini['dev_index'], + device_mode=args.mode, asyncio_loop=loop, + transport_directory=transport_directory) + + signal.signal(signal.SIGTERM, signal_handler) + + bt_dev = hci_commands.HCI_Commands(send=transport.send, + rx_buffer_q=transport.rx_buffer_q, + asyncio_loop=loop, + device_mode=args.mode) + + transport.start() + + if args.mode == 'rx': + loop.run_until_complete(async_main_rx(bt_dev, ini, cfg)) + elif args.mode == 'tx': + loop.run_until_complete(async_main_tx(bt_dev, ini, cfg)) + + except Exception as e: + logging.error(traceback.format_exc()) + except (KeyboardInterrupt or ParentCalledException): + logging.critical("Hard exit triggered.") + logging.error(traceback.format_exc()) + finally: + if transport is not None: + transport.stop() + sys.exit() + + +if __name__ == '__main__': + main() diff --git a/tools/hci_throughput/hci_socket.py b/tools/hci_throughput/hci_socket.py new file mode 100644 index 0000000000..da908b8f60 --- /dev/null +++ b/tools/hci_throughput/hci_socket.py @@ -0,0 +1,173 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +import hci +import socket +import ctypes +import struct +import asyncio +import logging +import subprocess +import sys +import time +import multiprocessing + + +SOCKET_RECV_BUFFER_SIZE = 425984 +SOCKET_RECV_TIMEOUT = 3 + + +def btmgmt_dev_reset(index): + logging.info(f"Selecting index {index}") + proc = subprocess.Popen(['btmgmt', '-i', str(index), 'power', 'off'], + shell=False, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + proc.communicate() + + +class BindingError(Exception): + pass + + +class HCI_User_Channel_Socket_Error(BaseException): + pass + + +class HCI_User_Channel_Socket(): + def __init__(self, device_index=0, device_mode=None, + asyncio_loop=None): + logging.debug( + "Device index: %s, Device address: %s", + device_index, + device_mode) + self.loop = asyncio_loop + self.libc = ctypes.cdll.LoadLibrary('libc.so.6') + self.rx_buffer_q = multiprocessing.Manager().Queue() + self.counter = 0 + self.device_index = device_index + self.device_mode = device_mode + self.hci_socket = self.socket_create() + self.socket_bind(self.device_index) + self.socket_clear() + self.listener_proc = None + self.listener_ev = multiprocessing.Manager().Event() + + def socket_create(self): + logging.debug("%s", self.socket_create.__name__) + new_socket = socket.socket(socket.AF_BLUETOOTH, + socket.SOCK_RAW | socket.SOCK_NONBLOCK, + socket.BTPROTO_HCI) + if new_socket is None: + raise HCI_User_Channel_Socket_Error("Socket error. \ + Opening socket failed") + new_socket.setblocking(False) + socket_size = new_socket.getsockopt( + socket.SOL_SOCKET, socket.SO_RCVBUF) + logging.info(f"Default socket recv buffer size: {socket_size}") + new_socket.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 500000) + socket_size = new_socket.getsockopt( + socket.SOL_SOCKET, socket.SO_RCVBUF) + logging.info(f"Set socket recv buffer size: {socket_size}") + return new_socket + + def socket_bind(self, index): + logging.debug("%s index: %s", self.socket_bind.__name__, index) + # addr: struct sockaddr_hci from /usr/include/bluetooth/hci.h + addr = struct.pack( + 'HHH', + hci.AF_BLUETOOTH, + index, + hci.HCI_CHANNEL_USER) + retry_binding = 2 + for i in range(retry_binding): + try: + bind = self.libc.bind(self.hci_socket.fileno(), + ctypes.cast(addr, + ctypes.POINTER(ctypes.c_ubyte)), + len(addr)) + if bind != 0: + raise BindingError + except BindingError: + logging.warning("Binding error. Trying to reset bluetooth.") + btmgmt_dev_reset(self.device_index) + if i < retry_binding - 1: + continue + else: + self.hci_socket.close() + logging.error("Binding error. Check HCI index present.") + sys.exit() + logging.info("Binding done!") + break + + def socket_clear(self): + logging.debug("%s", self.socket_clear.__name__) + try: + logging.info("Clearing the buffer...") + time.sleep(1) + cnt = 0 + while True: + buff = self.hci_socket.recv(SOCKET_RECV_BUFFER_SIZE) + cnt += len(buff) + logging.debug(f"Read from buffer {cnt} bytes") + except BlockingIOError: + logging.info("Buffer empty and ready!") + return + + async def send(self, ba_message): + await self.loop.sock_sendall(self.hci_socket, ba_message) + + def socket_listener(self): + recv_at_once = 0 + while True: + try: + if self.listener_ev.is_set(): + logging.info("listener_ev set") + break + buffer = self.hci_socket.recv(SOCKET_RECV_BUFFER_SIZE) + logging.info( + f"Socket recv: {self.counter} th packet with len: {len(buffer)}") + self.rx_buffer_q.put((buffer, time.perf_counter())) + recv_at_once += 1 + self.counter += 1 + + except BlockingIOError: + if recv_at_once > 1: + logging.info(f"Socket recv in one loop: {recv_at_once}") + recv_at_once = 0 + pass + except BrokenPipeError: + logging.info("BrokenPipeError: Closing...") + print("BrokenPipeError. Press Ctrl-C to exit...") + + def close(self): + logging.debug("%s ", self.close.__name__) + return self.hci_socket.close() + + def start(self): + self.listener_proc = multiprocessing.Process( + target=self.socket_listener, daemon=True) + self.listener_proc.start() + logging.info(f"start listener_proc pid: {self.listener_proc.pid}") + + def stop(self): + logging.info(f"stop listener_proc pid: {self.listener_proc.pid}") + self.listener_ev.set() + self.listener_proc.join() + self.close() diff --git a/tools/hci_throughput/init.yaml.sample b/tools/hci_throughput/init.yaml.sample new file mode 100644 index 0000000000..f097d9cf2c --- /dev/null +++ b/tools/hci_throughput/init.yaml.sample @@ -0,0 +1,36 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +rx: + dev_index: '1' + own_address_type: 1 + own_address: C0:0D:A5:1A:98:EF + peer_dev_index: '2' + peer_address_type: 1 + peer_address: FE:69:8F:77:2F:49 +tx: + dev_index: '2' + own_address_type: 1 + own_address: FE:69:8F:77:2F:49 + peer_dev_index: '1' + peer_address_type: 1 + peer_address: C0:0D:A5:1A:98:EF +test_dir: /path/to/blehci_throughput/tests/Mon_May_23_12:29:10_2022 +transport_directory: default or /path/to/custom_transport.py +ltk: '0xXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' \ No newline at end of file diff --git a/tools/hci_throughput/log/.gitignore b/tools/hci_throughput/log/.gitignore new file mode 100644 index 0000000000..c96a04f008 --- /dev/null +++ b/tools/hci_throughput/log/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/tools/hci_throughput/main.py b/tools/hci_throughput/main.py new file mode 100644 index 0000000000..1f9d6e1518 --- /dev/null +++ b/tools/hci_throughput/main.py @@ -0,0 +1,264 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +import multiprocessing +import check_addr +import argparse +import yaml +import sys +import subprocess +import traceback +import matplotlib.pyplot as plt +import csv +import util +import os +import math +import random + +PROCESS_TIMEOUT = 500 # seconds, adjust if necessary + + +def parse_arguments(): + parser = argparse.ArgumentParser( + description='App for measuring BLE throughput over ACL.', + epilog='How to run python script for hci0 -> rx and hci1 -> tx: \ + sudo python main.py -i 0 1 -m rx tx \ + -t path/to/custom_transport_directory -cf config.yaml') + parser.add_argument('-i', '--indexes', type=str, nargs='*', + help='specify adapters indexes', default=[0, 1]) + parser.add_argument('-m', '--modes', type=str, nargs="*", + help='devices modes - receiver, transmitter', + choices=['rx', 'tx'], default=['rx', 'tx']) + parser.add_argument('-t', '--transport_directory', type=str, nargs='*', + help='specify hci transport directory path. \ + Use for transport other than the default linux socket.', + default=["default"]) + parser.add_argument('-cf', '--config_file', type=str, nargs="*", + help='configuration file for devices', + default=["config.yaml"]) + try: + args = parser.parse_args() + except Exception as e: + print(traceback.format_exc()) + + print(f"Indexes: {args.indexes}") + print(f"Modes: {args.modes}") + print(f"Transport directory: {args.transport_directory}") + + return args + + +def get_dev_addr_and_type(hci_indexes: list, transport_directory: str): + if (len(hci_indexes) != 2): + raise Exception("HCI index error.") + manager = multiprocessing.Manager() + addr_list = manager.list() + check_addrs_proc = multiprocessing.Process(target=check_addr.check_addr, + name="Check addresses", + args=(hci_indexes, addr_list, + transport_directory)) + check_addrs_proc.start() + print("check_addrs_proc pid: ", check_addrs_proc.pid) + check_addrs_proc.join() + dev_addr_type_list = [] + for i in range(0, len(addr_list)): + dev_addr_type_list.append((hci_indexes[i],) + addr_list[i]) + return dev_addr_type_list + + +def change_config_var(filename: str, group: str, variable: str, + new_value: int): + with open(filename, "r") as file: + cfg = yaml.safe_load(file) + + if group: + cfg[group][variable] = new_value + else: + cfg[variable] = new_value + + with open(filename, "w") as file: + yaml.safe_dump(cfg, file, indent=1, sort_keys=False, + default_style=None, default_flow_style=False) + +def generate_long_term_key(): + rand_val = random.getrandbits(128) + return rand_val.to_bytes(16, byteorder='little') + + +def get_init_dict(filename: str, args_list: list, modes: list, dir: str, + transport_directory: str): + ini = { + modes[0]: { + "dev_index": args_list[0][0], + "own_address_type": args_list[0][1], + "own_address": args_list[0][2], + "peer_dev_index": args_list[1][0], + "peer_address_type": args_list[1][1], + "peer_address": args_list[1][2] + }, + modes[1]: { + "dev_index": args_list[1][0], + "own_address_type": args_list[1][1], + "own_address": args_list[1][2], + "peer_dev_index": args_list[0][0], + "peer_address_type": args_list[0][1], + "peer_address": args_list[0][2] + }, + "test_dir": dir, + "transport_directory": transport_directory, + "ltk": hex(random.getrandbits(128)) + } + + with open(filename, 'w') as file: + yaml.safe_dump(ini, file, indent=1, sort_keys=False) + + return ini + + +def run_once(modes: list, cfg_file: str, init_file: str): + list_proc = [] + for mode in modes: + proc = subprocess.Popen(["python", "hci_device.py", "-m", + mode, "-if", init_file, "-cf", cfg_file]) + print("start subprocess pid: ", proc.pid) + list_proc.append(proc) + try: + for proc in list_proc: + proc.wait(PROCESS_TIMEOUT) + except subprocess.TimeoutExpired: + for proc in list_proc: + print("TimeoutExpired subprocess pid: ", proc.pid) + proc.terminate() + for proc in list_proc: + proc.wait() + return -1 + + for proc in list_proc: + print("stop subprocess pid: ", proc.pid) + proc.terminate() + proc.wait() + return 0 + + +def testing_variable_influence(cfg: dict, modes: list, cfg_file: str, + init_file: str, init_dict: dict, + save_to_file: bool): + tp_test_counter = 1 + changed_params_list = [] + averages = [] + cfg_group = cfg["test"]["change_param_group"] + cfg_variable = cfg["test"]["change_param_variable"] + cfg_start_val = cfg["test"]["start_value"] + cfg_stop_val = cfg["test"]["stop_value"] + cfg_step = cfg["test"]["step"] + data_type = cfg["tp"]["data_type"] + total_iterations = math.ceil((cfg_stop_val - cfg_start_val) / cfg_step) + average_tp_csv_path = init_dict["test_dir"] + "/average_rx_tp.csv" + + with open(average_tp_csv_path, "w") as file: + file.write(f"Average throughput [{data_type}ps]\n") + + for i in range(cfg_start_val, cfg_stop_val, cfg_step): + changed_params_list.append(i) + + if cfg_group and cfg_variable: + print(f"Current param value: {i}") + num_of_params_to_change = len(cfg_variable) + + for j in range(0, num_of_params_to_change): + change_config_var(filename=cfg_file, group=cfg_group[j], + variable=cfg_variable[j], new_value=i) + + print(f"Running test: {tp_test_counter}/{total_iterations}...") + rc = run_once(modes, cfg_file, init_file) + if rc != 0: + print(f"Test {i} failed. Closing...") + return + + tp_test_counter += 1 + + with open(average_tp_csv_path, "r") as file: + csv_reader = csv.reader(file) + next(csv_reader) + for row in csv_reader: + averages.append(float(*row)) + + fig, ax = plt.subplots() + ax.plot(changed_params_list[:len(averages)], averages, '-k') + ax.set_ylabel(f"Average throughput [{data_type}/s]") + ax.set_xlabel("Changed parameter/next iteration") + ax.set_title("Average througput") + + if save_to_file: + name = init_dict["test_dir"] + "/average_tps" + plt.savefig(fname=name, format='png') + + plt.show(block=True) + + +def main(): + args = parse_arguments() + + init_file = "init.yaml" + cfg_file = args.config_file[0] + if (isinstance(args.transport_directory, list)): + args.transport_directory = args.transport_directory.pop() + else: + args.transport_directory = args.transport_directory + + with open(cfg_file, "r") as file: + cfg = yaml.safe_load(file) + + addr_list = get_dev_addr_and_type(args.indexes, args.transport_directory) + if len(addr_list) != len(args.indexes): + raise Exception("No device address received. Check HCI indexes.") + print(f"Received: {addr_list}") + + test_dir_path = util.create_test_directory() + init_dict = get_init_dict(filename=init_file, args_list=addr_list, + modes=args.modes, dir=test_dir_path, + transport_directory=args.transport_directory) + + util.copy_config_files_to_test_directory([init_file, cfg_file], + init_dict["test_dir"]) + + try: + if cfg["flag_testing"]: + testing_variable_influence(cfg, args.modes, *args.config_file, + init_file, init_dict, True) + else: + print(f"Running test...") + rc = run_once(args.modes, cfg_file, init_file) + if rc != 0: + print("Test failed.") + + print("Finished. Closing...") + + except KeyboardInterrupt: + pass + except Exception as e: + print(traceback.format_exc()) + finally: + # Set default ownership for dirs and files + util.set_default_chmod_recurs(os.getcwd() + "/tests") + sys.exit() + + +if __name__ == "__main__": + main() diff --git a/tools/hci_throughput/requirements.txt b/tools/hci_throughput/requirements.txt new file mode 100644 index 0000000000..8b2a114e44 --- /dev/null +++ b/tools/hci_throughput/requirements.txt @@ -0,0 +1,3 @@ +matplotlib==3.1.2 +PyYAML==6.0 +libusb1 \ No newline at end of file diff --git a/tools/hci_throughput/targets/nordic_pca10040_blehci/pkg.yml b/tools/hci_throughput/targets/nordic_pca10040_blehci/pkg.yml new file mode 100644 index 0000000000..9cd3540e7d --- /dev/null +++ b/tools/hci_throughput/targets/nordic_pca10040_blehci/pkg.yml @@ -0,0 +1,24 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +pkg.name: tools/hci_throughput/targets/nordic_pca10040_blehci +pkg.type: target +pkg.description: +pkg.author: +pkg.homepage: diff --git a/tools/hci_throughput/targets/nordic_pca10040_blehci/syscfg.yml b/tools/hci_throughput/targets/nordic_pca10040_blehci/syscfg.yml new file mode 100644 index 0000000000..8751b379b5 --- /dev/null +++ b/tools/hci_throughput/targets/nordic_pca10040_blehci/syscfg.yml @@ -0,0 +1,27 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +syscfg.vals: + BLE_LL_CFG_FEAT_DATA_LEN_EXT: 1 + BLE_PHY_2M: 1 + BLE_LL_HCI_VS_EVENT_ON_ASSERT: 1 + MSYS_1_BLOCK_COUNT: 80 + MSYS_1_BLOCK_SIZE: 308 + BLE_TRANSPORT_ACL_COUNT: 80 + diff --git a/tools/hci_throughput/targets/nordic_pca10040_blehci/target.yml b/tools/hci_throughput/targets/nordic_pca10040_blehci/target.yml new file mode 100644 index 0000000000..f9d6d0fb02 --- /dev/null +++ b/tools/hci_throughput/targets/nordic_pca10040_blehci/target.yml @@ -0,0 +1,22 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +target.app: "@apache-mynewt-nimble/apps/blehci" +target.bsp: "@apache-mynewt-core/hw/bsp/nordic_pca10040" +target.build_profile: optimized diff --git a/tools/hci_throughput/targets/nordic_pca10040_boot/pkg.yml b/tools/hci_throughput/targets/nordic_pca10040_boot/pkg.yml new file mode 100644 index 0000000000..b4f0ee6c19 --- /dev/null +++ b/tools/hci_throughput/targets/nordic_pca10040_boot/pkg.yml @@ -0,0 +1,23 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +pkg.name: targets/nordic_pca10040_boot +pkg.type: target +pkg.description: +pkg.author: +pkg.homepage: + diff --git a/tools/hci_throughput/targets/nordic_pca10040_boot/target.yml b/tools/hci_throughput/targets/nordic_pca10040_boot/target.yml new file mode 100644 index 0000000000..ad6f05a347 --- /dev/null +++ b/tools/hci_throughput/targets/nordic_pca10040_boot/target.yml @@ -0,0 +1,20 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +target.app: "@mcuboot/boot/mynewt" +target.bsp: "@apache-mynewt-core/hw/bsp/nordic_pca10040" +target.build_profile: optimized diff --git a/nimble/transport/da1469x/cmac_driver/pkg.yml b/tools/hci_throughput/targets/nordic_pca10056_blehci/pkg.yml similarity index 82% rename from nimble/transport/da1469x/cmac_driver/pkg.yml rename to tools/hci_throughput/targets/nordic_pca10056_blehci/pkg.yml index 90a8931865..a60adc72f3 100644 --- a/nimble/transport/da1469x/cmac_driver/pkg.yml +++ b/tools/hci_throughput/targets/nordic_pca10056_blehci/pkg.yml @@ -17,11 +17,11 @@ # under the License. # -pkg.name: nimble/transport/da1469x/cmac_driver -pkg.description: Driver for Dialog's BLE controller +pkg.name: tools/hci_throughput/targets/nordic_pca10056_blehci +pkg.type: target +pkg.description: pkg.author: pkg.homepage: -pkg.keywords: -pkg.pre_link_cmds.BLE_HOST: - scripts/build_libcmac.sh: 100 +pkg.deps: + - "@apache-mynewt-core/hw/usb/tinyusb/std_descriptors" diff --git a/tools/hci_throughput/targets/nordic_pca10056_blehci/syscfg.yml b/tools/hci_throughput/targets/nordic_pca10056_blehci/syscfg.yml new file mode 100644 index 0000000000..f054a3ff46 --- /dev/null +++ b/tools/hci_throughput/targets/nordic_pca10056_blehci/syscfg.yml @@ -0,0 +1,31 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +syscfg.vals: + BLE_PHY_2M: 1 + BLE_LL_CFG_FEAT_DATA_LEN_EXT: 1 + BLE_LL_HCI_VS_EVENT_ON_ASSERT: 1 + BLE_TRANSPORT_HS: usb + USBD_VID: 0xDCAB + USBD_PID: 0x1234 + USBD_BTH: 1 + USBD_PRODUCT_STRING: '"throughput"' + MSYS_1_BLOCK_COUNT: 80 + MSYS_1_BLOCK_SIZE: 308 + BLE_TRANSPORT_ACL_COUNT: 80 diff --git a/tools/hci_throughput/targets/nordic_pca10056_blehci/target.yml b/tools/hci_throughput/targets/nordic_pca10056_blehci/target.yml new file mode 100644 index 0000000000..e6317f2d44 --- /dev/null +++ b/tools/hci_throughput/targets/nordic_pca10056_blehci/target.yml @@ -0,0 +1,22 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +target.app: "@apache-mynewt-nimble/apps/blehci" +target.bsp: "@apache-mynewt-core/hw/bsp/nordic_pca10056" +target.build_profile: optimized diff --git a/tools/hci_throughput/targets/nordic_pca10056_boot/pkg.yml b/tools/hci_throughput/targets/nordic_pca10056_boot/pkg.yml new file mode 100644 index 0000000000..5546afa89a --- /dev/null +++ b/tools/hci_throughput/targets/nordic_pca10056_boot/pkg.yml @@ -0,0 +1,23 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +pkg.name: targets/nordic_pca10056_boot +pkg.type: target +pkg.description: +pkg.author: +pkg.homepage: + diff --git a/tools/hci_throughput/targets/nordic_pca10056_boot/target.yml b/tools/hci_throughput/targets/nordic_pca10056_boot/target.yml new file mode 100644 index 0000000000..ff3aec125a --- /dev/null +++ b/tools/hci_throughput/targets/nordic_pca10056_boot/target.yml @@ -0,0 +1,20 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +target.app: "@mcuboot/boot/mynewt" +target.bsp: "@apache-mynewt-core/hw/bsp/nordic_pca10056" +target.build_profile: optimized diff --git a/tools/hci_throughput/targets/nordic_pca10059_blehci/pkg.yml b/tools/hci_throughput/targets/nordic_pca10059_blehci/pkg.yml new file mode 100644 index 0000000000..6b9edc3bb9 --- /dev/null +++ b/tools/hci_throughput/targets/nordic_pca10059_blehci/pkg.yml @@ -0,0 +1,27 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +pkg.name: tools/hci_throughput/targets/nordic_pca10059_blehci +pkg.type: target +pkg.description: +pkg.author: +pkg.homepage: + +pkg.deps: + - "@apache-mynewt-core/hw/usb/tinyusb/std_descriptors" diff --git a/tools/hci_throughput/targets/nordic_pca10059_blehci/syscfg.yml b/tools/hci_throughput/targets/nordic_pca10059_blehci/syscfg.yml new file mode 100644 index 0000000000..618bd4506f --- /dev/null +++ b/tools/hci_throughput/targets/nordic_pca10059_blehci/syscfg.yml @@ -0,0 +1,31 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +syscfg.vals: + BLE_LL_CFG_FEAT_DATA_LEN_EXT: 1 + BLE_PHY_2M: 1 + BLE_LL_HCI_VS_EVENT_ON_ASSERT: 1 + BLE_TRANSPORT_HS: usb + USBD_VID: 0xDCAB + USBD_PID: 0x1234 + USBD_BTH: 1 + USBD_PRODUCT_STRING: '"throughput_dongle"' + MSYS_1_BLOCK_COUNT: 80 + MSYS_1_BLOCK_SIZE: 308 + BLE_TRANSPORT_ACL_COUNT: 80 diff --git a/tools/hci_throughput/targets/nordic_pca10059_blehci/target.yml b/tools/hci_throughput/targets/nordic_pca10059_blehci/target.yml new file mode 100644 index 0000000000..b582fddd49 --- /dev/null +++ b/tools/hci_throughput/targets/nordic_pca10059_blehci/target.yml @@ -0,0 +1,22 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +target.app: "@apache-mynewt-nimble/apps/blehci" +target.bsp: "@apache-mynewt-core/hw/bsp/nordic_pca10059" +target.build_profile: optimized diff --git a/tools/hci_throughput/targets/nordic_pca10095_app_blehci/pkg.yml b/tools/hci_throughput/targets/nordic_pca10095_app_blehci/pkg.yml new file mode 100644 index 0000000000..eab5e9872b --- /dev/null +++ b/tools/hci_throughput/targets/nordic_pca10095_app_blehci/pkg.yml @@ -0,0 +1,24 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +pkg.name: tools/hci_throughput/targets/nordic_pca10095_app_blehci +pkg.type: target +pkg.description: +pkg.author: +pkg.homepage: diff --git a/tools/hci_throughput/targets/nordic_pca10095_app_blehci/syscfg.yml b/tools/hci_throughput/targets/nordic_pca10095_app_blehci/syscfg.yml new file mode 100644 index 0000000000..420e5f58f7 --- /dev/null +++ b/tools/hci_throughput/targets/nordic_pca10095_app_blehci/syscfg.yml @@ -0,0 +1,42 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +syscfg.vals: + BSP_NRF5340_NET_ENABLE: 1 + NRF5340_EMBED_NET_CORE: 1 + NET_CORE_IMAGE_TARGET_NAME: '@apache-mynewt-nimble/tools/hci_throughput/targets/nordic_pca10095_net_blehci' + + BLE_TRANSPORT_HS: usb + USBD_VID: 0xDCAB + USBD_PID: 0x1234 + USBD_PRODUCT_STRING: '"throughput"' + USBD_BTH: 1 + USBD_BTH_EVENT_EP: 0x81 + USBD_BTH_DATA_IN_EP: 0x82 + USBD_BTH_DATA_OUT_EP: 0x02 + USBD_WINDOWS_COMP_ID: 1 + + BLE_TRANSPORT_ACL_COUNT: 80 + MSYS_1_BLOCK_COUNT: 80 + MSYS_1_BLOCK_SIZE: 308 + IPC_NRF5340_BUF_SZ: 3072 + + BLE_LL_CFG_FEAT_DATA_LEN_EXT: 1 + BLE_PHY_2M: 1 + BLE_LL_HCI_VS_EVENT_ON_ASSERT: 1 diff --git a/tools/hci_throughput/targets/nordic_pca10095_app_blehci/target.yml b/tools/hci_throughput/targets/nordic_pca10095_app_blehci/target.yml new file mode 100644 index 0000000000..9d5dbb7203 --- /dev/null +++ b/tools/hci_throughput/targets/nordic_pca10095_app_blehci/target.yml @@ -0,0 +1,22 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +target.app: "@apache-mynewt-nimble/apps/blehci" +target.bsp: "@apache-mynewt-core/hw/bsp/nordic_pca10095" +target.build_profile: optimized diff --git a/tools/hci_throughput/targets/nordic_pca10095_app_boot/pkg.yml b/tools/hci_throughput/targets/nordic_pca10095_app_boot/pkg.yml new file mode 100644 index 0000000000..505dcbd5ce --- /dev/null +++ b/tools/hci_throughput/targets/nordic_pca10095_app_boot/pkg.yml @@ -0,0 +1,24 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +pkg.name: tools/hci_throughput/targets/nordic_pca10095_app_boot +pkg.type: target +pkg.description: +pkg.author: +pkg.homepage: diff --git a/tools/hci_throughput/targets/nordic_pca10095_app_boot/syscfg.yml b/tools/hci_throughput/targets/nordic_pca10095_app_boot/syscfg.yml new file mode 100644 index 0000000000..30097ef048 --- /dev/null +++ b/tools/hci_throughput/targets/nordic_pca10095_app_boot/syscfg.yml @@ -0,0 +1,18 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# diff --git a/tools/hci_throughput/targets/nordic_pca10095_app_boot/target.yml b/tools/hci_throughput/targets/nordic_pca10095_app_boot/target.yml new file mode 100644 index 0000000000..0ccd2a988b --- /dev/null +++ b/tools/hci_throughput/targets/nordic_pca10095_app_boot/target.yml @@ -0,0 +1,22 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +target.app: "@mcuboot/boot/mynewt" +target.bsp: "@apache-mynewt-core/hw/bsp/nordic_pca10095" +target.build_profile: optimized diff --git a/tools/hci_throughput/targets/nordic_pca10095_net_blehci/pkg.yml b/tools/hci_throughput/targets/nordic_pca10095_net_blehci/pkg.yml new file mode 100644 index 0000000000..3983cea9d5 --- /dev/null +++ b/tools/hci_throughput/targets/nordic_pca10095_net_blehci/pkg.yml @@ -0,0 +1,24 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +pkg.name: tools/hci_throughput/targets/nordic_pca10095_net_blehci +pkg.type: target +pkg.description: +pkg.author: +pkg.homepage: diff --git a/tools/hci_throughput/targets/nordic_pca10095_net_blehci/syscfg.yml b/tools/hci_throughput/targets/nordic_pca10095_net_blehci/syscfg.yml new file mode 100644 index 0000000000..1328c03b22 --- /dev/null +++ b/tools/hci_throughput/targets/nordic_pca10095_net_blehci/syscfg.yml @@ -0,0 +1,34 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +syscfg.vals: + BLE_VERSION: 53 + BLE_TRANSPORT_HS: nrf5340 + BLE_LL_SCA: 50 + OS_CRASH_FILE_LINE: 1 + + BLE_PHY_2M: 1 + + BLE_LL_CFG_FEAT_DATA_LEN_EXT: 1 + BLE_LL_HCI_VS_EVENT_ON_ASSERT: 1 + + BLE_TRANSPORT_ACL_COUNT: 80 + MSYS_1_BLOCK_COUNT: 80 + MSYS_1_BLOCK_SIZE: 308 + IPC_NRF5340_BUF_SZ: 3072 diff --git a/tools/hci_throughput/targets/nordic_pca10095_net_blehci/target.yml b/tools/hci_throughput/targets/nordic_pca10095_net_blehci/target.yml new file mode 100644 index 0000000000..0bf51ba8bc --- /dev/null +++ b/tools/hci_throughput/targets/nordic_pca10095_net_blehci/target.yml @@ -0,0 +1,22 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +target.app: "@apache-mynewt-nimble/apps/blehci" +target.bsp: "@apache-mynewt-core/hw/bsp/nordic_pca10095_net" +target.build_profile: optimized diff --git a/tools/hci_throughput/targets/nordic_pca10095_net_boot/pkg.yml b/tools/hci_throughput/targets/nordic_pca10095_net_boot/pkg.yml new file mode 100644 index 0000000000..61c48efcb4 --- /dev/null +++ b/tools/hci_throughput/targets/nordic_pca10095_net_boot/pkg.yml @@ -0,0 +1,24 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +pkg.name: tools/hci_throughput/targets/nordic_pca10095_net_boot +pkg.type: target +pkg.description: +pkg.author: +pkg.homepage: diff --git a/tools/hci_throughput/targets/nordic_pca10095_net_boot/syscfg.yml b/tools/hci_throughput/targets/nordic_pca10095_net_boot/syscfg.yml new file mode 100644 index 0000000000..10b03c60cc --- /dev/null +++ b/tools/hci_throughput/targets/nordic_pca10095_net_boot/syscfg.yml @@ -0,0 +1,22 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +syscfg.vals: + BOOTUTIL_OVERWRITE_ONLY: 1 + WATCHDOG_INTERVAL: 0 diff --git a/tools/hci_throughput/targets/nordic_pca10095_net_boot/target.yml b/tools/hci_throughput/targets/nordic_pca10095_net_boot/target.yml new file mode 100644 index 0000000000..a293a4cadd --- /dev/null +++ b/tools/hci_throughput/targets/nordic_pca10095_net_boot/target.yml @@ -0,0 +1,22 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +target.app: "@mcuboot/boot/mynewt" +target.bsp: "@apache-mynewt-core/hw/bsp/nordic_pca10095_net" +target.build_profile: optimized diff --git a/tools/hci_throughput/tests/.gitignore b/tools/hci_throughput/tests/.gitignore new file mode 100755 index 0000000000..c96a04f008 --- /dev/null +++ b/tools/hci_throughput/tests/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/tools/hci_throughput/throughput.py b/tools/hci_throughput/throughput.py new file mode 100644 index 0000000000..e2b78b72c7 --- /dev/null +++ b/tools/hci_throughput/throughput.py @@ -0,0 +1,216 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +import time +import matplotlib.pyplot as plt +import csv +import struct +import argparse +import traceback + +data_types = ['kb', 'kB'] + + +def parse_arguments(): + parser = argparse.ArgumentParser( + description='Plot throughput from the csv file.', + epilog='How to run script: \ + python throughput.py -f tests/Wed_Apr_13_08:36:29_2022/tp_receiver.csv -s 0.1') + + parser.add_argument('-f', '--file', type=str, nargs='*', + help='csv file path', default=["tp_receiver"]) + parser.add_argument('-s', '--samp_t', type=float, nargs='*', + help='specify throughput sample time', default=1.0) + try: + args = parser.parse_args() + except Exception as e: + print(traceback.format_exc()) + return args + + +def gen_data(num_of_bytes_in_packet: int, + last_number_from_previous_data_packet: int): + counter = last_number_from_previous_data_packet + 1 + rem = num_of_bytes_in_packet % 4 + valid_data_len = int((num_of_bytes_in_packet - rem) / 4) + total_data_len = valid_data_len + rem + data = [0] * total_data_len + for i in range(rem, total_data_len): + data[i] = counter + counter += 1 + last_value = data[len(data) - 1] + if rem: + fmt = "<" + str(rem) + "B" + str(valid_data_len) + "I" + else: + fmt = "<" + str(valid_data_len) + "I" + data_ba = struct.pack(fmt, *data) + return data_ba, last_value + + +class Throughput(): + def __init__( + self, + name="tp_chart", + mode="rx", + total_packets_number=0, + bytes_number_in_packet=0, + throughput_data_type='kb', + flag_plot_packets=True, + sample_time=1, + test_directory=None): + self.name = name + self.mode = mode + self.total_packets_number = total_packets_number + self.bytes_number_in_packet = bytes_number_in_packet + self.predef_packet_key = int( + (bytes_number_in_packet - (bytes_number_in_packet % 4)) / 4) + self.total_bits_number = bytes_number_in_packet * 8 + assert throughput_data_type in data_types + self.throughput_data_type = throughput_data_type + self.flag_plot_packets = flag_plot_packets + self.sample_time = sample_time + self.test_directory = test_directory + + if self.test_directory is not None: + self.csv_file_name = self.test_directory + "/" + \ + time.strftime("%Y_%m_%d_%H_%M_%S_") + self.name + ".csv" + else: + self.csv_file_name = time.strftime( + "%Y_%m_%d_%H_%M_%S_") + self.name + ".csv" + self.clean_csv_file() + + def calc_throughput(self, current_num, last_num, current_time, last_time): + if self.throughput_data_type == 'kb': + return float( + (((current_num - last_num) * self.total_bits_number) / + (current_time - last_time)) / 1000) + elif self.throughput_data_type == 'kB': + return float( + (((current_num - last_num) * self.bytes_number_in_packet) / + (current_time - last_time)) / 1000) + + def clean_csv_file(self): + file = open(self.csv_file_name, 'w') + file.write("Time,Packet\n") + + def append_to_csv_file( + self, + timestamp: float = 0.0, + packet_number: int = 0): + with open(self.csv_file_name, "a") as file: + csv_writer = csv.writer(file) + csv_writer.writerow([timestamp, packet_number]) + + def get_average(self, packet_numbers, timestamps): + if self.throughput_data_type == 'kb': + average_tp = ((packet_numbers * self.total_bits_number) + / (timestamps[-1] - timestamps[0])) / 1000 + elif self.throughput_data_type == 'kB': + average_tp = ((packet_numbers * self.bytes_number_in_packet) + / (timestamps[-1] - timestamps[0])) / 1000 + return average_tp + + def save_average(self, tp_csv_filename=None): + if self.mode == "rx": + timestamps = [] + packet_numbers = [] + + if tp_csv_filename is None: + tp_csv_filename = self.csv_file_name + else: + tp_csv_filename += ".csv" + + with open(tp_csv_filename, "r") as file: + csv_reader = csv.reader(file) + next(csv_reader) + for row in csv_reader: + timestamps.append(float(row[0])) + packet_numbers.append(float(row[1])) + + average_tp = self.get_average(packet_numbers[-1], timestamps) + print( + f"Average rx throughput: {round(average_tp, 3)} {self.throughput_data_type}ps") + + with open(self.test_directory + "/average_rx_tp.csv", "a") as file: + csv_writer = csv.writer(file) + csv_writer.writerow([average_tp]) + + def plot_tp_from_file(self, filename: str = None, sample_time: float = 1, + save_to_file: bool = True): + timestamps = [] + packet_numbers = [] + + if filename is None: + filename = self.csv_file_name + print("Results:", filename) + + with open(filename, "r") as file: + csv_reader = csv.reader(file) + next(csv_reader) + for row in csv_reader: + timestamps.append(float(row[0])) + packet_numbers.append(float(row[1])) + + last_time = 0 + last_number = packet_numbers[0] + throughput = [] + offset = timestamps[0] + + for i in range(0, len(timestamps)): + timestamps[i] -= offset + if timestamps[i] - last_time > sample_time: + throughput.append((timestamps[i], + self.calc_throughput(packet_numbers[i], + last_number, + timestamps[i], + last_time))) + last_time = timestamps[i] + last_number = packet_numbers[i] + + average_tp = self.get_average(packet_numbers[-1], timestamps) + + fig, ax = plt.subplots() + if self.flag_plot_packets: + ax2 = ax.twinx() + + ax.plot(*zip(*throughput), 'k-') + if self.flag_plot_packets: + ax2.plot(timestamps, packet_numbers, 'b-') + + ax.set_title(self.name) + ax.set_ylabel(f"Throughput [{self.throughput_data_type}/s]") + ax.set_xlabel("Time [s]") + ax.text(0.9, 1.02, f"Average: {round(average_tp, 3)}" + f"{self.throughput_data_type}ps", transform=ax.transAxes, + color='k') + if self.flag_plot_packets: + ax2 = ax2.set_ylabel(f"Packets [Max:{len(packet_numbers)}]", + color='b') + + if save_to_file: + path = filename.replace(".csv", ".png") + plt.savefig(path) + + plt.show(block=True) + + +if __name__ == "__main__": + args = parse_arguments() + tp = Throughput(bytes_number_in_packet=247) + tp.plot_tp_from_file(*args.file, args.samp_t[0], save_to_file=False) diff --git a/tools/hci_throughput/transport_factory.py b/tools/hci_throughput/transport_factory.py new file mode 100644 index 0000000000..9b5f07aa90 --- /dev/null +++ b/tools/hci_throughput/transport_factory.py @@ -0,0 +1,55 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +import hci_socket +import logging +import traceback +import sys + + +class TransportFactory: + def __init__(self, device_index: str = None, device_mode=None, + asyncio_loop=None, transport_directory=None) -> None: + if (device_index.isnumeric()): + self.transport = hci_socket.HCI_User_Channel_Socket( + int(device_index), device_mode, asyncio_loop) + else: + try: + if (transport_directory != "default"): + sys.path.append(transport_directory) + print(sys.path) + import custom_transport + self.transport = custom_transport.Transport(device_index, + device_mode, + asyncio_loop) + else: + raise Exception( + "Device index and transport does not match.") + except Exception as e: + logging.error(traceback.format_exc()) + sys.exit() + + self.rx_buffer_q = self.transport.rx_buffer_q + self.send = self.transport.send + + def start(self): + self.transport.start() + + def stop(self): + self.transport.stop() diff --git a/tools/hci_throughput/util.py b/tools/hci_throughput/util.py new file mode 100644 index 0000000000..96bfd9086e --- /dev/null +++ b/tools/hci_throughput/util.py @@ -0,0 +1,72 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +import logging +import shutil +import time +import os +from pathlib import Path + + +def create_test_directory(): + test_dir_name = "tests/" + time.strftime("%Y_%m_%d_%H_%M_%S") + path = os.path.join(os.getcwd(), test_dir_name) + os.mkdir(path, mode=0o777) + print("Test directory: ", path) + return path + + +def configure_logging(log_filename, clear_log_file=True): + format_template = ("%(asctime)s %(threadName)s %(name)s %(levelname)s " + "%(filename)-25s %(lineno)-5s " + "%(funcName)-25s : %(message)s") + logging.basicConfig(format=format_template, + filename=log_filename, + filemode='a', + level=logging.DEBUG) + if clear_log_file: + with open(log_filename, "w") as f: + f.write("asctime\t\t\t\t\tthreadName name levelname filename\ + \tlineno\tfuncName\t\t\t\tmessage\n") + + logging.getLogger("asyncio").setLevel(logging.WARNING) + logging.getLogger("matplotlib").setLevel(logging.WARNING) + + +def copy_config_files_to_test_directory(files: list, test_directory: str): + for file in files: + shutil.copy(file, test_directory + "/" + Path(file).name) + + +def copy_log_files_to_test_directory(dir: str): + log_files = ["log/log_rx.log", "log/log_tx.log", "log/check_addr.log"] + for file in log_files: + shutil.copy(file, dir + "/" + time.strftime("%Y_%m_%d_%H_%M_%S_") + + file.replace("log/", "")) + + +# Running tests as sudo implies root permissions on created directories/files. +# This function sets the default permission mode to dirs/files in given path +# recursively. +def set_default_chmod_recurs(path): + for root, dirs, files in os.walk(path): + for d in dirs: + os.chmod(os.path.join(root, d), 0o0777) + for f in files: + os.chmod(os.path.join(root, f), 0o0777) diff --git a/uncrustify.cfg b/uncrustify.cfg deleted file mode 100644 index 481a62ab05..0000000000 --- a/uncrustify.cfg +++ /dev/null @@ -1,1959 +0,0 @@ -# -# General options -# - -# The type of line endings. Default=Auto -newlines = lf # auto/lf/crlf/cr - -# The original size of tabs in the input. Default=8 -input_tab_size = 4 # number - -# The size of tabs in the output (only used if align_with_tabs=true). Default=8 -output_tab_size = 4 # number - -# The ASCII value of the string escape char, usually 92 (\) or 94 (^). (Pawn) -string_escape_char = 92 # number - -# Alternate string escape char for Pawn. Only works right before the quote char. -string_escape_char2 = 0 # number - -# Replace tab characters found in string literals with the escape sequence \t instead. -string_replace_tab_chars = false # false/true - -# Allow interpreting '>=' and '>>=' as part of a template in 'void f(list>=val);'. -# If true, 'assert(x<0 && y>=3)' will be broken. Default=False -# Improvements to template detection may make this option obsolete. -tok_split_gte = false # false/true - -# Override the default ' *INDENT-OFF*' in comments for disabling processing of part of the file. -disable_processing_cmt = "" # string - -# Override the default ' *INDENT-ON*' in comments for enabling processing of part of the file. -enable_processing_cmt = "" # string - -# Enable parsing of digraphs. Default=False -enable_digraphs = false # false/true - -# Control what to do with the UTF-8 BOM (recommend 'remove') -utf8_bom = ignore # ignore/add/remove/force - -# If the file contains bytes with values between 128 and 255, but is not UTF-8, then output as UTF-8 -utf8_byte = false # false/true - -# Force the output encoding to UTF-8 -utf8_force = false # false/true - -# -# Indenting -# - -# The number of columns to indent per level. -# Usually 2, 3, 4, or 8. Default=8 -indent_columns = 4 # number - -# The continuation indent. If non-zero, this overrides the indent of '(' and '=' continuation indents. -# For FreeBSD, this is set to 4. Negative value is absolute and not increased for each ( level -indent_continue = 0 # number - -# How to use tabs when indenting code -# 0=spaces only -# 1=indent with tabs to brace level, align with spaces (default) -# 2=indent and align with tabs, using spaces when not on a tabstop -indent_with_tabs = 0 # number - -# Comments that are not a brace level are indented with tabs on a tabstop. -# Requires indent_with_tabs=2. If false, will use spaces. -indent_cmt_with_tabs = false # false/true - -# Whether to indent strings broken by '\' so that they line up -indent_align_string = false # false/true - -# The number of spaces to indent multi-line XML strings. -# Requires indent_align_string=True -indent_xml_string = 0 # number - -# Spaces to indent '{' from level -indent_brace = 0 # number - -# Whether braces are indented to the body level -indent_braces = false # false/true - -# Disabled indenting function braces if indent_braces is true -indent_braces_no_func = false # false/true - -# Disabled indenting class braces if indent_braces is true -indent_braces_no_class = false # false/true - -# Disabled indenting struct braces if indent_braces is true -indent_braces_no_struct = false # false/true - -# Indent based on the size of the brace parent, i.e. 'if' => 3 spaces, 'for' => 4 spaces, etc. -indent_brace_parent = false # false/true - -# Indent based on the paren open instead of the brace open in '({\n', default is to indent by brace. -indent_paren_open_brace = false # false/true - -# indent a C# delegate by another level, default is to not indent by another level. -indent_cs_delegate_brace = false # false/true - -# Whether the 'namespace' body is indented -indent_namespace = false # false/true - -# Only indent one namespace and no sub-namespaces. -# Requires indent_namespace=true. -indent_namespace_single_indent = false # false/true - -# The number of spaces to indent a namespace block -indent_namespace_level = 0 # number - -# If the body of the namespace is longer than this number, it won't be indented. -# Requires indent_namespace=true. Default=0 (no limit) -indent_namespace_limit = 0 # number - -# Whether the 'extern "C"' body is indented -indent_extern = false # false/true - -# Whether the 'class' body is indented -indent_class = true # false/true - -# Whether to indent the stuff after a leading base class colon -indent_class_colon = true # false/true - -# Indent based on a class colon instead of the stuff after the colon. -# Requires indent_class_colon=true. Default=False -indent_class_on_colon = false # false/true - -# Whether to indent the stuff after a leading class initializer colon -indent_constr_colon = false # false/true - -# Virtual indent from the ':' for member initializers. Default=2 -indent_ctor_init_leading = 2 # number - -# Additional indenting for constructor initializer list -indent_ctor_init = 0 # number - -# False=treat 'else\nif' as 'else if' for indenting purposes -# True=indent the 'if' one level -indent_else_if = false # false/true - -# Amount to indent variable declarations after a open brace. neg=relative, pos=absolute -indent_var_def_blk = 0 # number - -# Indent continued variable declarations instead of aligning. -indent_var_def_cont = false # false/true - -# Indent continued shift expressions ('<<' and '>>') instead of aligning. -# Turn align_left_shift off when enabling this. -indent_shift = false # false/true - -# True: force indentation of function definition to start in column 1 -# False: use the default behavior -indent_func_def_force_col1 = false # false/true - -# True: indent continued function call parameters one indent level -# False: align parameters under the open paren -indent_func_call_param = false # false/true - -# Same as indent_func_call_param, but for function defs -indent_func_def_param = false # false/true - -# Same as indent_func_call_param, but for function protos -indent_func_proto_param = false # false/true - -# Same as indent_func_call_param, but for class declarations -indent_func_class_param = false # false/true - -# Same as indent_func_call_param, but for class variable constructors -indent_func_ctor_var_param = false # false/true - -# Same as indent_func_call_param, but for templates -indent_template_param = false # false/true - -# Double the indent for indent_func_xxx_param options -indent_func_param_double = false # false/true - -# Indentation column for standalone 'const' function decl/proto qualifier -indent_func_const = 0 # number - -# Indentation column for standalone 'throw' function decl/proto qualifier -indent_func_throw = 0 # number - -# The number of spaces to indent a continued '->' or '.' -# Usually set to 0, 1, or indent_columns. -indent_member = 0 # number - -# Spaces to indent single line ('//') comments on lines before code -indent_sing_line_comments = 0 # number - -# If set, will indent trailing single line ('//') comments relative -# to the code instead of trying to keep the same absolute column -indent_relative_single_line_comments = false # false/true - -# Spaces to indent 'case' from 'switch' -# Usually 0 or indent_columns. -indent_switch_case = 0 # number - -# Spaces to shift the 'case' line, without affecting any other lines -# Usually 0. -indent_case_shift = 0 # number - -# Spaces to indent '{' from 'case'. -# By default, the brace will appear under the 'c' in case. -# Usually set to 0 or indent_columns. -indent_case_brace = 0 # number - -# Whether to indent comments found in first column -indent_col1_comment = false # false/true - -# How to indent goto labels -# >0: absolute column where 1 is the leftmost column -# <=0: subtract from brace indent -# Default=1 -indent_label = 1 # number - -# Same as indent_label, but for access specifiers that are followed by a colon. Default=1 -indent_access_spec = 1 # number - -# Indent the code after an access specifier by one level. -# If set, this option forces 'indent_access_spec=0' -indent_access_spec_body = false # false/true - -# If an open paren is followed by a newline, indent the next line so that it lines up after the open paren (not recommended) -indent_paren_nl = false # false/true - -# Controls the indent of a close paren after a newline. -# 0: Indent to body level -# 1: Align under the open paren -# 2: Indent to the brace level -indent_paren_close = 0 # number - -# Controls the indent of a comma when inside a paren.If TRUE, aligns under the open paren -indent_comma_paren = false # false/true - -# Controls the indent of a BOOL operator when inside a paren.If TRUE, aligns under the open paren -indent_bool_paren = false # false/true - -# If 'indent_bool_paren' is true, controls the indent of the first expression. If TRUE, aligns the first expression to the following ones -indent_first_bool_expr = false # false/true - -# If an open square is followed by a newline, indent the next line so that it lines up after the open square (not recommended) -indent_square_nl = false # false/true - -# Don't change the relative indent of ESQL/C 'EXEC SQL' bodies -indent_preserve_sql = false # false/true - -# Align continued statements at the '='. Default=True -# If FALSE or the '=' is followed by a newline, the next line is indent one tab. -indent_align_assign = true # false/true - -# Indent OC blocks at brace level instead of usual rules. -indent_oc_block = false # false/true - -# Indent OC blocks in a message relative to the parameter name. -# 0=use indent_oc_block rules, 1+=spaces to indent -indent_oc_block_msg = 0 # number - -# Minimum indent for subsequent parameters -indent_oc_msg_colon = 0 # number - -# If true, prioritize aligning with initial colon (and stripping spaces from lines, if necessary). -# Default=True. -indent_oc_msg_prioritize_first_colon = true # false/true - -# If indent_oc_block_msg and this option are on, blocks will be indented the way that Xcode does by default (from keyword if the parameter is on its own line; otherwise, from the previous indentation level). -indent_oc_block_msg_xcode_style = false # false/true - -# If indent_oc_block_msg and this option are on, blocks will be indented from where the brace is relative to a msg keyword. -indent_oc_block_msg_from_keyword = false # false/true - -# If indent_oc_block_msg and this option are on, blocks will be indented from where the brace is relative to a msg colon. -indent_oc_block_msg_from_colon = false # false/true - -# If indent_oc_block_msg and this option are on, blocks will be indented from where the block caret is. -indent_oc_block_msg_from_caret = false # false/true - -# If indent_oc_block_msg and this option are on, blocks will be indented from where the brace is. -indent_oc_block_msg_from_brace = false # false/true - -# When identing after virtual brace open and newline add further spaces to reach this min. indent. -indent_min_vbrace_open = 0 # number - -# TRUE: When identing after virtual brace open and newline add further spaces after regular indent to reach next tabstop. -indent_vbrace_open_on_tabstop = false # false/true - -# If true, a brace followed by another token (not a newline) will indent all contained lines to match the token.Default=True. -indent_token_after_brace = true # false/true - -# If true, cpp lambda body will be indentedDefault=False. -indent_cpp_lambda_body = false # false/true - -# -# Spacing options -# - -# Add or remove space around arithmetic operator '+', '-', '/', '*', etc -# also '>>>' '<<' '>>' '%' '|' -sp_arith = ignore # ignore/add/remove/force - -# Add or remove space around assignment operator '=', '+=', etc -sp_assign = force # ignore/add/remove/force - -# Add or remove space around '=' in C++11 lambda capture specifications. Overrides sp_assign -sp_cpp_lambda_assign = ignore # ignore/add/remove/force - -# Add or remove space after the capture specification in C++11 lambda. -sp_cpp_lambda_square_paren = ignore # ignore/add/remove/force - -# Add or remove space around assignment operator '=' in a prototype -sp_assign_default = ignore # ignore/add/remove/force - -# Add or remove space before assignment operator '=', '+=', etc. Overrides sp_assign. -sp_before_assign = ignore # ignore/add/remove/force - -# Add or remove space after assignment operator '=', '+=', etc. Overrides sp_assign. -sp_after_assign = ignore # ignore/add/remove/force - -# Add or remove space in 'NS_ENUM (' -sp_enum_paren = ignore # ignore/add/remove/force - -# Add or remove space around assignment '=' in enum -sp_enum_assign = ignore # ignore/add/remove/force - -# Add or remove space before assignment '=' in enum. Overrides sp_enum_assign. -sp_enum_before_assign = ignore # ignore/add/remove/force - -# Add or remove space after assignment '=' in enum. Overrides sp_enum_assign. -sp_enum_after_assign = ignore # ignore/add/remove/force - -# Add or remove space around preprocessor '##' concatenation operator. Default=Add -sp_pp_concat = add # ignore/add/remove/force - -# Add or remove space after preprocessor '#' stringify operator. Also affects the '#@' charizing operator. -sp_pp_stringify = ignore # ignore/add/remove/force - -# Add or remove space before preprocessor '#' stringify operator as in '#define x(y) L#y'. -sp_before_pp_stringify = ignore # ignore/add/remove/force - -# Add or remove space around boolean operators '&&' and '||' -sp_bool = force # ignore/add/remove/force - -# Add or remove space around compare operator '<', '>', '==', etc -sp_compare = force # ignore/add/remove/force - -# Add or remove space inside '(' and ')' -sp_inside_paren = remove # ignore/add/remove/force - -# Add or remove space between nested parens: '((' vs ') )' -sp_paren_paren = remove # ignore/add/remove/force - -# Add or remove space between back-to-back parens: ')(' vs ') (' -sp_cparen_oparen = ignore # ignore/add/remove/force - -# Whether to balance spaces inside nested parens -sp_balance_nested_parens = false # false/true - -# Add or remove space between ')' and '{' -sp_paren_brace = force # ignore/add/remove/force - -# Add or remove space before pointer star '*' -sp_before_ptr_star = force # ignore/add/remove/force - -# Add or remove space before pointer star '*' that isn't followed by a variable name -# If set to 'ignore', sp_before_ptr_star is used instead. -sp_before_unnamed_ptr_star = ignore # ignore/add/remove/force - -# Add or remove space between pointer stars '*' -sp_between_ptr_star = remove # ignore/add/remove/force - -# Add or remove space after pointer star '*', if followed by a word. -sp_after_ptr_star = ignore # ignore/add/remove/force - -# Add or remove space after pointer star '*', if followed by a qualifier. -sp_after_ptr_star_qualifier = ignore # ignore/add/remove/force - -# Add or remove space after a pointer star '*', if followed by a func proto/def. -sp_after_ptr_star_func = ignore # ignore/add/remove/force - -# Add or remove space after a pointer star '*', if followed by an open paren (function types). -sp_ptr_star_paren = ignore # ignore/add/remove/force - -# Add or remove space before a pointer star '*', if followed by a func proto/def. -sp_before_ptr_star_func = ignore # ignore/add/remove/force - -# Add or remove space before a reference sign '&' -sp_before_byref = ignore # ignore/add/remove/force - -# Add or remove space before a reference sign '&' that isn't followed by a variable name -# If set to 'ignore', sp_before_byref is used instead. -sp_before_unnamed_byref = ignore # ignore/add/remove/force - -# Add or remove space after reference sign '&', if followed by a word. -sp_after_byref = ignore # ignore/add/remove/force - -# Add or remove space after a reference sign '&', if followed by a func proto/def. -sp_after_byref_func = ignore # ignore/add/remove/force - -# Add or remove space before a reference sign '&', if followed by a func proto/def. -sp_before_byref_func = ignore # ignore/add/remove/force - -# Add or remove space between type and word. Default=Force -sp_after_type = force # ignore/add/remove/force - -# Add or remove space before the paren in the D constructs 'template Foo(' and 'class Foo('. -sp_before_template_paren = ignore # ignore/add/remove/force - -# Add or remove space in 'template <' vs 'template<'. -# If set to ignore, sp_before_angle is used. -sp_template_angle = ignore # ignore/add/remove/force - -# Add or remove space before '<>' -sp_before_angle = ignore # ignore/add/remove/force - -# Add or remove space inside '<' and '>' -sp_inside_angle = ignore # ignore/add/remove/force - -# Add or remove space after '<>' -sp_after_angle = ignore # ignore/add/remove/force - -# Add or remove space between '<>' and '(' as found in 'new List(foo);' -sp_angle_paren = ignore # ignore/add/remove/force - -# Add or remove space between '<>' and '()' as found in 'new List();' -sp_angle_paren_empty = ignore # ignore/add/remove/force - -# Add or remove space between '<>' and a word as in 'List m;' or 'template static ...' -sp_angle_word = ignore # ignore/add/remove/force - -# Add or remove space between '>' and '>' in '>>' (template stuff C++/C# only). Default=Add -sp_angle_shift = add # ignore/add/remove/force - -# Permit removal of the space between '>>' in 'foo >' (C++11 only). Default=False -# sp_angle_shift cannot remove the space without this option. -sp_permit_cpp11_shift = false # false/true - -# Add or remove space before '(' of 'if', 'for', 'switch', 'while', etc. -sp_before_sparen = add # ignore/add/remove/force - -# Add or remove space inside if-condition '(' and ')' -sp_inside_sparen = remove # ignore/add/remove/force - -# Add or remove space before if-condition ')'. Overrides sp_inside_sparen. -sp_inside_sparen_close = ignore # ignore/add/remove/force - -# Add or remove space after if-condition '('. Overrides sp_inside_sparen. -sp_inside_sparen_open = ignore # ignore/add/remove/force - -# Add or remove space after ')' of 'if', 'for', 'switch', and 'while', etc. -sp_after_sparen = ignore # ignore/add/remove/force - -# Add or remove space between ')' and '{' of 'if', 'for', 'switch', and 'while', etc. -sp_sparen_brace = add # ignore/add/remove/force - -# Add or remove space between 'invariant' and '(' in the D language. -sp_invariant_paren = ignore # ignore/add/remove/force - -# Add or remove space after the ')' in 'invariant (C) c' in the D language. -sp_after_invariant_paren = ignore # ignore/add/remove/force - -# Add or remove space before empty statement ';' on 'if', 'for' and 'while' -sp_special_semi = ignore # ignore/add/remove/force - -# Add or remove space before ';'. Default=Remove -sp_before_semi = remove # ignore/add/remove/force - -# Add or remove space before ';' in non-empty 'for' statements -sp_before_semi_for = ignore # ignore/add/remove/force - -# Add or remove space before a semicolon of an empty part of a for statement. -sp_before_semi_for_empty = ignore # ignore/add/remove/force - -# Add or remove space after ';', except when followed by a comment. Default=Add -sp_after_semi = add # ignore/add/remove/force - -# Add or remove space after ';' in non-empty 'for' statements. Default=Force -sp_after_semi_for = force # ignore/add/remove/force - -# Add or remove space after the final semicolon of an empty part of a for statement: for ( ; ; ). -sp_after_semi_for_empty = remove # ignore/add/remove/force - -# Add or remove space before '[' (except '[]') -sp_before_square = ignore # ignore/add/remove/force - -# Add or remove space before '[]' -sp_before_squares = ignore # ignore/add/remove/force - -# Add or remove space inside a non-empty '[' and ']' -sp_inside_square = ignore # ignore/add/remove/force - -# Add or remove space after ',' -sp_after_comma = ignore # ignore/add/remove/force - -# Add or remove space before ','. Default=Remove -sp_before_comma = remove # ignore/add/remove/force - -# Add or remove space between ',' and ']' in multidimensional array type 'int[,,]' -sp_after_mdatype_commas = ignore # ignore/add/remove/force - -# Add or remove space between '[' and ',' in multidimensional array type 'int[,,]' -sp_before_mdatype_commas = ignore # ignore/add/remove/force - -# Add or remove space between ',' in multidimensional array type 'int[,,]' -sp_between_mdatype_commas = ignore # ignore/add/remove/force - -# Add or remove space between an open paren and comma: '(,' vs '( ,'. Default=Force -sp_paren_comma = force # ignore/add/remove/force - -# Add or remove space before the variadic '...' when preceded by a non-punctuator -sp_before_ellipsis = ignore # ignore/add/remove/force - -# Add or remove space after class ':' -sp_after_class_colon = ignore # ignore/add/remove/force - -# Add or remove space before class ':' -sp_before_class_colon = ignore # ignore/add/remove/force - -# Add or remove space after class constructor ':' -sp_after_constr_colon = ignore # ignore/add/remove/force - -# Add or remove space before class constructor ':' -sp_before_constr_colon = ignore # ignore/add/remove/force - -# Add or remove space before case ':'. Default=Remove -sp_before_case_colon = remove # ignore/add/remove/force - -# Add or remove space between 'operator' and operator sign -sp_after_operator = ignore # ignore/add/remove/force - -# Add or remove space between the operator symbol and the open paren, as in 'operator ++(' -sp_after_operator_sym = ignore # ignore/add/remove/force - -# Add or remove space between the operator symbol and the open paren when the operator has no arguments, as in 'operator *()' -sp_after_operator_sym_empty = ignore # ignore/add/remove/force - -# Add or remove space after C/D cast, i.e. 'cast(int)a' vs 'cast(int) a' or '(int)a' vs '(int) a' -sp_after_cast = ignore # ignore/add/remove/force - -# Add or remove spaces inside cast parens -sp_inside_paren_cast = ignore # ignore/add/remove/force - -# Add or remove space between the type and open paren in a C++ cast, i.e. 'int(exp)' vs 'int (exp)' -sp_cpp_cast_paren = ignore # ignore/add/remove/force - -# Add or remove space between 'sizeof' and '(' -sp_sizeof_paren = ignore # ignore/add/remove/force - -# Add or remove space after the tag keyword (Pawn) -sp_after_tag = ignore # ignore/add/remove/force - -# Add or remove space inside enum '{' and '}' -sp_inside_braces_enum = ignore # ignore/add/remove/force - -# Add or remove space inside struct/union '{' and '}' -sp_inside_braces_struct = ignore # ignore/add/remove/force - -# Add or remove space inside '{' and '}' -sp_inside_braces = ignore # ignore/add/remove/force - -# Add or remove space inside '{}' -sp_inside_braces_empty = ignore # ignore/add/remove/force - -# Add or remove space between return type and function name -# A minimum of 1 is forced except for pointer return types. -sp_type_func = ignore # ignore/add/remove/force - -# Add or remove space between function name and '(' on function declaration -sp_func_proto_paren = remove # ignore/add/remove/force - -# Add or remove space between function name and '()' on function declaration without parameters -sp_func_proto_paren_empty = remove # ignore/add/remove/force - -# Add or remove space between function name and '(' on function definition -sp_func_def_paren = remove # ignore/add/remove/force - -# Add or remove space between function name and '()' on function definition without parameters -sp_func_def_paren_empty = ignore # ignore/add/remove/force - -# Add or remove space inside empty function '()' -sp_inside_fparens = ignore # ignore/add/remove/force - -# Add or remove space inside function '(' and ')' -sp_inside_fparen = remove # ignore/add/remove/force - -# Add or remove space inside the first parens in the function type: 'void (*x)(...)' -sp_inside_tparen = ignore # ignore/add/remove/force - -# Add or remove between the parens in the function type: 'void (*x)(...)' -sp_after_tparen_close = ignore # ignore/add/remove/force - -# Add or remove space between ']' and '(' when part of a function call. -sp_square_fparen = ignore # ignore/add/remove/force - -# Add or remove space between ')' and '{' of function -sp_fparen_brace = add # ignore/add/remove/force - -# Java: Add or remove space between ')' and '{{' of double brace initializer. -sp_fparen_dbrace = ignore # ignore/add/remove/force - -# Add or remove space between function name and '(' on function calls -sp_func_call_paren = ignore # ignore/add/remove/force - -# Add or remove space between function name and '()' on function calls without parameters. -# If set to 'ignore' (the default), sp_func_call_paren is used. -sp_func_call_paren_empty = ignore # ignore/add/remove/force - -# Add or remove space between the user function name and '(' on function calls -# You need to set a keyword to be a user function, like this: 'set func_call_user _' in the config file. -sp_func_call_user_paren = ignore # ignore/add/remove/force - -# Add or remove space between a constructor/destructor and the open paren -sp_func_class_paren = ignore # ignore/add/remove/force - -# Add or remove space between a constructor without parameters or destructor and '()' -sp_func_class_paren_empty = ignore # ignore/add/remove/force - -# Add or remove space between 'return' and '(' -sp_return_paren = ignore # ignore/add/remove/force - -# Add or remove space between '__attribute__' and '(' -sp_attribute_paren = ignore # ignore/add/remove/force - -# Add or remove space between 'defined' and '(' in '#if defined (FOO)' -sp_defined_paren = ignore # ignore/add/remove/force - -# Add or remove space between 'throw' and '(' in 'throw (something)' -sp_throw_paren = ignore # ignore/add/remove/force - -# Add or remove space between 'throw' and anything other than '(' as in '@throw [...];' -sp_after_throw = ignore # ignore/add/remove/force - -# Add or remove space between 'catch' and '(' in 'catch (something) { }' -# If set to ignore, sp_before_sparen is used. -sp_catch_paren = ignore # ignore/add/remove/force - -# Add or remove space between 'version' and '(' in 'version (something) { }' (D language) -# If set to ignore, sp_before_sparen is used. -sp_version_paren = ignore # ignore/add/remove/force - -# Add or remove space between 'scope' and '(' in 'scope (something) { }' (D language) -# If set to ignore, sp_before_sparen is used. -sp_scope_paren = ignore # ignore/add/remove/force - -# Add or remove space between 'super' and '(' in 'super (something)'. Default=Remove -sp_super_paren = remove # ignore/add/remove/force - -# Add or remove space between 'this' and '(' in 'this (something)'. Default=Remove -sp_this_paren = remove # ignore/add/remove/force - -# Add or remove space between macro and value -sp_macro = ignore # ignore/add/remove/force - -# Add or remove space between macro function ')' and value -sp_macro_func = ignore # ignore/add/remove/force - -# Add or remove space between 'else' and '{' if on the same line -sp_else_brace = add # ignore/add/remove/force - -# Add or remove space between '}' and 'else' if on the same line -sp_brace_else = add # ignore/add/remove/force - -# Add or remove space between '}' and the name of a typedef on the same line -sp_brace_typedef = add # ignore/add/remove/force - -# Add or remove space between 'catch' and '{' if on the same line -sp_catch_brace = ignore # ignore/add/remove/force - -# Add or remove space between '}' and 'catch' if on the same line -sp_brace_catch = ignore # ignore/add/remove/force - -# Add or remove space between 'finally' and '{' if on the same line -sp_finally_brace = ignore # ignore/add/remove/force - -# Add or remove space between '}' and 'finally' if on the same line -sp_brace_finally = ignore # ignore/add/remove/force - -# Add or remove space between 'try' and '{' if on the same line -sp_try_brace = ignore # ignore/add/remove/force - -# Add or remove space between get/set and '{' if on the same line -sp_getset_brace = ignore # ignore/add/remove/force - -# Add or remove space between a variable and '{' for C++ uniform initialization. Default=Add -sp_word_brace = add # ignore/add/remove/force - -# Add or remove space between a variable and '{' for a namespace. Default=Add -sp_word_brace_ns = add # ignore/add/remove/force - -# Add or remove space before the '::' operator -sp_before_dc = ignore # ignore/add/remove/force - -# Add or remove space after the '::' operator -sp_after_dc = ignore # ignore/add/remove/force - -# Add or remove around the D named array initializer ':' operator -sp_d_array_colon = ignore # ignore/add/remove/force - -# Add or remove space after the '!' (not) operator. Default=Remove -sp_not = remove # ignore/add/remove/force - -# Add or remove space after the '~' (invert) operator. Default=Remove -sp_inv = remove # ignore/add/remove/force - -# Add or remove space after the '&' (address-of) operator. Default=Remove -# This does not affect the spacing after a '&' that is part of a type. -sp_addr = remove # ignore/add/remove/force - -# Add or remove space around the '.' or '->' operators. Default=Remove -sp_member = remove # ignore/add/remove/force - -# Add or remove space after the '*' (dereference) operator. Default=Remove -# This does not affect the spacing after a '*' that is part of a type. -sp_deref = remove # ignore/add/remove/force - -# Add or remove space after '+' or '-', as in 'x = -5' or 'y = +7'. Default=Remove -sp_sign = remove # ignore/add/remove/force - -# Add or remove space before or after '++' and '--', as in '(--x)' or 'y++;'. Default=Remove -sp_incdec = remove # ignore/add/remove/force - -# Add or remove space before a backslash-newline at the end of a line. Default=Add -sp_before_nl_cont = add # ignore/add/remove/force - -# Add or remove space after the scope '+' or '-', as in '-(void) foo;' or '+(int) bar;' -sp_after_oc_scope = ignore # ignore/add/remove/force - -# Add or remove space after the colon in message specs -# '-(int) f:(int) x;' vs '-(int) f: (int) x;' -sp_after_oc_colon = ignore # ignore/add/remove/force - -# Add or remove space before the colon in message specs -# '-(int) f: (int) x;' vs '-(int) f : (int) x;' -sp_before_oc_colon = ignore # ignore/add/remove/force - -# Add or remove space after the colon in immutable dictionary expression -# 'NSDictionary *test = @{@"foo" :@"bar"};' -sp_after_oc_dict_colon = ignore # ignore/add/remove/force - -# Add or remove space before the colon in immutable dictionary expression -# 'NSDictionary *test = @{@"foo" :@"bar"};' -sp_before_oc_dict_colon = ignore # ignore/add/remove/force - -# Add or remove space after the colon in message specs -# '[object setValue:1];' vs '[object setValue: 1];' -sp_after_send_oc_colon = ignore # ignore/add/remove/force - -# Add or remove space before the colon in message specs -# '[object setValue:1];' vs '[object setValue :1];' -sp_before_send_oc_colon = ignore # ignore/add/remove/force - -# Add or remove space after the (type) in message specs -# '-(int)f: (int) x;' vs '-(int)f: (int)x;' -sp_after_oc_type = ignore # ignore/add/remove/force - -# Add or remove space after the first (type) in message specs -# '-(int) f:(int)x;' vs '-(int)f:(int)x;' -sp_after_oc_return_type = ignore # ignore/add/remove/force - -# Add or remove space between '@selector' and '(' -# '@selector(msgName)' vs '@selector (msgName)' -# Also applies to @protocol() constructs -sp_after_oc_at_sel = ignore # ignore/add/remove/force - -# Add or remove space between '@selector(x)' and the following word -# '@selector(foo) a:' vs '@selector(foo)a:' -sp_after_oc_at_sel_parens = ignore # ignore/add/remove/force - -# Add or remove space inside '@selector' parens -# '@selector(foo)' vs '@selector( foo )' -# Also applies to @protocol() constructs -sp_inside_oc_at_sel_parens = ignore # ignore/add/remove/force - -# Add or remove space before a block pointer caret -# '^int (int arg){...}' vs. ' ^int (int arg){...}' -sp_before_oc_block_caret = ignore # ignore/add/remove/force - -# Add or remove space after a block pointer caret -# '^int (int arg){...}' vs. '^ int (int arg){...}' -sp_after_oc_block_caret = ignore # ignore/add/remove/force - -# Add or remove space between the receiver and selector in a message. -# '[receiver selector ...]' -sp_after_oc_msg_receiver = ignore # ignore/add/remove/force - -# Add or remove space after @property. -sp_after_oc_property = ignore # ignore/add/remove/force - -# Add or remove space around the ':' in 'b ? t : f' -sp_cond_colon = ignore # ignore/add/remove/force - -# Add or remove space before the ':' in 'b ? t : f'. Overrides sp_cond_colon. -sp_cond_colon_before = ignore # ignore/add/remove/force - -# Add or remove space after the ':' in 'b ? t : f'. Overrides sp_cond_colon. -sp_cond_colon_after = ignore # ignore/add/remove/force - -# Add or remove space around the '?' in 'b ? t : f' -sp_cond_question = ignore # ignore/add/remove/force - -# Add or remove space before the '?' in 'b ? t : f'. Overrides sp_cond_question. -sp_cond_question_before = ignore # ignore/add/remove/force - -# Add or remove space after the '?' in 'b ? t : f'. Overrides sp_cond_question. -sp_cond_question_after = ignore # ignore/add/remove/force - -# In the abbreviated ternary form (a ?: b), add/remove space between ? and :.'. Overrides all other sp_cond_* options. -sp_cond_ternary_short = ignore # ignore/add/remove/force - -# Fix the spacing between 'case' and the label. Only 'ignore' and 'force' make sense here. -sp_case_label = ignore # ignore/add/remove/force - -# Control the space around the D '..' operator. -sp_range = ignore # ignore/add/remove/force - -# Control the spacing after ':' in 'for (TYPE VAR : EXPR)' -sp_after_for_colon = ignore # ignore/add/remove/force - -# Control the spacing before ':' in 'for (TYPE VAR : EXPR)' -sp_before_for_colon = ignore # ignore/add/remove/force - -# Control the spacing in 'extern (C)' (D) -sp_extern_paren = ignore # ignore/add/remove/force - -# Control the space after the opening of a C++ comment '// A' vs '//A' -sp_cmt_cpp_start = ignore # ignore/add/remove/force - -# TRUE: If space is added with sp_cmt_cpp_start, do it after doxygen sequences like '///', '///<', '//!' and '//!<'. -sp_cmt_cpp_doxygen = false # false/true - -# TRUE: If space is added with sp_cmt_cpp_start, do it after Qt translator or meta-data comments like '//:', '//=', and '//~'. -sp_cmt_cpp_qttr = false # false/true - -# Controls the spaces between #else or #endif and a trailing comment -sp_endif_cmt = ignore # ignore/add/remove/force - -# Controls the spaces after 'new', 'delete' and 'delete[]' -sp_after_new = ignore # ignore/add/remove/force - -# Controls the spaces between new and '(' in 'new()' -sp_between_new_paren = ignore # ignore/add/remove/force - -# Controls the spaces before a trailing or embedded comment -sp_before_tr_emb_cmt = ignore # ignore/add/remove/force - -# Number of spaces before a trailing or embedded comment -sp_num_before_tr_emb_cmt = 0 # number - -# Control space between a Java annotation and the open paren. -sp_annotation_paren = ignore # ignore/add/remove/force - -# If true, vbrace tokens are dropped to the previous token and skipped. -sp_skip_vbrace_tokens = false # false/true - -# -# Code alignment (not left column spaces/tabs) -# - -# Whether to keep non-indenting tabs -align_keep_tabs = false # false/true - -# Whether to use tabs for aligning -align_with_tabs = false # false/true - -# Whether to bump out to the next tab when aligning -align_on_tabstop = false # false/true - -# Whether to left-align numbers -#align_number_left = false # false/true - -# Whether to keep whitespace not required for alignment. -align_keep_extra_space = false # false/true - -# Align variable definitions in prototypes and functions -align_func_params = false # false/true - -# Align parameters in single-line functions that have the same name. -# The function names must already be aligned with each other. -align_same_func_call_params = false # false/true - -# The span for aligning variable definitions (0=don't align) -align_var_def_span = 0 # number - -# How to align the star in variable definitions. -# 0=Part of the type 'void * foo;' -# 1=Part of the variable 'void *foo;' -# 2=Dangling 'void *foo;' -align_var_def_star_style = 1 # number - -# How to align the '&' in variable definitions. -# 0=Part of the type -# 1=Part of the variable -# 2=Dangling -align_var_def_amp_style = 0 # number - -# The threshold for aligning variable definitions (0=no limit) -align_var_def_thresh = 0 # number - -# The gap for aligning variable definitions -align_var_def_gap = 0 # number - -# Whether to align the colon in struct bit fields -align_var_def_colon = false # false/true - -# Whether to align any attribute after the variable name -align_var_def_attribute = false # false/true - -# Whether to align inline struct/enum/union variable definitions -align_var_def_inline = true # false/true - -# The span for aligning on '=' in assignments (0=don't align) -align_assign_span = 0 # number - -# The threshold for aligning on '=' in assignments (0=no limit) -align_assign_thresh = 0 # number - -# The span for aligning on '=' in enums (0=don't align) -align_enum_equ_span = 0 # number - -# The threshold for aligning on '=' in enums (0=no limit) -align_enum_equ_thresh = 0 # number - -# The span for aligning class (0=don't align) -align_var_class_span = 0 # number - -# The threshold for aligning class member definitions (0=no limit) -align_var_class_thresh = 0 # number - -# The gap for aligning class member definitions -align_var_class_gap = 0 # number - -# The span for aligning struct/union (0=don't align) -align_var_struct_span = 0 # number - -# The threshold for aligning struct/union member definitions (0=no limit) -align_var_struct_thresh = 0 # number - -# The gap for aligning struct/union member definitions -align_var_struct_gap = 0 # number - -# The span for aligning struct initializer values (0=don't align) -align_struct_init_span = 0 # number - -# The minimum space between the type and the synonym of a typedef -align_typedef_gap = 0 # number - -# The span for aligning single-line typedefs (0=don't align) -align_typedef_span = 0 # number - -# How to align typedef'd functions with other typedefs -# 0: Don't mix them at all -# 1: align the open paren with the types -# 2: align the function type name with the other type names -align_typedef_func = 0 # number - -# Controls the positioning of the '*' in typedefs. Just try it. -# 0: Align on typedef type, ignore '*' -# 1: The '*' is part of type name: typedef int *pint; -# 2: The '*' is part of the type, but dangling: typedef int *pint; -align_typedef_star_style = 1 # number - -# Controls the positioning of the '&' in typedefs. Just try it. -# 0: Align on typedef type, ignore '&' -# 1: The '&' is part of type name: typedef int &pint; -# 2: The '&' is part of the type, but dangling: typedef int &pint; -align_typedef_amp_style = 0 # number - -# The span for aligning comments that end lines (0=don't align) -align_right_cmt_span = 0 # number - -# If aligning comments, mix with comments after '}' and #endif with less than 3 spaces before the comment -align_right_cmt_mix = false # false/true - -# If a trailing comment is more than this number of columns away from the text it follows, -# it will qualify for being aligned. This has to be > 0 to do anything. -align_right_cmt_gap = 0 # number - -# Align trailing comment at or beyond column N; 'pulls in' comments as a bonus side effect (0=ignore) -align_right_cmt_at_col = 0 # number - -# The span for aligning function prototypes (0=don't align) -align_func_proto_span = 0 # number - -# Minimum gap between the return type and the function name. -align_func_proto_gap = 0 # number - -# Align function protos on the 'operator' keyword instead of what follows -align_on_operator = false # false/true - -# Whether to mix aligning prototype and variable declarations. -# If true, align_var_def_XXX options are used instead of align_func_proto_XXX options. -align_mix_var_proto = false # false/true - -# Align single-line functions with function prototypes, uses align_func_proto_span -align_single_line_func = false # false/true - -# Aligning the open brace of single-line functions. -# Requires align_single_line_func=true, uses align_func_proto_span -align_single_line_brace = false # false/true - -# Gap for align_single_line_brace. -align_single_line_brace_gap = 0 # number - -# The span for aligning ObjC msg spec (0=don't align) -align_oc_msg_spec_span = 0 # number - -# Whether to align macros wrapped with a backslash and a newline. -# This will not work right if the macro contains a multi-line comment. -align_nl_cont = false # false/true - -# # Align macro functions and variables together -align_pp_define_together = false # false/true - -# The minimum space between label and value of a preprocessor define -align_pp_define_gap = 0 # number - -# The span for aligning on '#define' bodies (0=don't align, other=number of lines including comments between blocks) -align_pp_define_span = 0 # number - -# Align lines that start with '<<' with previous '<<'. Default=True -align_left_shift = true # false/true - -# Align text after asm volatile () colons. -align_asm_colon = false # false/true - -# Span for aligning parameters in an Obj-C message call on the ':' (0=don't align) -align_oc_msg_colon_span = 0 # number - -# If true, always align with the first parameter, even if it is too short. -align_oc_msg_colon_first = false # false/true - -# Aligning parameters in an Obj-C '+' or '-' declaration on the ':' -align_oc_decl_colon = false # false/true - -# -# Newline adding and removing options -# - -# Whether to collapse empty blocks between '{' and '}' -nl_collapse_empty_body = false # false/true - -# Don't split one-line braced assignments - 'foo_t f = { 1, 2 };' -nl_assign_leave_one_liners = true # false/true - -# Don't split one-line braced statements inside a class xx { } body -nl_class_leave_one_liners = false # false/true - -# Don't split one-line enums: 'enum foo { BAR = 15 };' -nl_enum_leave_one_liners = false # false/true - -# Don't split one-line get or set functions -nl_getset_leave_one_liners = false # false/true - -# Don't split one-line function definitions - 'int foo() { return 0; }' -nl_func_leave_one_liners = false # false/true - -# Don't split one-line C++11 lambdas - '[]() { return 0; }' -nl_cpp_lambda_leave_one_liners = false # false/true - -# Don't split one-line if/else statements - 'if(a) b++;' -nl_if_leave_one_liners = false # false/true - -# Don't split one-line while statements - 'while(a) b++;' -nl_while_leave_one_liners = true # false/true - -# Don't split one-line OC messages -nl_oc_msg_leave_one_liner = false # false/true - -# Add or remove newline between Objective-C block signature and '{' -nl_oc_block_brace = ignore # ignore/add/remove/force - -# Add or remove newlines at the start of the file -nl_start_of_file = remove # ignore/add/remove/force - -# The number of newlines at the start of the file (only used if nl_start_of_file is 'add' or 'force' -nl_start_of_file_min = 0 # number - -# Add or remove newline at the end of the file -nl_end_of_file = ignore # ignore/add/remove/force - -# The number of newlines at the end of the file (only used if nl_end_of_file is 'add' or 'force') -nl_end_of_file_min = 0 # number - -# Add or remove newline between '=' and '{' -nl_assign_brace = remove # ignore/add/remove/force - -# Add or remove newline between '=' and '[' (D only) -nl_assign_square = ignore # ignore/add/remove/force - -# Add or remove newline after '= [' (D only). Will also affect the newline before the ']' -nl_after_square_assign = ignore # ignore/add/remove/force - -# The number of blank lines after a block of variable definitions at the top of a function body -# 0 = No change (default) -nl_func_var_def_blk = 0 # number - -# The number of newlines before a block of typedefs -# 0 = No change (default) -# the option 'nl_after_access_spec' takes preference over 'nl_typedef_blk_start' -nl_typedef_blk_start = 0 # number - -# The number of newlines after a block of typedefs -# 0 = No change (default) -nl_typedef_blk_end = 0 # number - -# The maximum consecutive newlines within a block of typedefs -# 0 = No change (default) -nl_typedef_blk_in = 0 # number - -# The number of newlines before a block of variable definitions not at the top of a function body -# 0 = No change (default) -# the option 'nl_after_access_spec' takes preference over 'nl_var_def_blk_start' -nl_var_def_blk_start = 0 # number - -# The number of newlines after a block of variable definitions not at the top of a function body -# 0 = No change (default) -nl_var_def_blk_end = 0 # number - -# The maximum consecutive newlines within a block of variable definitions -# 0 = No change (default) -nl_var_def_blk_in = 0 # number - -# Add or remove newline between a function call's ')' and '{', as in: -# list_for_each(item, &list) { } -nl_fcall_brace = remove # ignore/add/remove/force - -# Add or remove newline between 'enum' and '{' -nl_enum_brace = ignore # ignore/add/remove/force - -# Add or remove newline between 'struct and '{' -nl_struct_brace = remove # ignore/add/remove/force - -# Add or remove newline between 'union' and '{' -nl_union_brace = remove # ignore/add/remove/force - -# Add or remove newline between 'if' and '{' -nl_if_brace = remove # ignore/add/remove/force - -# Add or remove newline between '}' and 'else' -nl_brace_else = remove # ignore/add/remove/force - -# Add or remove newline between 'else if' and '{' -# If set to ignore, nl_if_brace is used instead -nl_elseif_brace = remove # ignore/add/remove/force - -# Add or remove newline between 'else' and '{' -nl_else_brace = remove # ignore/add/remove/force - -# Add or remove newline between 'else' and 'if' -nl_else_if = remove # ignore/add/remove/force - -# Add or remove newline between '}' and 'finally' -nl_brace_finally = ignore # ignore/add/remove/force - -# Add or remove newline between 'finally' and '{' -nl_finally_brace = ignore # ignore/add/remove/force - -# Add or remove newline between 'try' and '{' -nl_try_brace = ignore # ignore/add/remove/force - -# Add or remove newline between get/set and '{' -nl_getset_brace = ignore # ignore/add/remove/force - -# Add or remove newline between 'for' and '{' -nl_for_brace = remove # ignore/add/remove/force - -# Add or remove newline between 'catch' and '{' -nl_catch_brace = ignore # ignore/add/remove/force - -# Add or remove newline between '}' and 'catch' -nl_brace_catch = ignore # ignore/add/remove/force - -# Add or remove newline between '}' and ']' -nl_brace_square = ignore # ignore/add/remove/force - -# Add or remove newline between '}' and ')' in a function invocation -nl_brace_fparen = ignore # ignore/add/remove/force - -# Add or remove newline between 'while' and '{' -nl_while_brace = remove # ignore/add/remove/force - -# Add or remove newline between 'scope (x)' and '{' (D) -nl_scope_brace = ignore # ignore/add/remove/force - -# Add or remove newline between 'unittest' and '{' (D) -nl_unittest_brace = ignore # ignore/add/remove/force - -# Add or remove newline between 'version (x)' and '{' (D) -nl_version_brace = ignore # ignore/add/remove/force - -# Add or remove newline between 'using' and '{' -nl_using_brace = ignore # ignore/add/remove/force - -# Add or remove newline between two open or close braces. -# Due to general newline/brace handling, REMOVE may not work. -nl_brace_brace = ignore # ignore/add/remove/force - -# Add or remove newline between 'do' and '{' -nl_do_brace = remove # ignore/add/remove/force - -# Add or remove newline between '}' and 'while' of 'do' statement -nl_brace_while = remove # ignore/add/remove/force - -# Add or remove newline between 'switch' and '{' -nl_switch_brace = remove # ignore/add/remove/force - -# Add or remove newline between 'synchronized' and '{' -nl_synchronized_brace = ignore # ignore/add/remove/force - -# Add a newline between ')' and '{' if the ')' is on a different line than the if/for/etc. -# Overrides nl_for_brace, nl_if_brace, nl_switch_brace, nl_while_switch and nl_catch_brace. -nl_multi_line_cond = false # false/true - -# Force a newline in a define after the macro name for multi-line defines. -nl_multi_line_define = false # false/true - -# Whether to put a newline before 'case' statement, not after the first 'case' -nl_before_case = false # false/true - -# Add or remove newline between ')' and 'throw' -nl_before_throw = ignore # ignore/add/remove/force - -# Whether to put a newline after 'case' statement -nl_after_case = false # false/true - -# Add or remove a newline between a case ':' and '{'. Overrides nl_after_case. -nl_case_colon_brace = ignore # ignore/add/remove/force - -# Newline between namespace and { -nl_namespace_brace = ignore # ignore/add/remove/force - -# Add or remove newline between 'template<>' and whatever follows. -nl_template_class = ignore # ignore/add/remove/force - -# Add or remove newline between 'class' and '{' -nl_class_brace = ignore # ignore/add/remove/force - -# Add or remove newline before/after each ',' in the base class list, -# (tied to pos_class_comma). -nl_class_init_args = ignore # ignore/add/remove/force - -# Add or remove newline after each ',' in the constructor member initialization. -# Related to nl_constr_colon, pos_constr_colon and pos_constr_comma. -nl_constr_init_args = ignore # ignore/add/remove/force - -# Add or remove newline before first element, after comma, and after last element in enum -nl_enum_own_lines = ignore # ignore/add/remove/force - -# Add or remove newline between return type and function name in a function definition -nl_func_type_name = add # ignore/add/remove/force - -# Add or remove newline between return type and function name inside a class {} -# Uses nl_func_type_name or nl_func_proto_type_name if set to ignore. -nl_func_type_name_class = ignore # ignore/add/remove/force - -# Add or remove newline between class specification and '::' in 'void A::f() { }' -# Only appears in separate member implementation (does not appear with in-line implmementation) -nl_func_class_scope = ignore # ignore/add/remove/force - -# Add or remove newline between function scope and name -# Controls the newline after '::' in 'void A::f() { }' -nl_func_scope_name = ignore # ignore/add/remove/force - -# Add or remove newline between return type and function name in a prototype -nl_func_proto_type_name = ignore # ignore/add/remove/force - -# Add or remove newline between a function name and the opening '(' in the declaration -nl_func_paren = remove # ignore/add/remove/force - -# Add or remove newline between a function name and the opening '(' in the definition -nl_func_def_paren = remove # ignore/add/remove/force - -# Add or remove newline after '(' in a function declaration -nl_func_decl_start = remove # ignore/add/remove/force - -# Add or remove newline after '(' in a function definition -nl_func_def_start = remove # ignore/add/remove/force - -# Overrides nl_func_decl_start when there is only one parameter. -nl_func_decl_start_single = ignore # ignore/add/remove/force - -# Overrides nl_func_def_start when there is only one parameter. -nl_func_def_start_single = ignore # ignore/add/remove/force - -# Whether to add newline after '(' in a function declaration if '(' and ')' are in different lines. -nl_func_decl_start_multi_line = false # false/true - -# Whether to add newline after '(' in a function definition if '(' and ')' are in different lines. -nl_func_def_start_multi_line = false # false/true - -# Add or remove newline after each ',' in a function declaration -nl_func_decl_args = ignore # ignore/add/remove/force - -# Add or remove newline after each ',' in a function definition -nl_func_def_args = ignore # ignore/add/remove/force - -# Whether to add newline after each ',' in a function declaration if '(' and ')' are in different lines. -nl_func_decl_args_multi_line = false # false/true - -# Whether to add newline after each ',' in a function definition if '(' and ')' are in different lines. -nl_func_def_args_multi_line = false # false/true - -# Add or remove newline before the ')' in a function declaration -nl_func_decl_end = remove # ignore/add/remove/force - -# Add or remove newline before the ')' in a function definition -nl_func_def_end = remove # ignore/add/remove/force - -# Overrides nl_func_decl_end when there is only one parameter. -nl_func_decl_end_single = ignore # ignore/add/remove/force - -# Overrides nl_func_def_end when there is only one parameter. -nl_func_def_end_single = ignore # ignore/add/remove/force - -# Whether to add newline before ')' in a function declaration if '(' and ')' are in different lines. -nl_func_decl_end_multi_line = false # false/true - -# Whether to add newline before ')' in a function definition if '(' and ')' are in different lines. -nl_func_def_end_multi_line = false # false/true - -# Add or remove newline between '()' in a function declaration. -nl_func_decl_empty = ignore # ignore/add/remove/force - -# Add or remove newline between '()' in a function definition. -nl_func_def_empty = ignore # ignore/add/remove/force - -# Whether to add newline after '(' in a function call if '(' and ')' are in different lines. -nl_func_call_start_multi_line = false # false/true - -# Whether to add newline after each ',' in a function call if '(' and ')' are in different lines. -nl_func_call_args_multi_line = false # false/true - -# Whether to add newline before ')' in a function call if '(' and ')' are in different lines. -nl_func_call_end_multi_line = false # false/true - -# Whether to put each OC message parameter on a separate line -# See nl_oc_msg_leave_one_liner -nl_oc_msg_args = false # false/true - -# Add or remove newline between function signature and '{' -nl_fdef_brace = add # ignore/add/remove/force - -# Add or remove newline between C++11 lambda signature and '{' -nl_cpp_ldef_brace = ignore # ignore/add/remove/force - -# Add or remove a newline between the return keyword and return expression. -nl_return_expr = ignore # ignore/add/remove/force - -# Whether to put a newline after semicolons, except in 'for' statements -nl_after_semicolon = false # false/true - -# Java: Control the newline between the ')' and '{{' of the double brace initializer. -nl_paren_dbrace_open = ignore # ignore/add/remove/force - -# Whether to put a newline after brace open. -# This also adds a newline before the matching brace close. -nl_after_brace_open = false # false/true - -# If nl_after_brace_open and nl_after_brace_open_cmt are true, a newline is -# placed between the open brace and a trailing single-line comment. -nl_after_brace_open_cmt = false # false/true - -# Whether to put a newline after a virtual brace open with a non-empty body. -# These occur in un-braced if/while/do/for statement bodies. -nl_after_vbrace_open = false # false/true - -# Whether to put a newline after a virtual brace open with an empty body. -# These occur in un-braced if/while/do/for statement bodies. -nl_after_vbrace_open_empty = false # false/true - -# Whether to put a newline after a brace close. -# Does not apply if followed by a necessary ';'. -nl_after_brace_close = false # false/true - -# Whether to put a newline after a virtual brace close. -# Would add a newline before return in: 'if (foo) a++; return;' -nl_after_vbrace_close = false # false/true - -# Control the newline between the close brace and 'b' in: 'struct { int a; } b;' -# Affects enums, unions and structures. If set to ignore, uses nl_after_brace_close -nl_brace_struct_var = ignore # ignore/add/remove/force - -# Whether to alter newlines in '#define' macros -nl_define_macro = false # false/true - -# Whether to remove blanks after '#ifxx' and '#elxx', or before '#elxx' and '#endif'. Does not affect top-level #ifdefs. -nl_squeeze_ifdef = false # false/true - -# Makes the nl_squeeze_ifdef option affect the top-level #ifdefs as well. -nl_squeeze_ifdef_top_level = false # false/true - -# Add or remove blank line before 'if' -nl_before_if = ignore # ignore/add/remove/force - -# Add or remove blank line after 'if' statement -nl_after_if = ignore # ignore/add/remove/force - -# Add or remove blank line before 'for' -nl_before_for = ignore # ignore/add/remove/force - -# Add or remove blank line after 'for' statement -nl_after_for = ignore # ignore/add/remove/force - -# Add or remove blank line before 'while' -nl_before_while = ignore # ignore/add/remove/force - -# Add or remove blank line after 'while' statement -nl_after_while = ignore # ignore/add/remove/force - -# Add or remove blank line before 'switch' -nl_before_switch = ignore # ignore/add/remove/force - -# Add or remove blank line after 'switch' statement -nl_after_switch = ignore # ignore/add/remove/force - -# Add or remove blank line before 'synchronized' -nl_before_synchronized = ignore # ignore/add/remove/force - -# Add or remove blank line after 'synchronized' statement -nl_after_synchronized = ignore # ignore/add/remove/force - -# Add or remove blank line before 'do' -nl_before_do = ignore # ignore/add/remove/force - -# Add or remove blank line after 'do/while' statement -nl_after_do = ignore # ignore/add/remove/force - -# Whether to double-space commented-entries in struct/union/enum -nl_ds_struct_enum_cmt = false # false/true - -# force nl before } of a struct/union/enum -# (lower priority than 'eat_blanks_before_close_brace') -nl_ds_struct_enum_close_brace = false # false/true - -# Add or remove blank line before 'func_class_def' -nl_before_func_class_def = 0 # number - -# Add or remove blank line before 'func_class_proto' -nl_before_func_class_proto = 0 # number - -# Add or remove a newline before/after a class colon, -# (tied to pos_class_colon). -nl_class_colon = ignore # ignore/add/remove/force - -# Add or remove a newline around a class constructor colon. -# Related to nl_constr_init_args, pos_constr_colon and pos_constr_comma. -nl_constr_colon = ignore # ignore/add/remove/force - -# Change simple unbraced if statements into a one-liner -# 'if(b)\n i++;' => 'if(b) i++;' -nl_create_if_one_liner = false # false/true - -# Change simple unbraced for statements into a one-liner -# 'for (i=0;i<5;i++)\n foo(i);' => 'for (i=0;i<5;i++) foo(i);' -nl_create_for_one_liner = false # false/true - -# Change simple unbraced while statements into a one-liner -# 'while (i<5)\n foo(i++);' => 'while (i<5) foo(i++);' -nl_create_while_one_liner = false # false/true - -# Change a one-liner if statement into simple unbraced if -# 'if(b) i++;' => 'if(b) i++;' -nl_split_if_one_liner = false # false/true - -# Change a one-liner for statement into simple unbraced for -# 'for (i=0;<5;i++) foo(i);' => 'for (i=0;<5;i++) foo(i);' -nl_split_for_one_liner = false # false/true - -# Change simple unbraced while statements into a one-liner while -# 'while (i<5)\n foo(i++);' => 'while (i<5) foo(i++);' -nl_split_while_one_liner = false # false/true - -# -# Positioning options -# - -# The position of arithmetic operators in wrapped expressions -pos_arith = ignore # ignore/join/lead/lead_break/lead_force/trail/trail_break/trail_force - -# The position of assignment in wrapped expressions. -# Do not affect '=' followed by '{' -pos_assign = ignore # ignore/join/lead/lead_break/lead_force/trail/trail_break/trail_force - -# The position of boolean operators in wrapped expressions -pos_bool = ignore # ignore/join/lead/lead_break/lead_force/trail/trail_break/trail_force - -# The position of comparison operators in wrapped expressions -pos_compare = ignore # ignore/join/lead/lead_break/lead_force/trail/trail_break/trail_force - -# The position of conditional (b ? t : f) operators in wrapped expressions -pos_conditional = ignore # ignore/join/lead/lead_break/lead_force/trail/trail_break/trail_force - -# The position of the comma in wrapped expressions -pos_comma = ignore # ignore/join/lead/lead_break/lead_force/trail/trail_break/trail_force - -# The position of the comma in enum entries -pos_enum_comma = ignore # ignore/join/lead/lead_break/lead_force/trail/trail_break/trail_force - -# The position of the comma in the base class list if there are more than one line, -# (tied to nl_class_init_args). -pos_class_comma = ignore # ignore/join/lead/lead_break/lead_force/trail/trail_break/trail_force - -# The position of the comma in the constructor initialization list. -# Related to nl_constr_colon, nl_constr_init_args and pos_constr_colon. -pos_constr_comma = ignore # ignore/join/lead/lead_break/lead_force/trail/trail_break/trail_force - -# The position of trailing/leading class colon, between class and base class list -# (tied to nl_class_colon). -pos_class_colon = ignore # ignore/join/lead/lead_break/lead_force/trail/trail_break/trail_force - -# The position of colons between constructor and member initialization, -# (tied to UO_nl_constr_colon). -# Related to nl_constr_colon, nl_constr_init_args and pos_constr_comma. -pos_constr_colon = ignore # ignore/join/lead/lead_break/lead_force/trail/trail_break/trail_force - -# -# Line Splitting options -# - -# Try to limit code width to N number of columns -code_width = 119 # number - -# Whether to fully split long 'for' statements at semi-colons -ls_for_split_full = false # false/true - -# Whether to fully split long function protos/calls at commas -ls_func_split_full = false # false/true - -# Whether to split lines as close to code_width as possible and ignore some groupings -ls_code_width = false # false/true - -# -# Blank line options -# - -# The maximum consecutive newlines (3 = 2 blank lines) -nl_max = 0 # number - -# The number of newlines after a function prototype, if followed by another function prototype -nl_after_func_proto = 0 # number - -# The number of newlines after a function prototype, if not followed by another function prototype -nl_after_func_proto_group = 0 # number - -# The number of newlines after a function class prototype, if followed by another function class prototype -nl_after_func_class_proto = 0 # number - -# The number of newlines after a function class prototype, if not followed by another function class prototype -nl_after_func_class_proto_group = 0 # number - -# The number of newlines before a multi-line function def body -nl_before_func_body_def = 0 # number - -# The number of newlines before a multi-line function prototype body -nl_before_func_body_proto = 0 # number - -# The number of newlines after '}' of a multi-line function body -nl_after_func_body = 0 # number - -# The number of newlines after '}' of a multi-line function body in a class declaration -nl_after_func_body_class = 0 # number - -# The number of newlines after '}' of a single line function body -nl_after_func_body_one_liner = 0 # number - -# The minimum number of newlines before a multi-line comment. -# Doesn't apply if after a brace open or another multi-line comment. -nl_before_block_comment = 0 # number - -# The minimum number of newlines before a single-line C comment. -# Doesn't apply if after a brace open or other single-line C comments. -nl_before_c_comment = 0 # number - -# The minimum number of newlines before a CPP comment. -# Doesn't apply if after a brace open or other CPP comments. -nl_before_cpp_comment = 0 # number - -# Whether to force a newline after a multi-line comment. -nl_after_multiline_comment = false # false/true - -# Whether to force a newline after a label's colon. -nl_after_label_colon = false # false/true - -# The number of newlines after '}' or ';' of a struct/enum/union definition -nl_after_struct = 0 # number - -# The number of newlines before a class definition -nl_before_class = 0 # number - -# The number of newlines after '}' or ';' of a class definition -nl_after_class = 0 # number - -# The number of newlines before a 'private:', 'public:', 'protected:', 'signals:', or 'slots:' label. -# Will not change the newline count if after a brace open. -# 0 = No change. -nl_before_access_spec = 0 # number - -# The number of newlines after a 'private:', 'public:', 'protected:', 'signals:' or 'slots:' label. -# 0 = No change. -# the option 'nl_after_access_spec' takes preference over 'nl_typedef_blk_start' and 'nl_var_def_blk_start' -nl_after_access_spec = 0 # number - -# The number of newlines between a function def and the function comment. -# 0 = No change. -nl_comment_func_def = 0 # number - -# The number of newlines after a try-catch-finally block that isn't followed by a brace close. -# 0 = No change. -nl_after_try_catch_finally = 0 # number - -# The number of newlines before and after a property, indexer or event decl. -# 0 = No change. -nl_around_cs_property = 0 # number - -# The number of newlines between the get/set/add/remove handlers in C#. -# 0 = No change. -nl_between_get_set = 0 # number - -# Add or remove newline between C# property and the '{' -nl_property_brace = ignore # ignore/add/remove/force - -# Whether to remove blank lines after '{' -eat_blanks_after_open_brace = false # false/true - -# Whether to remove blank lines before '}' -eat_blanks_before_close_brace = false # false/true - -# How aggressively to remove extra newlines not in preproc. -# 0: No change -# 1: Remove most newlines not handled by other config -# 2: Remove all newlines and reformat completely by config -nl_remove_extra_newlines = 0 # number - -# Whether to put a blank line before 'return' statements, unless after an open brace. -nl_before_return = false # false/true - -# Whether to put a blank line after 'return' statements, unless followed by a close brace. -nl_after_return = false # false/true - -# Whether to put a newline after a Java annotation statement. -# Only affects annotations that are after a newline. -nl_after_annotation = ignore # ignore/add/remove/force - -# Controls the newline between two annotations. -nl_between_annotation = ignore # ignore/add/remove/force - -# -# Code modifying options (non-whitespace) -# - -# Add or remove braces on single-line 'do' statement -mod_full_brace_do = add # ignore/add/remove/force - -# Add or remove braces on single-line 'for' statement -mod_full_brace_for = add # ignore/add/remove/force - -# Add or remove braces on single-line function definitions. (Pawn) -mod_full_brace_function = ignore # ignore/add/remove/force - -# Add or remove braces on single-line 'if' statement. Will not remove the braces if they contain an 'else'. -mod_full_brace_if = add # ignore/add/remove/force - -# Make all if/elseif/else statements in a chain be braced or not. Overrides mod_full_brace_if. -# If any must be braced, they are all braced. If all can be unbraced, then the braces are removed. -mod_full_brace_if_chain = false # false/true - -# Make all if/elseif/else statements with at least one 'else' or 'else if' fully braced. -# If mod_full_brace_if_chain is used together with this option, all if-else chains will get braces, -# and simple 'if' statements will lose them (if possible). -mod_full_brace_if_chain_only = false # false/true - -# Don't remove braces around statements that span N newlines -mod_full_brace_nl = 0 # number - -# Add or remove braces on single-line 'while' statement -mod_full_brace_while = ignore # ignore/add/remove/force - -# Add or remove braces on single-line 'using ()' statement -mod_full_brace_using = ignore # ignore/add/remove/force - -# Add or remove unnecessary paren on 'return' statement -mod_paren_on_return = ignore # ignore/add/remove/force - -# Whether to change optional semicolons to real semicolons -mod_pawn_semicolon = false # false/true - -# Add parens on 'while' and 'if' statement around bools -mod_full_paren_if_bool = false # false/true - -# Whether to remove superfluous semicolons -mod_remove_extra_semicolon = false # false/true - -# If a function body exceeds the specified number of newlines and doesn't have a comment after -# the close brace, a comment will be added. -mod_add_long_function_closebrace_comment = 0 # number - -# If a namespace body exceeds the specified number of newlines and doesn't have a comment after -# the close brace, a comment will be added. -mod_add_long_namespace_closebrace_comment = 0 # number - -# If a class body exceeds the specified number of newlines and doesn't have a comment after -# the close brace, a comment will be added. -mod_add_long_class_closebrace_comment = 0 # number - -# If a switch body exceeds the specified number of newlines and doesn't have a comment after -# the close brace, a comment will be added. -mod_add_long_switch_closebrace_comment = 0 # number - -# If an #ifdef body exceeds the specified number of newlines and doesn't have a comment after -# the #endif, a comment will be added. -mod_add_long_ifdef_endif_comment = 0 # number - -# If an #ifdef or #else body exceeds the specified number of newlines and doesn't have a comment after -# the #else, a comment will be added. -mod_add_long_ifdef_else_comment = 0 # number - -# If TRUE, will sort consecutive single-line 'import' statements [Java, D] -mod_sort_import = false # false/true - -# If TRUE, will sort consecutive single-line 'using' statements [C#] -mod_sort_using = false # false/true - -# If TRUE, will sort consecutive single-line '#include' statements [C/C++] and '#import' statements [Obj-C] -# This is generally a bad idea, as it may break your code. -mod_sort_include = false # false/true - -# If TRUE, it will move a 'break' that appears after a fully braced 'case' before the close brace. -mod_move_case_break = false # false/true - -# Will add or remove the braces around a fully braced case statement. -# Will only remove the braces if there are no variable declarations in the block. -mod_case_brace = ignore # ignore/add/remove/force - -# If TRUE, it will remove a void 'return;' that appears as the last statement in a function. -mod_remove_empty_return = false # false/true - -# If TRUE, it will organize the properties (Obj-C) -mod_sort_oc_properties = false # false/true - -# Determines weight of atomic/nonatomic (Obj-C) -mod_sort_oc_property_thread_safe_weight = 0 # number - -# Determines weight of readwrite (Obj-C) -mod_sort_oc_property_readwrite_weight = 0 # number - -# Determines weight of reference type (retain, copy, assign, weak, strong) (Obj-C) -mod_sort_oc_property_reference_weight = 0 # number - -# Determines weight of getter type (getter=) (Obj-C) -mod_sort_oc_property_getter_weight = 0 # number - -# Determines weight of setter type (setter=) (Obj-C) -mod_sort_oc_property_setter_weight = 0 # number - -# Determines weight of nullability type (nullable/nonnull) (Obj-C) -mod_sort_oc_property_nullability_weight = 0 # number - -# -# Comment modifications -# - -# Try to wrap comments at cmt_width columns -cmt_width = 0 # number - -# Set the comment reflow mode (default: 0) -# 0: no reflowing (apart from the line wrapping due to cmt_width) -# 1: no touching at all -# 2: full reflow -cmt_reflow_mode = 0 # number - -# Whether to convert all tabs to spaces in comments. Default is to leave tabs inside comments alone, unless used for indenting. -cmt_convert_tab_to_spaces = true # false/true - -# If false, disable all multi-line comment changes, including cmt_width. keyword substitution and leading chars. -# Default=True. -cmt_indent_multi = true # false/true - -# Whether to group c-comments that look like they are in a block -cmt_c_group = false # false/true - -# Whether to put an empty '/*' on the first line of the combined c-comment -cmt_c_nl_start = false # false/true - -# Whether to put a newline before the closing '*/' of the combined c-comment -cmt_c_nl_end = false # false/true - -# Whether to group cpp-comments that look like they are in a block -cmt_cpp_group = true # false/true - -# Whether to put an empty '/*' on the first line of the combined cpp-comment -cmt_cpp_nl_start = true # false/true - -# Whether to put a newline before the closing '*/' of the combined cpp-comment -cmt_cpp_nl_end = true # false/true - -# Whether to change cpp-comments into c-comments -cmt_cpp_to_c = true # false/true - -# Whether to put a star on subsequent comment lines -cmt_star_cont = false # false/true - -# The number of spaces to insert at the start of subsequent comment lines -cmt_sp_before_star_cont = 0 # number - -# The number of spaces to insert after the star on subsequent comment lines -cmt_sp_after_star_cont = 0 # number - -# For multi-line comments with a '*' lead, remove leading spaces if the first and last lines of -# the comment are the same length. Default=True -cmt_multi_check_last = true # false/true - -# For multi-line comments with a '*' lead, remove leading spaces if the first and last lines of -# the comment are the same length AND if the length is bigger as the first_len minimum. Default=4 -cmt_multi_first_len_minimum = 4 # number - -# The filename that contains text to insert at the head of a file if the file doesn't start with a C/C++ comment. -# Will substitute $(filename) with the current file's name. -cmt_insert_file_header = "" # string - -# The filename that contains text to insert at the end of a file if the file doesn't end with a C/C++ comment. -# Will substitute $(filename) with the current file's name. -cmt_insert_file_footer = "" # string - -# The filename that contains text to insert before a function implementation if the function isn't preceded with a C/C++ comment. -# Will substitute $(function) with the function name and $(javaparam) with the javadoc @param and @return stuff. -# Will also substitute $(fclass) with the class name: void CFoo::Bar() { ... } -cmt_insert_func_header = "" # string - -# The filename that contains text to insert before a class if the class isn't preceded with a C/C++ comment. -# Will substitute $(class) with the class name. -cmt_insert_class_header = "" # string - -# The filename that contains text to insert before a Obj-C message specification if the method isn't preceded with a C/C++ comment. -# Will substitute $(message) with the function name and $(javaparam) with the javadoc @param and @return stuff. -cmt_insert_oc_msg_header = "" # string - -# If a preprocessor is encountered when stepping backwards from a function name, then -# this option decides whether the comment should be inserted. -# Affects cmt_insert_oc_msg_header, cmt_insert_func_header and cmt_insert_class_header. -cmt_insert_before_preproc = false # false/true - -# If a function is declared inline to a class definition, then -# this option decides whether the comment should be inserted. -# Affects cmt_insert_func_header. -cmt_insert_before_inlines = true # false/true - -# If the function is a constructor/destructor, then -# this option decides whether the comment should be inserted. -# Affects cmt_insert_func_header. -cmt_insert_before_ctor_dtor = false # false/true - -# -# Preprocessor options -# - -# Control indent of preprocessors inside #if blocks at brace level 0 (file-level) -pp_indent = ignore # ignore/add/remove/force - -# Whether to indent #if/#else/#endif at the brace level (true) or from column 1 (false) -pp_indent_at_level = false # false/true - -# Specifies the number of columns to indent preprocessors per level at brace level 0 (file-level). -# If pp_indent_at_level=false, specifies the number of columns to indent preprocessors per level at brace level > 0 (function-level). -# Default=1. -pp_indent_count = 1 # number - -# Add or remove space after # based on pp_level of #if blocks -pp_space = ignore # ignore/add/remove/force - -# Sets the number of spaces added with pp_space -pp_space_count = 0 # number - -# The indent for #region and #endregion in C# and '#pragma region' in C/C++ -pp_indent_region = 0 # number - -# Whether to indent the code between #region and #endregion -pp_region_indent_code = false # false/true - -# If pp_indent_at_level=true, sets the indent for #if, #else and #endif when not at file-level. -# 0: indent preprocessors using output_tab_size. -# >0: column at which all preprocessors will be indented. -pp_indent_if = 0 # number - -# Control whether to indent the code between #if, #else and #endif. -pp_if_indent_code = false # false/true - -# Whether to indent '#define' at the brace level (true) or from column 1 (false) -pp_define_at_level = false # false/true - -# -# Use or Do not Use options -# - -# True: indent_func_call_param will be used (default) -# False: indent_func_call_param will NOT be used -use_indent_func_call_param = false # false/true - -# The value of the indentation for a continuation line is calculate differently if the line is: -# a declaration :your case with QString fileName ... -# an assigment :your case with pSettings = new QSettings( ... -# At the second case the option value might be used twice: -# at the assigment -# at the function call (if present) -# To prevent the double use of the option value, use this option with the value 'true'. -# True: indent_continue will be used only once -# False: indent_continue will be used every time (default) -use_indent_continue_only_once = false # false/true - -# SIGNAL/SLOT Qt macros have special formatting options. See options_for_QT.cpp for details. -# Default=True. -use_options_overriding_for_qt_macros = true # false/true - -# -# Warn levels - 1: error, 2: warning (default), 3: note -# - -# Warning is given if doing tab-to-\t replacement and we have found one in a C# verbatim string literal. -warn_level_tabs_found_in_verbatim_string_literals = 2 # number - -# You can force a token to be a type with the 'type' option. -# Example: -# type myfoo1 myfoo2 -# -# You can create custom macro-based indentation using macro-open, -# macro-else and macro-close. -# Example: -# macro-open BEGIN_TEMPLATE_MESSAGE_MAP -# macro-open BEGIN_MESSAGE_MAP -# macro-close END_MESSAGE_MAP -# -# You can assign any keyword to any type with the set option. -# set func_call_user _ N_ -# -# The full syntax description of all custom definition config entries -# is shown below: -# -# define custom tokens as: -# - embed whitespace in token using '' escape character, or -# put token in quotes -# - these: ' " and ` are recognized as quote delimiters -# -# type token1 token2 token3 ... -# ^ optionally specify multiple tokens on a single line -# define def_token output_token -# ^ output_token is optional, then NULL is assumed -# macro-open token -# macro-close token -# macro-else token -# set id token1 token2 ... -# ^ optionally specify multiple tokens on a single line -# ^ id is one of the names in token_enum.h sans the CT_ prefix, -# e.g. PP_PRAGMA -# -# all tokens are separated by any mix of ',' commas, '=' equal signs -# and whitespace (space, tab) -# -# You can add support for other file extensions using the 'file_ext' command. -# The first arg is the language name used with the '-l' option. -# The remaining args are file extensions, matched with 'endswith'. -# file_ext CPP .ch .cxx .cpp.in -# -# option(s) with 'not default' value: 0 -#