wenbo13579 2 лет назад
Сommit
adfb11e0f0
100 измененных файлов с 7660 добавлено и 0 удалено
  1. 101 0
      .clang-format
  2. 7 0
      .gitignore
  3. 202 0
      LICENSE
  4. 317 0
      Makefile
  5. 228 0
      README.md
  6. 71 0
      SConscript
  7. 8 0
      chipset/artpi_ap6212/build.mk
  8. 13 0
      chipset/artpi_ap6212/chipset_artpi_ap6212.c
  9. 16 0
      chipset/artpi_ap6212/chipset_artpi_ap6212.h
  10. 8 0
      chipset/ats2851/build.mk
  11. 21 0
      chipset/ats2851/chipset_ats2851.c
  12. 15 0
      chipset/ats2851/chipset_ats2851.h
  13. 35 0
      chipset/chipset_interface.h
  14. 8 0
      chipset/common/build.mk
  15. 24 0
      chipset/common/chipset_common.c
  16. 15 0
      chipset/common/chipset_common.h
  17. 8 0
      chipset/csr8510/build.mk
  18. 147 0
      chipset/csr8510/chipset_csr8510.c
  19. 16 0
      chipset/csr8510/chipset_csr8510.h
  20. 8 0
      chipset/csr8910/build.mk
  21. 284 0
      chipset/csr8910/chipset_csr8910.c
  22. 16 0
      chipset/csr8910/chipset_csr8910.h
  23. 8 0
      chipset/pts_dongle/build.mk
  24. 21 0
      chipset/pts_dongle/chipset_pts_dongle.c
  25. 16 0
      chipset/pts_dongle/chipset_pts_dongle.h
  26. 27 0
      code_format.py
  27. 20 0
      doc/Makefile
  28. 958 0
      doc/_static/css/custom.css
  29. 93 0
      doc/_static/css/dark.css
  30. 91 0
      doc/_static/css/light.css
  31. BIN
      doc/_static/images/favicon.png
  32. BIN
      doc/_static/images/kite.png
  33. BIN
      doc/_static/images/logo-latex.pdf
  34. 167 0
      doc/_static/images/logo-readme.svg
  35. 174 0
      doc/_static/images/logo.svg
  36. 1 0
      doc/_static/js/dark-mode-toggle.min.mjs
  37. 10 0
      doc/_static/js/ga-tracker.js
  38. 48 0
      doc/_static/js/scorer.js
  39. 15 0
      doc/_static/latex/preamble.tex
  40. 44 0
      doc/_static/latex/title.tex
  41. 35 0
      doc/make.bat
  42. 14 0
      doc/requirements.txt
  43. 10 0
      doc/source/build/index.rst
  44. 35 0
      doc/source/build/kconfig/index.rst
  45. 108 0
      doc/source/build/make/index.rst
  46. 450 0
      doc/source/chipset/index.rst
  47. 76 0
      doc/source/conf.py
  48. 219 0
      doc/source/develop/application/index.rst
  49. 276 0
      doc/source/develop/getting_started/index.rst
  50. 11 0
      doc/source/develop/index.rst
  51. 39 0
      doc/source/develop/optimizations/footprint.rst
  52. 10 0
      doc/source/develop/optimizations/index.rst
  53. 32 0
      doc/source/develop/optimizations/tools.rst
  54. 26 0
      doc/source/index.rst
  55. 21 0
      doc/source/introduction/index.rst
  56. 127 0
      doc/source/porting/exist_porting/index.rst
  57. 273 0
      doc/source/porting/getting_started/index.rst
  58. 10 0
      doc/source/porting/index.rst
  59. 71 0
      example/beacon/app_main.c
  60. 31 0
      example/beacon/autoconfig.h
  61. 8 0
      example/beacon/build.mk
  62. 3 0
      example/beacon/prj.conf
  63. 84 0
      example/broadcaster/app_main.c
  64. 30 0
      example/broadcaster/autoconfig.h
  65. 8 0
      example/broadcaster/build.mk
  66. 2 0
      example/broadcaster/prj.conf
  67. 145 0
      example/central/app_main.c
  68. 50 0
      example/central/autoconfig.h
  69. 8 0
      example/central/build.mk
  70. 2 0
      example/central/prj.conf
  71. 9 0
      example/central_gatt_write/app_main.c
  72. 60 0
      example/central_gatt_write/autoconfig.h
  73. 8 0
      example/central_gatt_write/build.mk
  74. 118 0
      example/central_gatt_write/central_gatt_write.c
  75. 210 0
      example/central_gatt_write/gatt_write_common.c
  76. 13 0
      example/central_gatt_write/prj.conf
  77. 277 0
      example/central_hr/app_main.c
  78. 60 0
      example/central_hr/autoconfig.h
  79. 8 0
      example/central_hr/build.mk
  80. 5 0
      example/central_hr/prj.conf
  81. 313 0
      example/central_ht/app_main.c
  82. 60 0
      example/central_ht/autoconfig.h
  83. 8 0
      example/central_ht/build.mk
  84. 5 0
      example/central_ht/prj.conf
  85. 694 0
      example/eddystone/app_main.c
  86. 56 0
      example/eddystone/autoconfig.h
  87. 8 0
      example/eddystone/build.mk
  88. 4 0
      example/eddystone/prj.conf
  89. 17 0
      example/empty/app_main.c
  90. 31 0
      example/empty/autoconfig.h
  91. 8 0
      example/empty/build.mk
  92. 2 0
      example/empty/prj.conf
  93. 67 0
      example/ibeacon/app_main.c
  94. 31 0
      example/ibeacon/autoconfig.h
  95. 8 0
      example/ibeacon/build.mk
  96. 2 0
      example/ibeacon/prj.conf
  97. 62 0
      example/observer/app_main.c
  98. 31 0
      example/observer/autoconfig.h
  99. 8 0
      example/observer/build.mk
  100. 2 0
      example/observer/prj.conf

+ 101 - 0
.clang-format

@@ -0,0 +1,101 @@
+# SPDX-License-Identifier: Apache-2.0
+#
+# Note: The list of ForEachMacros can be obtained using:
+#
+#    git grep -h '^#define [^[:space:]]*FOR_EACH[^[:space:]]*(' include/ \
+#    | sed "s,^#define \([^[:space:]]*FOR_EACH[^[:space:]]*\)(.*$,  - '\1'," \
+#    | sort | uniq
+#
+# References:
+#   - https://clang.llvm.org/docs/ClangFormatStyleOptions.html
+
+---
+BasedOnStyle: LLVM
+AlignConsecutiveMacros: AcrossComments
+AllowShortBlocksOnASingleLine: false
+AllowShortCaseLabelsOnASingleLine: false
+AllowShortEnumsOnASingleLine: false
+AllowShortFunctionsOnASingleLine: None
+AllowShortIfStatementsOnASingleLine: false
+AllowShortLoopsOnASingleLine: false
+AttributeMacros:
+  - __aligned
+  - __deprecated
+  - __packed
+  - __printf_like
+  - __syscall
+  - __subsystem
+ColumnLimit: 100
+ConstructorInitializerIndentWidth: 8
+ContinuationIndentWidth: 8
+ForEachMacros:
+  - 'FOR_EACH'
+  - 'FOR_EACH_FIXED_ARG'
+  - 'FOR_EACH_IDX'
+  - 'FOR_EACH_IDX_FIXED_ARG'
+  - 'FOR_EACH_NONEMPTY_TERM'
+  - 'RB_FOR_EACH'
+  - 'RB_FOR_EACH_CONTAINER'
+  - 'SYS_DLIST_FOR_EACH_CONTAINER'
+  - 'SYS_DLIST_FOR_EACH_CONTAINER_SAFE'
+  - 'SYS_DLIST_FOR_EACH_NODE'
+  - 'SYS_DLIST_FOR_EACH_NODE_SAFE'
+  - 'SYS_SFLIST_FOR_EACH_CONTAINER'
+  - 'SYS_SFLIST_FOR_EACH_CONTAINER_SAFE'
+  - 'SYS_SFLIST_FOR_EACH_NODE'
+  - 'SYS_SFLIST_FOR_EACH_NODE_SAFE'
+  - 'SYS_SLIST_FOR_EACH_CONTAINER'
+  - 'SYS_SLIST_FOR_EACH_CONTAINER_SAFE'
+  - 'SYS_SLIST_FOR_EACH_NODE'
+  - 'SYS_SLIST_FOR_EACH_NODE_SAFE'
+  - '_WAIT_Q_FOR_EACH'
+  - 'Z_FOR_EACH'
+  - 'Z_FOR_EACH_ENGINE'
+  - 'Z_FOR_EACH_EXEC'
+  - 'Z_FOR_EACH_FIXED_ARG'
+  - 'Z_FOR_EACH_FIXED_ARG_EXEC'
+  - 'Z_FOR_EACH_IDX'
+  - 'Z_FOR_EACH_IDX_EXEC'
+  - 'Z_FOR_EACH_IDX_FIXED_ARG'
+  - 'Z_FOR_EACH_IDX_FIXED_ARG_EXEC'
+  - 'Z_GENLIST_FOR_EACH_CONTAINER'
+  - 'Z_GENLIST_FOR_EACH_CONTAINER_SAFE'
+  - 'Z_GENLIST_FOR_EACH_NODE'
+  - 'Z_GENLIST_FOR_EACH_NODE_SAFE'
+SortIncludes: Never
+IncludeBlocks: Regroup
+IncludeCategories:
+  - Regex: '^<(assert|complex|ctype|errno|fenv|float|inttypes|limits|locale|math|setjmp|signal|stdarg|stdbool|stddef|stdint|stdio|stdlib|string|tgmath|time|wchar|wctype)\.h>$'
+    Priority: 0
+  - Regex: '.*'
+    Priority: 1
+IndentCaseLabels: false
+IndentWidth: 4
+# SpaceBeforeParens: ControlStatementsExceptControlMacros # clang-format >= 13.0
+UseTab: Never
+WhitespaceSensitiveMacros:
+  - STRINGIFY
+  - Z_STRINGIFY
+
+AlignAfterOpenBracket: Align
+BraceWrapping:
+  AfterClass:      true
+  AfterControlStatement: true
+  AfterEnum:       true
+  AfterFunction:   true
+  AfterNamespace:  true
+  AfterObjCDeclaration: true
+  AfterStruct:     true
+  AfterUnion:      true
+  AfterCaseLabel:  true
+  AfterExternBlock: false # Fix "extern "C""
+  BeforeCatch:     true
+  BeforeElse:      true
+  BeforeWhile:     false
+  IndentBraces:    false
+  SplitEmptyFunction: true
+  SplitEmptyRecord: true
+  SplitEmptyNamespace: true
+BreakBeforeBraces: Custom # Fix "extern "C""
+IndentExternBlock: AfterExternBlock # Not useful for "extern "C""
+

+ 7 - 0
.gitignore

@@ -0,0 +1,7 @@
+*.dblite
+output
+*.o
+*.exe
+si
+.vscode
+/doc/build

+ 202 - 0
LICENSE

@@ -0,0 +1,202 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "{}"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright {yyyy} {name of copyright owner}
+
+   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.
+

+ 317 - 0
Makefile

@@ -0,0 +1,317 @@
+#
+# 'make'        build executable file 'main'
+# 'make clean'  removes all .o and executable files
+#
+.DEFAULT_GOAL := all
+
+# CROSS_COMPILE 	?= arm-linux-gnueabihf-
+CROSS_COMPILE 	?= 
+TARGET		  	?= main
+
+# define the C compiler to use
+CC 				:= $(CROSS_COMPILE)gcc
+LD				:= $(CROSS_COMPILE)ld
+OBJCOPY 		:= $(CROSS_COMPILE)objcopy
+OBJDUMP 		:= $(CROSS_COMPILE)objdump
+SIZE			:= $(CROSS_COMPILE)size
+
+# define any compile-time flags
+CFLAGS  := -O0
+CFLAGS  += -g
+
+# warning param setting
+CFLAGS	+= -Wall
+# think use -Os.
+CFLAGS	+= -Wno-unused-function
+CFLAGS	+= -Wno-unused-variable
+
+CFLAGS	+= -Wstrict-prototypes
+CFLAGS	+= -Wshadow
+# CFLAGS	+= -Werror
+
+# spec c version
+CFLAGS  += -std=c99
+
+# for makefile depend tree create
+CFLAGS  += -MMD -MP
+
+# for weak.
+CFLAGS  += -fno-common
+
+## MAKEFILE COMPILE MESSAGE CONTROL ##
+ifeq ($(V),1)
+	Q=
+else
+	Q=@
+endif
+
+# Put functions and data in their own binary sections so that ld can
+# garbage collect them
+ifeq ($(NOGC),1)
+GC_CFLAGS =
+GC_LDFLAGS =
+else
+GC_CFLAGS = -ffunction-sections -fdata-sections
+GC_LDFLAGS = -Wl,--gc-sections -Wl,--check-sections
+endif
+
+
+CFLAGS	+= $(GC_CFLAGS)
+
+# define ld params
+LDFLAGS	:=
+LDFLAGS	+= $(GC_LDFLAGS)
+
+
+# define library paths in addition to /usr/lib
+#   if I wanted to include libraries not in /usr/lib I'd specify
+#   their path using -Lpath, something like:
+LFLAGS :=
+
+# define output directory
+OUTPUT_PATH	:= output
+
+# define source directory
+SRC		:= 
+
+# define include directory
+INCLUDE	:=
+INCLUDE	+= output
+
+# define lib directory
+LIB		:= 
+
+
+# Kconfig Setting.
+# define user .config setting
+USER_CONFIG_SET := 
+
+# define menuconfig .config path
+DOTCONFIG_PATH := $(OUTPUT_PATH)/.config
+
+# define user merged path
+USER_RECORD_CONFIG_PATH := $(OUTPUT_PATH)/user_record.conf
+
+# define autoconfig.h path
+AUTOCONFIG_H := $(OUTPUT_PATH)/autoconfig.h
+
+#define Kconfig path
+KCONFIG_ROOT_PATH := src/Kconfig
+
+
+
+#set report setting. becareful, this only support elf. not work on windows.
+DEBUG_REPORT :=
+
+# load .conf setting.
+#include $(DOTCONFIG_PATH)
+
+# include bluetooth stack info
+BLUETOOTH := src
+include $(BLUETOOTH)/build.mk
+
+# include app info
+APP ?= beacon
+
+APP_ROOT_PATH = example
+APP_PATH = $(APP_ROOT_PATH)/$(APP)
+include $(APP_PATH)/build.mk
+USER_CONFIG_SET += $(APP_PATH)/prj.conf
+
+# include port info
+PORT ?= windows_libusb_win32
+
+PORT_ROOT_PATH = porting
+PORT_PATH = $(PORT_ROOT_PATH)/$(PORT)
+include $(PORT_PATH)/build.mk
+# USER_CONFIG_SET += $(PORT_PATH)/prj.conf
+
+# include chipset info
+CHIPSET ?= csr8510
+
+CHIPSET_ROOT_PATH = chipset
+INCLUDE	+= $(CHIPSET_ROOT_PATH)
+CHIPSET_PATH = $(CHIPSET_ROOT_PATH)/$(CHIPSET)
+include $(CHIPSET_PATH)/build.mk
+
+
+
+
+
+
+
+
+
+ifeq ($(OS),Windows_NT)
+ifdef ComSpec
+	WINCMD:=$(ComSpec)
+endif
+ifdef COMSPEC
+	WINCMD:=$(COMSPEC)
+endif
+
+SHELL:=$(WINCMD)
+
+MAIN	:= $(TARGET).exe
+ECHO=echo
+SOURCEDIRS	:= $(SRC)
+INCLUDEDIRS	:= $(INCLUDE)
+LIBDIRS		:= $(LIB)
+FIXPATH = $(subst /,\,$1)
+RM			:= del /q /s
+MD			:= mkdir
+else
+MAIN	:= $(TARGET)
+ECHO=echo
+SOURCEDIRS	:= $(shell find $(SRC) -type d)
+INCLUDEDIRS	:= $(shell find $(INCLUDE) -type d)
+LIBDIRS		:= $(shell find $(LIB) -type d)
+FIXPATH = $1
+RM = rm -rf
+MD	:= mkdir -p
+endif
+
+# define any directories containing header files other than /usr/include
+INCLUDES	:= $(patsubst %,-I%, $(INCLUDEDIRS:%/=%))
+@echo INCLUDES: $(INCLUDES)
+
+# define the C libs
+LIBS		:= $(patsubst %,-L%, $(LIBDIRS:%/=%))
+
+# define the C source files
+SOURCES		:= $(wildcard $(patsubst %,%/*.c, $(SOURCEDIRS)))
+
+# define the C object files 
+OBJDIR = $(OUTPUT_PATH)/obj
+OBJECTS			:= $(patsubst %, $(OBJDIR)/%, $(SOURCES:.c=.o))
+OBJ_MD			:= $(addprefix $(OBJDIR)/, $(SOURCEDIRS))
+
+
+
+
+
+ALL_DEPS := $(OBJECTS:.o=.d)
+
+# include dependency files of application
+ifneq ($(MAKECMDGOALS),clean)
+-include $(ALL_DEPS)
+endif
+
+#
+# The following part of the makefile is generic; it can be used to 
+# build any executable just by changing the definitions above and by
+# deleting dependencies appended to the file from 'make depend'
+#
+
+OUTPUT_MAIN		:= $(OUTPUT_PATH)/$(MAIN)
+OUTPUT_TARGET	:= $(OUTPUT_PATH)/$(TARGET)
+
+# Fix path error.
+#OUTPUT_MAIN := $(call FIXPATH,$(OUTPUT_MAIN))
+
+.PHONY: clean help info
+
+info:
+	@$(ECHO) Current Configuration: APP=$(APP) PORT=$(PORT) CHIPSET=$(CHIPSET)
+
+all: | info $(MAIN) $(DEBUG_REPORT)
+	@$(ECHO) Start Build Image.
+	$(OBJCOPY) -v -O binary $(OUTPUT_MAIN) $(OUTPUT_TARGET).bin
+	$(OBJDUMP) --source --all-headers --demangle --line-numbers --wide $(OUTPUT_MAIN) > $(OUTPUT_TARGET).lst
+	@$(ECHO) Print Size
+	$(Q)@$(SIZE) --format=berkeley $(OUTPUT_MAIN)
+#	@$(ECHO) Executing 'all' complete!
+
+# mk path for object.
+$(OBJ_MD):
+	$(Q)if not exist "$@" $(Q)$(MD) $(call FIXPATH, $@)
+
+# mk output path.
+$(OUTPUT_PATH):
+	$(Q)if not exist "$@" $(Q)$(MD) $(call FIXPATH, $@)
+
+$(OBJDIR):
+	$(Q)if not exist "$@" $(Q)$(MD) $(call FIXPATH, $@)
+
+$(MAIN): | $(OUTPUT_PATH) $(OBJDIR) $(OBJ_MD) $(OBJECTS) 
+	@$(ECHO) Linking    : "$@"
+	$(Q)$(CC) $(CFLAGS) $(LDFLAGS) $(INCLUDES) -Wl,-Map,$(OUTPUT_TARGET).map -o $(OUTPUT_MAIN) $(OBJECTS) $(LFLAGS) $(LIBS)
+
+# Static Pattern Rules [targets ...: target-pattern: prereq-patterns ...]
+$(OBJECTS): $(OBJDIR)/%.o : %.c $(AUTOCONFIG_H)
+	@$(ECHO) Compiling  : "$<"
+	$(Q)$(CC) $(CFLAGS) $(INCLUDES) -c $<  -o $@
+
+
+$(AUTOCONFIG_H): $(DOTCONFIG_PATH)
+	python scripts/kconfig/kconfig.py $(KCONFIG_ROOT_PATH) $(DOTCONFIG_PATH) $(AUTOCONFIG_H) $(OUTPUT_PATH)/autoconfig_log.txt $(DOTCONFIG_PATH)
+
+$(USER_RECORD_CONFIG_PATH): $(USER_CONFIG_SET)
+	@echo Using user config.
+#	create user_record.conf to record current setting.
+	@copy $(call FIXPATH, $(USER_CONFIG_SET)) $(call FIXPATH, $(USER_RECORD_CONFIG_PATH))
+#	create .config by user config setting.
+	python scripts/kconfig/kconfig.py --handwritten-input-configs $(KCONFIG_ROOT_PATH) $(DOTCONFIG_PATH) $(AUTOCONFIG_H) $(OUTPUT_PATH)/autoconfig_log.txt $(USER_CONFIG_SET)
+
+export KCONFIG_CONFIG=$(DOTCONFIG_PATH)
+$(DOTCONFIG_PATH):$(USER_RECORD_CONFIG_PATH)
+	@echo .config updated
+
+menuconfig:$(DOTCONFIG_PATH)
+#	set KCONFIG_CONFIG=$(DOTCONFIG_PATH)
+	menuconfig $(KCONFIG_ROOT_PATH)
+
+guiconfig:
+	guiconfig $(KCONFIG_ROOT_PATH)
+
+clean:
+#	$(RM) $(OUTPUT_MAIN)
+#	$(RM) $(OBJECTS)
+#	$(RM) $(OBJDIR)
+	$(Q)$(RM) $(call FIXPATH, $(OUTPUT_PATH))
+	@$(ECHO) Cleanup complete!
+
+run: all
+	./$(OUTPUT_MAIN)
+	@$(ECHO) Executing 'run: all' complete!
+
+ram_report:
+	python scripts/footprint/size_report -k $(OUTPUT_MAIN) -z $(OUTPUT_PATH) -o $(OUTPUT_PATH) --workspace=$(OUTPUT_PATH) -d 99 ram
+
+rom_report:
+	python scripts/footprint/size_report -k $(OUTPUT_MAIN) -z $(OUTPUT_PATH) -o $(OUTPUT_PATH) --workspace=$(OUTPUT_PATH) -d 99 rom
+
+all_report:
+	python scripts/footprint/size_report -k output/main.elf -z $(OUTPUT_PATH) -o $(OUTPUT_PATH) --workspace=$(OUTPUT_PATH) -d 99 all
+
+code_format:
+	python code_format.py
+
+
+help:
+	@$(ECHO) "zephyr_polling Software Development Kit"
+	@$(ECHO) "== For detailed user guide, please check xxxx"
+	@$(ECHO) "== Make variables used in SDK =="
+	@$(ECHO) "APP:         Select APP Demo built in SDK, will select <beacon> by default"
+	@$(ECHO) "PORT:        Select Porting info built in SDK, will select <windows_libusb_win32> by default"
+	@$(ECHO) "CHIPSET:     Select Chipset built in SDK, will select <csr8510> by default"
+	@$(ECHO) "NOGC:        NOGC=1 diable gc sections, default is 0"
+	@$(ECHO) "V:           V=1 verbose make, will print more information, by default V=0"
+	@$(ECHO) "== How to Use with Make =="
+	@$(ECHO) "1. Build Application:"
+	@$(ECHO) "all [APP=beacon] [PORT=windows_libusb_win32] [CHIPSET=csr8510]"
+	@$(ECHO) "   Build a software program."
+	@$(ECHO) "2. Show menuconfig:"
+	@$(ECHO) "menuconfig [APP=beacon] [PORT=windows_libusb_win32] [CHIPSET=csr8510]"
+	@$(ECHO) "   Use menuconfig to show the Kconfig setting."
+	@$(ECHO) "3. Show guiconfig:"
+	@$(ECHO) "guiconfig [APP=beacon] [PORT=windows_libusb_win32] [CHIPSET=csr8510]"
+	@$(ECHO) "   Use guiconfig to show the Kconfig setting."
+	@$(ECHO) "4: Format all code style by .clang-format"
+	@$(ECHO) "code_format"
+	@$(ECHO) "   It is recommended to modify the code format before submitting."
+	@$(ECHO) ""
+	@$(ECHO) "== Example Usage =="
+	@$(ECHO) "1. Build for default application: make all"
+	@$(ECHO) "2. Run app(Windows), output\main.exe"
+	@$(ECHO) ""

+ 228 - 0
README.md

@@ -0,0 +1,228 @@
+# 简介
+
+[![Compile Check](https://github.com/bobwenstudy/zephyr_polling/actions/workflows/github-actions-demo.yml/badge.svg)](https://github.com/bobwenstudy/zephyr_polling/actions/workflows/github-actions-demo.yml) [![Documentation Status](https://readthedocs.org/projects/zephyr-polling/badge/?version=latest)](https://zephyr-polling.readthedocs.io/en/latest/?badge=latest)
+
+本项目是基于[Zephyr Project](https://www.zephyrproject.org/)进行二次开发的,去除了OS调度部分,只保留了Bluetooth的Host协议栈。项目地址:[bobwenstudy/zephyr_polling (github.com)](https://github.com/bobwenstudy/zephyr_polling)。文档地址:[Welcome to Zephyr_polling’s documentation!](https://zephyr-polling.readthedocs.io/en/latest/)。
+
+一般蓝牙协议栈分为Host和Controller两个部分,根据是否包含BR/EDR还是LE,分为如下形式。
+
+![image-20221124185342589](https://markdown-1306347444.cos.ap-shanghai.myqcloud.com/img/image-20221124185342589.png)
+
+作为一个蓝牙芯片协议栈开发者,既做过Controller也做过Host,同时在多家公司任职过,接触过包括rwip\ceva\bluedroid\bluez\btstack\nimble\softdevice以及各种自定义协议栈(擅长的不多,哈哈),总体就是各个协议栈都有各自的写法,不管是代码风格还是环境都各不相同。
+
+**Controller侧**,虽然Controller要实现RF操作,和硬件行为强相关,不可避免代码差异大。但是Spec有明确规定HCI接口,大家都有一个标准可以遵循,API相对统一,从A切换B其实只要有HCI接口就能方便的使用。
+
+如下图所示,Host和Controller之间通过HCI连接,对于BLE而言只有C/E、ACL、ISO这4个通道。
+
+![image-20221124185611408](https://markdown-1306347444.cos.ap-shanghai.myqcloud.com/img/image-20221124185611408.png)
+
+**Host侧**,Spec只是规定了行为并没有规定接口,那就是天马行空,各家方案的API差异很大,学习成本较高,并且迁移成本也高,而且文档基本上都是靠代码、例程来学习,有些API还不是很友好。
+
+现行的开源Host协议栈还是比较多的,下面做一个简单的介绍:
+
+| 名称                                                         | 开源协议 | 双模支持             | 持续维护 | OS/轮询 | 备注                                                         |
+| ------------------------------------------------------------ | -------- | -------------------- | -------- | ------- | ------------------------------------------------------------ |
+| [bluedroid](https://android.googlesource.com/platform/external/bluetooth/bluedroid/+/refs/heads/master) | 开源免费 | 是                   | 是       | OS      | Android所使用的蓝牙协议栈,功能比较全,但是Profile层是在Java实现的,所以有个JNI层,相应的行为就复杂了一些。 |
+| [BlueZ](http://www.bluez.org/)                               | 开源免费 | 是                   | 是       | OS      | Linux系统所使用的蓝牙协议栈,没深入理解,但是bluedroid的是从blueZ演变过来的,记得Android4.0之前用的还是blueZ,后面改成了bluedroid。 |
+| [Zephyr](https://www.zephyrproject.org/)                     | 开源免费 | 是(经典蓝牙实现较少) | 是       | OS      | 本文所基于的协议栈,蓝牙之前其中的一个部分,包含Controller的实现,API很不错,目前很火的开源协议栈,没事大家可以上去学点东西,后面详细来讲。 |
+| [btstack](https://github.com/bluekitchen/btstack)            | 商业收费 | 是                   | 是       | 轮询    | 整体就是为了满足低成本方案设计来做的,没有OS需求,协议栈的调度就是轮询架构,可以轻易的porting到任何平台中,功能也全,本项目的架构也是参考这一项目来实现的。里面有很多芯片的Porting实现。 |
+| [nimble](https://github.com/apache/mynewt-nimble)            | 开源免费 | BLE                  | 是       | OS      | 没深入了解,不过很久没维护了,最近突然又开始维护了,好像是乐鑫开始用他们的方案。 |
+
+从上述可以看出,除了btstack在设计之处就是为了方便Porting存在的,其他方案都是捆绑了自己的OS。
+
+这块其实做的比较好的还是btstack,不过其商业是收费的,文档这块其实也不太多,同时其是极简实现的方案,所以使用体验上并不是很舒服,数据缓存之类都需要在应用层做。
+
+
+
+# 改动说明
+
+作为一个芯片开发人员,国内大多数芯片方案还是资源受限的平台,不管对于Code Size,RAM Size都非常敏感;同时对于低功耗设计,Retention RAM的大小也至关重要。上述协议栈在各自的领域都做的不错,但是对于国内市场需要开源免费、API友好、Code/RAM/Retention Size精简的需要来讲,多少还是有一些缺陷的。
+
+基于这一现状,基于Zephyr的蓝牙子系统,保留其API和蓝牙协议实现,做出如下调整:
+
+- 调度方式,由原本基于Zephyr OS调度,调整为轮询调度方式,以便于后续移植到其他平台,并减少对CPU mips的占用。
+- buffer管理,移除关于多thread的操作,保留pool和net_buf设计。
+- 配置系统,保留kconfig配置架构,支持.h单独配置方式,简化配置复杂度。
+- 存储系统,由原本的setting架构调整为简易的kv结构。
+- 系统架构,调整为btstack架构。
+- hci操作,原本有很多同步操作,调整为异步操作。
+- Retention RAM分离,Zephyr本身需要的RAM还是比较大的,将pool等大块memory调整为非retention设计,以便低成本方案移植需要。
+- API,移除同步操作接口,其他接口全部保留。
+- 代码风格,依然基于.clang-format来格式化代码,但是zephyr蓝牙部分的代码风格和他OS说明好像并不相同,所以重新定义了一个我自己舒服的格式。
+- 编译系统,全部基于makefile来组织编译,方便大家移植。
+
+
+
+# 系统架构
+
+蓝牙协议栈为Zephyr的结构,系统总体架构参考Btstack的实现,总体结构如下图所示。
+
+![image-20221125111329111](https://markdown-1306347444.cos.ap-shanghai.myqcloud.com/img/image-20221125111329111.png)
+
+如上图所示,系统主要分为5个部分,代码结构如下所示:
+
+- **chipset**:各家厂商在使用之前需要进行一些配置,有些是因为芯片是rom化版本,需要加载patch,有些要配置RF参数,有些要配置蓝牙地址等。
+- **example**:各种蓝牙例程,基本是照搬zephyr的来,当然会加入一些新的case。
+- **platform**:移植时重点关注的部分,蓝牙协议栈运行需要用到一些平台资源,不同平台有不同实现方式,主要包括log、timer、storage_kv和HCI接口的实现。
+- **porting**:程序的主入口,这些会将platform/chipset和协议栈接口进行绑定,并启动example,最后对协议栈进行调度。
+- **src**:zephyr的蓝牙协议栈部分,具体实现蓝牙协议栈的具体细节。
+
+```shell
+zephyr_polling
+ ├── chipset
+ │   ├── csr8510_usb
+ │   └── csr8910_uart
+ ├── example
+ │   ├── beacon
+ │   ├── broadcaster
+ │   ├── central
+ │   ├── observer
+ │   ├── peripheral
+ │   ...
+ ├── platform
+ │   └── windows
+ │   ...
+ ├── porting
+ │   ├── windows_libusb_win32
+ │   └── windows_serial
+ │   ...
+ └── src
+     ...
+```
+
+
+
+
+
+# 使用说明
+
+## 环境搭建
+
+目前暂时只支持Windows编译,最终生成exe,可以直接在PC上跑。
+
+目前需要安装如下环境:
+
+- [Python3](http://www.python.org/getit/),用于Kconfig,代码格式化,RAM&ROM分析等,编译工具类都用这个。
+- GCC环境,笔者用的msys64+mingw,用于编译生成exe,参考这个文章安装即可。[Win7下msys64安装mingw工具链 - Milton - 博客园 (cnblogs.com)](https://www.cnblogs.com/milton/p/11808091.html)。
+
+
+
+### Python环境准备
+
+python装好后,还需要安装一些环境,运行`python_require_env.py`脚本就会安装所有所需的python环境。
+
+```shell
+python python_require_env.py
+```
+
+
+
+
+
+## 编译说明
+
+本项目都是由makefile组织编译的,编译整个项目只需要执行`make all`即可,调用`make help`可以查看帮助。
+
+根据具体需要可以调整一些参数,目前Makefile支持如下参数配置。
+
+- **APP**:选择example中的例程,默认选择为`beacon`。
+- **PORT**:选择porting中的环境,也就是当前平台和HCI接口类型,默认选择为`windows_libusb_win32`。
+- **CHIPSET**:选择chipset中的芯片种类,默认选择为`csr8510_usb`。
+
+也就是可以通过如下指令来编译工程:
+
+```shell
+make all APP=beacon PORT=windows_libusb_win32 CHIPSET=csr8510_usb
+```
+
+
+
+
+
+## HCI Dongle部署
+
+在PC环境下,常见的设备有USB设备和UART设备,下面分别对这两个设备进行部署。
+
+### USB设备使用
+
+为了能操作这些USB蓝牙dongle,默认使用的驱动是蓝牙的驱动。所以需要更改设备所使用的驱动。
+
+- Step1:下载[Zadig](https://zadig.akeo.ie/)。
+- Step2:菜单栏点击Options -> List All Devices。
+
+![image-20221125133827682](https://markdown-1306347444.cos.ap-shanghai.myqcloud.com/img/image-20221125133827682.png)
+
+- Step3:通过下拉选中当前连接的蓝牙dongle,更换设备driver为`libusb-win32`,如下图所示,过一会就换好驱动了。
+
+![image-20221125133953130](https://markdown-1306347444.cos.ap-shanghai.myqcloud.com/img/image-20221125133953130.png)
+
+
+
+### UART设备使用
+
+这个直接看以下设备的串口号,在代码里面配置好后就可以正常使用了。(这块还没做,准备放在Makefile中操作)
+
+
+
+
+
+## 支持芯片列表
+
+makefile中配置**CHIPSET**,后续不断完善。
+
+
+| 厂商                                       | chipset                                                      | 接口 | 蓝牙版本 | 类型      |
+| ------------------------------------------ | ------------------------------------------------------------ | ---- | -------- | --------- |
+| [CSR](https://www.qualcomm.cn/)            | [csr8510](https://detail.tmall.com/item.htm?abbucket=2&id=534662513906&ns=1&spm=a230r.1.14.1.2f6811a37qFFQU&skuId=4910946697067) | USB  | 4.0      | Dual Mode |
+| [CSR](https://www.qualcomm.cn/)            | [csr8910](https://item.taobao.com/item.htm?spm=a1z09.2.0.0.6cd22e8dj2naR0&id=622836061708&_u=3m1kbkea372) | UART | 4.0      | Dual Mode |
+| [炬芯-Actions](http://www.actions.com.cn/) | [ats2851](https://detail.tmall.com/item.htm?abbucket=2&id=534662513906&ns=1&spm=a230r.1.14.1.2f6811a37qFFQU&skuId=5111551883875) | USB  | 5.3      | Dual Mode |
+| [Nordic](https://www.nordicsemi.com/)      | [pts_dongle](https://item.taobao.com/item.htm?spm=a1z09.2.0.0.6cd22e8dj2naR0&id=622836061708&_u=3m1kbkea372) | UART | 5.3      | LE Only   |
+
+
+
+
+
+# 蓝牙配置
+
+用的就是zephyr的Kconfig配置,使用办法就是输入如下指令:
+
+```shell
+make menuconfig
+```
+
+和zephyr一样,支持持久化配置和临时配置,各个example里面有一个`prj.conf`作为特定应用的永久化配置,当然使用过程中可以随时通过menuconfig调整配置,但是注意需要保存时,将差异保存在`prj.conf`中,不然下次clean后会失效。Kconfig的使用说明可以参考:[从零到一搭建Kconfig配置系统](https://blog.csdn.net/wenbo13579/article/details/127464764)。
+
+kconfig生成的`autoconfig.h`保存在output目录下。
+
+![image-20221125141858546](https://markdown-1306347444.cos.ap-shanghai.myqcloud.com/img/image-20221125141858546.png)
+
+**注意**:考虑到部分项目不想使用kconfig的配置方案,生成`autoconfig.h`的使用在`src\bt_config.h`中通过include导入,也就是说可以在其他环境下生成好`autoconfig.h`,而后将生成的`autoconfig.h`保存在`src`目录下即可。
+
+
+
+# 调试
+
+## 日志系统
+
+参考btstack,系统支持多种debug方式,生成的日志文件保存在output/log目录下:
+
+| 名称                 | 分析软件          | 备注                                                   |
+| -------------------- | ----------------- | ------------------------------------------------------ |
+| btsnoop(.cfa)        | frontline/eclipse | 分析蓝牙协议最好的一个协议存储格式                     |
+| packet_logger(.pklg) | wireshark         | 暂不支持,苹果推出的一个日志分析格式,支持log+协议分析 |
+| 日志(.log)           | 文本编辑器        | 将终端的日志保存成文件,方便离线分析                   |
+
+![image-20221125112900757](https://markdown-1306347444.cos.ap-shanghai.myqcloud.com/img/image-20221125112900757.png)
+
+## RAM_Report&ROM_Report
+
+参考zephyr,对生成的elf进行分析,最终会生成ram.json和rom.json。这两个文件也可以导入到nordic的vscode环境下,可以借助其图形化工具进行分析。
+
+**注意**:windows环境暂时不可用,只能对elf进行分析。
+
+![image-20221125112930355](https://markdown-1306347444.cos.ap-shanghai.myqcloud.com/img/image-20221125112930355.png)
+
+
+
+
+

+ 71 - 0
SConscript

@@ -0,0 +1,71 @@
+from building import *
+import rtconfig
+
+def get_path_files(dirs, file_ext):
+    path_files = []
+    # print('dir: ' + str(dirs))
+    for dir in dirs:
+        # print('dir: ' + dir)
+        path_files += Glob(dir + '/' + file_ext)
+    return path_files
+
+cwd = GetCurrentDir()
+path = []
+src = []
+
+C_DIRS = []
+
+app = GetConfigValue('PKG_ZEPHYR_POLLING_EXAMPLE').replace('"', '')
+chipset = GetConfigValue('PKG_ZEPHYR_POLLING_CHIPSET').replace('"', '')
+porting = GetConfigValue('PKG_ZEPHYR_POLLING_PORTING').replace('"', '')
+
+# print("app: %s" % app)
+# print("chipset: %s" % chipset)
+# print("porting: %s" % porting)
+
+# Include stack info
+stack_path = cwd + '/src'
+path.append(stack_path)
+
+C_DIRS.append(stack_path)
+C_DIRS.append(stack_path + '/base')
+C_DIRS.append(stack_path + '/bluetooth')
+C_DIRS.append(stack_path + '/common')
+C_DIRS.append(stack_path + '/drivers')
+C_DIRS.append(stack_path + '/host')
+C_DIRS.append(stack_path + '/logging')
+C_DIRS.append(stack_path + '/utils')
+C_DIRS.append(stack_path + '/services')
+
+tmp_path = cwd + '/example/' + app
+path.append(tmp_path)
+C_DIRS.append(tmp_path)
+
+tmp_path = cwd + '/chipset/'
+path.append(tmp_path)
+tmp_path = tmp_path + chipset
+path.append(tmp_path)
+C_DIRS.append(tmp_path)
+
+tmp_path = cwd + '/platform/'
+path.append(tmp_path)
+tmp_path = tmp_path + 'rtthread'
+path.append(tmp_path)
+C_DIRS.append(tmp_path)
+
+tmp_path = cwd + '/porting/'
+path.append(tmp_path)
+tmp_path = tmp_path + porting
+path.append(tmp_path)
+C_DIRS.append(tmp_path)
+
+src = get_path_files(C_DIRS, '*.c')
+
+# print("src: %s" % src)
+
+# if rtconfig.CROSS_TOOL == 'keil':
+#     LOCAL_CCFLAGS += ' --gnu --diag_suppress=111'
+    
+group = DefineGroup('zephyr_polling', src, depend = ['PKG_USING_ZEPHYR_POLLING'], CPPPATH = path)
+
+Return('group')

+ 8 - 0
chipset/artpi_ap6212/build.mk

@@ -0,0 +1,8 @@
+# define source directory
+SRC		+= $(CHIPSET_PATH)
+
+# define include directory
+INCLUDE	+= $(CHIPSET_PATH)
+
+# define lib directory
+LIB		+=

Разница между файлами не показана из-за своего большого размера
+ 13 - 0
chipset/artpi_ap6212/chipset_artpi_ap6212.c


+ 16 - 0
chipset/artpi_ap6212/chipset_artpi_ap6212.h

@@ -0,0 +1,16 @@
+
+#ifndef _CHIPSET_ARTPI_AP6212_H_
+#define _CHIPSET_ARTPI_AP6212_H_
+
+#include "chipset_interface.h"
+#include "platform_interface.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //_CHIPSET_ARTPI_AP6212_H_

+ 8 - 0
chipset/ats2851/build.mk

@@ -0,0 +1,8 @@
+# define source directory
+SRC		+= $(CHIPSET_PATH)
+
+# define include directory
+INCLUDE	+= $(CHIPSET_PATH)
+
+# define lib directory
+LIB		+=

+ 21 - 0
chipset/ats2851/chipset_ats2851.c

@@ -0,0 +1,21 @@
+#include <errno.h>
+
+#include "chipset_ats2851.h"
+
+// public API
+const struct bt_hci_chipset_driver *bt_hci_chipset_impl_local_instance(void)
+{
+    return NULL;
+}
+
+static const bt_usb_interface_t usb_interface = {0x10D7, 0xB012};
+
+const bt_usb_interface_t *bt_chipset_get_usb_interface(void)
+{
+    return &usb_interface;
+}
+
+const bt_uart_interface_t *bt_chipset_get_uart_interface(void)
+{
+    return NULL;
+}

+ 15 - 0
chipset/ats2851/chipset_ats2851.h

@@ -0,0 +1,15 @@
+
+#ifndef _CHIPSET_CSR8510_USB_H_
+#define _CHIPSET_CSR8510_USB_H_
+
+#include "chipset_interface.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //_CHIPSET_CSR8510_USB_H_

+ 35 - 0
chipset/chipset_interface.h

@@ -0,0 +1,35 @@
+
+#ifndef _CHIPSET_INTERFACE_H_
+#define _CHIPSET_INTERFACE_H_
+
+#include "drivers/hci_driver.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct
+{
+    uint16_t vid;
+    uint16_t pid;
+} bt_usb_interface_t;
+
+typedef struct
+{
+    int rate;
+    int databits;
+    int stopbits;
+    int parity;
+    bool flowcontrol;
+} bt_uart_interface_t;
+
+const bt_usb_interface_t *bt_chipset_get_usb_interface(void);
+const bt_uart_interface_t *bt_chipset_get_uart_interface(void);
+
+const struct bt_hci_chipset_driver *bt_hci_chipset_impl_local_instance(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //_CHIPSET_INTERFACE_H_

+ 8 - 0
chipset/common/build.mk

@@ -0,0 +1,8 @@
+# define source directory
+SRC		+= $(CHIPSET_PATH)
+
+# define include directory
+INCLUDE	+= $(CHIPSET_PATH)
+
+# define lib directory
+LIB		+=

+ 24 - 0
chipset/common/chipset_common.c

@@ -0,0 +1,24 @@
+#include <errno.h>
+
+#include "chipset_common.h"
+
+// public API
+const struct bt_hci_chipset_driver *bt_hci_chipset_impl_local_instance(void)
+{
+    return NULL;
+}
+
+// For test, you can set your customor setting here.
+static const bt_usb_interface_t usb_interface = {0, 0};
+
+const bt_usb_interface_t *bt_chipset_get_usb_interface(void)
+{
+    return &usb_interface;
+}
+
+// For test, you can set your customor setting here.
+static const bt_uart_interface_t uart_interface = {1000000, 8, 1, 0, true};
+const bt_uart_interface_t *bt_chipset_get_uart_interface(void)
+{
+    return &uart_interface;
+}

+ 15 - 0
chipset/common/chipset_common.h

@@ -0,0 +1,15 @@
+
+#ifndef _CHIPSET_CSR8510_USB_H_
+#define _CHIPSET_CSR8510_USB_H_
+
+#include "chipset_interface.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //_CHIPSET_CSR8510_USB_H_

+ 8 - 0
chipset/csr8510/build.mk

@@ -0,0 +1,8 @@
+# define source directory
+SRC		+= $(CHIPSET_PATH)
+
+# define include directory
+INCLUDE	+= $(CHIPSET_PATH)
+
+# define lib directory
+LIB		+=

+ 147 - 0
chipset/csr8510/chipset_csr8510.c

@@ -0,0 +1,147 @@
+#include <errno.h>
+
+#include "chipset_csr8510.h"
+
+#define STATE_POLLING_NONE      0
+#define STATE_POLLING_BOOTING   1
+#define STATE_POLLING_PREPARING 2
+
+int state;
+int step;
+
+static int csr_send_cmd_vs_hci_nop_disable(void)
+{
+    uint8_t data[] = {0xc2, 0x02, 0x00, 0x09, 0x00, 0x02, 0x00, 0x03, 0x70, 0x00,
+                      0x00, 0xf2, 0x00, 0x01, 0x00, 0x08, 0x00, 0x01, 0x00};
+    struct net_buf *buf;
+
+    buf = bt_hci_cmd_create(0xfc00, sizeof(data));
+    if (!buf)
+    {
+        return -ENOBUFS;
+    }
+    net_buf_add_mem(buf, data, sizeof(data));
+
+    return bt_hci_cmd_send(0xfc00, buf);
+}
+
+#define BLE_MAC_ADDR                                                                               \
+    {                                                                                              \
+        {                                                                                          \
+            0x11, 0x22, 0x33, 0x44, 0x55, 0x66                                                     \
+        }                                                                                          \
+    }
+static int csr_send_cmd_vs_set_public_addr(void)
+{
+    uint8_t data[] = {0xc2, 0x02, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x03, 0x70, 0x00, 0x00, 0x01, 0x00,
+                      0x04, 0x00, 0x08, 0x00, 0xf3, 0x00, 0xf5, 0xf4, 0xf0, 0x00, 0xf2, 0xf1};
+    struct net_buf *buf;
+    bt_addr_t addr = BLE_MAC_ADDR;
+
+    // addr.val[0] = (BLE_MAC_ADDR)&0xff;
+    // addr.val[1] = (BLE_MAC_ADDR >> 8) & 0xff;
+    // addr.val[2] = (BLE_MAC_ADDR >> 16) & 0xff;
+    // addr.val[3] = (BLE_MAC_ADDR >> 24) & 0xff;
+    // addr.val[4] = (BLE_MAC_ADDR >> 32) & 0xff;
+    // addr.val[5] = (BLE_MAC_ADDR >> 40) & 0xff;
+
+    data[17] = addr.val[3];
+    data[19] = addr.val[5];
+    data[20] = addr.val[4];
+    data[21] = addr.val[2];
+    data[23] = addr.val[1];
+    data[24] = addr.val[0];
+
+    buf = bt_hci_cmd_create(0xfc00, sizeof(data));
+    if (!buf)
+    {
+        return -ENOBUFS;
+    }
+    net_buf_add_mem(buf, data, sizeof(data));
+
+    return bt_hci_cmd_send(0xfc00, buf);
+}
+
+static int csr_send_cmd_vs_warn_reset(void)
+{
+    uint8_t data[] = {0xc2, 0x02, 0x00, 0x09, 0x00, 0x09, 0x00, 0x02, 0x40, 0x00,
+                      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+    struct net_buf *buf;
+
+    buf = bt_hci_cmd_create(0xfc00, sizeof(data));
+    if (!buf)
+    {
+        return -ENOBUFS;
+    }
+    net_buf_add_mem(buf, data, sizeof(data));
+
+    return bt_hci_cmd_send(0xfc00, buf);
+}
+
+void boot_start(void)
+{
+    state = STATE_POLLING_BOOTING;
+    step = 1;
+    csr_send_cmd_vs_hci_nop_disable();
+}
+
+void prepare_start(void)
+{
+    state = STATE_POLLING_PREPARING;
+    // nothing todo, just update state
+    bt_hci_set_prepare_ready();
+}
+
+void init_work(void)
+{
+    state = STATE_POLLING_BOOTING;
+    step = 0;
+}
+
+void reset_callback(void)
+{
+    bt_hci_set_boot_ready();
+}
+
+void event_process(uint8_t event, struct net_buf *buf)
+{
+    if (event == BT_HCI_EVT_VENDOR)
+    {
+        switch (step)
+        {
+        case 1:
+            csr_send_cmd_vs_set_public_addr();
+            step = 2;
+            break;
+        case 2:
+            csr_send_cmd_vs_warn_reset();
+
+            extern void reset_usb_driver(bt_hci_driver_reset_callback_t callback);
+            reset_usb_driver(reset_callback);
+            step = 0;
+            break;
+        }
+    }
+}
+
+static const struct bt_hci_chipset_driver chipset_drv = {
+        init_work, boot_start, prepare_start, event_process,
+};
+
+// public API
+const struct bt_hci_chipset_driver *bt_hci_chipset_impl_local_instance(void)
+{
+    return &chipset_drv;
+}
+
+static const bt_usb_interface_t usb_interface = {0x0a12, 0x0001};
+
+const bt_usb_interface_t *bt_chipset_get_usb_interface(void)
+{
+    return &usb_interface;
+}
+
+const bt_uart_interface_t *bt_chipset_get_uart_interface(void)
+{
+    return NULL;
+}

+ 16 - 0
chipset/csr8510/chipset_csr8510.h

@@ -0,0 +1,16 @@
+
+#ifndef _CHIPSET_CSR8510_H_
+#define _CHIPSET_CSR8510_H_
+
+#include "chipset_interface.h"
+#include "platform_interface.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //_CHIPSET_CSR8510_H_

+ 8 - 0
chipset/csr8910/build.mk

@@ -0,0 +1,8 @@
+# define source directory
+SRC		+= $(CHIPSET_PATH)
+
+# define include directory
+INCLUDE	+= $(CHIPSET_PATH)
+
+# define lib directory
+LIB		+=

+ 284 - 0
chipset/csr8910/chipset_csr8910.c

@@ -0,0 +1,284 @@
+#include <errno.h>
+
+#include "chipset_csr8910.h"
+#include "common\timer.h"
+
+#define STATE_POLLING_NONE      0
+#define STATE_POLLING_BOOTING   1
+#define STATE_POLLING_PREPARING 2
+
+struct k_timer csr_sync_timer;
+struct k_timer csr_warn_reset_timer;
+
+int state;
+int step;
+
+static int csr_send_cmd_vs_set_ana_freq_to_26mhz(void)
+{
+    uint8_t data[] = {0xc2, 0x02, 0x00, 0x09, 0x00, 0x01, 0x00, 0x03, 0x70, 0x00,
+                      0x00, 0xfe, 0x01, 0x01, 0x00, 0x08, 0x00, 0x90, 0x65};
+    struct net_buf *buf;
+
+    buf = bt_hci_cmd_create(0xfc00, sizeof(data));
+    if (!buf)
+    {
+        return -ENOBUFS;
+    }
+    net_buf_add_mem(buf, data, sizeof(data));
+
+    return bt_hci_cmd_send(0xfc00, buf);
+}
+
+static int csr_send_cmd_vs_set_ana_ftrim_0x24_for_csr8811(void)
+{
+    uint8_t data[] = {0xc2, 0x02, 0x00, 0x09, 0x00, 0x04, 0x00, 0x03, 0x70, 0x00,
+                      0x00, 0xf6, 0x01, 0x01, 0x00, 0x08, 0x00, 0x24, 0x00};
+    struct net_buf *buf;
+
+    buf = bt_hci_cmd_create(0xfc00, sizeof(data));
+    if (!buf)
+    {
+        return -ENOBUFS;
+    }
+    net_buf_add_mem(buf, data, sizeof(data));
+
+    return bt_hci_cmd_send(0xfc00, buf);
+}
+
+static int csr_send_cmd_vs_hci_nop_disable(void)
+{
+    uint8_t data[] = {0xc2, 0x02, 0x00, 0x09, 0x00, 0x02, 0x00, 0x03, 0x70, 0x00,
+                      0x00, 0xf2, 0x00, 0x01, 0x00, 0x08, 0x00, 0x01, 0x00};
+    struct net_buf *buf;
+
+    buf = bt_hci_cmd_create(0xfc00, sizeof(data));
+    if (!buf)
+    {
+        return -ENOBUFS;
+    }
+    net_buf_add_mem(buf, data, sizeof(data));
+
+    return bt_hci_cmd_send(0xfc00, buf);
+}
+
+static int csr_send_cmd_vs_enable_rts_cts_for_bcsp(void)
+{
+    uint8_t data[] = {0xc2, 0x02, 0x00, 0x09, 0x00, 0x01, 0x00, 0x03, 0x70, 0x00,
+                      0x00, 0xbf, 0x01, 0x01, 0x00, 0x08, 0x00, 0x0e, 0x08};
+    struct net_buf *buf;
+
+    buf = bt_hci_cmd_create(0xfc00, sizeof(data));
+    if (!buf)
+    {
+        return -ENOBUFS;
+    }
+    net_buf_add_mem(buf, data, sizeof(data));
+
+    return bt_hci_cmd_send(0xfc00, buf);
+}
+
+static int csr_send_cmd_vs_set_uart_baudrate_115200(void)
+{
+    uint8_t data[] = {0xc2, 0x02, 0x00, 0x0a, 0x00, 0x02, 0x00, 0x03, 0x70, 0x00, 0x00,
+                      0xea, 0x01, 0x02, 0x00, 0x08, 0x00, 0x01, 0x00, 0x00, 0xc2};
+    struct net_buf *buf;
+
+    buf = bt_hci_cmd_create(0xfc00, sizeof(data));
+    if (!buf)
+    {
+        return -ENOBUFS;
+    }
+    net_buf_add_mem(buf, data, sizeof(data));
+
+    return bt_hci_cmd_send(0xfc00, buf);
+}
+
+static int csr_send_cmd_vs_set_uart_baudrate_921600(void)
+{
+    uint8_t data[] = {0xc2, 0x02, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x03, 0x70, 0x00, 0x00,
+                      0xea, 0x01, 0x02, 0x00, 0x08, 0x00, 0x0e, 0x00, 0x00, 0x10};
+    struct net_buf *buf;
+
+    buf = bt_hci_cmd_create(0xfc00, sizeof(data));
+    if (!buf)
+    {
+        return -ENOBUFS;
+    }
+    net_buf_add_mem(buf, data, sizeof(data));
+
+    return bt_hci_cmd_send(0xfc00, buf);
+}
+
+#define BLE_MAC_ADDR                                                                               \
+    {                                                                                              \
+        {                                                                                          \
+            0x11, 0x22, 0x33, 0x44, 0x55, 0x66                                                     \
+        }                                                                                          \
+    }
+
+static int csr_send_cmd_vs_set_public_addr(void)
+{
+    uint8_t data[] = {0xc2, 0x02, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x03, 0x70, 0x00, 0x00, 0x01, 0x00,
+                      0x04, 0x00, 0x08, 0x00, 0xf3, 0x00, 0xf5, 0xf4, 0xf0, 0x00, 0xf2, 0xf1};
+    struct net_buf *buf;
+    bt_addr_t addr = BLE_MAC_ADDR;
+    size_t count = 1;
+
+    // addr.val[0] = (BLE_MAC_ADDR)&0xff;
+    // addr.val[1] = (BLE_MAC_ADDR >> 8) & 0xff;
+    // addr.val[2] = (BLE_MAC_ADDR >> 16) & 0xff;
+    // addr.val[3] = (BLE_MAC_ADDR >> 24) & 0xff;
+    // addr.val[4] = (BLE_MAC_ADDR >> 32) & 0xff;
+    // addr.val[5] = (BLE_MAC_ADDR >> 40) & 0xff;
+
+    data[17] = addr.val[3];
+    data[19] = addr.val[5];
+    data[20] = addr.val[4];
+    data[21] = addr.val[2];
+    data[23] = addr.val[1];
+    data[24] = addr.val[0];
+
+    buf = bt_hci_cmd_create(0xfc00, sizeof(data));
+    if (!buf)
+    {
+        return -ENOBUFS;
+    }
+    net_buf_add_mem(buf, data, sizeof(data));
+
+    return bt_hci_cmd_send(0xfc00, buf);
+}
+
+static int csr_send_cmd_vs_warn_reset(void)
+{
+    uint8_t data[] = {0xc2, 0x02, 0x00, 0x09, 0x00, 0x09, 0x00, 0x02, 0x40, 0x00,
+                      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+    struct net_buf *buf;
+
+    buf = bt_hci_cmd_create(0xfc00, sizeof(data));
+    if (!buf)
+    {
+        return -ENOBUFS;
+    }
+    net_buf_add_mem(buf, data, sizeof(data));
+
+    return bt_hci_cmd_send(0xfc00, buf);
+}
+
+static int csr_send_cmd_hci_reset_for_baudrate_sync(void)
+{
+    return bt_hci_cmd_send(BT_HCI_OP_RESET, NULL);
+}
+
+void boot_start(void)
+{
+    state = STATE_POLLING_BOOTING;
+
+    step = 1;
+    k_timer_start(&csr_sync_timer, K_MSEC(1000), Z_TIMEOUT_NO_WAIT);
+    csr_send_cmd_hci_reset_for_baudrate_sync();
+}
+
+void prepare_start(void)
+{
+    state = STATE_POLLING_PREPARING;
+    // nothing todo, just update state
+    bt_hci_set_prepare_ready();
+}
+
+void hci_uart_sync_timeout(struct k_timer *timer)
+{
+    printf("hci_uart_sync_timeout()\n");
+    k_timer_start(&csr_sync_timer, K_MSEC(1000), Z_TIMEOUT_NO_WAIT);
+    csr_send_cmd_hci_reset_for_baudrate_sync();
+}
+
+void csr_reset_callback(struct k_timer *timer)
+{
+    printf("csr_reset_callback()\n");
+    k_timer_stop(timer);
+
+    k_timer_start(&csr_sync_timer, K_MSEC(1000), Z_TIMEOUT_NO_WAIT);
+    csr_send_cmd_hci_reset_for_baudrate_sync();
+}
+
+void init_work(void)
+{
+    k_timer_init(&csr_sync_timer, hci_uart_sync_timeout, NULL);
+    k_timer_init(&csr_warn_reset_timer, csr_reset_callback, NULL);
+
+    state = STATE_POLLING_BOOTING;
+    step = 0;
+}
+
+void event_process(uint8_t event, struct net_buf *buf)
+{
+    if ((event == BT_HCI_EVT_VENDOR) ||
+        (event == BT_HCI_EVT_CMD_COMPLETE && (step == 1 || step == 20)))
+    {
+        switch (step)
+        {
+        case 1:
+            k_timer_stop(&csr_sync_timer);
+            csr_send_cmd_vs_set_ana_freq_to_26mhz();
+            step = 2;
+            break;
+        case 2:
+            csr_send_cmd_vs_set_ana_ftrim_0x24_for_csr8811();
+            step = 3;
+            break;
+        case 3:
+            csr_send_cmd_vs_hci_nop_disable();
+            step = 4;
+            break;
+        case 4:
+            csr_send_cmd_vs_enable_rts_cts_for_bcsp();
+            step = 5;
+            break;
+        case 5:
+            csr_send_cmd_vs_set_uart_baudrate_921600();
+            step = 6;
+            break;
+        case 6:
+            csr_send_cmd_vs_hci_nop_disable();
+            step = 7;
+            break;
+        case 7:
+            csr_send_cmd_vs_set_public_addr();
+            step = 8;
+            break;
+        case 8:
+            csr_send_cmd_vs_warn_reset();
+
+            k_timer_start(&csr_warn_reset_timer, K_MSEC(1000), Z_TIMEOUT_NO_WAIT);
+            step = 20;
+            break;
+
+        case 20:
+            bt_hci_set_boot_ready();
+            k_timer_stop(&csr_sync_timer);
+            step = 0;
+            break;
+        }
+    }
+}
+
+static const struct bt_hci_chipset_driver chipset_drv = {
+        init_work, boot_start, prepare_start, event_process,
+};
+
+// public API
+const struct bt_hci_chipset_driver *bt_hci_chipset_impl_local_instance(void)
+{
+    return &chipset_drv;
+}
+
+const bt_usb_interface_t *bt_chipset_get_usb_interface(void)
+{
+    return NULL;
+}
+
+static const bt_uart_interface_t uart_interface = {921600, 8, 1, 0, true};
+const bt_uart_interface_t *bt_chipset_get_uart_interface(void)
+{
+    return &uart_interface;
+}

+ 16 - 0
chipset/csr8910/chipset_csr8910.h

@@ -0,0 +1,16 @@
+
+#ifndef _CHIPSET_CSR8910_H_
+#define _CHIPSET_CSR8910_H_
+
+#include "chipset_interface.h"
+#include "platform_interface.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //_CHIPSET_CSR8910_H_

+ 8 - 0
chipset/pts_dongle/build.mk

@@ -0,0 +1,8 @@
+# define source directory
+SRC		+= $(CHIPSET_PATH)
+
+# define include directory
+INCLUDE	+= $(CHIPSET_PATH)
+
+# define lib directory
+LIB		+=

+ 21 - 0
chipset/pts_dongle/chipset_pts_dongle.c

@@ -0,0 +1,21 @@
+#include <errno.h>
+
+#include "chipset_pts_dongle.h"
+
+// public API
+const struct bt_hci_chipset_driver *bt_hci_chipset_impl_local_instance(void)
+{
+    return NULL;
+}
+
+const bt_usb_interface_t *bt_chipset_get_usb_interface(void)
+{
+    return NULL;
+}
+
+// For test, you can set your customor setting here.
+static const bt_uart_interface_t uart_interface = {1000000, 8, 1, 0, true};
+const bt_uart_interface_t *bt_chipset_get_uart_interface(void)
+{
+    return &uart_interface;
+}

+ 16 - 0
chipset/pts_dongle/chipset_pts_dongle.h

@@ -0,0 +1,16 @@
+
+#ifndef _CHIPSET_PTS_DONGLE_H_
+#define _CHIPSET_PTS_DONGLE_H_
+
+#include "chipset_interface.h"
+#include "platform_interface.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //_CHIPSET_PTS_DONGLE_H_

+ 27 - 0
code_format.py

@@ -0,0 +1,27 @@
+import os
+import subprocess
+import re
+import sys
+
+def format_all_file(root):
+    for root, dirs, files in os.walk(root):
+
+        # root 表示当前正在访问的文件夹路径
+        # dirs 表示该文件夹下的子目录名list
+        # files 表示该文件夹下的文件list
+
+        # 遍历文件
+        for f in files:
+            if f.endswith('.c') or f.endswith('.h'):
+                full_path = os.path.join(root, f)
+                #print("root: %s, path: %s" % (root, full_path))
+                print(full_path)
+                
+                command = 'clang-format -style=file -i %s' % full_path
+                #print(command)
+                proc = subprocess.run(command, shell=True, stdout=subprocess.PIPE)
+
+if __name__ == '__main__':
+    format_all_file('.')
+
+    #proc = subprocess.run(command, shell=True, stdout=subprocess.PIPE)

+ 20 - 0
doc/Makefile

@@ -0,0 +1,20 @@
+# Minimal makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line, and also
+# from the environment for the first two.
+SPHINXOPTS    ?=
+SPHINXBUILD   ?= sphinx-build
+SOURCEDIR     = source
+BUILDDIR      = build
+
+# Put it first so that "make" without argument is like "make help".
+help:
+	@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
+
+.PHONY: help Makefile
+
+# Catch-all target: route all unknown targets to Sphinx using the new
+# "make mode" option.  $(O) is meant as a shortcut for $(SPHINXOPTS).
+%: Makefile
+	@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

+ 958 - 0
doc/_static/css/custom.css

@@ -0,0 +1,958 @@
+/**
+ * Copyright (c) 2019-2020, Juan Linietsky, Ariel Manzur and the Godot community
+ * Copyright (c) 2021, Teslabs Engineering S.L.
+ * SPDX-License-Identifier: CC-BY-3.0
+ *
+ * Various tweaks to the Read the Docs theme to better conform with Zephyr's
+ * visual identity. Many colors are also overridden to use CSS variables.
+ */
+
+body,
+h1,
+h2,
+h3,
+h4,
+h5,
+h6,
+input[type="text"],
+input[type="button"],
+input[type="reset"],
+input[type="submit"],
+textarea,
+legend,
+.btn,
+.rst-content .toctree-wrapper p.caption,
+.rst-versions {
+    /* Use a system font stack for better performance (no Web fonts required) */
+    font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
+}
+
+h1,
+h2,
+h3,
+h4,
+h5,
+h6,
+legend,
+.rst-content .toctree-wrapper p.caption {
+    /* Use a lighter font for headers (Medium instead of Bold) */
+    font-weight: 500;
+}
+
+.rst-content div.figure p.caption {
+    /* Tweak caption styling to be closer to typical captions */
+    text-align: center;
+    margin-top: 8px;
+    opacity: 0.75;
+}
+
+.rst-content div.figure.figure-w480 {
+    max-width: 480px;
+}
+
+p,
+article ul,
+article ol,
+.wy-plain-list-disc,
+.wy-plain-list-decimal,
+.rst-content ol.arabic,
+.rst-content .section ul,
+.rst-content .toctree-wrapper ul,
+.rst-content .section ol {
+    /* Increase the line height slightly to account for the different font */
+    line-height: 25px;
+}
+
+body,
+.rst-content table.docutils thead {
+    color: var(--body-color);
+}
+
+a {
+    color: var(--link-color);
+}
+
+a:hover {
+    color: var(--link-color-hover);
+    text-decoration: underline;
+}
+
+a:active {
+    /* Add visual feedback when clicking on a link */
+    color: var(--link-color-active);
+}
+
+a:visited {
+    color: var(--link-color-visited);
+}
+
+a.btn:hover {
+    text-decoration: none;
+}
+
+.sphinx-tabs .sphinx-menu a.item {
+    /* Original definition has `!important` */
+    color: var(--link-color) !important;
+}
+
+.rst-content .toc-backref {
+    color: var(--link-color);
+}
+
+/* Style external links differently to make them easier to distinguish from internal links. */
+.reference.external {
+    background-position: center right;
+    background-repeat: no-repeat;
+    background-image: var(--external-reference-icon);
+    padding-right: 13px;
+}
+
+hr,
+#search-results .search li:first-child,
+#search-results .search li {
+    border-color: var(--hr-color);
+}
+
+/* JavaScript documentation directives */
+.rst-content dl:not(.docutils) dt {
+    background-color: var(--admonition-note-background-color) !important;
+    border-color: var(--admonition-note-title-background-color) !important;
+    color: var(--admonition-note-color) !important;
+}
+.rst-content dl:not(.docutils) dl dt {
+    background-color: var(--admonition-attention-background-color) !important;
+    border-color: var(--admonition-attention-title-background-color) !important;
+    color: var(--admonition-attention-color) !important;
+}
+
+.rst-content dt.sig .k {
+    color: var(--highlight-keyword2-color) !important;
+    font-style: normal !important;
+}
+
+.rst-content dt.sig .kt {
+    color: var(--highlight-keyword-color) !important;
+    font-style: normal !important;
+}
+
+.rst-content dt.sig .sig-name .n {
+    color: var(--highlight-function-color) !important;
+}
+
+.rst-content dt.sig .k,
+.rst-content dt.sig .kt,
+.rst-content dt.sig .n {
+    font-weight: normal !important;
+}
+
+.rst-content dl:not(.docutils) dt a.headerlink {
+    color: var(--link-color) !important;
+}
+.rst-content dl:not(.docutils) dt a.headerlink:visited {
+    color: var(--link-color-visited) !important;
+}
+
+footer,
+#search-results .context {
+    color: var(--footer-color);
+}
+
+/* Icon tweaks */
+a.icon-home,
+a.icon-home:visited {
+    color: var(--navbar-level-1-color);
+}
+
+/* Sphinx Search extension */
+/* .wy-body-for-nav is used for higher rule specificity */
+
+/* Search popup body */
+.wy-body-for-nav .search__outer {
+    background-color: var(--content-background-color);
+    border: 2px solid var(--content-background-color);
+}
+.wy-body-for-nav .search__cross svg {
+    fill: var(--body-color);
+}
+
+.wy-body-for-nav .search__outer::-webkit-scrollbar-track {
+    border-radius: 10px;
+    background-color: var(--content-background-color);
+}
+.wy-body-for-nav .search__outer::-webkit-scrollbar {
+    width: 7px;
+    height: 7px;
+    background-color: var(--content-background-color);
+}
+.wy-body-for-nav .search__outer::-webkit-scrollbar-thumb {
+    border-radius: 10px;
+    background-color: var(--hr-color);
+}
+
+/* Search input */
+.wy-body-for-nav .search__outer__input {
+    background-color: var(--search-input-background-color);
+    background-image: none;
+    border-radius: 50px;
+    border: 2px solid transparent;
+    color: var(--body-color);
+    height: 36px;
+    padding: 6px 12px;
+}
+.wy-body-for-nav .search__outer__input:focus {
+    border-color: var(--input-focus-border-color);
+}
+.wy-body-for-nav .search__outer .bar:after,
+.wy-body-for-nav .search__outer .bar:before {
+    display: none;
+}
+
+/* Search results item */
+.wy-body-for-nav .search__result__single {
+    border-bottom-color: var(--hr-color);
+}
+/* Search item title */
+.wy-body-for-nav .search__result__title {
+    color: var(--link-color);
+    border-bottom: none;
+    font-size: 120%;
+    font-weight: 400;
+}
+
+/* Search item section */
+.wy-body-for-nav .outer_div_page_results:hover,
+.wy-body-for-nav .search__result__box .active {
+    background-color: var(--search-active-color);
+}
+.wy-body-for-nav .search__result__subheading{
+    color: var(--body-color);
+    font-size: 100%;
+    font-weight: 400;
+}
+.wy-body-for-nav .search__result__content {
+    color: var(--footer-color);
+}
+
+/* Search item matching substring */
+.wy-body-for-nav .search__outer .search__result__title span,
+.wy-body-for-nav .search__outer .search__result__content span {
+    color: var(--search-match-color);
+    border-bottom: 1px solid var(--search-match-color);
+    background-color: var(--search-match-background-color);
+    padding: 0 2px;
+}
+.wy-body-for-nav .search__result__subheading span {
+    border-bottom-color: var(--body-color);
+}
+
+/* Search empty results */
+/* The original styles are inlined, see https://github.com/readthedocs/readthedocs-sphinx-search/issues/48 */
+.wy-body-for-nav .search__result__box {
+    color: var(--body-color) !important;
+}
+
+/* Search footer & credits */
+.wy-body-for-nav .rtd__search__credits {
+    background-color: var(--search-credits-background-color);
+    border-color: var(--search-credits-background-color);
+    color: var(--search-credits-color);
+    padding: 4px 8px;
+}
+.wy-body-for-nav .rtd__search__credits a {
+    color: var(--search-credits-link-color);
+}
+
+/* Main sections */
+
+.wy-nav-content-wrap {
+    background-color: var(--content-wrap-background-color);
+}
+
+.wy-nav-content {
+    background-color: var(--content-background-color);
+}
+
+.wy-body-for-nav {
+    background-color: var(--content-wrap-background-color);
+}
+
+@media only screen and (min-width: 769px) {
+    .wy-nav-content {
+        max-width: 915px;
+    }
+}
+
+/* Table display tweaks */
+
+.rst-content table.docutils,
+.wy-table-bordered-all td,
+.rst-content table.docutils td,
+.wy-table thead th,
+.rst-content table.docutils thead th,
+.rst-content table.field-list thead th {
+    border-color: var(--code-border-color);
+}
+
+.wy-table-odd td,
+.wy-table-striped tr:nth-child(2n-1) td,
+.rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td {
+    background-color: var(--table-row-odd-background-color);
+}
+
+/* Override table no-wrap */
+/* The first column cells are not verbose, no need to wrap them */
+.wy-table-responsive table td:not(:nth-child(1)),
+.wy-table-responsive table th:not(:nth-child(1)) {
+    white-space: normal;
+}
+
+/* Make sure not to wrap keyboard shortcuts */
+.wy-table-responsive table td kbd {
+    white-space: nowrap;
+}
+
+/* Force table content font-size in responsive tables to be 100%
+ * fixing larger font size for paragraphs in the kconfig tables */
+ .wy-table-responsive td p {
+    font-size: 100%;
+}
+
+/* Code display tweaks */
+
+code,
+.rst-content tt,
+.rst-content code {
+    font-size: 14px;
+    background-color: var(--code-background-color);
+    border: 1px solid var(--code-border-color);
+}
+
+.rst-content tt.literal,
+.rst-content code.literal {
+    color: var(--code-literal-color);
+}
+
+.rst-content div[class^="highlight"] {
+    border-color: none;
+    border: none;
+}
+
+.rst-content pre.literal-block,
+.rst-content div[class^="highlight"] pre,
+.rst-content .linenodiv pre {
+    /* Increase the font size and line height in code blocks */
+    font-size: 14px;
+    line-height: 1.5;
+}
+
+.rst-content pre.literal-block {
+    border: none;
+    border-radius: 0.25rem;
+    background-color: var(--code-background-color);
+}
+
+/* Code tab display tweaks */
+
+.ui.tabular.menu .active.item,
+.ui.segment,
+.sphinx-tabs-panel {
+    background-color: var(--code-background-color) !important;
+}
+
+.sphinx-tabs-tab {
+    color: var(--link-color) !important;
+}
+
+.sphinx-tabs-tab[aria-selected="true"] {
+    background-color: var(--code-background-color) !important;
+    border-bottom: 1px solid var(--code-background-color) !important;
+}
+
+/* Code literals */
+a.internal code.literal {
+    color: var(--link-color);
+}
+
+a.internal:visited code.literal {
+    color: var(--link-color-visited);
+}
+
+/* Syntax highlighting */
+
+.tab div[class^='highlight']:last-child {
+    margin-bottom: 1em;
+}
+
+.rst-content tt.literal, .rst-content code.literal, .highlight {
+    border-radius: 0.25rem;
+}
+
+.highlight {
+    background-color: var(--highlight-background-color);
+}
+
+/* Emphasized lines */
+.highlight .hll {
+    background-color: var(--highlight-background-emph-color);
+}
+
+.highlight .gh /* Generic.Heading */,
+.highlight .gu /* Generic.Subheading */,
+.highlight .go /* Generic.Output */,
+.highlight .gt /* Generic.Traceback */ {
+    color: var(--highlight-default-color);
+}
+
+.highlight .c  /* Comment */,
+.highlight .c1 /* Comment.Single */,
+.highlight .cm /* Comment.Multiline */,
+.highlight .cs /* Comment.Special */ {
+    color: var(--highlight-comment-color);
+}
+
+.highlight .bp /* Name.Builtin.Pseudo */,
+.highlight .k  /* Keyword */,
+.highlight .kc /* Keyword.Constant */,
+.highlight .kd /* Keyword.Declaration */,
+.highlight .kn /* Keyword.Namespace */,
+.highlight .kp /* Keyword.Pseudo */,
+.highlight .kr /* Keyword.Reserved */,
+.highlight .kt /* Keyword.Type */,
+.highlight .ow /* Operator.Word */ {
+    color: var(--highlight-keyword-color);
+}
+
+.highlight .ch /* Comment.Hashbang */,
+.highlight .cp /* Comment.Preproc */ {
+    color: var(--highlight-keyword2-color);
+}
+
+.highlight .m  /* Literal.Number */,
+.highlight .mf /* Literal.Number.Float */,
+.highlight .mi /* Literal.Number.Integer */,
+.highlight .il /* Literal.Number.Integer.Long */,
+.highlight .mb /* Literal.Number.Bin */,
+.highlight .mh /* Literal.Number.Hex */,
+.highlight .mo /* Literal.Number.Oct */ {
+    color: var(--highlight-number-color);
+}
+
+.highlight .na /* Name.Attribute */,
+.highlight .nd /* Name.Decorator */,
+.highlight .ni /* Name.Entity */,
+.highlight .nl /* Name.Label */ {
+    color: var(--highlight-decorator-color);
+}
+
+.highlight .nb /* Name.Builtin */,
+.highlight .ne /* Name.Exception */ {
+    color: var(--highlight-type-color);
+}
+
+.highlight .nc /* Name.Class */,
+.highlight .nn /* Name.Namespace */,
+.highlight .no /* Name.Constant */,
+.highlight .nv /* Name.Variable */,
+.highlight .vc /* Name.Variable.Class */,
+.highlight .vg /* Name.Variable.Global */,
+.highlight .vi /* Name.Variable.Instance */,
+.highlight .vm /* Name.Variable.Magic */ {
+    color: var(--highlight-type2-color);
+}
+
+.highlight .nf /* Name.Function */,
+.highlight .fm /* Name.Function.Magic */,
+.highlight .nt /* Name.Tag */ {
+    color: var(--highlight-function-color);
+}
+
+.highlight .o  /* Operator */,
+.highlight .si /* Literal.String.Interpol */,
+.highlight .sx /* Literal.String.Other */,
+.highlight .sr /* Literal.String.Regex */,
+.highlight .ss /* Literal.String.Symbol */ {
+    color: var(--highlight-operator-color);
+}
+
+.highlight .cpf/* Comment.PreprocFile */,
+.highlight .s  /* Literal.String */,
+.highlight .s1 /* Literal.String.Single */,
+.highlight .s2 /* Literal.String.Double */,
+.highlight .sc /* Literal.String.Char */,
+.highlight .se /* Literal.String.Escape */,
+.highlight .sa /* Literal.String.Affix */,
+.highlight .sb /* Literal.String.Backtick */,
+.highlight .dl /* Literal.String.Delimiter */,
+.highlight .sd /* Literal.String.Doc */,
+.highlight .sh /* Literal.String.Heredoc */ {
+    color: var(--highlight-string-color);
+}
+
+/* Admonition tweaks */
+
+.rst-content .admonition,
+.rst-content .admonition.note,
+.rst-content .admonition.seealso {
+    background-color: var(--admonition-note-background-color);
+    color: var(--admonition-note-color);
+    overflow: auto;
+}
+
+.rst-content .admonition .admonition-title,
+.rst-content .admonition.note .admonition-title,
+.rst-content .admonition.seealso .admonition-title {
+    background-color: var(--admonition-note-title-background-color);
+    color: var(--admonition-note-title-color);
+}
+
+.rst-content .admonition.attention,
+.rst-content .admonition.caution,
+.rst-content .admonition.warning {
+    background-color: var(--admonition-attention-background-color);
+    color: var(--admonition-attention-color);
+    overflow: auto;
+}
+
+.rst-content .admonition.attention .admonition-title,
+.rst-content .admonition.caution .admonition-title,
+.rst-content .admonition.warning .admonition-title {
+    background-color: var(--admonition-attention-title-background-color);
+    color: var(--admonition-attention-title-color);
+}
+
+.rst-content .admonition.danger {
+    background-color: var(--admonition-danger-background-color);
+    color: var(--admonition-danger-color);
+    overflow: auto;
+}
+
+.rst-content .admonition.danger .admonition-title {
+    background-color: var(--admonition-danger-title-background-color);
+    color: var(--admonition-danger-title-color);
+}
+
+.rst-content .admonition.tip,
+.rst-content .admonition.important {
+    background-color: var(--admonition-tip-background-color);
+    color: var(--admonition-tip-color);
+    overflow: auto;
+}
+
+.rst-content .admonition.tip .admonition-title,
+.rst-content .admonition.important .admonition-title {
+    background-color: var(--admonition-tip-title-background-color);
+    color: var(--admonition-tip-title-color);
+}
+
+/* Keyboard shortcuts tweaks */
+kbd, .kbd {
+    background-color: var(--kbd-background-color);
+    border: 1px solid var(--kbd-outline-color);
+    border-radius: 3px;
+    box-shadow: inset 0 -1px 0 var(--kbd-shadow-color);
+    color: var(--kbd-text-color);
+    display: inline-block;
+    font-size: 12px;
+    line-height: 11px;
+    padding: 4px 5px;
+    vertical-align: middle;
+}
+
+/* Buttons */
+
+.btn-neutral {
+    background-color: var(--btn-neutral-background-color) !important;
+    color: var(--body-color) !important;
+}
+
+.btn-neutral:hover {
+    background-color: var(--btn-neutral-hover-background-color) !important;
+}
+
+.btn-neutral:visited {
+    color: var(--body-color) !important;
+}
+
+/* Navigation bar logo and search */
+
+.logo {
+    opacity: var(--logo-opacity);
+}
+
+.wy-side-nav-search > a img.logo {
+    /* Fixed size to prevent reflows and support hiDPI displays */
+    /* A 5 pixel margin is added on each side. The logo itself displays at 200×100 at 100% scaling. */
+    width: 210px;
+    height: 105px;
+}
+
+.wy-side-nav-search {
+    background-color: var(--navbar-background-color);
+}
+
+.wy-side-nav-search.fixed {
+    position: fixed;
+}
+
+@media only screen and (min-width: 769px) {
+    /* Simulate a drop shadow that only affects the bottom edge */
+    /* This is used to indicate the search bar is fixed */
+    .wy-side-nav-search.fixed-and-scrolled::after {
+        content: '';
+        position: absolute;
+        left: 0;
+        bottom: -8px;
+        width: 300px;
+        height: 8px;
+        pointer-events: none;
+        background: linear-gradient(hsla(0, 0%, 0%, 0.2), transparent);
+    }
+}
+
+.wy-side-nav-search > a:hover,
+.wy-side-nav-search .wy-dropdown > a:hover {
+    background-color: var(--navbar-background-color-hover);
+}
+
+.wy-side-nav-search > a:active,
+.wy-side-nav-search .wy-dropdown > a:active {
+    background-color: var(--navbar-background-color-active);
+}
+
+.wy-side-nav-search input[type="text"] {
+    background-color: var(--input-background-color);
+    color: var(--body-color);
+    /* Avoid reflowing when toggling the focus state */
+    border: 2px solid transparent;
+    box-shadow: none;
+    /* Make visual feedback instant */
+    transition: none;
+    font-size: 14px;
+}
+
+.wy-side-nav-search input[type="text"]:focus {
+    border: 2px solid var(--input-focus-border-color);
+}
+
+.wy-side-nav-search input[type="text"]::placeholder {
+    color: var(--body-color);
+    opacity: 0.55;
+}
+
+/* Navigation bar */
+
+.wy-nav-side {
+    background-color: var(--navbar-background-color);
+}
+
+.wy-menu-vertical header,
+.wy-menu-vertical p.caption {
+    color: var(--navbar-heading-color);
+
+    /* Improves the appearance of uppercase text */
+    letter-spacing: 0.75px;
+}
+
+/* Mobile navigation */
+
+.wy-nav-top,
+.wy-nav-top a {
+    background-color: var(--navbar-background-color);
+    color: var(--navbar-level-1-color);
+}
+
+/* Version branch label below the logo */
+.wy-side-nav-search > div.version {
+    color: var(--navbar-level-3-color);
+    opacity: 0.9;
+}
+
+/* First level of navigation items */
+
+.wy-menu-vertical a {
+    color: var(--navbar-level-1-color);
+}
+
+.wy-menu-vertical a:hover {
+    background-color: var(--navbar-background-color-hover);
+    color: var(--navbar-level-1-color);
+}
+
+.wy-menu-vertical a:active {
+    background-color: var(--navbar-background-color-active);
+}
+
+.wy-menu-vertical li.toctree-l1.current > a {
+    border: none;
+}
+
+.wy-side-nav-search, .wy-menu-vertical a, .wy-menu-vertical a span.toctree-expand,
+.wy-menu-vertical li.toctree-l2 a span.toctree-expand {
+    color: var(--navbar-level-3-color);
+    opacity: 0.9;
+    margin-right: 8px;
+}
+
+.wy-side-nav-search, .wy-menu-vertical a, .wy-menu-vertical a:hover span.toctree-expand,
+.wy-menu-vertical li.toctree-l2 a:hover span.toctree-expand {
+    color: var(--navbar-level-2-color);
+    opacity: 1;
+}
+
+.wy-side-nav-search, .wy-menu-vertical a, .wy-menu-vertical a:active span.toctree-expand,
+.wy-menu-vertical li.toctree-l2 a:active span.toctree-expand {
+    color: var(--navbar-level-1-color);
+    opacity: 1;
+}
+
+/* Second (and higher) levels of navigation items */
+
+.wy-menu-vertical li.current a {
+    /* Make long words always display on a single line, keep wrapping for multiple words */
+    /* This fixes the class reference titles' display with very long class names */
+    display: flex;
+}
+
+.wy-menu-vertical li.current a,
+.wy-menu-vertical li.toctree-l2.current > a,
+.wy-menu-vertical li.toctree-l2.current li.toctree-l3 > a,
+.wy-menu-vertical li.toctree-l2.current li.toctree-l4 > a {
+    background-color: var(--navbar-current-background-color);
+    color: var(--navbar-level-2-color);
+    border-color: var(--navbar-current-background-color);
+}
+
+.wy-menu-vertical li.current a:hover,
+.wy-menu-vertical li.toctree-l2.current > a:hover,
+.wy-menu-vertical li.toctree-l2.current li.toctree-l3 > a:hover,
+.wy-menu-vertical li.toctree-l3.current li.toctree-l4 > a:hover {
+    background-color: var(--navbar-current-background-color-hover);
+}
+
+.wy-menu-vertical li.current a:active,
+.wy-menu-vertical li.toctree-l2.current > a:active,
+.wy-menu-vertical li.toctree-l2.current li.toctree-l3 > a:active,
+.wy-menu-vertical li.toctree-l3.current li.toctree-l4 > a:active {
+    background-color: var(--navbar-current-background-color-active);
+}
+
+.wy-menu-vertical a {
+    /* This overrides 8px margin added in other multi-selector rules */
+    margin-right: 0;
+}
+
+/* Banner panel in sidebar */
+.wy-nav-side .ethical-rtd.fixed {
+    position: fixed;
+}
+
+/* Version selector (only visible on Read the Docs) */
+
+.rst-versions {
+    background-color: var(--navbar-current-background-color);
+}
+
+.rst-versions a,
+.rst-versions .rst-current-version,
+.rst-versions .rst-current-version .fa,
+.rst-versions .rst-other-versions dd a {
+    color: var(--navbar-level-1-color);
+}
+
+.rst-versions .rst-other-versions small {
+    color: var(--navbar-level-3-color);
+}
+
+.rst-versions .rst-other-versions dd a:hover {
+    text-decoration: underline;
+}
+
+.rst-versions .rst-other-versions {
+    color: var(--navbar-heading-color);
+}
+
+.rst-versions .rst-current-version {
+    background-color: var(--navbar-current-background-color);
+}
+
+.rst-versions .rst-current-version:hover {
+    background-color: var(--navbar-current-background-color-hover);
+}
+
+.rst-versions .rst-current-version:active {
+    background-color: var(--navbar-current-background-color-active);
+}
+
+.rst-versions.shift-up {
+    overflow-y: auto;
+}
+
+/* Hide the obnoxious automatic highlight in search results */
+.rst-content .highlighted {
+    background-color: transparent;
+    font-weight: inherit;
+    padding: 0;
+}
+
+/* Allows the scrollbar to be shown in the sidebar */
+@media only screen and (min-width: 769px) {
+    .wy-side-scroll {
+        overflow: hidden;
+    }
+
+    .wy-nav-side .wy-side-scroll .ethical-rtd {
+        width: calc(300px - 1.25em);
+        padding: 0 0 0 1em;
+    }
+}
+.wy-menu.wy-menu-vertical {
+    overflow-y: auto;
+    overflow-x: hidden;
+    max-height: calc(100% - 243px);
+}
+@media screen and (max-width: 768px) {
+    .wy-nav-side {
+        padding-bottom: 44px;
+    }
+    .wy-menu.wy-menu-vertical {
+        overflow-y: initial;
+        max-height: initial;
+    }
+}
+
+/* Scrollbar styling */
+.wy-menu.wy-menu-vertical {
+    scrollbar-color: var(--navbar-scrollbar-color) var(--navbar-scrollbar-background);
+}
+.wy-menu.wy-menu-vertical::-webkit-scrollbar {
+    width: .75rem;
+}
+.wy-menu.wy-menu-vertical::-webkit-scrollbar-track {
+    background-color: var(--navbar-scrollbar-background);
+}
+.wy-menu.wy-menu-vertical::-webkit-scrollbar-thumb {
+    background-color: var(--navbar-scrollbar-color);
+}
+/* Firefox does the dimming on hover automatically. We emulate it for Webkit-based browsers. */
+.wy-menu.wy-menu-vertical::-webkit-scrollbar-thumb:hover {
+    background-color: var(--navbar-scrollbar-hover-color);
+}
+.wy-menu.wy-menu-vertical::-webkit-scrollbar-thumb:active {
+    background-color: var(--navbar-scrollbar-active-color);
+}
+
+/* Breathe tweaks */
+
+.rst-content .section > dl > dd {
+    margin-left: 0;
+}
+
+.rst-content p.breathe-sectiondef-title {
+    font-size: 115%;
+    color: var(--link-color);
+}
+
+.rst-content dl:not(.docutils) dl:not(.rst-other-versions) dt {
+    background: var(--admonition-note-background-color) !important;
+    border-top: none !important;
+    border-left: none !important;
+}
+
+/* Misc tweaks */
+
+.rst-columns {
+    column-width: 18em;
+}
+
+.rst-content div.figure, .rst-content figure {
+    text-align: center;
+}
+
+.wy-alert.wy-alert-danger {
+    background-color: var(--admonition-danger-background-color);
+}
+
+
+dark-mode-toggle::part(fieldset) {
+  padding-inline: 0.75rem;
+  padding-block: 0;
+}
+
+dark-mode-toggle::part(darkLabel),
+dark-mode-toggle::part(lightLabel),
+dark-mode-toggle::part(toggleLabel){
+  font-size: unset;
+}
+
+/* Home page grid display */
+.grid {
+    list-style-type: none !important;
+    display: -webkit-box;
+    display: -ms-flexbox;
+    display: flex;
+    -ms-flex-wrap: wrap;
+        flex-wrap: wrap;
+    -webkit-box-pack: center;
+        -ms-flex-pack: center;
+            justify-content: center;
+    margin: 1rem auto;
+    max-width: calc((160px + 2rem) * 4);
+}
+
+.grid-item {
+    list-style-type: none !important;
+    -webkit-box-flex: 0;
+        -ms-flex: 0 0 auto;
+            flex: 0 0 auto;
+    width: 150px;
+    text-align: center;
+    margin: 1rem;
+}
+
+.grid-item a {
+    display: block;
+    width: 150px;
+    height: 150px;
+    padding: 20px;
+    display: -webkit-box;
+    display: -ms-flexbox;
+    display: flex;
+    -webkit-box-orient: vertical;
+    -webkit-box-direction: normal;
+        -ms-flex-direction: column;
+            flex-direction: column;
+    -webkit-box-pack: center;
+        -ms-flex-pack: center;
+            justify-content: center;
+    -webkit-box-align: center;
+        -ms-flex-align: center;
+            align-items: center;
+    border-radius: 0.5rem;
+    background: linear-gradient(135deg, #0070c5 0%, #5c13a5 100%);
+    color: white;
+}
+
+.grid-item h2 {
+    font-size: 1rem;
+}
+
+.grid-item img {
+    margin-bottom: 1rem;
+    max-width: 75%;
+}
+
+.grid-item a:hover {
+    text-decoration: none;
+}
+
+.grid-item p {
+    font-size: 0.9rem;
+    margin-top: 0.5rem;
+    color: var(--body-color);
+}
+
+.grid-icon {
+   line-height: 1.5;
+   font-size: 3rem;
+   color: white;
+}

+ 93 - 0
doc/_static/css/dark.css

@@ -0,0 +1,93 @@
+/**
+ * Copyright (c) 2019-2020, Juan Linietsky, Ariel Manzur and the Godot community
+ * Copyright (c) 2021, Teslabs Engineering S.L.
+ * SPDX-License-Identifier: CC-BY-3.0
+ *
+ * Dark theme colors
+ */
+
+:root {
+    --body-color: rgba(255, 255, 255, 0.85);
+    --content-wrap-background-color: #202326;
+    --content-background-color: #2e3236;
+    /* Decrease the logo opacity when using the dark theme to be less distracting */
+    --logo-opacity: 0.85;
+    --navbar-background-color: #25282b;
+    --navbar-background-color-hover: #333639;
+    --navbar-background-color-active: #111417;
+    --navbar-current-background-color: #333639;
+    --navbar-current-background-color-hover: #44474a;
+    --navbar-current-background-color-active: #222528;
+    --navbar-level-1-color: #ddd;
+    --navbar-level-2-color: #ccc;
+    --navbar-level-3-color: #bbb;
+    --navbar-heading-color: #af7fe4;
+    --navbar-scrollbar-color: #af7fe4;
+    --navbar-scrollbar-hover-color: #9454db;
+    --navbar-scrollbar-active-color: #7929d2;
+    --navbar-scrollbar-background: #1c1e21;
+
+    --link-color: #8cf;
+    --link-color-hover: #9df;
+    --link-color-active: #6ad;
+    --link-color-visited: #cb99f6;
+    --external-reference-icon: url("data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9IjEyIiB3aWR0aD0iMTIiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGcgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjOGNmIj48cGF0aCBkPSJtNy41IDcuMXYzLjRoLTZ2LTZoMy40Ii8+PHBhdGggZD0ibTUuNzY1IDFoNS4yMzV2NS4zOWwtMS41NzMgMS41NDctMS4zMS0xLjMxLTIuNzI0IDIuNzIzLTIuNjktMi42ODggMi44MS0yLjgwOC0xLjMxMy0xLjMxeiIvPjwvZz48L3N2Zz4K");
+    --classref-badge-text-color: hsl(0, 0%, 70%);
+
+    --hr-color: #555;
+    --table-row-odd-background-color: #3b3e41;
+    --code-background-color: #434649;
+    --code-border-color: #505356;
+    --code-literal-color: #faa;
+    --input-background-color: #333537;
+    --input-focus-border-color: #5f8cff;
+
+    --search-input-background-color: #43464a; /* derived from --input-background-color */
+    --search-match-color: #52b4ff; /* derived from --link-color */
+    --search-match-background-color: #414c56; /* derived from --link-color */
+    --search-active-color: #202326;
+    --search-credits-background-color: #202123; /* derived from --navbar-background-color */
+    --search-credits-color: #6b6b6b; /* derived from --footer-color */
+    --search-credits-link-color: #628fb1; /* derived from --link-color */
+
+    /* Colors taken from the Godot script editor with the Adaptive theme */
+    --highlight-background-color: #202531;
+    --highlight-background-emph-color: #2d3444;
+    --highlight-default-color: rgba(255, 255, 255, 0.85);
+    --highlight-comment-color: rgba(204, 206, 211, 0.5);
+    --highlight-keyword-color: #ff7085;
+    --highlight-keyword2-color: #42ffc2;
+    --highlight-number-color: #a1ffe0;
+    --highlight-decorator-color: #abc8ff;
+    --highlight-type-color: #8effda;
+    --highlight-type2-color: #c6ffed;
+    --highlight-function-color: #57b3ff;
+    --highlight-operator-color: #abc8ff;
+    --highlight-string-color: #ffeca1;
+
+    --admonition-note-background-color: #303d4f;
+    --admonition-note-color: #bfeeff;
+    --admonition-note-title-background-color: #305070;
+    --admonition-note-title-color: #bfefff;
+    --admonition-attention-background-color: #444033;
+    --admonition-attention-color: #ffeeaf;
+    --admonition-attention-title-background-color: #665022;
+    --admonition-attention-title-color: #ffeeaf;
+    --admonition-danger-background-color: #433;
+    --admonition-danger-color: #fcc;
+    --admonition-danger-title-background-color: #633;
+    --admonition-danger-title-color: #fcc;
+    --admonition-tip-background-color: #28382d;
+    --admonition-tip-color: #dfd;
+    --admonition-tip-title-background-color: #336648;
+    --admonition-tip-title-color: #dfd;
+
+    --kbd-background-color: #595b5d;
+    --kbd-outline-color: #3d4144;
+    --kbd-shadow-color: #1e2023;
+    --kbd-text-color: #e2f2ff;
+
+    --btn-neutral-background-color: #404040;
+    --btn-neutral-hover-background-color: #505050;
+    --footer-color: #aaa;
+}

+ 91 - 0
doc/_static/css/light.css

@@ -0,0 +1,91 @@
+/**
+ * Copyright (c) 2019-2020, Juan Linietsky, Ariel Manzur and the Godot community
+ * Copyright (c) 2021, Teslabs Engineering S.L.
+ * SPDX-License-Identifier: CC-BY-3.0
+ *
+ * Light theme colors
+ */
+
+:root {
+    --body-color: #404040;
+    --content-wrap-background-color: #efefef;
+    --content-background-color: #fcfcfc;
+    --logo-opacity: 1.0;
+    --navbar-background-color: #333f67;
+    --navbar-background-color-hover: #29355c;
+    --navbar-background-color-active: #212d51;
+    --navbar-current-background-color: #212d51;
+    --navbar-current-background-color-hover: #182343;
+    --navbar-current-background-color-active: #131e3b;
+    --navbar-level-1-color: #c3e3ff;
+    --navbar-level-2-color: #b8d6f0;
+    --navbar-level-3-color: #a3c4e1;
+    --navbar-heading-color: #af7fe4;
+    --navbar-scrollbar-color: #af7fe4;
+    --navbar-scrollbar-hover-color: #9454db;
+    --navbar-scrollbar-active-color: #7929d2;
+    --navbar-scrollbar-background: #131e2b;
+
+    --link-color: #2980b9;
+    --link-color-hover: #3091d1;
+    --link-color-active: #105078;
+    --link-color-visited: #9b59b6;
+    --external-reference-icon: url("data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9IjEyIiB3aWR0aD0iMTIiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGcgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjMjk4MGI5Ij48cGF0aCBkPSJtNy41IDcuMXYzLjRoLTZ2LTZoMy40Ii8+PHBhdGggZD0ibTUuNzY1IDFoNS4yMzV2NS4zOWwtMS41NzMgMS41NDctMS4zMS0xLjMxLTIuNzI0IDIuNzIzLTIuNjktMi42ODggMi44MS0yLjgwOC0xLjMxMy0xLjMxeiIvPjwvZz48L3N2Zz4K");
+    --classref-badge-text-color: hsl(0, 0%, 45%);
+
+    --hr-color: #e1e4e5;
+    --table-row-odd-background-color: #f3f6f6;
+    --code-background-color: #fff;
+    --code-border-color: #e1e4e5;
+    --code-literal-color: #d04c60;
+    --input-background-color: #fcfcfc;
+    --input-focus-border-color: #5f8cff;
+
+    --search-input-background-color: #e6eef3; /* derived from --input-background-color */
+    --search-match-color: #2c6b96; /* derived from --link-color */
+    --search-match-background-color: #e3f2fd; /* derived from --link-color */
+    --search-active-color: #efefef;
+    --search-credits-background-color: #333f67; /* derived from --navbar-background-color */
+    --search-credits-color: #b3b3b3; /* derived from --footer-color */
+    --search-credits-link-color: #4392c5; /* derived from --link-color */
+
+    --highlight-background-color: #f0f2f4;
+    --highlight-background-emph-color: #dbe6c3;
+    --highlight-default-color: #404040;
+    --highlight-comment-color: #408090;
+    --highlight-keyword-color: #007020;
+    --highlight-keyword2-color: #902000;
+    --highlight-number-color: #208050;
+    --highlight-decorator-color: #4070a0;
+    --highlight-type-color: #007020;
+    --highlight-type2-color: #0e84b5;
+    --highlight-function-color: #06287e;
+    --highlight-operator-color: #666666;
+    --highlight-string-color: #4070a0;
+
+    --admonition-note-background-color: #e7f2fa;
+    --admonition-note-color: #404040;
+    --admonition-note-title-background-color: #6ab0de;
+    --admonition-note-title-color: #fff;
+    --admonition-attention-background-color: #ffedcc;
+    --admonition-attention-color: #404040;
+    --admonition-attention-title-background-color: #f0b37e;
+    --admonition-attention-title-color: #fff;
+    --admonition-danger-background-color: #fcf3f2;
+    --admonition-danger-color: #404040;
+    --admonition-danger-title-background-color: #e9a499;
+    --admonition-danger-title-color: #fff;
+    --admonition-tip-background-color: #dbfaf4;
+    --admonition-tip-color: #404040;
+    --admonition-tip-title-background-color: #1abc9c;
+    --admonition-tip-title-color: #fff;
+
+    --kbd-background-color: #fafbfc;
+    --kbd-outline-color: #d1d5da;
+    --kbd-shadow-color: #b0b7bf;
+    --kbd-text-color: #444d56;
+
+    --btn-neutral-background-color: #f3f6f6;
+    --btn-neutral-hover-background-color: #e5ebeb;
+    --footer-color: #808080;
+}

BIN
doc/_static/images/favicon.png


BIN
doc/_static/images/kite.png


BIN
doc/_static/images/logo-latex.pdf


+ 167 - 0
doc/_static/images/logo-readme.svg

@@ -0,0 +1,167 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   viewBox="0 0 360 185"
+   version="1.1"
+   id="svg55"
+   width="360"
+   height="185">
+  <metadata
+     id="metadata59">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs20">
+    <style
+       id="style2">.cls-1{fill:#7929d2;}.cls-2{fill:#9454db;}.cls-3{fill:#af7fe4;}.cls-4{fill:url(#linear-gradient);}.cls-5{fill:url(#linear-gradient-2);}.cls-6{fill:url(#linear-gradient-3);}.cls-7{fill:url(#linear-gradient-4);}.cls-8{fill:#2d3136;}</style>
+    <linearGradient
+       id="linear-gradient"
+       x1="173.22662"
+       y1="83.041153"
+       x2="269.62073"
+       y2="83.041153"
+       gradientUnits="userSpaceOnUse">
+      <stop
+         offset="0"
+         stop-color="#7929d2"
+         id="stop4" />
+      <stop
+         offset="1"
+         stop-color="#0070c5"
+         id="stop6" />
+    </linearGradient>
+    <linearGradient
+       id="linear-gradient-2"
+       x1="179.78728"
+       y1="-1.87884"
+       x2="178.9799"
+       y2="93.40757"
+       gradientUnits="userSpaceOnUse">
+      <stop
+         offset="0"
+         stop-color="#00aeff"
+         id="stop9" />
+      <stop
+         offset="1"
+         stop-color="#9454db"
+         id="stop11" />
+    </linearGradient>
+    <linearGradient
+       id="linear-gradient-3"
+       x1="232.84549"
+       y1="37.632019"
+       x2="212.26581"
+       y2="1.98698"
+       gradientUnits="userSpaceOnUse">
+      <stop
+         offset="0"
+         stop-color="#66a9dc"
+         id="stop14" />
+      <stop
+         offset="1"
+         stop-color="#b1e4fa"
+         id="stop16" />
+    </linearGradient>
+    <linearGradient
+       id="linear-gradient-4"
+       x1="237.4232"
+       y1="9.7026796"
+       x2="249.11588"
+       y2="90.576942"
+       xlink:href="#linear-gradient-2" />
+    <linearGradient
+       xlink:href="#linear-gradient-2"
+       id="linearGradient884"
+       gradientUnits="userSpaceOnUse"
+       x1="179.78728"
+       y1="-1.87884"
+       x2="178.9799"
+       y2="93.40757" />
+  </defs>
+  <g
+     id="Colored_Positive"
+     data-name="Colored Positive"
+     transform="matrix(0.81480572,0,0,0.81480572,1.6221167,-0.40622648)">
+    <polygon
+       class="cls-1"
+       points="105.31,135.046 132.385,148.72 137.154,121.601 "
+       id="polygon22" />
+    <polygon
+       class="cls-2"
+       points="34.434,126.703 42.309,153.408 68.401,139.419 "
+       id="polygon24" />
+    <polygon
+       class="cls-3"
+       points="105.31,135.046 68.401,139.419 84.508,115.518 "
+       id="polygon26" />
+    <polygon
+       class="cls-3"
+       points="34.434,126.703 8.759,101.076 38.535,97.167 "
+       id="polygon28" />
+    <polygon
+       class="cls-4"
+       points="220.982,44.482 258.666,94.416 137.154,121.601 "
+       id="polygon30"
+       style="fill:url(#linear-gradient)" />
+    <polygon
+       class="cls-5"
+       points="172.959,8.13 220.982,44.482 137.154,121.601 "
+       id="polygon32"
+       style="fill:url(#linearGradient884)" />
+    <polygon
+       class="cls-6"
+       points="258.666,8.13 220.982,44.482 172.959,8.13 "
+       id="polygon34"
+       style="fill:url(#linear-gradient-3)" />
+    <polygon
+       class="cls-7"
+       points="258.666,8.13 220.982,44.482 258.666,94.416 "
+       id="polygon36"
+       style="fill:url(#linear-gradient-4)" />
+    <path
+       class="cls-8"
+       d="m 172.56179,206.12831 v -9.06612 l 24.189,-33.82651 h -23.04621 v -9.828 h 35.88353 v 8.6471 l -24.41756,34.24553 h 25.06514 v 9.828 z"
+       id="path38" />
+    <path
+       class="cls-8"
+       d="m 225.19819,188.71984 q 0.26614,5.33352 2.59032,7.65668 2.32317,2.32392 7.31384,2.32367 a 16.21678,16.21678 0 0 0 5.0854,-0.72377 8.14694,8.14694 0 0 0 3.82834,-2.78078 l 7.31384,5.21873 a 14.7969,14.7969 0 0 1 -6.22819,5.18064 q -3.82835,1.71418 -10.45651,1.71418 -9.86706,0 -14.72291,-5.18064 -4.85685,-5.18013 -4.85685,-15.65619 0,-21.44607 19.19883,-21.44631 8.53182,0 13.00874,4.81875 4.47491,4.81926 4.47592,14.03724 v 4.8378 z m 16.799,-6.78054 q 0,-9.10395 -7.96142,-9.10421 a 9.102,9.102 0 0 0 -4.3045,0.89519 6.69237,6.69237 0 0 0 -2.68555,2.6665 16.81823,16.81823 0 0 0 -1.58086,5.54252 z"
+       id="path40" />
+    <path
+       class="cls-8"
+       d="m 295.96782,185.86287 a 30.72681,30.72681 0 0 1 -1.94274,11.35169 16.29,16.29 0 0 1 -5.56156,7.50431 14.46506,14.46506 0 0 1 -8.6471,2.59032 16.46611,16.46611 0 0 1 -11.3136,-4.15213 V 221.175 h -9.828 v -55.00617 h 9.06618 v 3.92357 a 23.592,23.592 0 0 1 5.77107,-3.71406 16.89719,16.89719 0 0 1 6.952,-1.35229 q 7.58,0 11.54216,5.333 3.96059,5.33352 3.96159,15.50382 z m -10.13272,0.15238 q 0,-5.82822 -2.01892,-9.08517 a 6.62576,6.62576 0 0 0 -6.01868,-3.25694 12.12546,12.12546 0 0 0 -4.933,1.12374 16.5144,16.5144 0 0 0 -4.36164,2.76174 v 17.48465 a 15.71263,15.71263 0 0 0 3.86644,2.49508 11.0079,11.0079 0 0 0 4.74256,1.08565 7.3295,7.3295 0 0 0 6.38057,-3.44741 q 2.34268,-3.44715 2.34267,-9.16134 z"
+       id="path42" />
+    <path
+       class="cls-8"
+       d="M 328.834,206.12831 V 184.1106 q 0,-6.32292 -1.18088,-8.38044 a 4.41856,4.41856 0 0 0 -4.19022,-2.057 q -4.38168,0 -10.55174,5.79012 v 26.66505 h -9.828 V 149.408 h 9.828 v 21.94152 a 22.63076,22.63076 0 0 1 6.66626,-4.72352 16.77074,16.77074 0 0 1 6.93292,-1.5999 q 6.70335,0 9.428,3.77119 2.72315,3.77121 2.72365,10.666 v 26.66505 z"
+       id="path44" />
+    <path
+       class="cls-8"
+       d="m 343.30229,211.49941 a 17.84733,17.84733 0 0 0 5.752,1.1047 6.06415,6.06415 0 0 0 3.88548,-1.33326 q 1.67508,-1.33375 3.46645,-5.52347 l 1.02851,-2.36176 -14.43722,-37.21679 h 10.20891 l 9.447,25.52226 9.6756,-25.52226 h 9.98035 L 365.12953,208.871 a 31.82753,31.82753 0 0 1 -4.07594,7.61858 11.66364,11.66364 0 0 1 -4.62829,3.58074 17.35552,17.35552 0 0 1 -6.64722,1.10469 32.71115,32.71115 0 0 1 -8.5709,-1.14278 z"
+       id="path46" />
+    <path
+       class="cls-8"
+       d="m 410.98539,175.76825 a 9.086,9.086 0 0 0 -4.03785,-0.76186 10.86745,10.86745 0 0 0 -5.19968,1.31421 22.916,22.916 0 0 0 -5.04731,3.82834 v 25.97937 h -9.828 v -39.95948 h 9.828 v 5.71394 a 25.65574,25.65574 0 0 1 5.40919,-4.53306 12.06278,12.06278 0 0 1 6.4758,-1.79036 8.69776,8.69776 0 0 1 4.34259,0.79995 z"
+       id="path48" />
+    <path
+       class="cls-8"
+       d="m 424.04622,167.02661 h -0.904 v 2.07682 h -1.234 v -5.79574 h 2.71145 a 1.8049,1.8049 0 0 1 1.94644,1.86828 1.66317,1.66317 0 0 1 -1.26926,1.72025 l 1.30385,2.20721 h -1.4166 z m 0.39081,-2.65889 h -1.29486 v 1.59886 h 1.29483 a 0.8022,0.8022 0 1 0 0,-1.59886 z"
+       id="path50" />
+    <path
+       class="cls-8"
+       d="m 424.254,172.49932 a 6.29376,6.29376 0 1 1 6.29434,-6.294 6.30082,6.30082 0 0 1 -6.29434,6.294 z m 0,-11.7913 a 5.49754,5.49754 0 1 0 5.49812,5.49735 5.50374,5.50374 0 0 0 -5.49812,-5.49737 z"
+       id="path52" />
+  </g>
+</svg>

+ 174 - 0
doc/_static/images/logo.svg

@@ -0,0 +1,174 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   viewBox="0 0 1050 549.99998"
+   version="1.1"
+   id="svg55"
+   width="1050"
+   height="550">
+  <metadata
+     id="metadata59">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs20">
+    <style
+       id="style2">.cls-1{fill:#7929d2;}.cls-2{fill:#9454db;}.cls-3{fill:#af7fe4;}.cls-4{fill:url(#linear-gradient);}.cls-5{fill:url(#linear-gradient-2);}.cls-6{fill:url(#linear-gradient-3);}.cls-7{fill:url(#linear-gradient-4);}.cls-8{fill:#2d3136;}</style>
+    <linearGradient
+       id="linear-gradient"
+       x1="173.22662"
+       y1="83.041153"
+       x2="269.62073"
+       y2="83.041153"
+       gradientUnits="userSpaceOnUse">
+      <stop
+         offset="0"
+         stop-color="#7929d2"
+         id="stop4" />
+      <stop
+         offset="1"
+         stop-color="#0070c5"
+         id="stop6" />
+    </linearGradient>
+    <linearGradient
+       id="linear-gradient-2"
+       x1="179.78728"
+       y1="-1.87884"
+       x2="178.9799"
+       y2="93.40757"
+       gradientUnits="userSpaceOnUse">
+      <stop
+         offset="0"
+         stop-color="#00aeff"
+         id="stop9" />
+      <stop
+         offset="1"
+         stop-color="#9454db"
+         id="stop11" />
+    </linearGradient>
+    <linearGradient
+       id="linear-gradient-3"
+       x1="232.84549"
+       y1="37.632019"
+       x2="212.26581"
+       y2="1.98698"
+       gradientUnits="userSpaceOnUse">
+      <stop
+         offset="0"
+         stop-color="#66a9dc"
+         id="stop14" />
+      <stop
+         offset="1"
+         stop-color="#b1e4fa"
+         id="stop16" />
+    </linearGradient>
+    <linearGradient
+       id="linear-gradient-4"
+       x1="237.4232"
+       y1="9.7026796"
+       x2="249.11588"
+       y2="90.576942"
+       xlink:href="#linear-gradient-2" />
+    <linearGradient
+       xlink:href="#linear-gradient-2"
+       id="linearGradient61"
+       gradientUnits="userSpaceOnUse"
+       x1="179.78728"
+       y1="-1.87884"
+       x2="178.9799"
+       y2="93.40757" />
+  </defs>
+  <g
+     id="g918"
+     transform="matrix(2.4165646,0,0,2.4165646,-3.9527031,-3.5166707)">
+    <polygon
+       class="cls-1"
+       points="137.154,121.601 105.31,135.046 132.385,148.72 "
+       id="polygon22" />
+    <polygon
+       class="cls-2"
+       points="68.401,139.419 34.434,126.703 42.309,153.408 "
+       id="polygon24" />
+    <polygon
+       class="cls-3"
+       points="84.508,115.518 105.31,135.046 68.401,139.419 "
+       id="polygon26" />
+    <polygon
+       class="cls-3"
+       points="38.535,97.167 34.434,126.703 8.759,101.076 "
+       id="polygon28" />
+    <polygon
+       class="cls-4"
+       points="137.154,121.601 220.982,44.482 258.666,94.416 "
+       id="polygon30"
+       style="fill:url(#linear-gradient)" />
+    <polygon
+       class="cls-5"
+       points="137.154,121.601 172.959,8.13 220.982,44.482 "
+       id="polygon32"
+       style="fill:url(#linearGradient61)" />
+    <polygon
+       class="cls-6"
+       points="172.959,8.13 258.666,8.13 220.982,44.482 "
+       id="polygon34"
+       style="fill:url(#linear-gradient-3)" />
+    <polygon
+       class="cls-7"
+       points="258.666,94.416 258.666,8.13 220.982,44.482 "
+       id="polygon36"
+       style="fill:url(#linear-gradient-4)" />
+    <path
+       class="cls-8"
+       d="m 172.56179,206.12831 v -9.06612 l 24.189,-33.82651 h -23.04621 v -9.828 h 35.88353 v 8.6471 l -24.41756,34.24553 h 25.06514 v 9.828 z"
+       id="path38"
+       style="fill:#ffffff;fill-opacity:1" />
+    <path
+       class="cls-8"
+       d="m 225.19819,188.71984 q 0.26614,5.33352 2.59032,7.65668 2.32317,2.32392 7.31384,2.32367 a 16.21678,16.21678 0 0 0 5.0854,-0.72377 8.14694,8.14694 0 0 0 3.82834,-2.78078 l 7.31384,5.21873 a 14.7969,14.7969 0 0 1 -6.22819,5.18064 q -3.82835,1.71418 -10.45651,1.71418 -9.86706,0 -14.72291,-5.18064 -4.85685,-5.18013 -4.85685,-15.65619 0,-21.44607 19.19883,-21.44631 8.53182,0 13.00874,4.81875 4.47491,4.81926 4.47592,14.03724 v 4.8378 z m 16.799,-6.78054 q 0,-9.10395 -7.96142,-9.10421 a 9.102,9.102 0 0 0 -4.3045,0.89519 6.69237,6.69237 0 0 0 -2.68555,2.6665 16.81823,16.81823 0 0 0 -1.58086,5.54252 z"
+       id="path40"
+       style="fill:#ffffff;fill-opacity:1" />
+    <path
+       class="cls-8"
+       d="m 295.96782,185.86287 a 30.72681,30.72681 0 0 1 -1.94274,11.35169 16.29,16.29 0 0 1 -5.56156,7.50431 14.46506,14.46506 0 0 1 -8.6471,2.59032 16.46611,16.46611 0 0 1 -11.3136,-4.15213 V 221.175 h -9.828 v -55.00617 h 9.06618 v 3.92357 a 23.592,23.592 0 0 1 5.77107,-3.71406 16.89719,16.89719 0 0 1 6.952,-1.35229 q 7.58,0 11.54216,5.333 3.96059,5.33352 3.96159,15.50382 z m -10.13272,0.15238 q 0,-5.82822 -2.01892,-9.08517 a 6.62576,6.62576 0 0 0 -6.01868,-3.25694 12.12546,12.12546 0 0 0 -4.933,1.12374 16.5144,16.5144 0 0 0 -4.36164,2.76174 v 17.48465 a 15.71263,15.71263 0 0 0 3.86644,2.49508 11.0079,11.0079 0 0 0 4.74256,1.08565 7.3295,7.3295 0 0 0 6.38057,-3.44741 q 2.34268,-3.44715 2.34267,-9.16134 z"
+       id="path42"
+       style="fill:#ffffff;fill-opacity:1" />
+    <path
+       class="cls-8"
+       d="M 328.834,206.12831 V 184.1106 q 0,-6.32292 -1.18088,-8.38044 a 4.41856,4.41856 0 0 0 -4.19022,-2.057 q -4.38168,0 -10.55174,5.79012 v 26.66505 h -9.828 V 149.408 h 9.828 v 21.94152 a 22.63076,22.63076 0 0 1 6.66626,-4.72352 16.77074,16.77074 0 0 1 6.93292,-1.5999 q 6.70335,0 9.428,3.77119 2.72315,3.77121 2.72365,10.666 v 26.66505 z"
+       id="path44"
+       style="fill:#ffffff;fill-opacity:1" />
+    <path
+       class="cls-8"
+       d="m 343.30229,211.49941 a 17.84733,17.84733 0 0 0 5.752,1.1047 6.06415,6.06415 0 0 0 3.88548,-1.33326 q 1.67508,-1.33375 3.46645,-5.52347 l 1.02851,-2.36176 -14.43722,-37.21679 h 10.20891 l 9.447,25.52226 9.6756,-25.52226 h 9.98035 L 365.12953,208.871 a 31.82753,31.82753 0 0 1 -4.07594,7.61858 11.66364,11.66364 0 0 1 -4.62829,3.58074 17.35552,17.35552 0 0 1 -6.64722,1.10469 32.71115,32.71115 0 0 1 -8.5709,-1.14278 z"
+       id="path46"
+       style="fill:#ffffff;fill-opacity:1" />
+    <path
+       class="cls-8"
+       d="m 410.98539,175.76825 a 9.086,9.086 0 0 0 -4.03785,-0.76186 10.86745,10.86745 0 0 0 -5.19968,1.31421 22.916,22.916 0 0 0 -5.04731,3.82834 v 25.97937 h -9.828 v -39.95948 h 9.828 v 5.71394 a 25.65574,25.65574 0 0 1 5.40919,-4.53306 12.06278,12.06278 0 0 1 6.4758,-1.79036 8.69776,8.69776 0 0 1 4.34259,0.79995 z"
+       id="path48"
+       style="fill:#ffffff;fill-opacity:1" />
+    <path
+       class="cls-8"
+       d="m 424.04622,167.02661 h -0.904 v 2.07682 h -1.234 v -5.79574 h 2.71145 a 1.8049,1.8049 0 0 1 1.94644,1.86828 1.66317,1.66317 0 0 1 -1.26926,1.72025 l 1.30385,2.20721 h -1.4166 z m 0.39081,-2.65889 h -1.29486 v 1.59886 h 1.29483 a 0.8022,0.8022 0 1 0 0,-1.59886 z"
+       id="path50"
+       style="fill:#ffffff;fill-opacity:1" />
+    <path
+       class="cls-8"
+       d="m 424.254,172.49932 a 6.29376,6.29376 0 1 1 6.29434,-6.294 6.30082,6.30082 0 0 1 -6.29434,6.294 z m 0,-11.7913 a 5.49754,5.49754 0 1 0 5.49812,5.49735 5.50374,5.50374 0 0 0 -5.49812,-5.49737 z"
+       id="path52"
+       style="fill:#ffffff;fill-opacity:1" />
+  </g>
+</svg>

Разница между файлами не показана из-за своего большого размера
+ 1 - 0
doc/_static/js/dark-mode-toggle.min.mjs


+ 10 - 0
doc/_static/js/ga-tracker.js

@@ -0,0 +1,10 @@
+// <!-- Global site tag (gtag.js) - Google Analytics -->
+
+// Copyright (c) 2019, Intel Corporation
+// SPDX-License-Identifier: Apache-2.0
+
+
+  window.dataLayer = window.dataLayer || [];
+  function gtag(){dataLayer.push(arguments);}
+  gtag('js', new Date());
+  gtag('config', 'UA-831873-47');

+ 48 - 0
doc/_static/js/scorer.js

@@ -0,0 +1,48 @@
+/**
+ * Simple search result scoring code.
+ *
+ * Copyright 2007-2018 by the Sphinx team
+ * Copyright (c) 2019, Intel
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+var Scorer = {
+  // Implement the following function to further tweak the score for
+  // each result The function takes a result array [filename, title,
+  // anchor, descr, score] and returns the new score.
+
+  // For Zephyr search results, push display down for kconfig, boards,
+  // and samples so "regular" docs will show up before them
+
+  score: function(result) {
+    if (result[0].search("reference/kconfig/")>=0) {
+       return -5;
+    }
+    else if (result[0].search("boards/")>=0) {
+       return -5;
+    }
+    else if (result[0].search("samples/")>=0) {
+       return -5;
+    }
+    else {
+       return result[4];
+    }
+  },
+
+
+  // query matches the full name of an object
+  objNameMatch: 11,
+  // or matches in the last dotted part of the object name
+  objPartialMatch: 6,
+  // Additive scores depending on the priority of the object
+  objPrio: {0:  15,   // used to be importantResults
+            1:  5,   // used to be objectResults
+            2: -5},  // used to be unimportantResults
+  //  Used when the priority is not in the mapping.
+  objPrioDefault: 0,
+
+  // query found in title
+  title: 15,
+  // query found in terms
+  term: 5
+};

+ 15 - 0
doc/_static/latex/preamble.tex

@@ -0,0 +1,15 @@
+% LaTeX documentation preamble
+%
+% Copyright (c) 2021 Nordic Semiconductor ASA
+% SPDX-License-Identifier: Apache-2.0
+
+\usepackage[some]{background}
+\usepackage{sectsty}
+
+\definecolor{bg-color}{HTML}{333f67}
+
+\setcounter{tocdepth}{2}
+
+\addto\captionsenglish{\renewcommand{\contentsname}{Table of contents}}
+
+\allsectionsfont{\color{bg-color}}

+ 44 - 0
doc/_static/latex/title.tex

@@ -0,0 +1,44 @@
+% LaTeX documentation title page
+%
+% Copyright (c) 2021 Nordic Semiconductor ASA
+% SPDX-License-Identifier: Apache-2.0
+
+\makeatletter
+\newgeometry{top=3cm,left=0cm,right=0cm,bottom=2.5cm}
+
+\backgroundsetup{
+    scale=2.3,
+    contents={\sphinxlogo},
+    opacity=0.2,
+    angle=0,
+    position={0.25\textwidth,-0.4\textheight}
+}
+
+\BgThispage
+
+\begin{minipage}{2cm}
+    \color{bg-color} \rule{2cm}{1.7cm}
+\end{minipage}
+\hspace{0.2cm}
+\begin{minipage}{3cm}
+    \sphinxlogo
+\end{minipage}
+\hspace{0.2cm}
+\begin{minipage}{15cm}
+    \Huge \textbf{\@title}\\
+    \LARGE \py@release\releaseinfo
+\end{minipage}
+
+\vspace{21cm}
+
+\begin{flushright}
+    \begin{minipage}{7cm}
+        \large \@author\\\@date
+    \end{minipage}
+    \begin{minipage}{1.5cm}
+        \color{bg-color} \rule{1.5cm}{1.3cm}
+    \end{minipage}
+\end{flushright}
+
+\restoregeometry
+\makeatother

+ 35 - 0
doc/make.bat

@@ -0,0 +1,35 @@
+@ECHO OFF
+
+pushd %~dp0
+
+REM Command file for Sphinx documentation
+
+if "%SPHINXBUILD%" == "" (
+	set SPHINXBUILD=sphinx-build
+)
+set SOURCEDIR=source
+set BUILDDIR=build
+
+%SPHINXBUILD% >NUL 2>NUL
+if errorlevel 9009 (
+	echo.
+	echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
+	echo.installed, then set the SPHINXBUILD environment variable to point
+	echo.to the full path of the 'sphinx-build' executable. Alternatively you
+	echo.may add the Sphinx directory to PATH.
+	echo.
+	echo.If you don't have Sphinx installed, grab it from
+	echo.https://www.sphinx-doc.org/
+	exit /b 1
+)
+
+if "%1" == "" goto help
+
+%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
+goto end
+
+:help
+%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
+
+:end
+popd

+ 14 - 0
doc/requirements.txt

@@ -0,0 +1,14 @@
+# DOC: used to generate docs
+
+breathe>=4.30,<4.33 # 4.33: disabled due to #803 and #805 issues
+sphinx~=4.0
+sphinx_rtd_theme~=1.0
+sphinx-tabs
+sphinxcontrib-svg2pdfconverter
+pygments>=2.9
+sphinx-notfound-page
+sphinx-copybutton
+
+# markdown
+#recommonmark==0.7.1
+#sphinx-markdown-tables==0.0.17

+ 10 - 0
doc/source/build/index.rst

@@ -0,0 +1,10 @@
+.. _build:
+
+编译和配置系统
+###############
+
+.. toctree::
+   :maxdepth: 1
+
+   make/index.rst
+   kconfig/index.rst

+ 35 - 0
doc/source/build/kconfig/index.rst

@@ -0,0 +1,35 @@
+.. _kconfig:
+
+配置系统(Kconfig)
+=================
+
+Kconfig基本概念
+---------------
+
+蓝牙有非常多的feature,在实际细分的应用领域中,为了节省code size和ram
+size,就要调整一些配置参数。当然有些场景需要修改蓝牙名称之类的行为时,也需要改一些配置参数,这样的灵活性导致蓝牙可配置参数非常多,而且参数之间还有耦合。
+
+如何组织这些参数是一个比较麻烦的问题,zephyr引入了linux的kconfig配置系统,并且zephyr提出了持久化配置的场景,可以确保不同应用使用独立的配置,同时也可以随时修改配置参数。
+
+关于Kconfig的基本概念,可以看\ `从零到一搭建Kconfig配置系统 <https://blog.csdn.net/wenbo13579/article/details/127464764>`__\ 。
+
+配置架构
+--------
+
+Kconfig的总入口在\ ``src/Kconfig``\ 中,由于本项目只为蓝牙服务,所以只有蓝牙系统的配置。
+
+持久化配置
+~~~~~~~~~~
+
+不同应用场景下需要的配置参数各不相同,所以在\ ``example/${APP}/prj.conf``\ 中定义了当前应用的配置参数。
+
+**prj.conf**\ 的生成可以通过\ ``make menuconfig``\ ,修改配置参数后,键入\ ``D``\ ,就会在根目录生成\ ``<home>/defconfig``\ ,这个替换所编写应用的\ **prj.conf**\ 即可。
+
+临时配置
+~~~~~~~~
+
+在写应用时,通常需要动态调整参数,反复改\ **prj.conf**\ 并不是很方便,而且没有图形界面,这时可以通过\ ``make menuconfig``\ 修改,而后键入\ ``S``\ ,就会使用当前配置。
+
+.. note::
+
+    \ ``make clean``\ 后,临时配置会清空,请及时将需要的配置保存到\ **prj.conf**\ 中。

+ 108 - 0
doc/source/build/make/index.rst

@@ -0,0 +1,108 @@
+.. _make:
+
+构建系统(make)
+==============
+
+编译架构
+--------
+
+为了方便移植,本项目是用makefile组织编译的。
+
+根路径的\ ``<home>/Makefile``\ 是总入口,考虑到协议栈、应用层、chipset以及platform之类的有其独特的编译配置,每个模块下面都有\ ``build.mk``\ ,用于配置所需参与编译的代码文件、头文件和所需的库。
+
+如下所示,Home目录的Makefile会依次加载:
+
+-  ``src/build.mk``\ :蓝牙协议栈编译配置。
+
+-  ``example/${APP}/build.mk``\ :根据输入的\ **APP**\ 参数选择example中例程进行编译。
+
+-  ``chipset/${CHIPSET}/build.mk``\ :根据输入的\ **CHIPSET**\ 参数选择chipset中芯片进行编译。
+
+-  ``porting/${PORT}/build.mk``\ :根据输入的\ **PORT**\ 参数选择porting中部署进行编译。
+
+.. code:: 
+
+   zephyr_polling
+    ├── Makefile
+    ├── chipset
+    │   └── ${CHIPSET}
+    │       ├── ...
+    │       └── build.mk
+    ├── example
+    │   └── ${APP}
+    │       ├── ...
+    │       └── build.mk
+    ├── platform
+    │   └── windows
+    │       ├── ...
+    │       └── build.mk
+    ├── porting
+    │   └── ${PORT}
+    │       ├── build.mk
+    │       └── main.c
+    └── src
+        ├── ...
+        └── build.mk
+
+编译参数
+--------
+
+由于蓝牙Dongle的接口、运行平台和例程不相同,为了区分不同的场景,特定应用只编译应用相关的东西,需要用户编译时配置不同的参数。
+
+核心参数
+~~~~~~~~
+
+-  **APP**\ :实际就是去找example/${APP}路径。如配置为\ ``APP=beacon``\ 。
+
+-  **CHIPSET**\ :实际就是去找chipset/${CHIPSET}路径。如配置为\ ``CHIPSET=csr8510``\ 。
+
+-  **PORT**\ :实际就是去找porting/${PORT}路径。如配置为\ ``PORT=windows_libusb_win32``\ 。
+
+GCC参数
+
+**SRC**\ :代码文件路径,需要在各个分模块配置路径。
+
+**INCLUDE**\ :头文件路径,需要在各个分模块配置路径。
+
+**LIB**\ :库文件路径,需要在各个分模块配置路径。
+
+**LFLAGS**\ :库文件名称,需要在各个分模块按需配置。
+
+**CFLAGS**\ :gcc编译的c flags,如优化配置\ ``-O0``\ 。
+
+**LDFLAGS**\ :gcc编译的link
+flags,如\ ``-Wl,--gc-sections -Wl,--check-sections``\ 。
+
+**CPU_ARCH**\ :cpu架构配置,由于windows平台的cpu架构不同,需要应用不同的lib,所以需要特别配置。
+
+其他参数
+~~~~~~~~
+
+**V**\ :调试开关,配置\ ``V=1``\ 可以显示所有make过程的日志,便于调整编译流程。
+
+**NOGC**\ :开启或关闭gcc编译的\ ``gc sections``\ ,配置\ ``NOGC=1``\ 就会关闭\ ``gc sections``\ 。
+
+编译目标
+--------
+
+**all**\ :编译生成执行文件。
+
+**clean**\ :清空中间文件和生成文件。
+
+**help**\ :编译帮助,显示help文档。
+
+**info**\ :打印当前的配置参数。
+
+**run**\ :编译&执行程序。
+
+**code_format**\ :对项目代码进行格式化,格式化配置为:\ ``<home>/.clang-format``
+
+**menuconfig**\ :kconfig的配置界面。
+
+**guiconfig**\ :kconfig的配置界面-另外一个显示方式。
+
+**ram_report**\ :对生成的main.elf进行ram分析,并生成\ ``output/ram.json``\ 。
+
+**rom_report**\ :对生成的main.elf进行rom分析,并生成\ ``output/rom.json``\ 。
+
+**all_report**\ :执行ram_report和rom_report。

+ 450 - 0
doc/source/chipset/index.rst

@@ -0,0 +1,450 @@
+Chipsets
+========
+
+本项目主要实现了蓝牙Host协议栈,并没有包含Controller部分,如果需要实现蓝牙交互,按照Core
+Spec,需要通过HCI接口连接其他蓝牙芯片实现蓝牙功能。
+
+由于HCI接口层是Spec有规定的,所以只要符合HCI接口的设备理论上都可以使用本项目的协议栈实现蓝牙功能。但是各家方案不同,存在一些特殊的配置行为,所以需要根据具体情况具体调整。
+
+如下图所示,通过HCI接口,可以对接CSR/RTK/ATS/Nordic等厂商的蓝牙芯片,从而实现蓝牙功能。
+
+.. figure:: https://markdown-1306347444.cos.ap-shanghai.myqcloud.com/img/image-20221208193337208.png
+   :alt: 
+
+HCI接口
+-------
+
+| 在Sig定义中,Host和Controller通过HCI接口进行通信。HCI协议本身只有5种接口。包括Command、Event、ACL、SCO以及ISO接口。
+| 如下图所示,BLE只支持Command、Event、ACL和ISO数据通道,由于目前项目只完成BLE,并不涉及BLE
+  Audio业务,所以只使用上述的3种接口,分别是:Command、Event和ACL接口。
+
+-  **Command**\ :Host到Controller的单向通道,主要传输Host发送给Controller的控制指令;
+
+-  **Event**\ :Controller到Host的单向通道,主要传输Controller上报给Host的事件;
+
+-  **ACL**\ :双向通道,承载了两个设备之间的数据交互;
+
+-  **ISO**\ :双向通道,承载了两个设备之间的音频数据交互;
+
+.. figure:: https://markdown-1306347444.cos.ap-shanghai.myqcloud.com/img/image-20221208193922536.png
+   :alt: 
+
+HCI包格式
+---------
+
+在Sig提供的\ `Core
+Spec5.3 <https://www.bluetooth.com/specifications/specs/core-specification-5-3/>`__\ 中的Vol4中对HCI层有详细说明,重点说明了各个通道的包格式以及HCI
+command和events。
+
+.. figure:: https://markdown-1306347444.cos.ap-shanghai.myqcloud.com/img/image-20221208194858460.png
+   :alt: 
+
+HCI Command包格式
+~~~~~~~~~~~~~~~~~
+
+.. figure:: https://markdown-1306347444.cos.ap-shanghai.myqcloud.com/img/image-20221208194723153.png
+   :alt: 
+
+HCI Event包格式
+~~~~~~~~~~~~~~~
+
+.. figure:: https://markdown-1306347444.cos.ap-shanghai.myqcloud.com/img/image-20221208194705967.png
+   :alt: 
+
+HCI ACL包格式
+~~~~~~~~~~~~~
+
+.. figure:: https://markdown-1306347444.cos.ap-shanghai.myqcloud.com/img/image-20221208194743750.png
+   :alt: 
+
+.. figure:: https://markdown-1306347444.cos.ap-shanghai.myqcloud.com/img/image-20221208194755353.png
+   :alt: 
+
+HCI ISO包格式
+~~~~~~~~~~~~~
+
+.. figure:: https://markdown-1306347444.cos.ap-shanghai.myqcloud.com/img/image-20221208195240829.png
+   :alt: 
+
+.. figure:: https://markdown-1306347444.cos.ap-shanghai.myqcloud.com/img/image-20221208195250336.png
+   :alt: 
+
+.. figure:: https://markdown-1306347444.cos.ap-shanghai.myqcloud.com/img/image-20221208195258443.png
+   :alt: 
+
+HCI接口类型
+-----------
+
+由于物理传输接口的不同,在HCI包格式的基础上,还会加入接口层协议,去固定不同接口类型下HCI数据包如何进行数据收发。
+
+.. _uart接口h4):
+
+UART接口(H4)
+~~~~~~~~~~~~~~
+
+通常也被称之为H4接口,其结构如下所示。
+
+.. figure:: https://markdown-1306347444.cos.ap-shanghai.myqcloud.com/img/image-20221208195528187.png
+   :alt: 
+
+在原本HCI交互的基础上,需要加入1个字节的Packet Type。
+
+也就是说,HCI Reset
+Command,按照Sig来说是\ ``03 0C 00``\ ,通过UART发送时就变成为\ ``01 03 0C 00``\ ,在开始的时候加入了1个字节的Packet
+type。
+
+.. figure:: https://markdown-1306347444.cos.ap-shanghai.myqcloud.com/img/image-20221208195537948.png
+   :alt: 
+
+.. note::
+
+   由于UART接口的不确定性,一般UART接口都会开启流控,不然在大数据吞吐时容易丢包。但是这样的话需要连接的IO就需要5根了,\ ``TX/RX/CTS/RTS/GND``\ 。
+
+.. note::
+
+   由于UART本身没有同步接口,对于SCO等同步数据交互,该接口的体验并不是很好。
+
+.. note::
+
+   UART接口一般需要确认串口号,波特率,流控等参数,这些参数根据不同厂商有不同的定义。在不开启流控的芯片中可以不接CTS/RTS接口。
+
+.. _3线uart接口h5):
+
+3线UART接口(H5)
+~~~~~~~~~~~~~~~~~
+
+一般的UART接口加上流控就有\ ``TX/RX/CTS/RTS/GND``\ 5个IO了,对于资源有限的场景,IO很多时候并不充裕,并且就算加上流控,当UART接口收到错误数据时,依然无法实现重传,进而整个协议栈就崩溃了。
+
+考虑到这个情况,Sig提出了既省IO,又有流控、重传和唤醒功能的\ **H5**\ 接口。通过在UART接口上加上一层协议来实现这一功能需要。该方案只需要\ ``TX/RX/GND``\ 三个IO,所以又称之为3线UART。
+
+其架构如下,通过协议来保证数据交互的可靠性。具体可以看Core Spec。
+
+.. figure:: https://markdown-1306347444.cos.ap-shanghai.myqcloud.com/img/image-20221208200444004.png
+   :alt: 
+
+H5协议的功能较为完善,但是其实现较为复杂,占用系统资源不少,对系统可靠性和资源有限场景会使用该协议。
+
+.. _usb接口h2):
+
+USB接口(H2)
+~~~~~~~~~~~~~
+
+目前市面上大多数HCI
+Dongle都是使用这一接口协议,借助于USB接口的高速和可靠性,完全可以满足HCI数据/音频传输要求。实际的PC蓝牙Dongle设备很多都是使用USB接口。
+
+在spec中规定了USB接口行为,Host一般作为USB Host端,Controller为USB
+Controller。
+
+.. figure:: https://markdown-1306347444.cos.ap-shanghai.myqcloud.com/img/image-20230103160944400.png
+   :alt: 
+
+两个USB Dongle设备的交互框图如下所示。
+
+.. figure:: https://markdown-1306347444.cos.ap-shanghai.myqcloud.com/img/image-20230103161054215.png
+   :alt: 
+
+USB接口关键就是数据交互的端点配置,针对于蓝牙HCI接口的特点,SPEC定义了多种接口来分别承载不同类型的数据交互。
+
+如下所示,Command通过0x00的Control
+Endpoint传输,Event数据包通过0x81的Interrupt
+Endpoint传输,ACL数据包通过0x82和0x02的Buck接口进行传输。
+
+.. figure:: https://markdown-1306347444.cos.ap-shanghai.myqcloud.com/img/image-20230103161719636.png
+   :alt: 
+
+音频传输通过Isoch端口传输,此外又根据不同的同步传输格式,固定了不同的接口行为。
+
+.. figure:: https://markdown-1306347444.cos.ap-shanghai.myqcloud.com/img/image-20230103161942944.png
+   :alt: 
+
+.. figure:: https://markdown-1306347444.cos.ap-shanghai.myqcloud.com/img/image-20230103161959635.png
+   :alt: 
+
+在本项目中,也是按照Spec规定了完成和USB设备的数据交互,详见:\ ``platform/windows/windows_driver_libusb.c``\ 。
+
+.. figure:: https://markdown-1306347444.cos.ap-shanghai.myqcloud.com/img/image-20230103162233842.png
+   :alt: 
+
+
+.. note::
+
+   在嵌入式产品中,由于嵌入式主芯片资源受限,一般而言都是使用UART接口,部分场景下会使用SPI/SDIO接口。
+
+SD接口
+~~~~~~
+
+基于SDIO接口来完成HCI数据交互。
+
+其架构如下,由于笔者实际项目也没怎么用,就不在多数,实际使用看芯片手册定义,基本都会按照SPEC来配置接口。
+
+.. figure:: https://markdown-1306347444.cos.ap-shanghai.myqcloud.com/img/image-20230103162513561.png
+   :alt: 
+
+H4 over SPI
+~~~~~~~~~~~
+
+UART接口需要确定的波特率,对于一些高速需求并不是很好满足,并且可移植性相对较差。SPI接口由master提供时钟,无需预先知道两边的波特率配置即可进行通信。
+
+目前ST主推的是SPI接口的HCI Controller,详见\ `BlueNRG-2 -
+蓝牙低功耗无线单芯片 -
+STMicroelectronics <https://www.st.com/zh/wireless-connectivity/bluenrg-2.html>`__\ 。
+
+由于笔者基本没有用过这个接口,并且这个接口在Spec并未定义,所以也不具体展开,具体使用到特定芯片时,按照产商的要求使用即可。
+
+芯片启动配置
+------------
+
+目前市面上的HCI
+Dongle产品大多数并不能拿来直接使用,也就是说在用标准的HCI指令控制设备进行蓝牙操作之前,需要提前通过Vendor
+Command对设备进行配置,只有正确配置好的设备才能正常使用。
+
+为什么厂商不将设备配置为上电就能完成HCI蓝牙交互行为呢,反而需要配置这么多参数呢,这样并不利于用户使用。
+
+从产商角度来看。类似于HCI
+Dongle之类的产品一般而言是由芯片产商提供固件预烧录在芯片中,而芯片产商只出售芯片,并不关注外围电路和具体的产品形态,这些是具体的ODM厂商来实现的。也就是芯片产商提供带HCI蓝牙功能的芯片,ODM设计电路并设计产品,之后通过HCI和芯片进行交互。实际各家ODM产商的需求各不相同,芯片产商为了满足不同客户的需要,并且为了减少和客户的对接,就必然在同一套代码的基础上,需要提供一系列的配置参数来满足不同ODM厂商的需要。
+
+从使用角度来看。首先一点,像HCI
+Dongle这类产品一方面是提供给专业用户使用,如开发人员等,这些人使用之前必然要查看产商的手册进行配置;而像蓝牙适配器这类产品对应的PC都有相应的驱动程序,用户安装产商提供的驱动程序就可以正常使用产品,驱动程序屏蔽了HCI接口,也完成了相关配置。也就是说这样的行为并不影响绝大多数用户的使用。
+
+根据各家芯片产商的情况,所需配置的参数和种类各不相同,下面对一些参数配置进行说明。
+
+.. note::
+
+   由于嵌入式资源有限,现有市面上的产品基本都是通过HCI的Vendor
+   Cmd/Event接口来实现对设备的参数配置行为。
+
+固件烧录
+~~~~~~~~
+
+以Realtek为典型,这类芯片产品的代码基本都存储在ROM中,一个品类的产品ROM在芯片TO阶段就已经固定下来了,之后需要修改BUG或者加新功能时,就需要重新调整ROM,这样芯片产商需要维护的成本过高,并且不同应用场景所需的代码并不相同,所有都放入ROM中会导致芯片成本过大。
+
+那么其芯片结构基本为ROM+Patch形式,Patch如果存储在Flash之类的形态中,对于终端用户其实也无感,使用之前预烧录好特定的Patch即可(Nordic/ST/Actions之类都有Flash)。可是以Realtek/CSR的厂商所提供的芯片并没有Flash,而是有一个较大的Patch
+RAM,由于RAM掉电后就会丢失,所以在每次上电时都需要通过HCI将最新的固件下载到Patch
+RAM中,不然默认出厂的ROM大多数情况下是工作异常的。
+
+Patch RAM的形式虽然省却了Flash的成本,但是在低功耗产品时,由于Patch
+RAM一般都不小,其功耗普遍较高。并且RAM都是芯片成本,在设计之初就定好了,太大成本过高/功耗过高。太小的话能满足的应用场景就较少。
+
+同时由于每次掉电都需要烧录新的固件,要使用蓝牙功能之前准备时间都是百ms级别,对一些特定应用场景需要还是有点繁琐的。
+
+蓝牙地址配置
+~~~~~~~~~~~~
+
+由于蓝牙地址都是需要向Sig花钱买的,有一些芯片厂商(ST/CSR)将这部分成本转嫁到ODM和终端用户上(很多时候ODM和终端用户也并不会付费,由于他们体量较小,Sig一般也追不回这些费用)。基于这一实际需求,芯片产商会提供一个Vendor
+Command专门来实现蓝牙地址的配置,美曰其名给用户配置权利,实际大家懂的都懂。
+
+硬件接口配置
+~~~~~~~~~~~~
+
+如RF接口,晶振类型等,CSR的需要配置这些,如当前的RF接口的配置,系统时钟源,低功耗时钟源等硬件接口的配置,这个大厂灵活性较大,所需配置的东西就较多,大多数产品形态基本不需要管这些。
+
+串口波特率配置
+~~~~~~~~~~~~~~
+
+大多数是UART接口,一般默认都是运行在115200的配置下,但是这个速度太慢了,有时需要切换成更高的波特率。
+
+其他参数配置
+~~~~~~~~~~~~
+
+按照厂商手册需要配置即可。
+
+无需配置
+~~~~~~~~
+
+对于有Flash的芯片,如(Nordic/ST/Actions)等产商的芯片,完全可以将配置参数和Patch
+Code预烧录到Flash中,使用时完全不需要配置任何参数,直接通过HCI接口操作使用即可。
+
+芯片BOOT操作接口
+----------------
+
+zephyr_polling协议栈需要满足不同芯片的使用需要,而这些不同产商的特殊配置需要放在协议栈内部并不方便,并且也不利于后期用户添加新的chipset。从上述分析已经知道现在市面上芯片的启动配置需求,所以围绕于这些功能需要,项目提供了Boot流程接口和Prepare流程接口。
+
+系统启动流程如下,先进行Boot流程,之后下发HCI Reset
+Command,而后进行Prepare流程,最后进行常规的HCI boot流程。
+
+整个协议栈的HCI初始化流程是通过状态机来管理的,通过\ ``hci_state_polling()``\ 轮询进行调度,chipset通过\ ``bt_hci_chipset_driver_register()``\ 注册操作接口。
+
+.. figure:: https://markdown-1306347444.cos.ap-shanghai.myqcloud.com/img/image-20230103191652806.png
+   :alt: 
+
+Boot流程接口
+~~~~~~~~~~~~
+
+用于完成厂商的初始化流程,如固件下载,蓝牙地址配置等。
+
+chipset注册好接口后,协议栈启动时会通过\ ``boot_start()``\ 回调启动chipset的boot流程,由于操作接口是HCI,所以一般都是下发一个Vendor
+Command,然后根据Vendor
+Event来进行后续动作,协议栈会通过\ ``event_process()``\ 回调接口将收到的event上报给chipset,当chipset认为操作结束时,通过调用\ ``bt_hci_set_boot_ready()``\ 接口通知协议栈boot流程结束。
+
+Prepare流程接口
+~~~~~~~~~~~~~~~
+
+照理说Boot流程已经完成了厂商的参数配置等工作,为什么还需要定义一个Prepare流程呢?这是因为类似于ST厂商的参数要求在HCI_Reset
+Command之后进行,也就是说HCI_Reset Command会清空配置的参数。
+
+所以为了兼容这类参数形态,HCI_Reset
+Command之后还需要进行Prepare流程,协议栈收到HCI_Reset的Command Complete
+Event后会通过\ ``prepare_start()``\ 回调启动chipset的Prepare流程,和boot流程一样,协议栈会通过\ ``event_process()``\ 回调接口将收到的event上报给chipset,当chipset认为操作结束时,通过调用\ ``bt_hci_set_prepare_ready()``\ 接口通知协议栈prepare流程结束。
+
+支持芯片列表
+------------
+
+协议栈在不断完善中,后续会陆续加入更多支持的芯片,大家需要的话可以购买所需的Dongle来验证本项目协议栈,当然也可以在自家的芯片上,实现chipset接口,来玩本项目。
+
++-------------------+-------------------+------+----------+-----------+
+| 厂商              | chipset           | 接口 | 蓝牙版本 | 类型      |
++===================+===================+======+==========+===========+
+| `CSR <https://www | `csr8510 <ht      | USB  | 4.0      | Dual Mode |
+| .qualcomm.cn/>`__ | tps://detail.tmal |      |          |           |
+|                   | l.com/item.htm?ab |      |          |           |
+|                   | bucket=2&id=53466 |      |          |           |
+|                   | 2513906&ns=1&spm= |      |          |           |
+|                   | a230r.1.14.1.2f68 |      |          |           |
+|                   | 11a37qFFQU&skuId= |      |          |           |
+|                   | 4910946697067>`__ |      |          |           |
++-------------------+-------------------+------+----------+-----------+
+| `CSR <https://www | `csr89            | UART | 4.0      | Dual Mode |
+| .qualcomm.cn/>`__ | 10 <https://item. |      |          |           |
+|                   | taobao.com/item.h |      |          |           |
+|                   | tm?spm=a1z09.2.0. |      |          |           |
+|                   | 0.6cd22e8dj2naR0& |      |          |           |
+|                   | id=622836061708&_ |      |          |           |
+|                   | u=3m1kbkea372>`__ |      |          |           |
++-------------------+-------------------+------+----------+-----------+
+| `炬芯-Actio       | `ats2851 <ht      | USB  | 5.3      | Dual Mode |
+| ns <http://www.ac | tps://detail.tmal |      |          |           |
+| tions.com.cn/>`__ | l.com/item.htm?ab |      |          |           |
+|                   | bucket=2&id=53466 |      |          |           |
+|                   | 2513906&ns=1&spm= |      |          |           |
+|                   | a230r.1.14.1.2f68 |      |          |           |
+|                   | 11a37qFFQU&skuId= |      |          |           |
+|                   | 5111551883875>`__ |      |          |           |
++-------------------+-------------------+------+----------+-----------+
+| `Nordi            | `pts_dong         | UART | 5.3      | LE Only   |
+| c <https://www.no | le <https://item. |      |          |           |
+| rdicsemi.com/>`__ | taobao.com/item.h |      |          |           |
+|                   | tm?spm=a1z09.2.0. |      |          |           |
+|                   | 0.6cd22e8dj2naR0& |      |          |           |
+|                   | id=622836061708&_ |      |          |           |
+|                   | u=3m1kbkea372>`__ |      |          |           |
++-------------------+-------------------+------+----------+-----------+
+
+芯片厂商配置说明
+----------------
+
+.. _csr--qualcomm-incorporated:
+
+CSR / Qualcomm Incorporated
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+CSR目前已经被高通收购了,但是市面上还有蛮多CSR的Dongle在卖。
+
+市面上卖得比较多,有一套csr得命令,叫做《BCCMD Protocol》,利用里面的PS
+Command中《PSKEY_BDADDR》设置蓝牙地址。
+
+.. figure:: https://markdown-1306347444.cos.ap-shanghai.myqcloud.com/img/image-20230103193830348.png
+   :alt: 
+
+.. figure:: https://markdown-1306347444.cos.ap-shanghai.myqcloud.com/img/image-20230103193849093.png
+   :alt: 
+
+csr8510
+^^^^^^^
+
+市面买到的蓝牙适配器很多是这个。USB接口。
+
+**Boot流程**\ ,主要完成如下操作:关闭NOP;设置蓝牙地址;warn重启。
+
+**Prepare流程**\ ,None。
+
+csr8910
+^^^^^^^
+
+市面买到的蓝牙适配器很多是这个。USB接口。
+
+**Boot流程**\ ,主要完成如下操作:模拟参数配置;关闭NOP;启动串口流控;设置蓝牙地址;warn重启。
+
+**Prepare流程**\ ,None。
+
+ST
+~~
+
+ST推出了一套叫BlueNRG的ble东西,按照其官方推荐,到淘宝上分别买《X-NUCLEO-BNRG2A1》和《NUCLEO-L476RG》
+开发板。
+
+《X-NUCLEO-BNRG2A1》预烧录了BLE+SPI的程序。
+
+《NUCLEO-L476RG》
+按照下图,烧录一个Virtual_COM_Port的程序,就可以在PC上通过Uart控制蓝牙芯片了。
+
+默认其推荐的是用《BlueNRG GUI》来控制。
+
+ST的《X-NUCLEO-BNRG2A1》中的BLE本身是一个SOC,里面集成了Host的协议栈,ST提供了一套ACI指令来控制芯片行为,包括host的接口。
+
+也就是说默认的情况下,这个芯片的ACL交互都被芯片接管了,所以需要通过ACI命令,关闭Host行为。必须通过《aci_hal_write_config_data》将《LL_WITHOUT_HOST》关闭。
+
+public地址通过必须通过《aci_hal_write_config_data》将《CONFIG_DATA_PUBADDR_OFFSET》配置蓝牙地址。
+
+.. note::
+
+   官方提供的Virtual_COM_Port代码并不支持将ACL转发的功能,此外在压力测试时,由于其代码写的可靠性不高,会有丢包等问题,需要自己把这块串口接收转发的代码逻辑给修改掉。
+
+.. figure:: https://markdown-1306347444.cos.ap-shanghai.myqcloud.com/img/image-20230103194728104.png
+   :alt: 
+
+.. figure:: https://markdown-1306347444.cos.ap-shanghai.myqcloud.com/img/image-20230103194746236.png
+   :alt: 
+
+CSR目前已经被高通收购了,但是市面上还有蛮多CSR的Dongle在卖。
+
+市面上卖得比较多,有一套csr得命令,叫做《BCCMD Protocol》,利用里面的PS
+Command中《PSKEY_BDADDR》设置蓝牙地址。
+
+.. figure:: https://markdown-1306347444.cos.ap-shanghai.myqcloud.com/img/image-20230103193830348.png
+   :alt: 
+
+.. figure:: https://markdown-1306347444.cos.ap-shanghai.myqcloud.com/img/image-20230103193849093.png
+   :alt: 
+
+BlueNRG-2
+^^^^^^^^^
+
+LE Only的SOC,第二代产品,需要在其原本代码上进行修改进行使用。
+
+**Boot流程**\ ,None。
+
+**Prepare流程**\ ,蓝牙地址配置;关闭Host功能;设置TX
+power;GATT配置;GAP配置。
+
+Nordic
+~~~~~~
+
+nordic作为行业龙头,其芯片是全Flash的芯片,其并没有出专门的蓝牙适配器,但是市面上还是能购买到一些用他们家产品做的的HCI
+Dongle,并且Sig也用NRF52840做了PTS Dongle,用于Host的认证。
+
+nordic的蓝牙地址是每个芯片唯一,厂商预先配置好了(没细的研究)。
+
+PTS Dongle
+^^^^^^^^^^
+
+Sig用NRF52840做的一个HCI
+Dongle,可以说是最标准蓝牙行为的蓝牙Dongle了。所有的参数都是在Flash配置好的,直接使用即可。每个芯片有独立的蓝牙地址。
+
+**Boot流程**\ ,None。
+
+**Prepare流程**\ ,None。
+
+炬芯-Actions
+~~~~~~~~~~~~
+
+通过绿联的5.3 Dongle认识的,。
+
+ats2851
+^^^^^^^
+
+绿联在卖的5.3
+Dongle,应该也是Flash版本的芯片,每个设备的蓝牙地址都是唯一的,无需配置。
+
+**Boot流程**\ ,None。
+
+**Prepare流程**\ ,None。

+ 76 - 0
doc/source/conf.py

@@ -0,0 +1,76 @@
+# Configuration file for the Sphinx documentation builder.
+#
+# This file only contains a selection of the most common options. For a full
+# list see the documentation:
+# https://www.sphinx-doc.org/en/master/usage/configuration.html
+
+# -- Path setup --------------------------------------------------------------
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#
+# import os
+# import sys
+# sys.path.insert(0, os.path.abspath('.'))
+import sys
+import os
+from pathlib import Path
+import re
+
+ZEPHYR_BASE = Path(__file__).resolve().parents[1]
+
+# -- Project information -----------------------------------------------------
+
+project = 'Zephyr_polling'
+copyright = '2022, CoderBob'
+author = 'CoderBob'
+
+# The full version, including alpha/beta/rc tags
+release = 'v1'
+
+
+# -- General configuration ---------------------------------------------------
+
+# Add any Sphinx extension module names here, as strings. They can be
+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
+# ones.
+extensions = [
+#    'recommonmark',
+#    'sphinx_markdown_tables',
+    "sphinx_tabs.tabs",
+    "sphinx.ext.todo",
+    "sphinx.ext.extlinks",
+    "sphinx.ext.autodoc",
+    "sphinx.ext.graphviz",
+]
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#
+# This is also used if you do content translation via gettext catalogs.
+# Usually you set "language" from the command line for these cases.
+language = 'zh_CN'
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+# This pattern also affects html_static_path and html_extra_path.
+exclude_patterns = []
+
+
+# -- Options for HTML output -------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages.  See the documentation for
+# a list of builtin themes.
+#
+html_theme = 'sphinx_rtd_theme'
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = [str(ZEPHYR_BASE / "_static")]
+
+html_title = "Zephyr_polling项目文档"

+ 219 - 0
doc/source/develop/application/index.rst

@@ -0,0 +1,219 @@
+应用说明
+========
+
+简介
+----
+
+本项目的编译环境是基于make来编译的。
+
+蓝牙本身有各种各样的场景的业务,不同业务场景的功能需求各不相同,为了满足不同场景的需要,并确保资源有限的设备在特殊场景下使用足够少的Code
+Size和RAM Size,项目提供了丰富的配置参数,来实现相关功能代码的开关。
+
+为了方便用户理解本项目,编译是以\ **example**\ 中的例程为中心的,每个例程都有不同的配置参数和业务代码。通过学习这些例程,便于用户快速掌握如何使用本项目的API和Kconfig配置系统。
+
+本文具体对\ **应用**\ 设计和实现进行说明。
+
+本项目所有的\ **应用**\ 都在\ **example**\ 目录中,通常的目录结构如下:
+
+.. code:: bash
+
+   <home>/example/xxx
+    ├── prj.conf(应用层Kconfig配置)
+    ├── build.mk(编译系统所需)
+    └── app_main.c(程序代码)
+
+**prj.conf**\ :Kconfig持久化设计,关于Kconfig的设计可以看 :ref:`kconfig`,每个应用可以根据需要单独配置,修改这个会最终影响生成的\ **autoconfig.h**\ ,也就是蓝牙协议栈编译出来的Code和RAM。
+
+**build.mk**\ :根目录的makefile会引用这个文件,这里需要配置\ **应用**\ 所需编译的文件和头文件路径。
+
+**app_main.c**\ :应用层代码,文件名并没有特别指定,但是需要在build.mk中引用。
+
+新增应用
+--------
+
+按照下面的流程可以创建一个你自己的\ **应用**\ 。
+
+创建应用目录
+~~~~~~~~~~~~
+
+到example目录下,创建一个自己感兴趣的目录即可,可以通过GUI创建当然也可以通过命令行创建。
+
+如:创建一个名为\ **app_test**\ 的工程。后续已这个例程为例进行介绍。
+
+.. code:: bash
+
+   mkdir app_test
+
+.. _创建appmainc:
+
+创建app_main.c
+~~~~~~~~~~~~~~
+
+到\ **app_test**\ 目录下,创建\ ``app_main.c``\ 即可,由于本项目主要实现蓝牙功能,所以所有例程都会开启蓝牙功能,项目的入口函数也不再是\ ``main``\ 函数,而是\ ``bt_ready``\ 函数。
+
+**bt_ready**\ :是蓝牙开启结束的回调函数,在porting中的\ ``main.c``\ 调用。
+
+**app_polling_work**\ :是平台提供给应用层的轮询函数,注意这里不能写\ ``while(1)``\ ,只能写一些轮询业务,在porting中的\ ``main.c``\ 中有个\ ``while(1)``\ 函数周期调用。
+
+**printk**\ :是平台提供的日志打印函数,所有的日志都需要使用本接口,不能使用\ ``printf``\ ,不然一些日志记录之类的功能可能不好用。
+
+.. code:: c
+
+   #include <logging/bt_log_impl.h>
+
+   void bt_ready(int err)
+   {
+       if (err)
+       {
+           printk("Bluetooth init failed (err %d)\n", err);
+           return;
+       }
+
+       printk("Bluetooth initialized\n");
+   }
+
+   void app_polling_work(void)
+   {
+       return;
+   }
+
+.. _创建buildmk:
+
+创建build.mk
+~~~~~~~~~~~~
+
+这个比较简单,就是配置\ ``SRC``\ 代码路径、\ ``INCLUDE``\ 头文件路径以及\ ``LIB``\ 库路径(应用层一般不建议使用,由于平台异构,lib使用会比较麻烦。)
+
+需要注意的是\ ``APP_PATH``\ ,这个是编译系统提供的当前应用的路径,也就是\ ``example/app_test``\ ,新加的路径必须加这个根路径参数。
+
+.. code:: makefile
+
+   # define source directory
+   SRC		+= $(APP_PATH)
+
+   # define include directory
+   INCLUDE	+= $(APP_PATH)
+
+   # define lib directory
+   LIB		+=
+
+.. _创建prjconf:
+
+创建prj.conf
+~~~~~~~~~~~~
+
+这个要理解需要去看懂 :ref:`kconfig`,默认情况下我们只需要开启日志功能和蓝牙功能即可,其他的可以通过\ ``make menuconfig``\ ,修改配置后,用\ ``D``\ 保存差异,生成在根目录的\ ``defconfig``\ 文件就是所需的\ ``prj.conf``\ 。
+
+.. code:: 
+
+   CONFIG_BT=y
+   CONFIG_BT_DEBUG_LOG=y
+
+编译应用
+~~~~~~~~
+
+上述操作完成后,目录结构如下:
+
+.. code:: 
+
+   <home>/example/app_test
+    ├── prj.conf
+    ├── build.mk
+    └── app_main.c
+
+这时可以通过调整make传入的APP参数来使用本应用程序,键入该指令就可以完成对APP的编译。
+
+.. code:: bash
+
+   make all APP=app_test
+
+运行应用
+~~~~~~~~
+
+生成的执行文件在output目录下,直接执行即可,Windows下的执行效果如下:
+
+可以看到启动蓝牙后,就什么都没干了。
+
+.. code:: 
+
+   PS D:\worksplace\github\zephyr_polling> .\output\main.exe
+   [2022-12-07 11:06:12.194] [0xb8bc] display_devices(), idVendor: 0xbda, idProduct: 0x8771
+   [2022-12-07 11:06:12.196] [0xb8bc] display_devices(), idVendor: 0x10d7, idProduct: 0xb012
+   [2022-12-07 11:06:12.198] [0xb8bc] display_devices(), idVendor: 0xa12, idProduct: 0x1
+   [2022-12-07 11:06:12.200] [0xb8bc] success: set configuration #1
+   [2022-12-07 11:06:12.202] [0xb8bc] success: claim_interface #0
+   [2022-12-07 11:06:12.205] [0x77dc] tx_process_loop
+   [2022-12-07 11:06:12.205] [0xca8c] rx_evt_process_loop
+   [2022-12-07 11:06:12.205] [0xb8bc] hci_driver_open()
+   [2022-12-07 11:06:12.209] [0xb8bc] I: (bt_hci_core)hci_init():3220: work start.
+   [2022-12-07 11:06:12.211] [0xb8bc] CMD =>  00 FC 13 C2 02 00 09 00 02 00 03 70 00 00 F2 00 01 00 08 00 01 00
+   [2022-12-07 11:06:13.241] [0xb8bc] EVT <=  FF 13 C2 01 00 09 00 02 00 03 70 00 00 F2 00 01 00 08 00 01 00
+   [2022-12-07 11:06:13.247] [0xb8bc] CMD =>  00 FC 19 C2 02 00 0C 00 08 00 03 70 00 00 01 00 04 00 08 00 44 00 66 55 33 00 22 11
+   [2022-12-07 11:06:13.254] [0xb8bc] EVT <=  FF 19 C2 01 00 0C 00 08 00 03 70 00 00 01 00 04 00 08 00 44 00 66 55 33 00 22 11
+   [2022-12-07 11:06:13.258] [0xb8bc] CMD =>  00 FC 13 C2 02 00 09 00 09 00 02 40 00 00 00 00 00 00 00 00 00 00
+   [2022-12-07 11:06:13.258] [0xc71c] reset_driver_process, wait usb reboot.
+   [2022-12-07 11:06:13.264] [0x77dc] error tx:
+   libusb0-dll:err [control_msg] sending control message failed, win error: 连到系统上的设备没有发挥作用。
+
+
+   [2022-12-07 11:06:18.270] [0xc71c] reset_driver_process, usb reboot ready.
+   [2022-12-07 11:06:18.272] [0xca8c] error reading:
+   libusb0-dll:err [submit_async] submitting request failed, win error: 设备不识别此命令。
+
+   [2022-12-07 11:06:18.381] [0xca8c] rx_evt_process_loop end
+   [2022-12-07 11:06:18.384] [0xc71c] display_devices(), idVendor: 0xa12, idProduct: 0x1
+   [2022-12-07 11:06:18.386] [0xc71c] display_devices(), idVendor: 0xbda, idProduct: 0x8771
+   [2022-12-07 11:06:18.388] [0xc71c] display_devices(), idVendor: 0x10d7, idProduct: 0xb012
+   [2022-12-07 11:06:18.390] [0xc71c] success: set configuration #1
+   [2022-12-07 11:06:18.392] [0xc71c] success: claim_interface #0
+   [2022-12-07 11:06:18.394] [0xb8bc] CMD =>  03 0C 00
+   [2022-12-07 11:06:18.394] [0x130c] tx_process_loop
+   [2022-12-07 11:06:18.394] [0xbddc] rx_evt_process_loop
+   [2022-12-07 11:06:19.559] [0xb8bc] CMD =>  02 10 00
+   [2022-12-07 11:06:19.568] [0xb8bc] EVT <=  0E 44 01 02 10 00 FF FF FF 03 FE FF FF FF FF FF FF FF F3 0F E8 FE 3F F7 83 FF 1C 00 00 00 61 F7 FF FF 7F 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+   [2022-12-07 11:06:19.578] [0xb8bc] CMD =>  03 20 00
+   [2022-12-07 11:06:19.581] [0xb8bc] EVT <=  0E 0C 01 03 20 00 01 00 00 00 00 00 00 00
+   [2022-12-07 11:06:19.583] [0xb8bc] CMD =>  6D 0C 02 01 00
+   [2022-12-07 11:06:19.587] [0xb8bc] EVT <=  0E 04 01 6D 0C 00[2022-12-07 11:06:19.590] [0xb8bc] CMD =>  01 20 08 02 00 00 00 00 00 00 00
+   [2022-12-07 11:06:19.595] [0xb8bc] EVT <=  0E 04 01 01 20 00
+   [2022-12-07 11:06:19.596] [0xb8bc] CMD =>  01 0C 08 00 80 00 02 00 00 00 20
+   [2022-12-07 11:06:19.600] [0xb8bc] EVT <=  0E 04 01 01 0C 00
+   [2022-12-07 11:06:19.602] [0xb8bc] CMD =>  09 10 00
+   [2022-12-07 11:06:19.608] [0xb8bc] EVT <=  0E 0A 01 09 10 00 66 55 44 33 22 11
+   [2022-12-07 11:06:19.610] [0xb8bc] I: (bt_hci_core)hci_init_end():3195: work end.
+   [2022-12-07 11:06:19.612] [0xb8bc] I: (bt_hci_core)bt_dev_show_info():2998: Identity: 11:22:33:44:55:66 (public)
+   [2022-12-07 11:06:19.614] [0xb8bc] I: (bt_hci_core)bt_dev_show_info():3030: HCI: version 4.0 (0x06) revision 0x22bb, manufacturer 0x000a
+   [2022-12-07 11:06:19.617] [0xb8bc] I: (bt_hci_core)bt_dev_show_info():3033: LMP: version 4.0 (0x06) subver 0x22bb
+   [2022-12-07 11:06:19.623] [0xb8bc] Bluetooth initialized
+
+应用调试
+--------
+
+编译系统除了生成执行文件外,还会生成反编译文件以及map文件,以便用户对代码进行分析。
+
+生成的目录结构如下所示。
+
+.. code:: 
+
+   <home>/output
+    ├── log
+    │   ├── log.cfa
+    │   └── log.txt
+    ├── main.bin
+    ├── main.exe
+    ├── main.lst
+    └── main.map
+
+GDB调试
+~~~~~~~
+
+编译的工程都开启了\ **-g**\ 选项,所以可以直接通过\ **GDB**\ 进行调试,也可以自己根据具体需要使用VSCODE或者其他IDE来用GDB调试。
+
+日志调试
+~~~~~~~~
+
+在交互终端中,可以会打印核心的日志信息。
+
+此外除了实时打印外,项目还会在\ ``output/log``\ 目录下保存日志文件。其中终端显示的交互日志保存为\ **log.txt**\ ;交互的hci数据包会保存为\ ``btsnoop``\ 格式的文件\ **log.cfa**\ 。
+
+默认打印的日志只是开启了INFO级别以上的日志,如果需要看所有日志,可以在\ ``prj.conf``\ 中加入,初期学习的时候可以通过开启\ ``CONFIG_BT_LOG_LEVEL_DBG=y``\ 来显示所有日志来学习代码。

+ 276 - 0
doc/source/develop/getting_started/index.rst

@@ -0,0 +1,276 @@
+快速开始
+========
+
+简介
+----
+
+通过本文可以实现:
+
+-  配置基于Windows/Ubuntu系统的命令行开发环境。
+
+-  获取源代码
+
+-  运行Zephyr_polling项目
+
+安装软件环境
+------------
+
+为了方便大家移植,本项目都是用makefile来组织编译的,一些脚本通过python来实现,所以系统主要安装好make环境和python环境即可运行本项目。
+
+GCC环境
+~~~~~~~
+
+参考这个文章安装即可。\ `Win7下msys64安装mingw工具链 - Milton - 博客园
+(cnblogs.com) <https://www.cnblogs.com/milton/p/11808091.html>`__
+
+安装完以后,键入\ ``gcc -v``\ ,得到如下提示说明环境安装好了,目前笔者用的是mingw32的gcc。
+
+.. figure:: https://img-blog.csdnimg.cn/img_convert/e0f445cdb5fc3174219e763cfdc71194.png
+   :alt: 
+
+`Python环境 <https://www.python.org/>`__
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+脚本/Kconfig都是python运行环境,为了方便,本项目是用python3环境。
+
+网上有很多配置python环境教程了,\ `Python安装教程-史上最全\ 壬杰的博客-CSDN博客\ python安装教程 <https://blog.csdn.net/weixin_49237144/article/details/122915089>`__\ 安装可以参考这个,当然也可以直接到\ `Welcome
+to Python.org <https://www.python.org/>`__\ 下载。
+
+最终安装结束后,键入\ ``python -V``\ ,能看到python版本,代表环境安装好了。
+
+.. figure:: https://img-blog.csdnimg.cn/img_convert/02f37e912230aa160c7310234e82579e.png
+   :alt: 
+
+Python依赖环境
+~~~~~~~~~~~~~~
+
+Python运行过程中,需要安装一些module,所需的环境都在\ ``python_require_env.py``\ 配置好了,只要运行下该脚本,即可安装好python依赖环境。
+
+.. code:: bash
+
+
+   D:\worksplace\github\zephyr_polling>python python_require_env.py
+   Requirement already satisfied: pyelftools~=0.29 in c:\users\wenbo\appdata\local\programs\python\python310\lib\site-packages (from -r scripts/footprint/requirements.txt (line 1)) (0.29)
+   Requirement already satisfied: anytree~=2.8.0 in c:\users\wenbo\appdata\local\programs\python\python310\lib\site-packages (from -r scripts/footprint/requirements.txt (line 2)) (2.8.0)
+   Requirement already satisfied: six>=1.9.0 in c:\users\wenbo\appdata\local\programs\python\python310\lib\site-packages (from anytree~=2.8.0->-r scripts/footprint/requirements.txt (line 2)) (1.16.0)
+
+   [notice] A new release of pip available: 22.2.2 -> 22.3.1
+   [notice] To update, run: python.exe -m pip install --upgrade pip
+   Requirement already satisfied: kconfiglib~=14.1.0 in c:\users\wenbo\appdata\local\programs\python\python310\lib\site-packages (from -r scripts/kconfig/requirements.txt (line 1)) (14.1.0)
+   Requirement already satisfied: windows-curses~=2.3.0 in c:\users\wenbo\appdata\local\programs\python\python310\lib\site-packages (from -r scripts/kconfig/requirements.txt (line 2)) (2.3.0)
+
+   [notice] A new release of pip available: 22.2.2 -> 22.3.1
+   [notice] To update, run: python.exe -m pip install --upgrade pip
+   Requirement already satisfied: Sphinx==5.1.1 in c:\users\wenbo\appdata\local\programs\python\python310\lib\site-packages (from -r doc/requirements.txt (line 1)) (5.1.1)
+   Requirement already satisfied: recommonmark==0.7.1 in c:\users\wenbo\appdata\local\programs\python\python310\lib\site-packages (from -r doc/requirements.txt (line 2)) (0.7.1)
+   Requirement already satisfied: sphinx-markdown-tables==0.0.17 in c:\users\wenbo\appdata\local\programs\python\python310\lib\site-packages (from -r doc/requirements.txt (line 3)) (0.0.17)
+   Requirement already satisfied: sphinx-rtd-theme==1.0.0 in c:\users\wenbo\appdata\local\programs\python\python310\lib\site-packages (from -r doc/requirements.txt (line 4)) (1.0.0)
+   Requirement already satisfied: sphinxcontrib-jsmath in c:\users\wenbo\appdata\local\programs\python\python310\lib\site-packages (from Sphinx==5.1.1->-r doc/requirements.txt (line 1)) (1.0.1)
+   Requirement already satisfied: Pygments>=2.0 in c:\users\wenbo\appdata\local\programs\python\python310\lib\site-packages (from Sphinx==5.1.1->-r doc/requirements.txt (line 1)) (2.12.0)
+   Requirement already satisfied: colorama>=0.3.5 in c:\users\wenbo\appdata\local\programs\python\python310\lib\site-packages (from Sphinx==5.1.1->-r doc/requirements.txt (line 1)) (0.4.5)
+   Requirement already satisfied: requests>=2.5.0 in c:\users\wenbo\appdata\local\programs\python\python310\lib\site-packages (from Sphinx==5.1.1->-r doc/requirements.txt (line 1)) (2.28.1)
+   Requirement already satisfied: imagesize in c:\users\wenbo\appdata\local\programs\python\python310\lib\site-packages (from Sphinx==5.1.1->-r doc/requirements.txt (line 1)) (1.4.1)
+   Requirement already satisfied: sphinxcontrib-applehelp in c:\users\wenbo\appdata\local\programs\python\python310\lib\site-packages (from Sphinx==5.1.1->-r doc/requirements.txt (line 1)) (1.0.2)
+   Requirement already satisfied: alabaster<0.8,>=0.7 in c:\users\wenbo\appdata\local\programs\python\python310\lib\site-packages (from Sphinx==5.1.1->-r doc/requirements.txt (line 1)) (0.7.12)
+   Requirement already satisfied: sphinxcontrib-htmlhelp>=2.0.0 in c:\users\wenbo\appdata\local\programs\python\python310\lib\site-packages (from Sphinx==5.1.1->-r doc/requirements.txt (line 1)) (2.0.0)
+   Requirement already satisfied: sphinxcontrib-qthelp in c:\users\wenbo\appdata\local\programs\python\python310\lib\site-packages (from Sphinx==5.1.1->-r doc/requirements.txt (line 1)) (1.0.3)
+   Requirement already satisfied: Jinja2>=2.3 in c:\users\wenbo\appdata\local\programs\python\python310\lib\site-packages (from Sphinx==5.1.1->-r doc/requirements.txt (line 1)) (3.1.2)
+   Requirement already satisfied: babel>=1.3 in c:\users\wenbo\appdata\local\programs\python\python310\lib\site-packages (from Sphinx==5.1.1->-r doc/requirements.txt (line 1)) (2.10.3)
+   Requirement already satisfied: sphinxcontrib-devhelp in c:\users\wenbo\appdata\local\programs\python\python310\lib\site-packages (from Sphinx==5.1.1->-r doc/requirements.txt (line 1)) (1.0.2)
+   Requirement already satisfied: snowballstemmer>=1.1 in c:\users\wenbo\appdata\local\programs\python\python310\lib\site-packages (from Sphinx==5.1.1->-r doc/requirements.txt (line 1)) (2.2.0)
+   Requirement already satisfied: packaging in c:\users\wenbo\appdata\local\programs\python\python310\lib\site-packages (from Sphinx==5.1.1->-r doc/requirements.txt (line 1)) (21.3)
+   Requirement already satisfied: docutils<0.20,>=0.14 in c:\users\wenbo\appdata\local\programs\python\python310\lib\site-packages (from Sphinx==5.1.1->-r doc/requirements.txt (line 1)) (0.17.1)
+   Requirement already satisfied: sphinxcontrib-serializinghtml>=1.1.5 in c:\users\wenbo\appdata\local\programs\python\python310\lib\site-packages (from Sphinx==5.1.1->-r doc/requirements.txt (line 1)) (1.1.5)
+   Requirement already satisfied: commonmark>=0.8.1 in c:\users\wenbo\appdata\local\programs\python\python310\lib\site-packages (from recommonmark==0.7.1->-r doc/requirements.txt (line 2)) (0.9.1)
+   Requirement already satisfied: markdown>=3.4 in c:\users\wenbo\appdata\local\programs\python\python310\lib\site-packages (from sphinx-markdown-tables==0.0.17->-r doc/requirements.txt (line 3)) (3.4.1)
+   Requirement already satisfied: pytz>=2015.7 in c:\users\wenbo\appdata\local\programs\python\python310\lib\site-packages (from babel>=1.3->Sphinx==5.1.1->-r doc/requirements.txt (line 1)) (2022.1)
+   Requirement already satisfied: MarkupSafe>=2.0 in c:\users\wenbo\appdata\local\programs\python\python310\lib\site-packages (from Jinja2>=2.3->Sphinx==5.1.1->-r doc/requirements.txt (line 1)) (2.1.1)
+   Requirement already satisfied: idna<4,>=2.5 in c:\users\wenbo\appdata\local\programs\python\python310\lib\site-packages (from requests>=2.5.0->Sphinx==5.1.1->-r doc/requirements.txt (line 1)) (3.3)
+   Requirement already satisfied: urllib3<1.27,>=1.21.1 in c:\users\wenbo\appdata\local\programs\python\python310\lib\site-packages (from requests>=2.5.0->Sphinx==5.1.1->-r doc/requirements.txt (line 1)) (1.26.11)
+   Requirement already satisfied: charset-normalizer<3,>=2 in c:\users\wenbo\appdata\local\programs\python\python310\lib\site-packages (from requests>=2.5.0->Sphinx==5.1.1->-r doc/requirements.txt (line 1)) (2.1.0)
+   Requirement already satisfied: certifi>=2017.4.17 in c:\users\wenbo\appdata\local\programs\python\python310\lib\site-packages (from requests>=2.5.0->Sphinx==5.1.1->-r doc/requirements.txt (line 1)) (2022.6.15)
+   Requirement already satisfied: pyparsing!=3.0.5,>=2.0.2 in c:\users\wenbo\appdata\local\programs\python\python310\lib\site-packages (from packaging->Sphinx==5.1.1->-r doc/requirements.txt (line 1)) (3.0.9)
+
+   [notice] A new release of pip available: 22.2.2 -> 22.3.1
+   [notice] To update, run: python.exe -m pip install --upgrade pip
+
+   D:\worksplace\github\zephyr_polling>
+
+下载源码
+--------
+
+项目的源码都在github上维护\ `bobwenstudy/zephyr_polling <https://github.com/bobwenstudy/zephyr_polling>`__\ ,直接clone即可。
+
+.. code:: bash
+
+   git clone https://github.com/bluekitchen/btstack.git
+
+下载项目后的工程目录如下:
+
+.. code:: bash
+
+   zephyr_polling
+    ├── chipset(支持芯片列表)
+    ├── doc(文档目录)
+    ├── example(应用例程)
+    ├── platform(各个平台的支持)
+    ├── porting(部署,包含platform和HCI driver配置)
+    ├── scripts(脚本)
+    ├── src(协议栈核心部分)
+    ├── code_format.py(代码格式化,可以通过make code_format调用,当然也可以直接运行)
+    ├── python_require_env.py(python依赖安装,直接运行即可)
+    ├── LICENSE(LICENSE信息)
+    ├── Makefile(项目的makefile)
+    └── README.md(ReadMe说明)
+
+编译工程
+--------
+
+本项目都由makefile组织编译,像很多项目一样,在命令行中键入\ ``make all``\ 即可。编译过程如下,在Windows环境下最终会生成\ ``output/main.exe``\ 。
+
+.. code:: bash
+
+   D:\worksplace\github\zephyr_polling>make all
+   Current Configuration: APP=beacon PORT=windows_libusb_win32 CHIPSET=csr8510
+   Using user config.
+   已复制         1 个文件。
+   python scripts/kconfig/kconfig.py --handwritten-input-configs src/Kconfig output/.config output/autoconfig.h output/autoconfig_log.txt example/beacon/prj.conf
+   Parsing src/Kconfig
+   Loaded configuration 'example/beacon/prj.conf'
+   Configuration saved to 'output/.config'
+   Kconfig header saved to 'output/autoconfig.h'
+   .config updated
+   python scripts/kconfig/kconfig.py src/Kconfig output/.config output/autoconfig.h output/autoconfig_log.txt output/.config
+   Parsing src/Kconfig
+   Loaded configuration 'output/.config'
+   No change to configuration in 'output/.config'
+   No change to Kconfig header in 'output/autoconfig.h'
+   Compiling  : "src/common/aes_soft.c"
+   Compiling  : "src/common/bt_buf.c"
+   Compiling  : "src/common/bt_storage_kv.c"
+   Compiling  : "src/common/hex.c"
+   Compiling  : "src/common/net_buf.c"
+   Compiling  : "src/common/rpa.c"
+   Compiling  : "src/common/timeout.c"
+   Compiling  : "src/common/timer.c"
+   Compiling  : "src/common/work.c"
+   Compiling  : "src/drivers/hci_h4.c"
+   Compiling  : "src/host/addr.c"
+   Compiling  : "src/host/adv.c"
+   Compiling  : "src/host/att.c"
+   Compiling  : "src/host/conn.c"
+   Compiling  : "src/host/crypto.c"
+   Compiling  : "src/host/ecc.c"
+   Compiling  : "src/host/gatt.c"
+   Compiling  : "src/host/hci_common.c"
+   Compiling  : "src/host/hci_core.c"
+   Compiling  : "src/host/id.c"
+   Compiling  : "src/host/keys.c"
+   Compiling  : "src/host/l2cap.c"
+   Compiling  : "src/host/scan.c"
+   Compiling  : "src/host/smp.c"
+   Compiling  : "src/host/uuid.c"
+   Compiling  : "src/logging/bt_log.c"
+   Compiling  : "src/logging/bt_log_impl.c"
+   Compiling  : "src/utils/k_queue.c"
+   Compiling  : "src/utils/mem_slab.c"
+   Compiling  : "src/utils/spool.c"
+   Compiling  : "src/services/bas.c"
+   Compiling  : "src/services/dis.c"
+   Compiling  : "src/services/hrs.c"
+   Compiling  : "src/services/tps.c"
+   Compiling  : "example/beacon/app_main.c"
+   Compiling  : "porting/windows_libusb_win32/main.c"
+   Compiling  : "platform/windows/windows_bt_log_impl.c"
+   Compiling  : "platform/windows/windows_bt_storage_kv_impl.c"
+   Compiling  : "platform/windows/windows_bt_timer_impl.c"
+   Compiling  : "platform/windows/windows_driver_libusb.c"
+   Compiling  : "platform/windows/windows_driver_serial.c"
+   Compiling  : "chipset/csr8510/chipset_csr8510.c"
+   Linking    : "main.exe"
+   Start Build Image.
+   objcopy -v -O binary output/main.exe output/main.bin
+   copy from `output/main.exe' [pei-i386] to `output/main.bin' [binary]
+   objdump --source --all-headers --demangle --line-numbers --wide output/main.exe > output/main.lst
+   Print Size
+      text    data     bss     dec     hex filename
+    129224    7016    2676  138916   21ea4 output/main.exe
+
+运行
+----
+
+默认选的是\ `CSR8510 <https://detail.tmall.com/item.htm?abbucket=2&id=534662513906&ns=1&skuId=4910946697067&spm=a230r.1.14.1.2f6811a37qFFQU>`__\ 芯片,接口是USB接口,接好dongle后,直接运行即可。
+
+运行过程如下。
+
+.. code:: 
+
+   D:\worksplace\github\zephyr_polling>.\output\main.exe
+   [2022-12-06 16:31:16.488] [0xad38] display_devices(), idVendor: 0xbda, idProduct: 0x8771
+   [2022-12-06 16:31:16.491] [0xad38] display_devices(), idVendor: 0x10d7, idProduct: 0xb012
+   [2022-12-06 16:31:16.493] [0xad38] display_devices(), idVendor: 0xa12, idProduct: 0x1
+   [2022-12-06 16:31:16.495] [0xad38] success: set configuration #1
+   [2022-12-06 16:31:16.497] [0xad38] success: claim_interface #0
+   [2022-12-06 16:31:16.498] [0xa2f0] tx_process_loop
+   [2022-12-06 16:31:16.498] [0xa144] rx_evt_process_loop
+   [2022-12-06 16:31:16.498] [0xad38] hci_driver_open()
+   [2022-12-06 16:31:16.504] [0xad38] I: (bt_hci_core)hci_init():3220: work start.
+   [2022-12-06 16:31:16.506] [0xad38] CMD =>  00 FC 13 C2 02 00 09 00 02 00 03 70 00 00 F2 00 01 00 08 00 01 00
+   [2022-12-06 16:31:17.530] [0xad38] EVT <=  FF 13 C2 01 00 09 00 02 00 03 70 00 00 F2 00 01 00 08 00 01 00
+   [2022-12-06 16:31:17.535] [0xad38] CMD =>  00 FC 19 C2 02 00 0C 00 08 00 03 70 00 00 01 00 04 00 08 00 44 00 66 55 33 00 22 11
+   [2022-12-06 16:31:17.543] [0xad38] EVT <=  FF 19 C2 01 00 0C 00 08 00 03 70 00 00 01 00 04 00 08 00 44 00 66 55 33 00 22 11
+   [2022-12-06 16:31:17.548] [0xad38] CMD =>  00 FC 13 C2 02 00 09 00 09 00 02 40 00 00 00 00 00 00 00 00 00 00
+   [2022-12-06 16:31:17.548] [0xa3a0] reset_driver_process, wait usb reboot.
+   [2022-12-06 16:31:17.553] [0xa2f0] error tx:
+   libusb0-dll:err [control_msg] sending control message failed, win error: 连到系统上的设备没有发挥作用。
+
+
+   [2022-12-06 16:31:22.555] [0xa3a0] reset_driver_process, usb reboot ready.
+   [2022-12-06 16:31:22.557] [0xa144] error reading:
+   libusb0-dll:err [submit_async] submitting request failed, win error: 设备不识别此命令。
+
+   [2022-12-06 16:31:22.666] [0xa144] rx_evt_process_loop end
+   [2022-12-06 16:31:22.668] [0xa3a0] display_devices(), idVendor: 0xa12, idProduct: 0x1
+   [2022-12-06 16:31:22.670] [0xa3a0] display_devices(), idVendor: 0xbda, idProduct: 0x8771
+   [2022-12-06 16:31:22.674] [0xa3a0] display_devices(), idVendor: 0x10d7, idProduct: 0xb012
+   [2022-12-06 16:31:22.677] [0xa3a0] success: set configuration #1
+   [2022-12-06 16:31:22.679] [0xa3a0] success: claim_interface #0
+   [2022-12-06 16:31:22.680] [0xad38] CMD =>  03 0C 00
+   [2022-12-06 16:31:22.680] [0xb538] tx_process_loop
+   [2022-12-06 16:31:22.680] [0xabc4] rx_evt_process_loop
+   [2022-12-06 16:31:23.822] [0xad38] EVT <=  0E 04 01 03 0C 00
+   [2022-12-06 16:31:23.825] [0xad38] CMD =>  03 10 00
+   [2022-12-06 16:31:23.829] [0xad38] EVT <=  0E 0C 01 03 10 00 FF FF 8F FE DB FF 5B 87
+   [2022-12-06 16:31:23.832] [0xad38] CMD =>  01 10 00
+   [2022-12-06 16:31:23.835] [0xad38] EVT <=  0E 0C 01 01 10 00 06 BB 22 06 0A 00 BB 22
+   [2022-12-06 16:31:23.838] [0xad38] CMD =>  02 10 00
+   [2022-12-06 16:31:23.846] [0xad38] EVT <=  0E 44 01 02 10 00 FF FF FF 03 FE FF FF FF FF FF FF FF F3 0F E8 FE 3F F7 83 FF 1C 00 00 00 61 F7 FF FF 7F 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+   [2022-12-06 16:31:23.855] [0xad38] CMD =>  03 20 00
+   [2022-12-06 16:31:23.859] [0xad38] EVT <=  0E 0C 01 03 20 00 01 00 00 00 00 00 00 00
+   [2022-12-06 16:31:23.861] [0xad38] CMD =>  6D 0C 02 01 00
+   [2022-12-06 16:31:23.865] [0xad38] EVT <=  0E 04 01 6D 0C 00
+   [2022-12-06 16:31:23.866] [0xad38] CMD =>  01 20 08 02 00 00 00 00 00 00 00
+   [2022-12-06 16:31:23.873] [0xad38] EVT <=  0E 04 01 01 20 00
+   [2022-12-06 16:31:23.875] [0xad38] CMD =>  01 0C 08 00 80 00 02 00 00 00 20
+   [2022-12-06 16:31:23.879] [0xad38] EVT <=  0E 04 01 01 0C 00
+   [2022-12-06 16:31:23.880] [0xad38] CMD =>  09 10 00
+   [2022-12-06 16:31:23.884] [0xad38] EVT <=  0E 0A 01 09 10 00 66 55 44 33 22 11
+   [2022-12-06 16:31:23.886] [0xad38] I: (bt_hci_core)hci_init_end():3195: work end.
+   [2022-12-06 16:31:23.889] [0xad38] I: (bt_hci_core)bt_dev_show_info():2998: Identity: 11:22:33:44:55:66 (public)
+   [2022-12-06 16:31:23.892] [0xad38] I: (bt_hci_core)bt_dev_show_info():3030: HCI: version 4.0 (0x06) revision 0x22bb, manufacturer 0x000a
+   [2022-12-06 16:31:23.895] [0xad38] I: (bt_hci_core)bt_dev_show_info():3033: LMP: version 4.0 (0x06) subver 0x22bb
+   [2022-12-06 16:31:23.898] [0xad38] Bluetooth initialized
+   [2022-12-06 16:31:23.899] [0xad38] Beacon started, advertising as 11:22:33:44:55:66 (public)
+   [2022-12-06 16:31:23.904] [0xad38] CMD =>  06 20 0F A0 00 F0 00 02 00 00 00 00 00 00 00 00 07 00
+   [2022-12-06 16:31:23.906] [0xad38] CMD =>  08 20 20 1C 02 01 04 03 03 AA FE 14 16 AA FE 10 00 00 7A 65 70 68 79 72 70 72 6F 6A 65 63 74 08 00 00 00
+   [2022-12-06 16:31:23.910] [0xad38] EVT <=  0E 04 01 06 20 00
+   [2022-12-06 16:31:23.912] [0xad38] CMD =>  09 20 20 0D 0C 09 54 65 73 74 20 62 65 61 63 6F 6E 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+   [2022-12-06 16:31:23.918] [0xad38] EVT <=  0E 04 01 08 20 00
+   [2022-12-06 16:31:23.922] [0xad38] CMD =>  0A 20 01 01
+   [2022-12-06 16:31:23.924] [0xad38] EVT <=  0E 04 01 09 20 00
+   [2022-12-06 16:31:23.927] [0xad38] EVT <=  0E 04 01 0A 20 00
+
+默认工程是beacon项目,这时候手机打开nrf_connect就可以看到我们发的广播了。
+
+.. figure:: https://markdown-1306347444.cos.ap-shanghai.myqcloud.com/img/image-20221206163742869.png
+   :alt: 

+ 11 - 0
doc/source/develop/index.rst

@@ -0,0 +1,11 @@
+.. _developing_with_zephyr:
+
+开发说明
+########
+
+.. toctree::
+   :maxdepth: 1
+
+   getting_started/index.rst
+   application/index.rst
+   optimizations/index.rst

+ 39 - 0
doc/source/develop/optimizations/footprint.rst

@@ -0,0 +1,39 @@
+.. _footprint:
+
+优化占用空间
+============
+
+整个照搬zephyr项目的Kconfig配置系统,可以灵活的实现对各种场景的功能开关和参数管理。
+
+优化Code Size
+-------------
+
+整个蓝牙协议栈基本整个照搬zephyr项目的Kconfig系统,所有功能都可以根据需要进行开关,不需要的代码可以随时关闭,细节可以看 :ref:`kconfig`。
+
+如需要开启BT central相关功能只要在应用的prj.conf中配置如下即可。
+
+.. code:: 
+
+   CONFIG_BT_CENTRAL=y
+
+如需要开启日志打印功能,只需要配置如下就行。
+
+.. code:: 
+
+   CONFIG_BT_DEBUG_LOG=y
+
+优化RAM Size
+------------
+
+蓝牙最大的buffer就是HCI的交互缓存池,zephyr本身提供了很多的参数来配置,所以可以用如下方式去调整POOL的大小,并且会根据选择的link的个数动态调整pool大小。
+
+.. code:: 
+
+   CONFIG_BT_BUF_ACL_RX_SIZE=255
+   CONFIG_BT_BUF_ACL_TX_SIZE=251
+   CONFIG_BT_BUF_CMD_TX_SIZE=255
+   CONFIG_BT_BUF_EVT_DISCARDABLE_SIZE=255
+
+   CONFIG_BT_L2CAP_TX_MTU=247
+
+当然如果相关代码关闭了,相应的RAM也不需要了。

+ 10 - 0
doc/source/develop/optimizations/index.rst

@@ -0,0 +1,10 @@
+.. _optimizations:
+
+优化
+####
+
+.. toctree::
+   :maxdepth: 1
+
+   footprint.rst
+   tools.rst

+ 32 - 0
doc/source/develop/optimizations/tools.rst

@@ -0,0 +1,32 @@
+.. _optimization_tools:
+
+优化工具
+========
+
+map文件和反汇编文件
+-------------------
+
+系统编译后会在output目录下生成map和lst文件,可以直接对这些文件进行分析。
+
+生成的map文件也可以使用\ `Amap \| Sergey
+Sikorskiy <https://www.sikorskiy.net/info/prj/amap/>`__\ 来进行分析。
+
+.. figure:: https://www.sikorskiy.net/info/prj/amap/images/amap.05.03.png
+   :alt: 
+
+.. _ramreport和romreport:
+
+ram_report和rom_report
+----------------------
+
+实现Zephyr的ram_report和rom_report功能,目前只能对\ **elf**\ 文件进行分析,所以Windows下无法使用,但是嵌入式系统有需要可以使用。
+
+使用方式就是调用\ ``make ram_report``\ 或\ ``make rom_report``\ 或者\ ``make all_report``\ 。
+
+最终会生成\ **ram.json**\ 和\ **rom.json**\ 。这两个文件也可以导入到\ **nordic**\ 的\ **vscode**\ 环境下,可以借助其图形化工具进行分析。
+
+.. figure:: https://markdown-1306347444.cos.ap-shanghai.myqcloud.com/img/image-20221125112930355.png
+   :alt: 
+
+.. figure:: https://markdown-1306347444.cos.ap-shanghai.myqcloud.com/img/image-20221207155644150.png
+   :alt: 

+ 26 - 0
doc/source/index.rst

@@ -0,0 +1,26 @@
+.. Zephyr_polling documentation master file, created by
+   sphinx-quickstart on Fri Nov 25 14:57:53 2022.
+   You can adapt this file completely to your liking, but it should at least
+   contain the root `toctree` directive.
+
+欢迎来到Zephyr_polling的文档!
+==============================
+
+.. toctree::
+   :maxdepth: 1
+   :caption: 目录:
+
+   introduction/index.rst
+   develop/index.rst
+   build/index.rst
+   chipset/index.rst
+   porting/index.rst
+
+
+
+索引和表格
+==========
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`

+ 21 - 0
doc/source/introduction/index.rst

@@ -0,0 +1,21 @@
+.. _introducing_zephyr_polling:
+
+介绍
+####
+
+Zephyr_polling项目是基于 `Zephyr
+Project <https://www.zephyrproject.org/>`__ 进行二次开发的,去除了OS调度部分,只保留了Bluetooth的Host协议栈。项目地址:\ `bobwenstudy/zephyr_polling
+(github.com) <https://github.com/bobwenstudy/zephyr_polling>`__\ 。
+
+License
+*******
+
+同Zephyr项目,遵循 ``Apache 2.0`` 协议。
+
+
+蓝牙支持
+********
+
+随时跟进Zephyr版本,暂时还未支持Mesh。
+
+

+ 127 - 0
doc/source/porting/exist_porting/index.rst

@@ -0,0 +1,127 @@
+现有移植平台说明
+================
+
+.. _windowslibusbwin32:
+
+windows_libusb_win32
+--------------------
+
+windows平台下USB H2接口实现。USB使用libusb驱动。
+
+USB设备使用
+~~~~~~~~~~~
+
+为了能操作这些USB蓝牙dongle,默认使用的驱动是蓝牙的驱动。所以需要更改设备所使用的驱动。
+
+-  Step1:下载\ `Zadig <https://zadig.akeo.ie/>`__\ 。
+
+-  Step2:菜单栏点击Options -> List All Devices。
+
+.. figure:: https://markdown-1306347444.cos.ap-shanghai.myqcloud.com/img/image-20221125133827682.png
+   :alt: 
+
+-  Step3:通过下拉选中当前连接的蓝牙dongle,更换设备driver为\ ``libusb-win32``\ ,如下图所示,过一会就换好驱动了。
+
+.. figure:: https://markdown-1306347444.cos.ap-shanghai.myqcloud.com/img/image-20221125133953130.png
+   :alt: 
+
+.. _安装软件环境-1:
+
+安装软件环境
+~~~~~~~~~~~~
+
+参考\ `快速开始 — Zephyr_polling项目文档
+(zephyr-polling.readthedocs.io) <https://zephyr-polling.readthedocs.io/en/latest/develop/getting_started/index.html>`__\ 安装Windows环境。
+
+安装GCC环境,\ `Win7下msys64安装mingw工具链 - Milton - 博客园
+(cnblogs.com) <https://www.cnblogs.com/milton/p/11808091.html>`__\ 。
+
+安装Python环境,\ `Python安装教程-史上最全壬杰的博客-CSDN博客python安装教程 <https://blog.csdn.net/weixin_49237144/article/details/122915089>`__\ 。
+
+安装Python依赖,运行\ ``python_require_env.py``\ 。
+
+.. _编译运行-1:
+
+编译运行
+~~~~~~~~
+
+本项目都由makefile组织编译,命令行运行\ ``make all``\ 指定\ ``PORT``\ 为\ ``windows_libusb_win32``\ 即可,最终会生成\ ``output/main.exe``\ 。而后直接运行即可。
+
+.. code:: bash
+
+   PS D:\worksplace\github\zephyr_polling> make all PORT=windows_libusb_win32 CHIPSET=csr8510 APP=beacon
+
+   Current Configuration: APP=beacon PORT=windows_libusb_win32 CHIPSET=csr8510
+
+   Linking    : "main.exe"
+
+   Start Build Image.
+
+   objcopy -v -O binary output/main.exe output/main.bin
+
+   copy from `output/main.exe' [pei-i386] to `output/main.bin' [binary]
+
+   objdump --source --all-headers --demangle --line-numbers --wide output/main.exe > output/main.lst
+
+   Print Size
+
+      text    data     bss     dec     hex filename
+
+    129080    7016    2676  138772   21e14 output/main.exe
+
+   PS D:\worksplace\github\zephyr_polling> .\output\main.exe
+
+.. _windowsserial:
+
+windows_serial
+--------------
+
+windows UART H4接口实现。PC上有串口就行,注意观察串口号。
+
+.. _安装软件环境-2:
+
+安装软件环境
+~~~~~~~~~~~~
+
+参考\ `快速开始 — Zephyr_polling项目文档
+(zephyr-polling.readthedocs.io) <https://zephyr-polling.readthedocs.io/en/latest/develop/getting_started/index.html>`__\ 安装Windows环境。
+
+安装GCC环境,\ `Win7下msys64安装mingw工具链 - Milton - 博客园
+(cnblogs.com) <https://www.cnblogs.com/milton/p/11808091.html>`__\ 。
+
+安装Python环境,\ `Python安装教程-史上最全壬杰的博客-CSDN博客python安装教程 <https://blog.csdn.net/weixin_49237144/article/details/122915089>`__\ 。
+
+安装Python依赖,运行\ ``python_require_env.py``\ 。
+
+.. _编译运行-2:
+
+编译运行
+~~~~~~~~
+
+本项目都由makefile组织编译,命令行运行\ ``make all``\ 指定\ ``PORT``\ 为\ ``windows_serial``\ 即可,最终会生成\ ``output/main.exe``\ 。由于不同PC的串口号不同,需要在执行时传入COM口号,如\ ``COM1``\ 需要传入\ ``1``\ 。
+
+.. code:: bash
+
+   PS D:\worksplace\github\zephyr_polling> make all PORT=windows_serial CHIPSET=csr8510 APP=beacon      
+
+   Current Configuration: APP=beacon PORT=windows_serial CHIPSET=csr8510
+
+   Compiling  : "porting/windows_serial/main.c"
+
+   Linking    : "main.exe"
+
+   Start Build Image.
+
+   objcopy -v -O binary output/main.exe output/main.bin
+
+   copy from `output/main.exe' [pei-i386] to `output/main.bin' [binary]
+
+   objdump --source --all-headers --demangle --line-numbers --wide output/main.exe > output/main.lst
+
+   Print Size
+
+      text    data     bss     dec     hex filename
+
+    129388    7016    2676  139080   21f48 output/main.exe
+
+   PS D:\worksplace\github\zephyr_polling> .\output\main.exe 1

+ 273 - 0
doc/source/porting/getting_started/index.rst

@@ -0,0 +1,273 @@
+移植说明
+========
+
+简介
+----
+
+本项目设计之初就考虑到移植到不同平台的需要,毕竟代码最终要部署在实际运行环境中才有真实意义。
+
+移植时主要需要考虑以下几个问题:
+
+-  **代码运行平台**\ :也就是协议栈运行在哪,目前项目支持运行在\ **windows**\ 环境中,\ **platform**\ 文件夹中定义了\ ``platform_interface.h``\ 声明了平台侧所需实现的接口。
+
+-  **HCI接口实现**\ :本项目是Host协议栈,要实现蓝牙功能,需要通过HCI接口实现和Controller芯片的通信。目前项目支持windows平台下的USB和UART接口实现,分别对应:\ ``windows_libusb_win32``\ 和\ ``windows_serial``\ 。
+
+-  **协议栈接口实现**\ :就是协议栈在不同平台和HCI模式下的适配。总体来说包含log模块、chipset模块、storage_kv模块和定时器模块的实现。
+
+对于协议栈而言,部分功能需要根据平台的要求来实现。本项目所需的硬件资源很少,可以非常方便移植到不同应用平台中。
+
+Log模块
+-------
+
+本项目有很多日志需要打印,不同平台的log打印方式各不相同,平台需要实现\ ``bt_log_impl_t``\ 所定义的接口,分别是:
+
+-  **init**\ :初始化接口,通知平台log模块初始化开始,平台可以做一些准备,如在windows平台中,为了方便离线分析问题,会创建log文件和cfa文件,记录过程中的日志。调用\ ``bt_log_impl_register()``\ 函数时调用一次。
+
+-  **packet**\ :HCI数据包日志接口,每次HCI层的数据包交互会通过该接口通知平台,平台可以根据需要记录该日志。在windows平台会将该数据存在cfa文件中,方便后续借助btsnoop工具debug。
+
+-  **printf**\ :字符串日志接口,协议栈中\ ``BT_DBG``\ ,\ ``printk``\ 等字符串打印接口实现。
+
+-  **point**\ :高性能point点日志接口,暂未实现。
+
+平台需要通过\ ``bt_log_impl_register()``\ 传入Log接口实现。
+
+.. code:: c
+
+   typedef struct
+   {
+       // init work
+       void (*init)(void);
+       // log packet
+       void (*packet)(uint8_t packet_type, uint8_t in, uint8_t *packet, uint16_t len);
+       // log message
+       void (*printf)(uint8_t level, const char *format, va_list argptr);
+       // log point
+       void (*point)(uint32_t val);
+   } bt_log_impl_t;
+
+   void bt_log_impl_register(const bt_log_impl_t *log_impl);
+
+chipset模块
+-----------
+
+本项目是Host协议栈,不同Controller的行为除了标准HCI接口实现外,还需要一些特殊功能接口。在\ `Chipsets <https://zephyr-polling.readthedocs.io/en/latest/chipset/index.html#>`__\ 章节中有对现有市面的芯片进行抽象。平台需要根据不同的chipset实现该接口。\ ``struct bt_hci_chipset_driver``\ 包含如下接口:
+
+-  **init_work**\ :初始化接口,通知平台chipset模块初始化开始,平台可以做一些准备,如状态机初始化之类。调用\ ``bt_hci_chipset_driver_register()``\ 函数时调用一次。
+
+-  **boot_start**\ :HCI Reset
+   Command发送前会回调该流程,完成操作后需调用\ ``bt_hci_set_boot_ready()``\ 通知协议栈启动后续流程。
+
+-  **prepare_start**\ :HCI Reset
+   Command发送后会回调该流程,完成操作后需调用\ ``bt_hci_set_prepare_ready()``\ 通知协议栈启动后续流程。
+
+-  **event_process**\ :会将协议栈收到的HCI Event通过该接口上报。
+
+平台需要通过\ ``bt_hci_chipset_driver_register()``\ 传入chipset接口实现。
+
+
+.. note::
+
+    如果Controller无特殊操作,无需实现该接口,也就是传入NULL即可。
+
+.. code:: c
+
+   struct bt_hci_chipset_driver
+   {
+       /**
+        * @brief init work process.
+        *
+        */
+       void (*init_work)(void);
+       /**
+        * @brief Boot work process.
+        *
+        */
+       void (*boot_start)(void);
+
+       /**
+        * @brief Prepare work process.
+        *
+        * Work after send reset command.
+        *
+        */
+       void (*prepare_start)(void);
+
+       void (*event_process)(uint8_t event, struct net_buf *buf);
+   };
+
+   /**
+    * @typedef bt_hci_event_process_t
+    * @brief Callback for hci event handle.
+    *
+    * @param err zero on success or (negative) error code otherwise.
+    */
+   typedef void (*bt_hci_event_process_t)(uint8_t event, struct net_buf *buf);
+
+   void bt_hci_set_boot_ready(void);
+
+   void bt_hci_set_prepare_ready(void);
+
+   int bt_hci_chipset_driver_register(const struct bt_hci_chipset_driver *drv);
+
+.. _storagekv模块:
+
+storage_kv模块
+--------------
+
+蓝牙交互中有一些信息需要持久化存储中,确保下次掉电后能正常使用,如Link
+Key等信息。不同平台下的持久化存储方式各不相同,考虑到嵌入式芯片实际情况,采用轻量级key-value结构来存储持久化信息,以便掉电后重连。\ ``struct bt_storage_kv_impl``\ 包含如下接口:
+
+-  **init_list**\ :初始化接口,通知平台当前协议栈所需的key-value
+   header信息,暂无用处,后续根据需要再实现相关功能。
+
+-  **get**\ :获取key对应的data数据。windows平台下直接获取文件对应的内容。
+
+-  **set**\ :保存key对应的data数据。windows平台按照key命名文件,并保存data到文件中。
+
+-  **delete**\ :删除key对应的data数据。windows平台删除key对应的文件。
+
+平台需要通过\ ``bt_storage_kv_register()``\ 传入storage_kv接口实现。
+
+.. code:: c
+
+
+   enum bt_storage_kv_keys
+   {
+       KEY_INDEX_NULL = 0x0000,
+
+       KEY_INDEX_LE_ID_ADDR_LIST = 0x0001,
+       KEY_INDEX_LE_ID_IRK_LIST = 0x0002,
+       KEY_INDEX_LE_ID_NAME = 0x0003,
+       KEY_INDEX_LE_ID_APPEARANCE = 0x0004,
+
+       KEY_INDEX_LE_KEY_INFO_LIST = 0x0100,
+       KEY_INDEX_LE_KEY_INFO_ITEM_BASE = 0x0110,
+   };
+
+   #define KEY_INDEX_LE_KEY_INFO_ITEM(__x) (KEY_INDEX_LE_KEY_INFO_ITEM_BASE + (__x))
+
+   struct bt_storage_kv_header
+   {
+       uint16_t key;
+       uint16_t length; // zero length means length not same.
+   };
+
+   struct bt_storage_kv_impl
+   {
+       void (*init_list)(struct bt_storage_kv_header *list, uint16_t list_cnt);
+
+       int (*get)(uint16_t key, uint8_t *data, uint16_t *len);
+
+       void (*set)(uint16_t key, uint8_t *data, uint16_t len);
+
+       void (*delete)(uint16_t key, uint8_t *data, uint16_t len);
+   };
+
+   void bt_storage_kv_register(const struct bt_storage_kv_impl *impl);
+
+定时器模块
+----------
+
+蓝牙业务中有很多超时业务处理,和定时业务处理,同时实际应用开发也需要一些软件定时器实现。协议栈需要一个精度为1ms的定时器,平台通过周期调用\ ``sys_clock_announce()``\ 传入Elapsed
+time。
+
+.. code:: c
+
+   /**
+    * @brief Announce time progress to the kernel
+    *
+    * Informs the kernel that the specified number of ticks have elapsed
+    * since the last call to sys_clock_announce() (or system startup for
+    * the first call).  The timer driver is expected to delivery these
+    * announcements as close as practical (subject to hardware and
+    * latency limitations) to tick boundaries.
+    *
+    * @param ticks Elapsed time, in ticks
+    */
+   void sys_clock_announce(uint32_t ticks);
+
+HCI模块
+-------
+
+协议栈最主要要实现的就是HCI接口,不同平台下,不同芯片类型,其物理接口各不相同。HCI总的来说包含下行和上行通道,从Host层来看下行通道包含HCI
+Command和ACL交互。上行通道包含HCI Event和ACL交互。
+
+.. note::
+
+    协议栈的buffer申请和释放是FIFO结构,其支持申请和释放在不同线程进行,无需进入临界区处理。
+
+下行通道
+~~~~~~~~
+
+平台需要通过\ ``bt_hci_driver_register()``\ 注册实现\ ``struct bt_hci_driver``\ 相关接口:
+
+-  **open**\ :HCI开启接口,通知平台打开HCI通道,也就是打开串口或者进行USB枚举。
+
+-  **send**\ :协议栈所需下发的HCI数据会通过该回调通知平台,平台再将该HCI数据打包发送给Controller。
+
+.. code:: c
+
+
+   /**
+    * @brief Abstraction which represents the HCI transport to the controller.
+    *
+    * This struct is used to represent the HCI transport to the Bluetooth
+    * controller.
+    */
+   struct bt_hci_driver
+   {
+       /**
+        * @brief Open the HCI transport.
+        *
+        * Opens the HCI transport for operation. This function must not
+        * return until the transport is ready for operation, meaning it
+        * is safe to start calling the send() handler.
+        *
+        * If the driver uses its own RX thread, i.e.
+        * CONFIG_BT_RECV_IS_RX_THREAD is set, then this
+        * function is expected to start that thread.
+        *
+        * @return 0 on success or negative error number on failure.
+        */
+       int (*open)(void);
+
+       /**
+        * @brief Send HCI buffer to controller.
+        *
+        * Send an HCI command or ACL data to the controller. The exact
+        * type of the data can be checked with the help of bt_buf_get_type().
+        *
+        * @note This function must only be called from a cooperative thread.
+        *
+        * @param buf Buffer containing data to be sent to the controller.
+        *
+        * @return 0 on success or negative error number on failure.
+        */
+       int (*send)(struct net_buf *buf);
+   };
+
+   /**
+    * @brief Register a new HCI driver to the Bluetooth stack.
+    *
+    * This needs to be called before any application code runs. The bt_enable()
+    * API will fail if there is no driver registered.
+    *
+    * @param drv A bt_hci_driver struct representing the driver.
+    *
+    * @return 0 on success or negative error number on failure.
+    */
+   int bt_hci_driver_register(const struct bt_hci_driver *drv);
+
+上行通道
+~~~~~~~~
+
+平台收到Controller的数据包发送给协议栈需要先调用\ ``bt_buf_get_controller_tx_evt()``\ 或\ ``bt_buf_get_controller_tx_acl()``\ 获取buffer,将数据填充好后,调用\ ``bt_recv()``\ 接口将数据发送给协议栈处理。
+
+.. code:: c
+
+   // Alloc HCI Event buffer.
+   struct net_buf *buf = bt_buf_get_controller_tx_evt();
+   // Alloc HCI ACL buffer.
+   struct net_buf *buf = bt_buf_get_controller_tx_acl();
+   // Receive HCI Event/ACL
+   bt_recv(buf);

+ 10 - 0
doc/source/porting/index.rst

@@ -0,0 +1,10 @@
+.. _build:
+
+移植
+#######
+
+.. toctree::
+   :maxdepth: 1
+
+   getting_started/index.rst
+   exist_porting/index.rst

+ 71 - 0
example/beacon/app_main.c

@@ -0,0 +1,71 @@
+#include <stddef.h>
+#include <stdio.h>
+
+#include "base/types.h"
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <drivers/hci_driver.h>
+#include <logging/bt_log_impl.h>
+
+#define DEVICE_NAME     CONFIG_BT_DEVICE_NAME
+#define DEVICE_NAME_LEN (sizeof(DEVICE_NAME) - 1)
+
+/*
+ * Set Advertisement data. Based on the Eddystone specification:
+ * https://github.com/google/eddystone/blob/master/protocol-specification.md
+ * https://github.com/google/eddystone/tree/master/eddystone-url
+ */
+static const struct bt_data ad[] = {
+        BT_DATA_BYTES(BT_DATA_FLAGS, BT_LE_AD_NO_BREDR),
+        BT_DATA_BYTES(BT_DATA_UUID16_ALL, 0xaa, 0xfe),
+        BT_DATA_BYTES(BT_DATA_SVC_DATA16, 0xaa, 0xfe, /* Eddystone UUID */
+                      0x10,                           /* Eddystone-URL frame type */
+                      0x00,                           /* Calibrated Tx power at 0m */
+                      0x00,                           /* URL Scheme Prefix http://www. */
+                      'z', 'e', 'p', 'h', 'y', 'r', 'p', 'r', 'o', 'j', 'e', 'c', 't',
+                      0x08) /* .org */
+};
+
+/* Set Scan Response data */
+static const struct bt_data sd[] = {
+        BT_DATA(BT_DATA_NAME_COMPLETE, DEVICE_NAME, DEVICE_NAME_LEN),
+};
+
+void bt_ready(int err)
+{
+    char addr_s[BT_ADDR_LE_STR_LEN];
+    bt_addr_le_t addr = {0};
+    size_t count = 1;
+
+    if (err)
+    {
+        printk("Bluetooth init failed (err %d)\n", err);
+        return;
+    }
+
+    printk("Bluetooth initialized\n");
+
+    /* Start advertising */
+    err = bt_le_adv_start(BT_LE_ADV_NCONN_IDENTITY, ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd));
+    if (err)
+    {
+        printk("Advertising failed to start (err %d)\n", err);
+        return;
+    }
+
+    /* For connectable advertising you would use
+     * bt_le_oob_get_local().  For non-connectable non-identity
+     * advertising an non-resolvable private address is used;
+     * there is no API to retrieve that.
+     */
+
+    bt_id_get(&addr, &count);
+    bt_addr_le_to_str(&addr, addr_s, sizeof(addr_s));
+
+    printk("Beacon started, advertising as %s\n", addr_s);
+}
+
+void app_polling_work(void)
+{
+    return;
+}

+ 31 - 0
example/beacon/autoconfig.h

@@ -0,0 +1,31 @@
+#define CONFIG_BT 1
+#define CONFIG_BT_LOG_LEVEL_INF 1
+#define CONFIG_BT_LOG_LEVEL 3
+#define CONFIG_BT_BROADCASTER 1
+#define CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC 1000
+#define CONFIG_SYS_CLOCK_TICKS_PER_SEC 1000
+#define CONFIG_SYS_CLOCK_MAX_TIMEOUT_DAYS 365
+#define CONFIG_BT_BUF_ACL_TX_SIZE 27
+#define CONFIG_BT_BUF_ACL_TX_COUNT 3
+#define CONFIG_BT_BUF_ACL_RX_SIZE 27
+#define CONFIG_BT_BUF_ACL_RX_COUNT 6
+#define CONFIG_BT_BUF_EVT_RX_SIZE 68
+#define CONFIG_BT_BUF_EVT_RX_COUNT 10
+#define CONFIG_BT_BUF_EVT_DISCARDABLE_SIZE 43
+#define CONFIG_BT_BUF_EVT_DISCARDABLE_COUNT 3
+#define CONFIG_BT_BUF_CMD_TX_SIZE 255
+#define CONFIG_BT_BUF_CMD_TX_COUNT 6
+#define CONFIG_BT_ASSERT 1
+#define CONFIG_BT_ASSERT_VERBOSE 1
+#define CONFIG_BT_DEBUG 1
+#define CONFIG_BT_DEBUG_LOG 1
+#define CONFIG_BT_HCI_RESERVE 0
+#define CONFIG_BT_RX_PRIO 8
+#define CONFIG_BT_DRIVER_RX_HIGH_PRIO 6
+#define CONFIG_BT_HOST_CRYPTO 1
+#define CONFIG_BT_HOST_CRYPTO_PRNG 1
+#define CONFIG_BT_LIM_ADV_TIMEOUT 30
+#define CONFIG_BT_DEVICE_NAME "Test beacon"
+#define CONFIG_BT_DEVICE_APPEARANCE 0
+#define CONFIG_BT_ID_MAX 1
+#define CONFIG_BT_COMPANY_ID 0x05F1

+ 8 - 0
example/beacon/build.mk

@@ -0,0 +1,8 @@
+# define source directory
+SRC		+= $(APP_PATH)
+
+# define include directory
+INCLUDE	+= $(APP_PATH)
+
+# define lib directory
+LIB		+=

+ 3 - 0
example/beacon/prj.conf

@@ -0,0 +1,3 @@
+CONFIG_BT=y
+CONFIG_BT_DEBUG_LOG=y
+CONFIG_BT_DEVICE_NAME="Test beacon"

+ 84 - 0
example/broadcaster/app_main.c

@@ -0,0 +1,84 @@
+#include <stddef.h>
+#include <stdio.h>
+
+#include "base/types.h"
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <drivers/hci_driver.h>
+#include <logging/bt_log_impl.h>
+#include "common\timer.h"
+
+static uint8_t mfg_data[] = {0xff, 0xff, 0x00};
+
+static const struct bt_data ad[] = {
+        BT_DATA(BT_DATA_MANUFACTURER_DATA, mfg_data, 3),
+};
+
+struct k_timer adv_work_timer;
+
+void start_adv_process(void)
+{
+    int err;
+    printk("Sending advertising data: 0x%02X\n", mfg_data[2]);
+
+    /* Start advertising */
+    err = bt_le_adv_start(BT_LE_ADV_NCONN, ad, ARRAY_SIZE(ad), NULL, 0);
+    if (err)
+    {
+        printk("Advertising failed to start (err %d)\n", err);
+        return;
+    }
+}
+
+void stop_adv_process(void)
+{
+    int err;
+
+    err = bt_le_adv_stop();
+    if (err)
+    {
+        printk("Advertising failed to stop (err %d)\n", err);
+        return;
+    }
+
+    mfg_data[2]++;
+}
+
+uint8_t current_work_state;
+void adv_work_timer_expiry(struct k_timer *timer)
+{
+    current_work_state++;
+    printk("adv_work_timer_expiry, current_work_state: %d\n", current_work_state);
+
+    if (current_work_state % 0x02 == 0)
+    {
+        start_adv_process();
+    }
+    else
+    {
+        stop_adv_process();
+    }
+}
+
+void bt_ready(int err)
+{
+    char addr_s[BT_ADDR_LE_STR_LEN];
+    bt_addr_le_t addr = {0};
+    size_t count = 1;
+
+    if (err)
+    {
+        printk("Bluetooth init failed (err %d)\n", err);
+        return;
+    }
+
+    printk("Bluetooth initialized\n");
+
+    k_timer_init(&adv_work_timer, adv_work_timer_expiry, NULL);
+    k_timer_start(&adv_work_timer, K_SECONDS(1), K_SECONDS(1));
+}
+
+void app_polling_work(void)
+{
+    return;
+}

+ 30 - 0
example/broadcaster/autoconfig.h

@@ -0,0 +1,30 @@
+#define CONFIG_BT 1
+#define CONFIG_BT_LOG_LEVEL_INF 1
+#define CONFIG_BT_LOG_LEVEL 3
+#define CONFIG_BT_BROADCASTER 1
+#define CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC 1000
+#define CONFIG_SYS_CLOCK_TICKS_PER_SEC 1000
+#define CONFIG_SYS_CLOCK_MAX_TIMEOUT_DAYS 365
+#define CONFIG_BT_BUF_ACL_TX_SIZE 27
+#define CONFIG_BT_BUF_ACL_TX_COUNT 3
+#define CONFIG_BT_BUF_ACL_RX_SIZE 27
+#define CONFIG_BT_BUF_ACL_RX_COUNT 6
+#define CONFIG_BT_BUF_EVT_RX_SIZE 68
+#define CONFIG_BT_BUF_EVT_RX_COUNT 10
+#define CONFIG_BT_BUF_EVT_DISCARDABLE_SIZE 43
+#define CONFIG_BT_BUF_EVT_DISCARDABLE_COUNT 3
+#define CONFIG_BT_BUF_CMD_TX_SIZE 255
+#define CONFIG_BT_BUF_CMD_TX_COUNT 6
+#define CONFIG_BT_ASSERT 1
+#define CONFIG_BT_ASSERT_VERBOSE 1
+#define CONFIG_BT_DEBUG_NONE 1
+#define CONFIG_BT_HCI_RESERVE 0
+#define CONFIG_BT_RX_PRIO 8
+#define CONFIG_BT_DRIVER_RX_HIGH_PRIO 6
+#define CONFIG_BT_HOST_CRYPTO 1
+#define CONFIG_BT_HOST_CRYPTO_PRNG 1
+#define CONFIG_BT_LIM_ADV_TIMEOUT 30
+#define CONFIG_BT_DEVICE_NAME "Zephyr"
+#define CONFIG_BT_DEVICE_APPEARANCE 0
+#define CONFIG_BT_ID_MAX 1
+#define CONFIG_BT_COMPANY_ID 0x05F1

+ 8 - 0
example/broadcaster/build.mk

@@ -0,0 +1,8 @@
+# define source directory
+SRC		+= $(APP_PATH)
+
+# define include directory
+INCLUDE	+= $(APP_PATH)
+
+# define lib directory
+LIB		+=

+ 2 - 0
example/broadcaster/prj.conf

@@ -0,0 +1,2 @@
+CONFIG_BT=y
+CONFIG_BT_BROADCASTER=y

+ 145 - 0
example/central/app_main.c

@@ -0,0 +1,145 @@
+/* main.c - Application main entry point */
+
+/*
+ * Copyright (c) 2015-2016 Intel Corporation
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <errno.h>
+#include <stddef.h>
+#include <string.h>
+
+#include "base/types.h"
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/conn.h>
+#include <bluetooth/gatt.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/uuid.h>
+#include <logging/bt_log_impl.h>
+
+static void start_scan(void);
+
+static struct bt_conn *default_conn;
+
+static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type,
+                         struct net_buf_simple *ad)
+{
+    char addr_str[BT_ADDR_LE_STR_LEN];
+    int err;
+
+    if (default_conn)
+    {
+        return;
+    }
+
+    /* We're only interested in connectable events */
+    if (type != BT_GAP_ADV_TYPE_ADV_IND && type != BT_GAP_ADV_TYPE_ADV_DIRECT_IND)
+    {
+        return;
+    }
+
+    bt_addr_le_to_str(addr, addr_str, sizeof(addr_str));
+    printk("Device found: %s (RSSI %d)\n", addr_str, rssi);
+
+    /* connect only to devices in close proximity */
+    if (rssi < -70)
+    {
+        return;
+    }
+
+    if (bt_le_scan_stop())
+    {
+        return;
+    }
+
+    err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, BT_LE_CONN_PARAM_DEFAULT, &default_conn);
+    if (err)
+    {
+        printk("Create conn to %s failed (%u)\n", addr_str, err);
+        start_scan();
+    }
+}
+
+static void start_scan(void)
+{
+    int err;
+
+    /* This demo doesn't require active scan */
+    err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, device_found);
+    if (err)
+    {
+        printk("Scanning failed to start (err %d)\n", err);
+        return;
+    }
+
+    printk("Scanning successfully started\n");
+}
+
+static void connected(struct bt_conn *conn, uint8_t err)
+{
+    char addr[BT_ADDR_LE_STR_LEN];
+
+    bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
+
+    if (err)
+    {
+        printk("Failed to connect to %s (%u)\n", addr, err);
+
+        default_conn = NULL;
+
+        start_scan();
+        return;
+    }
+
+    if (conn != default_conn)
+    {
+        return;
+    }
+
+    printk("Connected: %s\n", addr);
+
+    bt_conn_disconnect(conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
+}
+
+static void disconnected(struct bt_conn *conn, uint8_t reason)
+{
+    char addr[BT_ADDR_LE_STR_LEN];
+
+    if (conn != default_conn)
+    {
+        return;
+    }
+
+    bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
+
+    printk("Disconnected: %s (reason 0x%02x)\n", addr, reason);
+
+    default_conn = NULL;
+
+    start_scan();
+}
+
+static struct bt_conn_cb conn_callbacks = {
+        .connected = connected,
+        .disconnected = disconnected,
+};
+
+void bt_ready(int err)
+{
+    if (err)
+    {
+        printk("Bluetooth init failed (err %d)\n", err);
+        return;
+    }
+
+    printk("Bluetooth initialized\n");
+
+    bt_conn_cb_register(&conn_callbacks);
+
+    start_scan();
+}
+
+void app_polling_work(void)
+{
+}

+ 50 - 0
example/central/autoconfig.h

@@ -0,0 +1,50 @@
+#define CONFIG_BT 1
+#define CONFIG_BT_LOG_LEVEL_INF 1
+#define CONFIG_BT_LOG_LEVEL 3
+#define CONFIG_BT_CENTRAL 1
+#define CONFIG_BT_OBSERVER 1
+#define CONFIG_BT_CONN 1
+#define CONFIG_BT_MAX_CONN 1
+#define CONFIG_BT_CONN_TX 1
+#define CONFIG_BT_PHY_UPDATE 1
+#define CONFIG_BT_DATA_LEN_UPDATE 1
+#define CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC 1000
+#define CONFIG_SYS_CLOCK_TICKS_PER_SEC 1000
+#define CONFIG_SYS_CLOCK_MAX_TIMEOUT_DAYS 365
+#define CONFIG_BT_BUF_ACL_TX_SIZE 27
+#define CONFIG_BT_BUF_ACL_TX_COUNT 3
+#define CONFIG_BT_BUF_ACL_RX_SIZE 27
+#define CONFIG_BT_BUF_ACL_RX_COUNT 6
+#define CONFIG_BT_BUF_EVT_RX_SIZE 68
+#define CONFIG_BT_BUF_EVT_RX_COUNT 10
+#define CONFIG_BT_BUF_EVT_DISCARDABLE_SIZE 43
+#define CONFIG_BT_BUF_EVT_DISCARDABLE_COUNT 3
+#define CONFIG_BT_BUF_CMD_TX_SIZE 255
+#define CONFIG_BT_BUF_CMD_TX_COUNT 6
+#define CONFIG_BT_ASSERT 1
+#define CONFIG_BT_ASSERT_VERBOSE 1
+#define CONFIG_BT_DEBUG_NONE 1
+#define CONFIG_BT_HCI_RESERVE 0
+#define CONFIG_BT_RX_PRIO 8
+#define CONFIG_BT_DRIVER_RX_HIGH_PRIO 6
+#define CONFIG_BT_HOST_CRYPTO 1
+#define CONFIG_BT_HOST_CRYPTO_PRNG 1
+#define CONFIG_BT_CONN_TX_MAX 3
+#define CONFIG_BT_AUTO_PHY_UPDATE 1
+#define CONFIG_BT_AUTO_DATA_LEN_UPDATE 1
+#define CONFIG_BT_L2CAP_TX_BUF_COUNT 3
+#define CONFIG_BT_L2CAP_TX_FRAG_COUNT 0
+#define CONFIG_BT_L2CAP_TX_MTU 23
+#define CONFIG_BT_GATT_FIXED_SERVICES_SIZE 7
+#define CONFIG_BT_ATT_PREPARE_COUNT 0
+#define CONFIG_BT_GATT_READ_MULTIPLE 1
+#define CONFIG_BT_GATT_READ_MULT_VAR_LEN 1
+#define CONFIG_BT_MAX_PAIRED 0
+#define CONFIG_BT_CREATE_CONN_TIMEOUT 3
+#define CONFIG_BT_CONN_PARAM_UPDATE_TIMEOUT 5000
+#define CONFIG_BT_BACKGROUND_SCAN_INTERVAL 2048
+#define CONFIG_BT_BACKGROUND_SCAN_WINDOW 18
+#define CONFIG_BT_DEVICE_NAME "Zephyr"
+#define CONFIG_BT_DEVICE_APPEARANCE 0
+#define CONFIG_BT_ID_MAX 1
+#define CONFIG_BT_COMPANY_ID 0x05F1

+ 8 - 0
example/central/build.mk

@@ -0,0 +1,8 @@
+# define source directory
+SRC		+= $(APP_PATH)
+
+# define include directory
+INCLUDE	+= $(APP_PATH)
+
+# define lib directory
+LIB		+=

+ 2 - 0
example/central/prj.conf

@@ -0,0 +1,2 @@
+CONFIG_BT=y
+CONFIG_BT_CENTRAL=y

+ 9 - 0
example/central_gatt_write/app_main.c

@@ -0,0 +1,9 @@
+/*
+ * Copyright (c) 2022 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <stdint.h>
+
+extern uint32_t central_gatt_write(uint32_t count);

+ 60 - 0
example/central_gatt_write/autoconfig.h

@@ -0,0 +1,60 @@
+#define CONFIG_BT 1
+#define CONFIG_BT_LOG_LEVEL_INF 1
+#define CONFIG_BT_LOG_LEVEL 3
+#define CONFIG_BT_CENTRAL 1
+#define CONFIG_BT_OBSERVER 1
+#define CONFIG_BT_CONN 1
+#define CONFIG_BT_MAX_CONN 1
+#define CONFIG_BT_CONN_TX 1
+#define CONFIG_BT_PHY_UPDATE 1
+#define CONFIG_BT_DATA_LEN_UPDATE 1
+#define CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC 1000
+#define CONFIG_SYS_CLOCK_TICKS_PER_SEC 1000
+#define CONFIG_SYS_CLOCK_MAX_TIMEOUT_DAYS 365
+#define CONFIG_BT_BUF_ACL_TX_SIZE 251
+#define CONFIG_BT_BUF_ACL_TX_COUNT 3
+#define CONFIG_BT_BUF_ACL_RX_SIZE 255
+#define CONFIG_BT_BUF_ACL_RX_COUNT 6
+#define CONFIG_BT_BUF_EVT_RX_SIZE 68
+#define CONFIG_BT_BUF_EVT_RX_COUNT 10
+#define CONFIG_BT_BUF_EVT_DISCARDABLE_SIZE 255
+#define CONFIG_BT_BUF_EVT_DISCARDABLE_COUNT 3
+#define CONFIG_BT_BUF_CMD_TX_SIZE 255
+#define CONFIG_BT_BUF_CMD_TX_COUNT 6
+#define CONFIG_BT_RPA 1
+#define CONFIG_BT_ASSERT 1
+#define CONFIG_BT_ASSERT_VERBOSE 1
+#define CONFIG_BT_DEBUG 1
+#define CONFIG_BT_DEBUG_LOG 1
+#define CONFIG_BT_HCI_RESERVE 0
+#define CONFIG_BT_RX_PRIO 8
+#define CONFIG_BT_DRIVER_RX_HIGH_PRIO 6
+#define CONFIG_BT_HOST_CRYPTO 1
+#define CONFIG_BT_HOST_CRYPTO_PRNG 1
+#define CONFIG_BT_CONN_TX_MAX 3
+#define CONFIG_BT_AUTO_PHY_UPDATE 1
+#define CONFIG_BT_AUTO_DATA_LEN_UPDATE 1
+#define CONFIG_BT_SMP 1
+#define CONFIG_BT_BONDABLE 1
+#define CONFIG_BT_SMP_ENFORCE_MITM 1
+#define CONFIG_BT_SMP_MIN_ENC_KEY_SIZE 7
+#define CONFIG_BT_L2CAP_TX_BUF_COUNT 3
+#define CONFIG_BT_L2CAP_TX_FRAG_COUNT 0
+#define CONFIG_BT_L2CAP_TX_MTU 247
+#define CONFIG_BT_GATT_FIXED_SERVICES_SIZE 7
+#define CONFIG_BT_ATT_PREPARE_COUNT 0
+#define CONFIG_BT_ATT_RETRY_ON_SEC_ERR 1
+#define CONFIG_BT_GATT_AUTO_SEC_REQ 1
+#define CONFIG_BT_GATT_CLIENT 1
+#define CONFIG_BT_GATT_READ_MULTIPLE 1
+#define CONFIG_BT_GATT_READ_MULT_VAR_LEN 1
+#define CONFIG_BT_MAX_PAIRED 1
+#define CONFIG_BT_CREATE_CONN_TIMEOUT 3
+#define CONFIG_BT_CONN_PARAM_UPDATE_TIMEOUT 5000
+#define CONFIG_BT_BACKGROUND_SCAN_INTERVAL 2048
+#define CONFIG_BT_BACKGROUND_SCAN_WINDOW 18
+#define CONFIG_BT_DEVICE_NAME "Zephyr"
+#define CONFIG_BT_DEVICE_APPEARANCE 0
+#define CONFIG_BT_ID_MAX 1
+#define CONFIG_BT_ECC 1
+#define CONFIG_BT_COMPANY_ID 0x05F1

+ 8 - 0
example/central_gatt_write/build.mk

@@ -0,0 +1,8 @@
+# define source directory
+SRC		+= $(APP_PATH)
+
+# define include directory
+INCLUDE	+= $(APP_PATH)
+
+# define lib directory
+LIB		+=

+ 118 - 0
example/central_gatt_write/central_gatt_write.c

@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2022 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include "base/types.h"
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/conn.h>
+#include <bluetooth/gatt.h>
+#include <logging/bt_log_impl.h>
+
+extern int mtu_exchange(struct bt_conn *conn);
+extern int write_cmd(struct bt_conn *conn);
+extern struct bt_conn *conn_connected;
+extern uint32_t last_write_rate;
+extern void (*start_scan_func)(void);
+extern struct bt_conn_cb conn_callbacks;
+
+static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type,
+                         struct net_buf_simple *ad)
+{
+    char dev[BT_ADDR_LE_STR_LEN];
+    struct bt_conn *conn;
+    int err;
+
+    bt_addr_le_to_str(addr, dev, sizeof(dev));
+    printk("[DEVICE]: %s, AD evt type %u, AD data len %u, RSSI %i\n", dev, type, ad->len, rssi);
+
+    /* We're only interested in connectable events */
+    if (type != BT_GAP_ADV_TYPE_ADV_IND && type != BT_GAP_ADV_TYPE_ADV_DIRECT_IND)
+    {
+        return;
+    }
+
+    /* connect only to devices in close proximity */
+    if (rssi < -50)
+    {
+        return;
+    }
+
+    err = bt_le_scan_stop();
+    if (err)
+    {
+        printk("%s: Stop LE scan failed (err %d)\n", __func__, err);
+        return;
+    }
+
+    err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, BT_LE_CONN_PARAM_DEFAULT, &conn);
+    if (err)
+    {
+        printk("%s: Create conn failed (err %d)\n", __func__, err);
+        start_scan_func();
+    }
+    else
+    {
+        // bt_conn_unref(conn);
+    }
+}
+
+static void start_scan(void)
+{
+    int err;
+
+    err = bt_le_scan_start(BT_LE_SCAN_ACTIVE, device_found);
+    if (err)
+    {
+        printk("%s: Scanning failed to start (err %d)\n", __func__, err);
+        return;
+    }
+
+    printk("%s: Scanning successfully started\n", __func__);
+}
+
+// void mtu_updated(struct bt_conn *conn, uint16_t tx, uint16_t rx)
+// {
+// 	printk("Updated MTU: TX: %d RX: %d bytes\n", tx, rx);
+// }
+
+// static struct bt_gatt_cb gatt_callbacks = {
+// 	.att_mtu_updated = mtu_updated
+// };
+
+static uint32_t count;
+void bt_ready(int err)
+{
+    if (err)
+    {
+        printk("Bluetooth init failed (err %d)\n", err);
+        return;
+    }
+    printk("Bluetooth initialized\n");
+
+    // bt_gatt_cb_register(&gatt_callbacks);
+    bt_conn_cb_register(&conn_callbacks);
+
+    conn_connected = NULL;
+    last_write_rate = 0U;
+
+    start_scan_func = start_scan;
+    start_scan_func();
+
+    count = 1;
+}
+
+void app_polling_work(void)
+{
+    struct bt_conn *conn = conn_connected;
+
+    if (conn)
+    {
+        if (count)
+        {
+            count--;
+            (void)write_cmd(conn);
+        }
+    }
+}

+ 210 - 0
example/central_gatt_write/gatt_write_common.c

@@ -0,0 +1,210 @@
+/*
+ * Copyright (c) 2022 Nordic Semiconductor ASA
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include "base/types.h"
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/conn.h>
+#include <bluetooth/gatt.h>
+#include <logging/bt_log_impl.h>
+
+static struct bt_gatt_exchange_params mtu_exchange_params;
+static uint32_t write_count;
+static uint32_t write_len;
+static uint32_t write_rate;
+struct bt_conn *conn_connected;
+uint32_t last_write_rate;
+void (*start_scan_func)(void);
+
+static void write_cmd_cb(struct bt_conn *conn, void *user_data)
+{
+    static uint32_t cycle_stamp;
+    uint64_t delta;
+    uint16_t len;
+    /* Extract the 16-bit data length stored in user_data */
+    len = (uint32_t)user_data & 0xFFFF;
+    printk("len= %u.\n", len);
+}
+
+static void mtu_exchange_cb(struct bt_conn *conn, uint8_t err,
+                            struct bt_gatt_exchange_params *params)
+{
+    printk("%s: MTU exchange %s (%u)\n", __func__, err == 0U ? "successful" : "failed",
+           bt_gatt_get_mtu(conn));
+}
+
+static int mtu_exchange(struct bt_conn *conn)
+{
+    int err;
+
+    printk("%s: Current MTU = %u\n", __func__, bt_gatt_get_mtu(conn));
+
+    mtu_exchange_params.func = mtu_exchange_cb;
+
+    printk("%s: Exchange MTU...\n", __func__);
+    err = bt_gatt_exchange_mtu(conn, &mtu_exchange_params);
+    if (err)
+    {
+        printk("%s: MTU exchange failed (err %d)", __func__, err);
+    }
+
+    return err;
+}
+
+static void connected(struct bt_conn *conn, uint8_t conn_err)
+{
+    struct bt_conn_info conn_info;
+    char addr[BT_ADDR_LE_STR_LEN];
+    int err;
+
+    bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
+
+    if (conn_err)
+    {
+        printk("%s: Failed to connect to %s (%u)\n", __func__, addr, conn_err);
+        return;
+    }
+
+    err = bt_conn_get_info(conn, &conn_info);
+    if (err)
+    {
+        printk("Failed to get connection info (%d).\n", err);
+        return;
+    }
+
+    printk("%s: %s role %u\n", __func__, addr, conn_info.role);
+
+    // conn_connected = bt_conn_ref(conn);
+    conn_connected = conn;
+
+    (void)mtu_exchange(conn);
+
+#if defined(CONFIG_BT_SMP)
+    if (conn_info.role == BT_CONN_ROLE_CENTRAL)
+    {
+        err = bt_conn_set_security(conn, BT_SECURITY_L2);
+        if (err)
+        {
+            printk("Failed to set security (%d).\n", err);
+        }
+    }
+#endif
+}
+
+static void disconnected(struct bt_conn *conn, uint8_t reason)
+{
+    struct bt_conn_info conn_info;
+    char addr[BT_ADDR_LE_STR_LEN];
+    int err;
+
+    bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
+
+    err = bt_conn_get_info(conn, &conn_info);
+    if (err)
+    {
+        printk("Failed to get connection info (%d).\n", err);
+        return;
+    }
+
+    printk("%s: %s role %u (reason %u)\n", __func__, addr, conn_info.role, reason);
+
+    conn_connected = NULL;
+
+    // bt_conn_unref(conn);
+
+    if (conn_info.role == BT_CONN_ROLE_CENTRAL)
+    {
+        start_scan_func();
+    }
+}
+
+static bool le_param_req(struct bt_conn *conn, struct bt_le_conn_param *param)
+{
+    printk("%s: int (0x%04x, 0x%04x) lat %u to %u\n", __func__, param->interval_min,
+           param->interval_max, param->latency, param->timeout);
+
+    return true;
+}
+
+static void le_param_updated(struct bt_conn *conn, uint16_t interval, uint16_t latency,
+                             uint16_t timeout)
+{
+    printk("%s: int 0x%04x lat %u to %u\n", __func__, interval, latency, timeout);
+}
+
+#if defined(CONFIG_BT_SMP)
+static void security_changed(struct bt_conn *conn, bt_security_t level, enum bt_security_err err)
+{
+    printk("%s: to level %u (err %u)\n", __func__, level, err);
+}
+#endif
+
+struct bt_conn_cb conn_callbacks = {
+        .connected = connected,
+        .disconnected = disconnected,
+        .le_param_req = le_param_req,
+        .le_param_updated = le_param_updated,
+#if defined(CONFIG_BT_SMP)
+        .security_changed = security_changed,
+#endif
+};
+
+int write_cmd(struct bt_conn *conn)
+{
+    static uint8_t data[BT_ATT_MAX_ATTRIBUTE_LEN] = {
+            0,
+    };
+    static uint16_t data_len;
+    uint16_t data_len_max;
+    int err;
+
+    data_len_max = bt_gatt_get_mtu(conn) - 3;
+    if (data_len_max > BT_ATT_MAX_ATTRIBUTE_LEN)
+    {
+        data_len_max = BT_ATT_MAX_ATTRIBUTE_LEN;
+    }
+
+#if TEST_FRAGMENTATION_WITH_VARIABLE_LENGTH_DATA
+    /* Use incremental length data for every write command */
+    /* TODO: Include test case in BabbleSim tests */
+    static bool decrement;
+
+    if (decrement)
+    {
+        data_len--;
+        if (data_len <= 1)
+        {
+            data_len = 1;
+            decrement = false;
+        }
+    }
+    else
+    {
+        data_len++;
+        if (data_len >= data_len_max)
+        {
+            data_len = data_len_max;
+            decrement = true;
+        }
+    }
+#else
+    /* Use fixed length data for every write command */
+    data_len = data_len_max;
+#endif
+
+    /* Pass the 16-bit data length value (instead of reference) in
+     * user_data so that unique value is pass for each write callback.
+     * Using handle 0x0001, we do not care if it is writable, we just want
+     * to transmit the data across.
+     */
+    err = bt_gatt_write_without_response_cb(conn, 0x0001, data, data_len, false, write_cmd_cb,
+                                            (void *)((uint32_t)data_len));
+    if (err)
+    {
+        printk("%s: Write cmd failed (%d).\n", __func__, err);
+    }
+
+    return err;
+}

+ 13 - 0
example/central_gatt_write/prj.conf

@@ -0,0 +1,13 @@
+CONFIG_BT=y
+CONFIG_BT_CENTRAL=y
+CONFIG_BT_SMP=y
+CONFIG_BT_GATT_CLIENT=y
+
+CONFIG_BT_BUF_ACL_RX_SIZE=255
+CONFIG_BT_BUF_ACL_TX_SIZE=251
+CONFIG_BT_BUF_CMD_TX_SIZE=255
+CONFIG_BT_BUF_EVT_DISCARDABLE_SIZE=255
+
+CONFIG_BT_L2CAP_TX_MTU=247
+
+CONFIG_BT_DEBUG_LOG=y

+ 277 - 0
example/central_hr/app_main.c

@@ -0,0 +1,277 @@
+/* main.c - Application main entry point */
+
+/*
+ * Copyright (c) 2015-2016 Intel Corporation
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <errno.h>
+#include <stddef.h>
+#include <string.h>
+
+#include "base/types.h"
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/conn.h>
+#include <bluetooth/gatt.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/uuid.h>
+#include <logging/bt_log_impl.h>
+
+static void start_scan(void);
+
+static struct bt_conn *default_conn;
+
+static struct bt_uuid_16 uuid = BT_UUID_INIT_16(0);
+static struct bt_gatt_discover_params discover_params;
+static struct bt_gatt_subscribe_params subscribe_params;
+
+static uint8_t notify_func(struct bt_conn *conn, struct bt_gatt_subscribe_params *params,
+                           const void *data, uint16_t length)
+{
+    if (!data)
+    {
+        printk("[UNSUBSCRIBED]\n");
+        params->value_handle = 0U;
+        return BT_GATT_ITER_STOP;
+    }
+
+    printk("[NOTIFICATION] data %p length %u\n", data, length);
+
+    return BT_GATT_ITER_CONTINUE;
+}
+
+static uint8_t discover_func(struct bt_conn *conn, const struct bt_gatt_attr *attr,
+                             struct bt_gatt_discover_params *params)
+{
+    int err;
+
+    if (!attr)
+    {
+        printk("Discover complete\n");
+        (void)memset(params, 0, sizeof(*params));
+        return BT_GATT_ITER_STOP;
+    }
+
+    printk("[ATTRIBUTE] handle %u\n", attr->handle);
+
+    if (!bt_uuid_cmp(discover_params.uuid, BT_UUID_HRS))
+    {
+        memcpy(&uuid, BT_UUID_HRS_MEASUREMENT, sizeof(uuid));
+        discover_params.uuid = &uuid.uuid;
+        discover_params.start_handle = attr->handle + 1;
+        discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC;
+
+        err = bt_gatt_discover(conn, &discover_params);
+        if (err)
+        {
+            printk("Discover failed (err %d)\n", err);
+        }
+    }
+    else if (!bt_uuid_cmp(discover_params.uuid, BT_UUID_HRS_MEASUREMENT))
+    {
+        memcpy(&uuid, BT_UUID_GATT_CCC, sizeof(uuid));
+        discover_params.uuid = &uuid.uuid;
+        discover_params.start_handle = attr->handle + 2;
+        discover_params.type = BT_GATT_DISCOVER_DESCRIPTOR;
+        subscribe_params.value_handle = bt_gatt_attr_value_handle(attr);
+
+        err = bt_gatt_discover(conn, &discover_params);
+        if (err)
+        {
+            printk("Discover failed (err %d)\n", err);
+        }
+    }
+    else
+    {
+        subscribe_params.notify = notify_func;
+        subscribe_params.value = BT_GATT_CCC_NOTIFY;
+        subscribe_params.ccc_handle = attr->handle;
+
+        err = bt_gatt_subscribe(conn, &subscribe_params);
+        if (err && err != -EALREADY)
+        {
+            printk("Subscribe failed (err %d)\n", err);
+        }
+        else
+        {
+            printk("[SUBSCRIBED]\n");
+        }
+
+        return BT_GATT_ITER_STOP;
+    }
+
+    return BT_GATT_ITER_STOP;
+}
+
+static bool eir_found(struct bt_data *data, void *user_data)
+{
+    bt_addr_le_t *addr = user_data;
+    int i;
+
+    printk("[AD]: %u data_len %u\n", data->type, data->data_len);
+
+    switch (data->type)
+    {
+    case BT_DATA_UUID16_SOME:
+    case BT_DATA_UUID16_ALL:
+        if (data->data_len % sizeof(uint16_t) != 0U)
+        {
+            printk("AD malformed\n");
+            return true;
+        }
+
+        for (i = 0; i < data->data_len; i += sizeof(uint16_t))
+        {
+            struct bt_le_conn_param *param;
+            struct bt_uuid *uuid;
+            uint16_t u16;
+            int err;
+
+            memcpy(&u16, &data->data[i], sizeof(u16));
+            uuid = BT_UUID_DECLARE_16(u16);
+            if (bt_uuid_cmp(uuid, BT_UUID_HRS))
+            {
+                continue;
+            }
+
+            err = bt_le_scan_stop();
+            if (err)
+            {
+                printk("Stop LE scan failed (err %d)\n", err);
+                continue;
+            }
+
+            param = BT_LE_CONN_PARAM_DEFAULT;
+            err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, param, &default_conn);
+            if (err)
+            {
+                printk("Create conn failed (err %d)\n", err);
+                start_scan();
+            }
+
+            return false;
+        }
+    }
+
+    return true;
+}
+
+static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type,
+                         struct net_buf_simple *ad)
+{
+    char dev[BT_ADDR_LE_STR_LEN];
+
+    bt_addr_le_to_str(addr, dev, sizeof(dev));
+    printk("[DEVICE]: %s, AD evt type %u, AD data len %u, RSSI %i\n", dev, type, ad->len, rssi);
+
+    /* We're only interested in connectable events */
+    if (type == BT_GAP_ADV_TYPE_ADV_IND || type == BT_GAP_ADV_TYPE_ADV_DIRECT_IND)
+    {
+        bt_data_parse(ad, eir_found, (void *)addr);
+    }
+}
+
+static void start_scan(void)
+{
+    int err;
+
+    /* Use active scanning and disable duplicate filtering to handle any
+     * devices that might update their advertising data at runtime. */
+    struct bt_le_scan_param scan_param = {
+            .type = BT_LE_SCAN_TYPE_ACTIVE,
+            .options = BT_LE_SCAN_OPT_NONE,
+            .interval = BT_GAP_SCAN_FAST_INTERVAL,
+            .window = BT_GAP_SCAN_FAST_WINDOW,
+    };
+
+    err = bt_le_scan_start(&scan_param, device_found);
+    if (err)
+    {
+        printk("Scanning failed to start (err %d)\n", err);
+        return;
+    }
+
+    printk("Scanning successfully started\n");
+}
+
+static void connected(struct bt_conn *conn, uint8_t conn_err)
+{
+    char addr[BT_ADDR_LE_STR_LEN];
+    int err;
+
+    bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
+
+    if (conn_err)
+    {
+        printk("Failed to connect to %s (%u)\n", addr, conn_err);
+
+        // bt_conn_unref(default_conn);
+        default_conn = NULL;
+
+        start_scan();
+        return;
+    }
+
+    printk("Connected: %s\n", addr);
+
+    if (conn == default_conn)
+    {
+        memcpy(&uuid, BT_UUID_HRS, sizeof(uuid));
+        discover_params.uuid = &uuid.uuid;
+        discover_params.func = discover_func;
+        discover_params.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE;
+        discover_params.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE;
+        discover_params.type = BT_GATT_DISCOVER_PRIMARY;
+
+        err = bt_gatt_discover(default_conn, &discover_params);
+        if (err)
+        {
+            printk("Discover failed(err %d)\n", err);
+            return;
+        }
+    }
+}
+
+static void disconnected(struct bt_conn *conn, uint8_t reason)
+{
+    char addr[BT_ADDR_LE_STR_LEN];
+
+    bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
+
+    printk("Disconnected: %s (reason 0x%02x)\n", addr, reason);
+
+    if (default_conn != conn)
+    {
+        return;
+    }
+
+    // bt_conn_unref(default_conn);
+    default_conn = NULL;
+
+    start_scan();
+}
+
+static struct bt_conn_cb conn_callbacks = {
+        .connected = connected,
+        .disconnected = disconnected,
+};
+
+void bt_ready(int err)
+{
+    if (err)
+    {
+        printk("Bluetooth init failed (err %d)\n", err);
+        return;
+    }
+
+    printk("Bluetooth initialized\n");
+
+    bt_conn_cb_register(&conn_callbacks);
+
+    start_scan();
+}
+
+void app_polling_work(void)
+{
+}

+ 60 - 0
example/central_hr/autoconfig.h

@@ -0,0 +1,60 @@
+#define CONFIG_BT 1
+#define CONFIG_BT_LOG_LEVEL_INF 1
+#define CONFIG_BT_LOG_LEVEL 3
+#define CONFIG_BT_CENTRAL 1
+#define CONFIG_BT_OBSERVER 1
+#define CONFIG_BT_CONN 1
+#define CONFIG_BT_MAX_CONN 1
+#define CONFIG_BT_CONN_TX 1
+#define CONFIG_BT_PHY_UPDATE 1
+#define CONFIG_BT_DATA_LEN_UPDATE 1
+#define CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC 1000
+#define CONFIG_SYS_CLOCK_TICKS_PER_SEC 1000
+#define CONFIG_SYS_CLOCK_MAX_TIMEOUT_DAYS 365
+#define CONFIG_BT_BUF_ACL_TX_SIZE 27
+#define CONFIG_BT_BUF_ACL_TX_COUNT 3
+#define CONFIG_BT_BUF_ACL_RX_SIZE 69
+#define CONFIG_BT_BUF_ACL_RX_COUNT 6
+#define CONFIG_BT_BUF_EVT_RX_SIZE 68
+#define CONFIG_BT_BUF_EVT_RX_COUNT 10
+#define CONFIG_BT_BUF_EVT_DISCARDABLE_SIZE 43
+#define CONFIG_BT_BUF_EVT_DISCARDABLE_COUNT 3
+#define CONFIG_BT_BUF_CMD_TX_SIZE 255
+#define CONFIG_BT_BUF_CMD_TX_COUNT 6
+#define CONFIG_BT_RPA 1
+#define CONFIG_BT_ASSERT 1
+#define CONFIG_BT_ASSERT_VERBOSE 1
+#define CONFIG_BT_DEBUG 1
+#define CONFIG_BT_DEBUG_LOG 1
+#define CONFIG_BT_HCI_RESERVE 0
+#define CONFIG_BT_RX_PRIO 8
+#define CONFIG_BT_DRIVER_RX_HIGH_PRIO 6
+#define CONFIG_BT_HOST_CRYPTO 1
+#define CONFIG_BT_HOST_CRYPTO_PRNG 1
+#define CONFIG_BT_CONN_TX_MAX 3
+#define CONFIG_BT_AUTO_PHY_UPDATE 1
+#define CONFIG_BT_AUTO_DATA_LEN_UPDATE 1
+#define CONFIG_BT_SMP 1
+#define CONFIG_BT_BONDABLE 1
+#define CONFIG_BT_SMP_ENFORCE_MITM 1
+#define CONFIG_BT_SMP_MIN_ENC_KEY_SIZE 7
+#define CONFIG_BT_L2CAP_TX_BUF_COUNT 3
+#define CONFIG_BT_L2CAP_TX_FRAG_COUNT 0
+#define CONFIG_BT_L2CAP_TX_MTU 65
+#define CONFIG_BT_GATT_FIXED_SERVICES_SIZE 7
+#define CONFIG_BT_ATT_PREPARE_COUNT 0
+#define CONFIG_BT_ATT_RETRY_ON_SEC_ERR 1
+#define CONFIG_BT_GATT_AUTO_SEC_REQ 1
+#define CONFIG_BT_GATT_CLIENT 1
+#define CONFIG_BT_GATT_READ_MULTIPLE 1
+#define CONFIG_BT_GATT_READ_MULT_VAR_LEN 1
+#define CONFIG_BT_MAX_PAIRED 1
+#define CONFIG_BT_CREATE_CONN_TIMEOUT 3
+#define CONFIG_BT_CONN_PARAM_UPDATE_TIMEOUT 5000
+#define CONFIG_BT_BACKGROUND_SCAN_INTERVAL 2048
+#define CONFIG_BT_BACKGROUND_SCAN_WINDOW 18
+#define CONFIG_BT_DEVICE_NAME "Zephyr"
+#define CONFIG_BT_DEVICE_APPEARANCE 0
+#define CONFIG_BT_ID_MAX 1
+#define CONFIG_BT_ECC 1
+#define CONFIG_BT_COMPANY_ID 0x05F1

+ 8 - 0
example/central_hr/build.mk

@@ -0,0 +1,8 @@
+# define source directory
+SRC		+= $(APP_PATH)
+
+# define include directory
+INCLUDE	+= $(APP_PATH)
+
+# define lib directory
+LIB		+=

+ 5 - 0
example/central_hr/prj.conf

@@ -0,0 +1,5 @@
+CONFIG_BT=y
+CONFIG_BT_DEBUG_LOG=y
+CONFIG_BT_CENTRAL=y
+CONFIG_BT_SMP=y
+CONFIG_BT_GATT_CLIENT=y

+ 313 - 0
example/central_ht/app_main.c

@@ -0,0 +1,313 @@
+/* main.c - Application main entry point */
+
+/*
+ * Copyright (c) 2015-2016 Intel Corporation
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <errno.h>
+#include <stddef.h>
+#include <string.h>
+
+#include "base/byteorder.h"
+#include "base/types.h"
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/conn.h>
+#include <bluetooth/gatt.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/uuid.h>
+#include <logging/bt_log_impl.h>
+
+static int scan_start(void);
+
+static struct bt_conn *default_conn;
+static struct bt_uuid_16 uuid = BT_UUID_INIT_16(0);
+static struct bt_gatt_discover_params discover_params;
+static struct bt_gatt_subscribe_params subscribe_params;
+
+static double pow(double x, double y)
+{
+    double result = 1;
+
+    if (y < 0)
+    {
+        y = -y;
+        while (y--)
+        {
+            result /= x;
+        }
+    }
+    else
+    {
+        while (y--)
+        {
+            result *= x;
+        }
+    }
+
+    return result;
+}
+
+static uint8_t notify_func(struct bt_conn *conn, struct bt_gatt_subscribe_params *params,
+                           const void *data, uint16_t length)
+{
+    double temperature;
+    uint32_t mantissa;
+    int8_t exponent;
+
+    if (!data)
+    {
+        printk("[UNSUBSCRIBED]\n");
+        params->value_handle = 0U;
+        return BT_GATT_ITER_STOP;
+    }
+
+    /* temperature value display */
+    mantissa = sys_get_le24(&((uint8_t *)data)[1]);
+    exponent = ((uint8_t *)data)[4];
+    temperature = (double)mantissa * pow(10, exponent);
+
+    printf("Temperature %gC.\n", temperature);
+
+    return BT_GATT_ITER_CONTINUE;
+}
+
+static uint8_t discover_func(struct bt_conn *conn, const struct bt_gatt_attr *attr,
+                             struct bt_gatt_discover_params *params)
+{
+    int err;
+
+    if (!attr)
+    {
+        printk("Discover complete\n");
+        (void)memset(params, 0, sizeof(*params));
+        return BT_GATT_ITER_STOP;
+    }
+
+    printk("[ATTRIBUTE] handle %u\n", attr->handle);
+
+    if (!bt_uuid_cmp(discover_params.uuid, BT_UUID_HTS))
+    {
+        memcpy(&uuid, BT_UUID_HTS_MEASUREMENT, sizeof(uuid));
+        discover_params.uuid = &uuid.uuid;
+        discover_params.start_handle = attr->handle + 1;
+        discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC;
+
+        err = bt_gatt_discover(conn, &discover_params);
+        if (err)
+        {
+            printk("Discover failed (err %d)\n", err);
+        }
+    }
+    else if (!bt_uuid_cmp(discover_params.uuid, BT_UUID_HTS_MEASUREMENT))
+    {
+        memcpy(&uuid, BT_UUID_GATT_CCC, sizeof(uuid));
+        discover_params.uuid = &uuid.uuid;
+        discover_params.start_handle = attr->handle + 2;
+        discover_params.type = BT_GATT_DISCOVER_DESCRIPTOR;
+        subscribe_params.value_handle = bt_gatt_attr_value_handle(attr);
+
+        err = bt_gatt_discover(conn, &discover_params);
+        if (err)
+        {
+            printk("Discover failed (err %d)\n", err);
+        }
+    }
+    else
+    {
+        subscribe_params.notify = notify_func;
+        subscribe_params.value = BT_GATT_CCC_INDICATE;
+        subscribe_params.ccc_handle = attr->handle;
+
+        err = bt_gatt_subscribe(conn, &subscribe_params);
+        if (err && err != -EALREADY)
+        {
+            printk("Subscribe failed (err %d)\n", err);
+        }
+        else
+        {
+            printk("[SUBSCRIBED]\n");
+        }
+
+        return BT_GATT_ITER_STOP;
+    }
+
+    return BT_GATT_ITER_STOP;
+}
+
+static void connected(struct bt_conn *conn, uint8_t conn_err)
+{
+    char addr[BT_ADDR_LE_STR_LEN];
+    int err;
+
+    bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
+
+    if (conn_err)
+    {
+        printk("Failed to connect to %s (%u)\n", addr, conn_err);
+
+        // bt_conn_unref(default_conn);
+        default_conn = NULL;
+
+        scan_start();
+        return;
+    }
+
+    printk("Connected: %s\n", addr);
+
+    if (conn == default_conn)
+    {
+        memcpy(&uuid, BT_UUID_HTS, sizeof(uuid));
+        discover_params.uuid = &uuid.uuid;
+        discover_params.func = discover_func;
+        discover_params.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE;
+        discover_params.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE;
+        discover_params.type = BT_GATT_DISCOVER_PRIMARY;
+
+        err = bt_gatt_discover(default_conn, &discover_params);
+        if (err)
+        {
+            printk("Discover failed(err %d)\n", err);
+            return;
+        }
+    }
+}
+
+static bool eir_found(struct bt_data *data, void *user_data)
+{
+    bt_addr_le_t *addr = user_data;
+    int i;
+
+    printk("[AD]: %u data_len %u\n", data->type, data->data_len);
+
+    switch (data->type)
+    {
+    case BT_DATA_UUID16_SOME:
+    case BT_DATA_UUID16_ALL:
+        if (data->data_len % sizeof(uint16_t) != 0U)
+        {
+            printk("AD malformed\n");
+            return true;
+        }
+
+        for (i = 0; i < data->data_len; i += sizeof(uint16_t))
+        {
+            struct bt_uuid *uuid;
+            uint16_t u16;
+            int err;
+
+            memcpy(&u16, &data->data[i], sizeof(u16));
+            uuid = BT_UUID_DECLARE_16(sys_le16_to_cpu(u16));
+            if (bt_uuid_cmp(uuid, BT_UUID_HTS))
+            {
+                continue;
+            }
+
+            err = bt_le_scan_stop();
+            if (err)
+            {
+                printk("Stop LE scan failed (err %d)\n", err);
+                continue;
+            }
+
+            err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, BT_LE_CONN_PARAM_DEFAULT,
+                                    &default_conn);
+            if (err)
+            {
+                printk("Create connection failed (err %d)\n", err);
+                scan_start();
+            }
+
+            return false;
+        }
+    }
+
+    return true;
+}
+
+static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type,
+                         struct net_buf_simple *ad)
+{
+    char dev[BT_ADDR_LE_STR_LEN];
+
+    bt_addr_le_to_str(addr, dev, sizeof(dev));
+    printk("[DEVICE]: %s, AD evt type %u, AD data len %u, RSSI %i\n", dev, type, ad->len, rssi);
+
+    /* We're only interested in connectable events */
+    if (type == BT_HCI_ADV_IND || type == BT_HCI_ADV_DIRECT_IND)
+    {
+        bt_data_parse(ad, eir_found, (void *)addr);
+    }
+}
+
+static int scan_start(void)
+{
+    /* Use active scanning and disable duplicate filtering to handle any
+     * devices that might update their advertising data at runtime.
+     */
+    struct bt_le_scan_param scan_param = {
+            .type = BT_LE_SCAN_TYPE_ACTIVE,
+            .options = BT_LE_SCAN_OPT_NONE,
+            .interval = BT_GAP_SCAN_FAST_INTERVAL,
+            .window = BT_GAP_SCAN_FAST_WINDOW,
+    };
+
+    return bt_le_scan_start(&scan_param, device_found);
+}
+
+static void disconnected(struct bt_conn *conn, uint8_t reason)
+{
+    char addr[BT_ADDR_LE_STR_LEN];
+    int err;
+
+    bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
+
+    printk("Disconnected: %s (reason 0x%02x)\n", addr, reason);
+
+    if (default_conn != conn)
+    {
+        return;
+    }
+
+    // bt_conn_unref(default_conn);
+    default_conn = NULL;
+
+    err = scan_start();
+    if (err)
+    {
+        printk("Scanning failed to start (err %d)\n", err);
+    }
+}
+
+static struct bt_conn_cb conn_callbacks = {
+        .connected = connected,
+        .disconnected = disconnected,
+};
+
+void bt_ready(int err)
+{
+    if (err)
+    {
+        printk("Bluetooth init failed (err %d)\n", err);
+        return;
+    }
+
+    printk("Bluetooth initialized\n");
+
+    bt_conn_cb_register(&conn_callbacks);
+
+    err = scan_start();
+
+    if (err)
+    {
+        printk("Scanning failed to start (err %d)\n", err);
+        return;
+    }
+
+    printk("Scanning successfully started\n");
+}
+
+void app_polling_work(void)
+{
+}

+ 60 - 0
example/central_ht/autoconfig.h

@@ -0,0 +1,60 @@
+#define CONFIG_BT 1
+#define CONFIG_BT_LOG_LEVEL_INF 1
+#define CONFIG_BT_LOG_LEVEL 3
+#define CONFIG_BT_CENTRAL 1
+#define CONFIG_BT_OBSERVER 1
+#define CONFIG_BT_CONN 1
+#define CONFIG_BT_MAX_CONN 1
+#define CONFIG_BT_CONN_TX 1
+#define CONFIG_BT_PHY_UPDATE 1
+#define CONFIG_BT_DATA_LEN_UPDATE 1
+#define CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC 1000
+#define CONFIG_SYS_CLOCK_TICKS_PER_SEC 1000
+#define CONFIG_SYS_CLOCK_MAX_TIMEOUT_DAYS 365
+#define CONFIG_BT_BUF_ACL_TX_SIZE 27
+#define CONFIG_BT_BUF_ACL_TX_COUNT 3
+#define CONFIG_BT_BUF_ACL_RX_SIZE 69
+#define CONFIG_BT_BUF_ACL_RX_COUNT 6
+#define CONFIG_BT_BUF_EVT_RX_SIZE 68
+#define CONFIG_BT_BUF_EVT_RX_COUNT 10
+#define CONFIG_BT_BUF_EVT_DISCARDABLE_SIZE 43
+#define CONFIG_BT_BUF_EVT_DISCARDABLE_COUNT 3
+#define CONFIG_BT_BUF_CMD_TX_SIZE 255
+#define CONFIG_BT_BUF_CMD_TX_COUNT 6
+#define CONFIG_BT_RPA 1
+#define CONFIG_BT_ASSERT 1
+#define CONFIG_BT_ASSERT_VERBOSE 1
+#define CONFIG_BT_DEBUG 1
+#define CONFIG_BT_DEBUG_LOG 1
+#define CONFIG_BT_HCI_RESERVE 0
+#define CONFIG_BT_RX_PRIO 8
+#define CONFIG_BT_DRIVER_RX_HIGH_PRIO 6
+#define CONFIG_BT_HOST_CRYPTO 1
+#define CONFIG_BT_HOST_CRYPTO_PRNG 1
+#define CONFIG_BT_CONN_TX_MAX 3
+#define CONFIG_BT_AUTO_PHY_UPDATE 1
+#define CONFIG_BT_AUTO_DATA_LEN_UPDATE 1
+#define CONFIG_BT_SMP 1
+#define CONFIG_BT_BONDABLE 1
+#define CONFIG_BT_SMP_ENFORCE_MITM 1
+#define CONFIG_BT_SMP_MIN_ENC_KEY_SIZE 7
+#define CONFIG_BT_L2CAP_TX_BUF_COUNT 3
+#define CONFIG_BT_L2CAP_TX_FRAG_COUNT 0
+#define CONFIG_BT_L2CAP_TX_MTU 65
+#define CONFIG_BT_GATT_FIXED_SERVICES_SIZE 7
+#define CONFIG_BT_ATT_PREPARE_COUNT 0
+#define CONFIG_BT_ATT_RETRY_ON_SEC_ERR 1
+#define CONFIG_BT_GATT_AUTO_SEC_REQ 1
+#define CONFIG_BT_GATT_CLIENT 1
+#define CONFIG_BT_GATT_READ_MULTIPLE 1
+#define CONFIG_BT_GATT_READ_MULT_VAR_LEN 1
+#define CONFIG_BT_MAX_PAIRED 1
+#define CONFIG_BT_CREATE_CONN_TIMEOUT 3
+#define CONFIG_BT_CONN_PARAM_UPDATE_TIMEOUT 5000
+#define CONFIG_BT_BACKGROUND_SCAN_INTERVAL 2048
+#define CONFIG_BT_BACKGROUND_SCAN_WINDOW 18
+#define CONFIG_BT_DEVICE_NAME "Zephyr"
+#define CONFIG_BT_DEVICE_APPEARANCE 0
+#define CONFIG_BT_ID_MAX 1
+#define CONFIG_BT_ECC 1
+#define CONFIG_BT_COMPANY_ID 0x05F1

+ 8 - 0
example/central_ht/build.mk

@@ -0,0 +1,8 @@
+# define source directory
+SRC		+= $(APP_PATH)
+
+# define include directory
+INCLUDE	+= $(APP_PATH)
+
+# define lib directory
+LIB		+=

+ 5 - 0
example/central_ht/prj.conf

@@ -0,0 +1,5 @@
+CONFIG_BT=y
+CONFIG_BT_DEBUG_LOG=y
+CONFIG_BT_CENTRAL=y
+CONFIG_BT_SMP=y
+CONFIG_BT_GATT_CLIENT=y

+ 694 - 0
example/eddystone/app_main.c

@@ -0,0 +1,694 @@
+/* main.c - Application main entry point */
+
+/*
+ * Copyright (c) 2015-2016 Intel Corporation
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <errno.h>
+#include <stddef.h>
+#include <string.h>
+
+#include "base/byteorder.h"
+#include "base/types.h"
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/conn.h>
+#include <bluetooth/gatt.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/uuid.h>
+#include <logging/bt_log_impl.h>
+#include "common\timer.h"
+
+#define NUMBER_OF_SLOTS      1
+#define EDS_VERSION          0x00
+#define EDS_URL_READ_OFFSET  2
+#define EDS_URL_WRITE_OFFSET 4
+#define EDS_IDLE_TIMEOUT     K_SECONDS(30)
+
+/* Idle timer */
+struct k_timer idle_work;
+
+static const struct bt_data ad[] = {
+        BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
+        /* Eddystone Service UUID a3c87500-8ed3-4bdf-8a39-a01bebede295 */
+        BT_DATA_BYTES(BT_DATA_UUID128_ALL, 0x95, 0xe2, 0xed, 0xeb, 0x1b, 0xa0, 0x39, 0x8a, 0xdf,
+                      0x4b, 0xd3, 0x8e, 0x00, 0x75, 0xc8, 0xa3),
+};
+
+/* Eddystone Service Variables */
+/* Service UUID a3c87500-8ed3-4bdf-8a39-a01bebede295 */
+static struct bt_uuid_128 eds_uuid =
+        BT_UUID_INIT_128(BT_UUID_128_ENCODE(0xa3c87500, 0x8ed3, 0x4bdf, 0x8a39, 0xa01bebede295));
+
+/* Characteristic UUID a3c87501-8ed3-4bdf-8a39-a01bebede295 */
+static struct bt_uuid_128 eds_caps_uuid =
+        BT_UUID_INIT_128(BT_UUID_128_ENCODE(0xa3c87501, 0x8ed3, 0x4bdf, 0x8a39, 0xa01bebede295));
+
+/* Characteristic UUID a3c87502-8ed3-4bdf-8a39-a01bebede295 */
+static struct bt_uuid_128 eds_slot_uuid =
+        BT_UUID_INIT_128(BT_UUID_128_ENCODE(0xa3c87502, 0x8ed3, 0x4bdf, 0x8a39, 0xa01bebede295));
+
+/* Characteristic UUID a3c87503-8ed3-4bdf-8a39-a01bebede295 */
+static struct bt_uuid_128 eds_intv_uuid =
+        BT_UUID_INIT_128(BT_UUID_128_ENCODE(0xa3c87503, 0x8ed3, 0x4bdf, 0x8a39, 0xa01bebede295));
+
+/* Characteristic UUID a3c87504-8ed3-4bdf-8a39-a01bebede295 */
+static struct bt_uuid_128 eds_tx_uuid =
+        BT_UUID_INIT_128(BT_UUID_128_ENCODE(0xa3c87504, 0x8ed3, 0x4bdf, 0x8a39, 0xa01bebede295));
+
+/* Characteristic UUID a3c87505-8ed3-4bdf-8a39-a01bebede295 */
+static struct bt_uuid_128 eds_adv_tx_uuid =
+        BT_UUID_INIT_128(BT_UUID_128_ENCODE(0xa3c87505, 0x8ed3, 0x4bdf, 0x8a39, 0xa01bebede295));
+
+/* Characteristic UUID a3c87506-8ed3-4bdf-8a39-a01bebede295 */
+static struct bt_uuid_128 eds_lock_uuid =
+        BT_UUID_INIT_128(BT_UUID_128_ENCODE(0xa3c87506, 0x8ed3, 0x4bdf, 0x8a39, 0xa01bebede295));
+
+/* Characteristic UUID a3c87507-8ed3-4bdf-8a39-a01bebede295 */
+static struct bt_uuid_128 eds_unlock_uuid =
+        BT_UUID_INIT_128(BT_UUID_128_ENCODE(0xa3c87507, 0x8ed3, 0x4bdf, 0x8a39, 0xa01bebede295));
+
+/* Characteristic UUID a3c87508-8ed3-4bdf-8a39-a01bebede295 */
+static struct bt_uuid_128 eds_ecdh_uuid =
+        BT_UUID_INIT_128(BT_UUID_128_ENCODE(0xa3c87508, 0x8ed3, 0x4bdf, 0x8a39, 0xa01bebede295));
+
+/* Characteristic UUID a3c87509-8ed3-4bdf-8a39-a01bebede295 */
+static struct bt_uuid_128 eds_eid_uuid =
+        BT_UUID_INIT_128(BT_UUID_128_ENCODE(0xa3c87509, 0x8ed3, 0x4bdf, 0x8a39, 0xa01bebede295));
+
+/* Characteristic UUID a3c8750a-8ed3-4bdf-8a39-a01bebede295 */
+static struct bt_uuid_128 eds_data_uuid =
+        BT_UUID_INIT_128(BT_UUID_128_ENCODE(0xa3c8750a, 0x8ed3, 0x4bdf, 0x8a39, 0xa01bebede295));
+
+/* Characteristic UUID a3c8750b-8ed3-4bdf-8a39-a01bebede295 */
+static struct bt_uuid_128 eds_reset_uuid =
+        BT_UUID_INIT_128(BT_UUID_128_ENCODE(0xa3c8750b, 0x8ed3, 0x4bdf, 0x8a39, 0xa01bebede295));
+
+/* Characteristic UUID a3c8750c-8ed3-4bdf-8a39-a01bebede295 */
+static struct bt_uuid_128 eds_connectable_uuid =
+        BT_UUID_INIT_128(BT_UUID_128_ENCODE(0xa3c8750c, 0x8ed3, 0x4bdf, 0x8a39, 0xa01bebede295));
+
+enum
+{
+    EDS_TYPE_UID = 0x00,
+    EDS_TYPE_URL = 0x10,
+    EDS_TYPE_TLM = 0x20,
+    EDS_TYPE_EID = 0x30,
+    EDS_TYPE_NONE = 0xff,
+};
+
+enum
+{
+    EDS_SLOT_UID = sys_cpu_to_be16(BIT(0)),
+    EDS_SLOT_URL = sys_cpu_to_be16(BIT(1)),
+    EDS_SLOT_TLM = sys_cpu_to_be16(BIT(2)),
+    EDS_SLOT_EID = sys_cpu_to_be16(BIT(3)),
+};
+
+struct eds_capabilities
+{
+    uint8_t version;
+    uint8_t slots;
+    uint8_t uids;
+    uint8_t adv_types;
+    uint16_t slot_types;
+    uint8_t tx_power;
+} __packed;
+
+static struct eds_capabilities eds_caps = {
+        .version = EDS_VERSION,
+        .slots = NUMBER_OF_SLOTS,
+        .slot_types = EDS_SLOT_URL, /* TODO: Add support for other slot types */
+};
+
+uint8_t eds_active_slot;
+
+enum
+{
+    EDS_LOCKED = 0x00,
+    EDS_UNLOCKED = 0x01,
+    EDS_UNLOCKED_NO_RELOCKING = 0x02,
+};
+
+struct eds_slot
+{
+    uint8_t type;
+    uint8_t state;
+    uint8_t connectable;
+    uint16_t interval;
+    uint8_t tx_power;
+    uint8_t adv_tx_power;
+    uint8_t lock[16];
+    uint8_t challenge[16];
+    struct bt_data ad[3];
+};
+
+static struct eds_slot eds_slots[NUMBER_OF_SLOTS] = {
+        [0 ...(NUMBER_OF_SLOTS - 1)] =
+                {
+                        .type = EDS_TYPE_NONE, /* Start as disabled */
+                        .state = EDS_UNLOCKED, /* Start unlocked */
+                        .interval = sys_cpu_to_be16(BT_GAP_ADV_FAST_INT_MIN_2),
+                        .lock = {'Z', 'e', 'p', 'h', 'y', 'r', ' ', 'E', 'd', 'd', 'y', 's', 't',
+                                 'o', 'n', 'e'},
+                        .challenge = {},
+                        .ad =
+                                {
+                                        BT_DATA_BYTES(BT_DATA_FLAGS, BT_LE_AD_NO_BREDR),
+                                        BT_DATA_BYTES(BT_DATA_UUID16_ALL, 0xaa, 0xfe),
+                                        BT_DATA_BYTES(BT_DATA_SVC_DATA16, 0xaa,
+                                                      0xfe, /* Eddystone UUID */
+                                                      0x10, /* Eddystone-URL frame type */
+                                                      0x00, /* Calibrated Tx power at 0m */
+                                                      0x00, /* URL Scheme Prefix http://www. */
+                                                      'z', 'e', 'p', 'h', 'y', 'r', 'p', 'r', 'o',
+                                                      'j', 'e', 'c', 't', 0x08) /* .org */
+                                },
+                },
+};
+
+static ssize_t read_caps(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf,
+                         uint16_t len, uint16_t offset)
+{
+    const struct eds_capabilities *caps = attr->user_data;
+
+    return bt_gatt_attr_read(conn, attr, buf, len, offset, caps, sizeof(*caps));
+}
+
+static ssize_t read_slot(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf,
+                         uint16_t len, uint16_t offset)
+{
+    return bt_gatt_attr_read(conn, attr, buf, len, offset, &eds_active_slot,
+                             sizeof(eds_active_slot));
+}
+
+static ssize_t write_slot(struct bt_conn *conn, const struct bt_gatt_attr *attr, const void *buf,
+                          uint16_t len, uint16_t offset, uint8_t flags)
+{
+    uint8_t value;
+
+    if (offset + len > sizeof(value))
+    {
+        return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET);
+    }
+
+    memcpy(&value, buf, len);
+
+    if (value + 1 > NUMBER_OF_SLOTS)
+    {
+        return BT_GATT_ERR(BT_ATT_ERR_WRITE_NOT_PERMITTED);
+    }
+
+    eds_active_slot = value;
+
+    return len;
+}
+
+static ssize_t read_tx_power(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf,
+                             uint16_t len, uint16_t offset)
+{
+    struct eds_slot *slot = &eds_slots[eds_active_slot];
+
+    if (slot->state == EDS_LOCKED)
+    {
+        return BT_GATT_ERR(BT_ATT_ERR_READ_NOT_PERMITTED);
+    }
+
+    return bt_gatt_attr_read(conn, attr, buf, len, offset, &slot->tx_power, sizeof(slot->tx_power));
+}
+
+static ssize_t write_tx_power(struct bt_conn *conn, const struct bt_gatt_attr *attr,
+                              const void *buf, uint16_t len, uint16_t offset, uint8_t flags)
+{
+    struct eds_slot *slot = &eds_slots[eds_active_slot];
+
+    if (slot->state == EDS_LOCKED)
+    {
+        return BT_GATT_ERR(BT_ATT_ERR_WRITE_NOT_PERMITTED);
+    }
+
+    if (offset + len > sizeof(slot->tx_power))
+    {
+        return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET);
+    }
+
+    memcpy(&slot->tx_power, buf, len);
+
+    return len;
+}
+
+static ssize_t read_adv_tx_power(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf,
+                                 uint16_t len, uint16_t offset)
+{
+    struct eds_slot *slot = &eds_slots[eds_active_slot];
+
+    if (slot->state == EDS_LOCKED)
+    {
+        return BT_GATT_ERR(BT_ATT_ERR_READ_NOT_PERMITTED);
+    }
+
+    return bt_gatt_attr_read(conn, attr, buf, len, offset, &slot->tx_power, sizeof(slot->tx_power));
+}
+
+static ssize_t write_adv_tx_power(struct bt_conn *conn, const struct bt_gatt_attr *attr,
+                                  const void *buf, uint16_t len, uint16_t offset, uint8_t flags)
+{
+    struct eds_slot *slot = &eds_slots[eds_active_slot];
+
+    if (slot->state == EDS_LOCKED)
+    {
+        return BT_GATT_ERR(BT_ATT_ERR_WRITE_NOT_PERMITTED);
+    }
+
+    if (offset + len > sizeof(slot->adv_tx_power))
+    {
+        return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET);
+    }
+
+    memcpy(&slot->adv_tx_power, buf, len);
+
+    return len;
+}
+
+static ssize_t read_interval(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf,
+                             uint16_t len, uint16_t offset)
+{
+    struct eds_slot *slot = &eds_slots[eds_active_slot];
+
+    if (slot->state == EDS_LOCKED)
+    {
+        return BT_GATT_ERR(BT_ATT_ERR_WRITE_NOT_PERMITTED);
+    }
+
+    return bt_gatt_attr_read(conn, attr, buf, len, offset, &slot->interval, sizeof(slot->interval));
+}
+
+static ssize_t read_lock(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf,
+                         uint16_t len, uint16_t offset)
+{
+    struct eds_slot *slot = &eds_slots[eds_active_slot];
+
+    return bt_gatt_attr_read(conn, attr, buf, len, offset, &slot->state, sizeof(slot->state));
+}
+
+static ssize_t write_lock(struct bt_conn *conn, const struct bt_gatt_attr *attr, const void *buf,
+                          uint16_t len, uint16_t offset, uint8_t flags)
+{
+    struct eds_slot *slot = &eds_slots[eds_active_slot];
+    uint8_t value;
+
+    if (slot->state == EDS_LOCKED)
+    {
+        return BT_GATT_ERR(BT_ATT_ERR_WRITE_NOT_PERMITTED);
+    }
+
+    if (offset)
+    {
+        return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET);
+    }
+
+    /* Write 1 byte to lock or 17 bytes to transition to a new lock state */
+    if (len != 1U)
+    {
+        /* TODO: Allow setting new lock code, using AES-128-ECB to
+         * decrypt with the existing lock code and set the unencrypted
+         * value as the new code.
+         */
+        return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
+    }
+
+    memcpy(&value, buf, sizeof(value));
+
+    if (value > EDS_UNLOCKED_NO_RELOCKING)
+    {
+        return BT_GATT_ERR(BT_ATT_ERR_WRITE_NOT_PERMITTED);
+    }
+
+    slot->state = value;
+
+    return len;
+}
+
+static ssize_t read_unlock(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf,
+                           uint16_t len, uint16_t offset)
+{
+    struct eds_slot *slot = &eds_slots[eds_active_slot];
+
+    if (slot->state != EDS_LOCKED)
+    {
+        return BT_GATT_ERR(BT_ATT_ERR_READ_NOT_PERMITTED);
+    }
+
+    /* returns a 128-bit challenge token. This token is for one-time use
+     * and cannot be replayed.
+     */
+    if (bt_rand(slot->challenge, sizeof(slot->challenge)))
+    {
+        return BT_GATT_ERR(BT_ATT_ERR_UNLIKELY);
+    }
+
+    return bt_gatt_attr_read(conn, attr, buf, len, offset, slot->challenge,
+                             sizeof(slot->challenge));
+}
+
+static ssize_t write_unlock(struct bt_conn *conn, const struct bt_gatt_attr *attr, const void *buf,
+                            uint16_t len, uint16_t offset, uint8_t flags)
+{
+    struct eds_slot *slot = &eds_slots[eds_active_slot];
+
+    if (slot->state != EDS_LOCKED)
+    {
+        return BT_GATT_ERR(BT_ATT_ERR_READ_NOT_PERMITTED);
+    }
+
+    /* TODO: accepts a 128-bit encrypted value that verifies the client
+     * knows the beacon's lock code.
+     */
+
+    return BT_GATT_ERR(BT_ATT_ERR_NOT_SUPPORTED);
+}
+
+static uint8_t eds_ecdh[32] = {}; /* TODO: Add ECDH key */
+
+static ssize_t read_ecdh(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf,
+                         uint16_t len, uint16_t offset)
+{
+    uint8_t *value = attr->user_data;
+
+    return bt_gatt_attr_read(conn, attr, buf, len, offset, value, sizeof(eds_ecdh));
+}
+
+static uint8_t eds_eid[16] = {}; /* TODO: Add EID key */
+
+static ssize_t read_eid(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf,
+                        uint16_t len, uint16_t offset)
+{
+    uint8_t *value = attr->user_data;
+
+    return bt_gatt_attr_read(conn, attr, buf, len, offset, value, sizeof(eds_eid));
+}
+
+static ssize_t read_adv_data(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf,
+                             uint16_t len, uint16_t offset)
+{
+    struct eds_slot *slot = &eds_slots[eds_active_slot];
+
+    if (slot->state == EDS_LOCKED)
+    {
+        return BT_GATT_ERR(BT_ATT_ERR_READ_NOT_PERMITTED);
+    }
+
+    /* If the slot is currently not broadcasting, reading the slot data
+     * shall return either an empty array or a single byte of 0x00.
+     */
+    if (slot->type == EDS_TYPE_NONE)
+    {
+        return 0;
+    }
+
+    return bt_gatt_attr_read(conn, attr, buf, len, offset, slot->ad[2].data + EDS_URL_READ_OFFSET,
+                             slot->ad[2].data_len - EDS_URL_READ_OFFSET);
+}
+
+static int eds_slot_restart(struct eds_slot *slot, uint8_t type)
+{
+    int err;
+    char addr_s[BT_ADDR_LE_STR_LEN];
+    bt_addr_le_t addr = {0};
+
+    /* Restart advertising */
+    bt_le_adv_stop();
+
+    if (type == EDS_TYPE_NONE)
+    {
+        // struct bt_le_oob oob;
+
+        // /* Restore connectable if slot */
+        // if (bt_le_oob_get_local(BT_ID_DEFAULT, &oob) == 0) {
+        // 	addr = oob.addr;
+        // }
+
+        err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, ARRAY_SIZE(ad), NULL, 0);
+    }
+    else
+    {
+        size_t count = 1;
+
+        bt_id_get(&addr, &count);
+        err = bt_le_adv_start(BT_LE_ADV_NCONN_IDENTITY, slot->ad, ARRAY_SIZE(slot->ad), NULL, 0);
+    }
+
+    if (err)
+    {
+        printk("Advertising failed to start (err %d)\n", err);
+        return err;
+    }
+
+    // bt_addr_le_to_str(&addr, addr_s, sizeof(addr_s));
+    // printk("Advertising as %s\n", addr_s);
+
+    slot->type = type;
+
+    return 0;
+}
+
+static ssize_t write_adv_data(struct bt_conn *conn, const struct bt_gatt_attr *attr,
+                              const void *buf, uint16_t len, uint16_t offset, uint8_t flags)
+{
+    struct eds_slot *slot = &eds_slots[eds_active_slot];
+    uint8_t type;
+
+    if (slot->state == EDS_LOCKED)
+    {
+        return BT_GATT_ERR(BT_ATT_ERR_READ_NOT_PERMITTED);
+    }
+
+    if (offset)
+    {
+        return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET);
+    }
+
+    /* Writing an empty array, clears the slot and stops Tx. */
+    if (!len)
+    {
+        eds_slot_restart(slot, EDS_TYPE_NONE);
+        return len;
+    }
+
+    /* Write length: 17 bytes (UID), 19 bytes (URL), 1 byte (TLM), 34 or
+     * 18 bytes (EID)
+     */
+    if (len > 19)
+    {
+        return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
+    }
+
+    memcpy(&type, buf, sizeof(type));
+
+    switch (type)
+    {
+    case EDS_TYPE_URL:
+        /* written data is just the frame type and any ID-related
+         * information, and doesn't include the Tx power since that is
+         * controlled by characteristics 4 (Radio Tx Power) and
+         * 5 (Advertised Tx Power).
+         */
+        slot->ad[2].data_len = MIN(slot->ad[2].data_len, len + EDS_URL_WRITE_OFFSET);
+        memcpy(&slot->ad[2].data + EDS_URL_WRITE_OFFSET, buf,
+               slot->ad[2].data_len - EDS_URL_WRITE_OFFSET);
+
+        /* Restart slot */
+        if (eds_slot_restart(slot, type) < 0)
+        {
+            return BT_GATT_ERR(BT_ATT_ERR_UNLIKELY);
+        }
+
+        return len;
+    case EDS_TYPE_UID:
+    case EDS_TYPE_TLM:
+    case EDS_TYPE_EID:
+    default:
+        /* TODO: Add support for other types. */
+        return BT_GATT_ERR(BT_ATT_ERR_WRITE_NOT_PERMITTED);
+    }
+}
+
+static ssize_t write_reset(struct bt_conn *conn, const struct bt_gatt_attr *attr, const void *buf,
+                           uint16_t len, uint16_t offset, uint8_t flags)
+{
+    /* TODO: Power cycle or reload for storage the values */
+    return BT_GATT_ERR(BT_ATT_ERR_WRITE_NOT_PERMITTED);
+}
+
+static ssize_t read_connectable(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf,
+                                uint16_t len, uint16_t offset)
+{
+    uint8_t connectable = 0x01;
+
+    /* Returning a non-zero value indicates that the beacon is capable
+     * of becoming non-connectable
+     */
+    return bt_gatt_attr_read(conn, attr, buf, len, offset, &connectable, sizeof(connectable));
+}
+
+static ssize_t write_connectable(struct bt_conn *conn, const struct bt_gatt_attr *attr,
+                                 const void *buf, uint16_t len, uint16_t offset, uint8_t flags)
+{
+    struct eds_slot *slot = &eds_slots[eds_active_slot];
+
+    if (slot->state == EDS_LOCKED)
+    {
+        return BT_GATT_ERR(BT_ATT_ERR_WRITE_NOT_PERMITTED);
+    }
+
+    if (offset)
+    {
+        return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET);
+    }
+
+    if (len > sizeof(slot->connectable))
+    {
+        return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
+    }
+
+    /* If any non-zero value is written, the beacon shall remain in its
+     * connectable state until any other value is written.
+     */
+    memcpy(&slot->connectable, buf, len);
+
+    return len;
+}
+
+/* Eddystone Configuration Service Declaration */
+BT_GATT_SERVICE_DEFINE(
+        eds_svc, BT_GATT_PRIMARY_SERVICE(&eds_uuid),
+        /* Capabilities: Readable only when unlocked. Never writable. */
+        BT_GATT_CHARACTERISTIC(&eds_caps_uuid.uuid, BT_GATT_CHRC_READ, BT_GATT_PERM_READ, read_caps,
+                               NULL, &eds_caps),
+        /* Active slot: Must be unlocked for both read and write. */
+        BT_GATT_CHARACTERISTIC(&eds_slot_uuid.uuid, BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE,
+                               BT_GATT_PERM_READ | BT_GATT_PERM_WRITE, read_slot, write_slot, NULL),
+        /* Advertising Interval: Must be unlocked for both read and write. */
+        BT_GATT_CHARACTERISTIC(&eds_intv_uuid.uuid, BT_GATT_CHRC_READ, BT_GATT_PERM_READ,
+                               read_interval, NULL, NULL),
+        /* Radio TX Power: Must be unlocked for both read and write. */
+        BT_GATT_CHARACTERISTIC(&eds_tx_uuid.uuid, BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE,
+                               BT_GATT_PERM_READ | BT_GATT_PERM_WRITE, read_tx_power,
+                               write_tx_power, NULL),
+        /* Advertised TX Power: Must be unlocked for both read and write. */
+        BT_GATT_CHARACTERISTIC(&eds_adv_tx_uuid.uuid, BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE,
+                               BT_GATT_PERM_READ | BT_GATT_PERM_WRITE, read_adv_tx_power,
+                               write_adv_tx_power, NULL),
+        /* Lock State:
+         * Readable in locked or unlocked state.
+         * Writeable only in unlocked state.
+         */
+        BT_GATT_CHARACTERISTIC(&eds_lock_uuid.uuid, BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE,
+                               BT_GATT_PERM_READ | BT_GATT_PERM_WRITE, read_lock, write_lock, NULL),
+        /* Unlock:
+         * Readable only in locked state.
+         * Writeable only in locked state.
+         */
+        BT_GATT_CHARACTERISTIC(&eds_unlock_uuid.uuid, BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE,
+                               BT_GATT_PERM_READ | BT_GATT_PERM_WRITE, read_unlock, write_unlock,
+                               NULL),
+        /* Public ECDH Key: Readable only in unlocked state. Never writable. */
+        BT_GATT_CHARACTERISTIC(&eds_ecdh_uuid.uuid, BT_GATT_CHRC_READ, BT_GATT_PERM_READ, read_ecdh,
+                               NULL, &eds_ecdh),
+        /* EID Identity Key:Readable only in unlocked state. Never writable. */
+        BT_GATT_CHARACTERISTIC(&eds_eid_uuid.uuid, BT_GATT_CHRC_READ, BT_GATT_PERM_READ, read_eid,
+                               NULL, eds_eid),
+        /* ADV Slot Data: Must be unlocked for both read and write. */
+        BT_GATT_CHARACTERISTIC(&eds_data_uuid.uuid, BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE,
+                               BT_GATT_PERM_READ | BT_GATT_PERM_WRITE, read_adv_data,
+                               write_adv_data, NULL),
+        /* ADV Factory Reset: Must be unlocked for write. */
+        BT_GATT_CHARACTERISTIC(&eds_reset_uuid.uuid, BT_GATT_CHRC_WRITE, BT_GATT_PERM_WRITE, NULL,
+                               write_reset, NULL),
+        /* ADV Remain Connectable: Must be unlocked for write. */
+        BT_GATT_CHARACTERISTIC(&eds_connectable_uuid.uuid, BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE,
+                               BT_GATT_PERM_READ | BT_GATT_PERM_WRITE, read_connectable,
+                               write_connectable, NULL), );
+
+static void idle_timeout(struct k_timer *work)
+{
+    if (eds_slots[eds_active_slot].type == EDS_TYPE_NONE)
+    {
+        printk("Switching to Beacon mode %u.\n", eds_active_slot);
+        eds_slot_restart(&eds_slots[eds_active_slot], EDS_TYPE_URL);
+    }
+}
+
+static void connected(struct bt_conn *conn, uint8_t err)
+{
+    if (err)
+    {
+        printk("Connection failed (err 0x%02x)\n", err);
+    }
+    else
+    {
+        printk("Connected\n");
+        k_timer_stop(&idle_work);
+    }
+}
+
+static void disconnected(struct bt_conn *conn, uint8_t reason)
+{
+    struct eds_slot *slot = &eds_slots[eds_active_slot];
+
+    printk("Disconnected (reason 0x%02x)\n", reason);
+
+    if (!slot->connectable)
+    {
+        k_timer_start(&idle_work, EDS_IDLE_TIMEOUT, Z_TIMEOUT_NO_WAIT);
+    }
+}
+
+static struct bt_conn_cb conn_callbacks = {
+        .connected = connected,
+        .disconnected = disconnected,
+};
+
+void bt_ready(int err)
+{
+    char addr_s[BT_ADDR_LE_STR_LEN];
+    struct bt_le_oob oob;
+
+    if (err)
+    {
+        printk("Bluetooth init failed (err %d)\n", err);
+        return;
+    }
+
+    printk("Bluetooth initialized\n");
+
+    extern struct bt_gatt_service_static _1_gatt_svc;
+    extern struct bt_gatt_service_static _2_gap_svc;
+
+    bt_gatt_service_init(3, _1_gatt_svc, _2_gap_svc, eds_svc);
+
+    bt_conn_cb_register(&conn_callbacks);
+
+    /* Start advertising */
+    err = bt_le_adv_start(BT_LE_ADV_CONN_NAME, ad, ARRAY_SIZE(ad), NULL, 0);
+    if (err)
+    {
+        printk("Advertising failed to start (err %d)\n", err);
+        return;
+    }
+
+    /* Restore connectable if slot */
+    // bt_le_oob_get_local(BT_ID_DEFAULT, &oob);
+    // bt_addr_le_to_str(&oob.addr, addr_s, sizeof(addr_s));
+    // printk("Initial advertising as %s\n", addr_s);
+
+    k_timer_init(&idle_work, idle_timeout, NULL);
+    k_timer_start(&idle_work, EDS_IDLE_TIMEOUT, Z_TIMEOUT_NO_WAIT);
+
+    printk("Configuration mode: waiting connections...\n");
+}
+
+void app_polling_work(void)
+{
+}

+ 56 - 0
example/eddystone/autoconfig.h

@@ -0,0 +1,56 @@
+#define CONFIG_BT 1
+#define CONFIG_BT_LOG_LEVEL_INF 1
+#define CONFIG_BT_LOG_LEVEL 3
+#define CONFIG_BT_PERIPHERAL 1
+#define CONFIG_BT_BROADCASTER 1
+#define CONFIG_BT_CONN 1
+#define CONFIG_BT_MAX_CONN 1
+#define CONFIG_BT_CONN_TX 1
+#define CONFIG_BT_PHY_UPDATE 1
+#define CONFIG_BT_DATA_LEN_UPDATE 1
+#define CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC 1000
+#define CONFIG_SYS_CLOCK_TICKS_PER_SEC 1000
+#define CONFIG_SYS_CLOCK_MAX_TIMEOUT_DAYS 365
+#define CONFIG_BT_BUF_ACL_TX_SIZE 27
+#define CONFIG_BT_BUF_ACL_TX_COUNT 3
+#define CONFIG_BT_BUF_ACL_RX_SIZE 27
+#define CONFIG_BT_BUF_ACL_RX_COUNT 6
+#define CONFIG_BT_BUF_EVT_RX_SIZE 68
+#define CONFIG_BT_BUF_EVT_RX_COUNT 10
+#define CONFIG_BT_BUF_EVT_DISCARDABLE_SIZE 43
+#define CONFIG_BT_BUF_EVT_DISCARDABLE_COUNT 3
+#define CONFIG_BT_BUF_CMD_TX_SIZE 255
+#define CONFIG_BT_BUF_CMD_TX_COUNT 6
+#define CONFIG_BT_ASSERT 1
+#define CONFIG_BT_ASSERT_VERBOSE 1
+#define CONFIG_BT_DEBUG 1
+#define CONFIG_BT_DEBUG_LOG 1
+#define CONFIG_BT_HCI_RESERVE 0
+#define CONFIG_BT_RX_PRIO 8
+#define CONFIG_BT_DRIVER_RX_HIGH_PRIO 6
+#define CONFIG_BT_HOST_CRYPTO 1
+#define CONFIG_BT_HOST_CRYPTO_PRNG 1
+#define CONFIG_BT_LIM_ADV_TIMEOUT 30
+#define CONFIG_BT_CONN_TX_MAX 3
+#define CONFIG_BT_AUTO_PHY_UPDATE 1
+#define CONFIG_BT_AUTO_DATA_LEN_UPDATE 1
+#define CONFIG_BT_L2CAP_TX_BUF_COUNT 3
+#define CONFIG_BT_L2CAP_TX_FRAG_COUNT 0
+#define CONFIG_BT_L2CAP_TX_MTU 23
+#define CONFIG_BT_GATT_FIXED_SERVICES_SIZE 7
+#define CONFIG_BT_ATT_PREPARE_COUNT 0
+#define CONFIG_BT_GATT_READ_MULTIPLE 1
+#define CONFIG_BT_GATT_READ_MULT_VAR_LEN 1
+#define CONFIG_BT_GAP_AUTO_UPDATE_CONN_PARAMS 1
+#define CONFIG_BT_GAP_PERIPHERAL_PREF_PARAMS 1
+#define CONFIG_BT_PERIPHERAL_PREF_MIN_INT 24
+#define CONFIG_BT_PERIPHERAL_PREF_MAX_INT 40
+#define CONFIG_BT_PERIPHERAL_PREF_LATENCY 0
+#define CONFIG_BT_PERIPHERAL_PREF_TIMEOUT 42
+#define CONFIG_BT_MAX_PAIRED 0
+#define CONFIG_BT_CREATE_CONN_TIMEOUT 3
+#define CONFIG_BT_CONN_PARAM_UPDATE_TIMEOUT 5000
+#define CONFIG_BT_DEVICE_NAME "Zephyr Eddystone"
+#define CONFIG_BT_DEVICE_APPEARANCE 0
+#define CONFIG_BT_ID_MAX 1
+#define CONFIG_BT_COMPANY_ID 0x05F1

+ 8 - 0
example/eddystone/build.mk

@@ -0,0 +1,8 @@
+# define source directory
+SRC		+= $(APP_PATH)
+
+# define include directory
+INCLUDE	+= $(APP_PATH)
+
+# define lib directory
+LIB		+=

+ 4 - 0
example/eddystone/prj.conf

@@ -0,0 +1,4 @@
+CONFIG_BT=y
+CONFIG_BT_DEBUG_LOG=y
+CONFIG_BT_PERIPHERAL=y
+CONFIG_BT_DEVICE_NAME="Zephyr Eddystone"

+ 17 - 0
example/empty/app_main.c

@@ -0,0 +1,17 @@
+#include <logging/bt_log_impl.h>
+
+void bt_ready(int err)
+{
+    if (err)
+    {
+        printk("Bluetooth init failed (err %d)\n", err);
+        return;
+    }
+
+    printk("Bluetooth initialized\n");
+}
+
+void app_polling_work(void)
+{
+    return;
+}

+ 31 - 0
example/empty/autoconfig.h

@@ -0,0 +1,31 @@
+#define CONFIG_BT 1
+#define CONFIG_BT_LOG_LEVEL_INF 1
+#define CONFIG_BT_LOG_LEVEL 3
+#define CONFIG_BT_BROADCASTER 1
+#define CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC 1000
+#define CONFIG_SYS_CLOCK_TICKS_PER_SEC 1000
+#define CONFIG_SYS_CLOCK_MAX_TIMEOUT_DAYS 365
+#define CONFIG_BT_BUF_ACL_TX_SIZE 27
+#define CONFIG_BT_BUF_ACL_TX_COUNT 3
+#define CONFIG_BT_BUF_ACL_RX_SIZE 27
+#define CONFIG_BT_BUF_ACL_RX_COUNT 6
+#define CONFIG_BT_BUF_EVT_RX_SIZE 68
+#define CONFIG_BT_BUF_EVT_RX_COUNT 10
+#define CONFIG_BT_BUF_EVT_DISCARDABLE_SIZE 43
+#define CONFIG_BT_BUF_EVT_DISCARDABLE_COUNT 3
+#define CONFIG_BT_BUF_CMD_TX_SIZE 255
+#define CONFIG_BT_BUF_CMD_TX_COUNT 6
+#define CONFIG_BT_ASSERT 1
+#define CONFIG_BT_ASSERT_VERBOSE 1
+#define CONFIG_BT_DEBUG 1
+#define CONFIG_BT_DEBUG_LOG 1
+#define CONFIG_BT_HCI_RESERVE 0
+#define CONFIG_BT_RX_PRIO 8
+#define CONFIG_BT_DRIVER_RX_HIGH_PRIO 6
+#define CONFIG_BT_HOST_CRYPTO 1
+#define CONFIG_BT_HOST_CRYPTO_PRNG 1
+#define CONFIG_BT_LIM_ADV_TIMEOUT 30
+#define CONFIG_BT_DEVICE_NAME "Zephyr"
+#define CONFIG_BT_DEVICE_APPEARANCE 0
+#define CONFIG_BT_ID_MAX 1
+#define CONFIG_BT_COMPANY_ID 0x05F1

+ 8 - 0
example/empty/build.mk

@@ -0,0 +1,8 @@
+# define source directory
+SRC		+= $(APP_PATH)
+
+# define include directory
+INCLUDE	+= $(APP_PATH)
+
+# define lib directory
+LIB		+=

+ 2 - 0
example/empty/prj.conf

@@ -0,0 +1,2 @@
+CONFIG_BT=y
+CONFIG_BT_DEBUG_LOG=y

+ 67 - 0
example/ibeacon/app_main.c

@@ -0,0 +1,67 @@
+/* main.c - Application main entry point */
+
+/*
+ * Copyright (c) 2015-2016 Intel Corporation
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <stddef.h>
+
+#include "base/types.h"
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <logging/bt_log_impl.h>
+
+#ifndef IBEACON_RSSI
+#define IBEACON_RSSI 0xc8
+#endif
+
+/*
+ * Set iBeacon demo advertisement data. These values are for
+ * demonstration only and must be changed for production environments!
+ *
+ * UUID:  18ee1516-016b-4bec-ad96-bcb96d166e97
+ * Major: 0
+ * Minor: 0
+ * RSSI:  -56 dBm
+ */
+static const struct bt_data ad[] = {
+        BT_DATA_BYTES(BT_DATA_FLAGS, BT_LE_AD_NO_BREDR),
+        BT_DATA_BYTES(BT_DATA_MANUFACTURER_DATA, 0x4c, 0x00, /* Apple */
+                      0x02, 0x15,                            /* iBeacon */
+                      0x18, 0xee, 0x15, 0x16,                /* UUID[15..12] */
+                      0x01, 0x6b,                            /* UUID[11..10] */
+                      0x4b, 0xec,                            /* UUID[9..8] */
+                      0xad, 0x96,                            /* UUID[7..6] */
+                      0xbc, 0xb9, 0x6d, 0x16, 0x6e, 0x97,    /* UUID[5..0] */
+                      0x00, 0x00,                            /* Major */
+                      0x00, 0x00,                            /* Minor */
+                      IBEACON_RSSI)                          /* Calibrated RSSI @ 1m */
+};
+
+void bt_ready(int err)
+{
+    if (err)
+    {
+        printk("Bluetooth init failed (err %d)\n", err);
+        return;
+    }
+
+    printk("Bluetooth initialized\n");
+
+    /* Start advertising */
+    err = bt_le_adv_start(BT_LE_ADV_NCONN, ad, ARRAY_SIZE(ad), NULL, 0);
+    if (err)
+    {
+        printk("Advertising failed to start (err %d)\n", err);
+        return;
+    }
+
+    printk("iBeacon started\n");
+}
+
+void app_polling_work(void)
+{
+    return;
+}

+ 31 - 0
example/ibeacon/autoconfig.h

@@ -0,0 +1,31 @@
+#define CONFIG_BT 1
+#define CONFIG_BT_LOG_LEVEL_INF 1
+#define CONFIG_BT_LOG_LEVEL 3
+#define CONFIG_BT_BROADCASTER 1
+#define CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC 1000
+#define CONFIG_SYS_CLOCK_TICKS_PER_SEC 1000
+#define CONFIG_SYS_CLOCK_MAX_TIMEOUT_DAYS 365
+#define CONFIG_BT_BUF_ACL_TX_SIZE 27
+#define CONFIG_BT_BUF_ACL_TX_COUNT 3
+#define CONFIG_BT_BUF_ACL_RX_SIZE 27
+#define CONFIG_BT_BUF_ACL_RX_COUNT 6
+#define CONFIG_BT_BUF_EVT_RX_SIZE 68
+#define CONFIG_BT_BUF_EVT_RX_COUNT 10
+#define CONFIG_BT_BUF_EVT_DISCARDABLE_SIZE 43
+#define CONFIG_BT_BUF_EVT_DISCARDABLE_COUNT 3
+#define CONFIG_BT_BUF_CMD_TX_SIZE 255
+#define CONFIG_BT_BUF_CMD_TX_COUNT 6
+#define CONFIG_BT_ASSERT 1
+#define CONFIG_BT_ASSERT_VERBOSE 1
+#define CONFIG_BT_DEBUG 1
+#define CONFIG_BT_DEBUG_LOG 1
+#define CONFIG_BT_HCI_RESERVE 0
+#define CONFIG_BT_RX_PRIO 8
+#define CONFIG_BT_DRIVER_RX_HIGH_PRIO 6
+#define CONFIG_BT_HOST_CRYPTO 1
+#define CONFIG_BT_HOST_CRYPTO_PRNG 1
+#define CONFIG_BT_LIM_ADV_TIMEOUT 30
+#define CONFIG_BT_DEVICE_NAME "Zephyr"
+#define CONFIG_BT_DEVICE_APPEARANCE 0
+#define CONFIG_BT_ID_MAX 1
+#define CONFIG_BT_COMPANY_ID 0x05F1

+ 8 - 0
example/ibeacon/build.mk

@@ -0,0 +1,8 @@
+# define source directory
+SRC		+= $(APP_PATH)
+
+# define include directory
+INCLUDE	+= $(APP_PATH)
+
+# define lib directory
+LIB		+=

+ 2 - 0
example/ibeacon/prj.conf

@@ -0,0 +1,2 @@
+CONFIG_BT=y
+CONFIG_BT_DEBUG_LOG=y

+ 62 - 0
example/observer/app_main.c

@@ -0,0 +1,62 @@
+/* main.c - Application main entry point */
+
+/*
+ * Copyright (c) 2015-2016 Intel Corporation
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <errno.h>
+#include <stddef.h>
+#include <string.h>
+
+#include "base/byteorder.h"
+#include "base/types.h"
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/conn.h>
+#include <bluetooth/gatt.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/uuid.h>
+#include <logging/bt_log_impl.h>
+#include "common\timer.h"
+
+static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type,
+                         struct net_buf_simple *ad)
+{
+    char addr_str[BT_ADDR_LE_STR_LEN];
+
+    bt_addr_le_to_str(addr, addr_str, sizeof(addr_str));
+    printk("Device found: %s (RSSI %d)\n", addr_str, rssi);
+}
+
+void bt_ready(int err)
+{
+    struct bt_le_scan_param scan_param = {
+            .type = BT_LE_SCAN_TYPE_PASSIVE,
+            .options = BT_LE_SCAN_OPT_FILTER_DUPLICATE,
+            .interval = BT_GAP_SCAN_FAST_INTERVAL,
+            .window = BT_GAP_SCAN_FAST_WINDOW,
+    };
+
+    if (err)
+    {
+        printk("Bluetooth init failed (err %d)\n", err);
+        return;
+    }
+
+    printk("Bluetooth initialized\n");
+
+    printk("Starting Observer\n");
+
+    err = bt_le_scan_start(&scan_param, device_found);
+    printk("\n");
+    if (err)
+    {
+        printk("Starting scanning failed (err %d)\n", err);
+        return;
+    }
+}
+
+void app_polling_work(void)
+{
+}

+ 31 - 0
example/observer/autoconfig.h

@@ -0,0 +1,31 @@
+#define CONFIG_BT 1
+#define CONFIG_BT_LOG_LEVEL_INF 1
+#define CONFIG_BT_LOG_LEVEL 3
+#define CONFIG_BT_OBSERVER 1
+#define CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC 1000
+#define CONFIG_SYS_CLOCK_TICKS_PER_SEC 1000
+#define CONFIG_SYS_CLOCK_MAX_TIMEOUT_DAYS 365
+#define CONFIG_BT_BUF_ACL_TX_SIZE 27
+#define CONFIG_BT_BUF_ACL_TX_COUNT 3
+#define CONFIG_BT_BUF_ACL_RX_SIZE 27
+#define CONFIG_BT_BUF_ACL_RX_COUNT 6
+#define CONFIG_BT_BUF_EVT_RX_SIZE 68
+#define CONFIG_BT_BUF_EVT_RX_COUNT 10
+#define CONFIG_BT_BUF_EVT_DISCARDABLE_SIZE 43
+#define CONFIG_BT_BUF_EVT_DISCARDABLE_COUNT 3
+#define CONFIG_BT_BUF_CMD_TX_SIZE 255
+#define CONFIG_BT_BUF_CMD_TX_COUNT 6
+#define CONFIG_BT_ASSERT 1
+#define CONFIG_BT_ASSERT_VERBOSE 1
+#define CONFIG_BT_DEBUG_NONE 1
+#define CONFIG_BT_HCI_RESERVE 0
+#define CONFIG_BT_RX_PRIO 8
+#define CONFIG_BT_DRIVER_RX_HIGH_PRIO 6
+#define CONFIG_BT_HOST_CRYPTO 1
+#define CONFIG_BT_HOST_CRYPTO_PRNG 1
+#define CONFIG_BT_BACKGROUND_SCAN_INTERVAL 2048
+#define CONFIG_BT_BACKGROUND_SCAN_WINDOW 18
+#define CONFIG_BT_DEVICE_NAME "Zephyr"
+#define CONFIG_BT_DEVICE_APPEARANCE 0
+#define CONFIG_BT_ID_MAX 1
+#define CONFIG_BT_COMPANY_ID 0x05F1

+ 8 - 0
example/observer/build.mk

@@ -0,0 +1,8 @@
+# define source directory
+SRC		+= $(APP_PATH)
+
+# define include directory
+INCLUDE	+= $(APP_PATH)
+
+# define lib directory
+LIB		+=

+ 2 - 0
example/observer/prj.conf

@@ -0,0 +1,2 @@
+CONFIG_BT=y
+CONFIG_BT_OBSERVER=y

Некоторые файлы не были показаны из-за большого количества измененных файлов